Landscape beta: Juju Installation

The Juju based Landscape beta installation will deploy Landscape on a single machine, with each component in its own separate container.


  1. Ubuntu 22.04 or Ubuntu 20.04 installed on a machine with the following minimum specifications:
    • a dual core 2ghz processor
    • 4GB of RAM, or more
    • 10GB of disk space, or more
  2. An IP address with an FQDN. Using a domain name with a public IP allows for valid SSL certificates to be applied, via LetsEncrypt’s certbot.

You will be up and running in 3 simple steps:

  1. Install Juju and deploy the Landscape Scalable charm bundle:
sudo snap install juju --classic
juju bootstrap localhost
juju set-model-constraints arch=$(dpkg --print-architecture)
juju deploy landscape-scalable --channel edge
  1. Install certbot and obtain a valid SSL certificate for (optional):
    replace all instances of in the following steps with your own FQDN
sudo snap install certbot --classic
sudo certbot -d --manual --preferred-challenges dns certonly
FULLCHAIN=$(sudo base64 -w 0 /etc/letsencrypt/live/
PRIVKEY=$(sudo base64 -w 0 /etc/letsencrypt/live/
juju remove-application haproxy --force --no-wait
juju deploy haproxy --config default_timeouts='queue 60000, connect 5000, client 120000, server 120000' --config services='' --config ssl_cert=$FULLCHAIN --config ssl_key=$PRIVKEY --config global_default_bind_options='no-tlsv10' --series focal
juju relate landscape-server haproxy
  1. Expose HAProxy over the host machine’s network interface by opening the LXD firewall, and adding iptables port forwarding rules:
juju expose haproxy
INTERFACE=$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | head -1)
INTERFACE_IP=$(ip -o -4 addr list $INTERFACE | awk '{print $4}' | cut -d'/' -f1)
CONTAINER_IP=$(juju run --unit haproxy/1 "network-get public --ingress-address=true")
sudo -E bash -c "iptables -t nat -I PREROUTING -i $INTERFACE -p tcp -d $INTERFACE_IP --dport $PORT -j DNAT --to-destination $CONTAINER_IP:$PORT -m comment --comment haproxy"
sudo -E bash -c "iptables -t nat -I PREROUTING -i $INTERFACE -p tcp -d $INTERFACE_IP --dport $PORT -j DNAT --to-destination $CONTAINER_IP:$PORT -m comment --comment haproxy"

Hello Rajan,

Is it possible to have a webserver running alongside the landscape-scalable juju installation?
It looks like the ppa installation sets up an apache server in the expected place, but it’s proving difficult to find the same in the juju/snap instances, and Google suggests that I shouldn’t interfere with contained config files anyway.

Can I:
A) modify landscape-scalable’s web configuration to serve some arbitrary number of static files, or
B) modify landscape-scalable’s web configuration to only listen to local traffic, and set up a reverse proxy in front of it?


1 Like

the landscape-quickstart sets up Apache, but the Juju installation sets up HAProxy and points it to a web application running on Twisted in the landscape-server instance. So there is no Apache. If you want to serve static files it sounds like a use-case outside of what Landscape should be doing. Why not spin up an Apache2 instance using Juju:

Then configure that Apache2 instance to do what you want?

Thanks! That set me in the right direction.
Is it considered best-practice then to manually configure the haproxy config file inside the haproxy container?
I’ve succeeded in adding new backends there that point to a full webserver.

1 Like

You should try and configure HAProxy using the Juju configuration parameters. - this makes it easy to decommission an instance and reprovision it. If you have manually configured the instance, you’re not reaping the benefits of Juju

1 Like

Is there a Helm chart for running Landscape? Or do we need to build our own?

Helm charts would be somewhat redundant with our Charms, so there isn’t any planned effort to create these. If you do produce some Helm charts and wish to share them with the world, please consider a PR at

Landscape does not yet have first class support with Kubernetes based deployments. We have put our muscle behind LXC-based containerized deployments, and bare-metal deployments, through Juju and deb/snap packages.

As opportunities present themselves to rebuild pieces of Landscape through a microservices based architecture, we will be paying closer attention to installation journeys which involve Kubernetes.

While there isn’t a planned effort to create Helm charts today, if you do make some and wish to share them with the world, please consider a PR at

1 Like

Hello again Rajan.

I’ve been experimenting with this, and I haven’t found a good way to do it using juju config.
For example, the way Landscape sets up its Haproxy rules seem to hardcode those frontends in a way that are not exposed by juju config haproxy services.

This is problematic because anything else relating with the haproxy application tries to set up its own frontend, bound to, which conflicts with Landscape, and fails.
For example, the canonical-livepatch-server bundle.

Is this intended behavior? Is there a workaround, aside from manually editing haproxy.cfg?
Also, strangely, haproxy.cfg has been resetting, discarding my manual changes but spreading the livepatch config across Landscape backends, causing the livepatch server to enter the balance rotation for landscape requests.

The goal is to have Landscape Server, Snap Store Proxy, Livepatch Server, and a static fileserver with config files, managed by Juju.


Hi ghill,

The HAProxy that is configured to act as a reverse proxy for Landscape Server is pretty tied to Landscape, as you pointed out (what with the port 80 and 443 mappings). Have you thought about using a second HAProxy (or Apache/Nginx) application for the other services, configured separately?

I think this is valuable feedback and we could stand to make the Landscape charm configuration a little more flexible, e.g., allowing for custom ports and paths, so that the same HAProxy could be used simultaneously for other purposes.

1 Like

Good to hear, Mitch, thank you.
Our solution was to put a reverse proxy up in front.

In case anyone else is looking to run Landscape and a snap store proxy side-by-side, registering a client sends a POST request to /v2/snaps/refresh, which haproxy by default translates into a GET request, which gets blocked with a 405 Method Not Allowed message.
Something like this in the haproxy frontend clears it up:
http-request redirect code 307 scheme https if snap

The next pin to knock down is this canonical-livepatch enable POST error…

1 Like