How to install Landscape manually

This is the production deployment recommendation for Landscape Server when Juju isn’t used. At a minimum, you need two machines: the database server and application server.

For a manual installation of Landscape 24.04 LTS or 26.04 LTS:

  • Database server: Runs Ubuntu 22.04 LTS (“jammy”) or Ubuntu 24.04 (“noble”), with the versions of PostgreSQL that are in the Ubuntu archives for Jammy and Noble. Jammy uses PostgreSQL 14 and Noble uses PostgreSQL 16. Landscape 26.04 LTS also runs on Ubuntu 26.04 (“resolute”), which uses PostgreSQL 18.

  • Application server: Runs Ubuntu 22.04 LTS (“jammy”) or Ubuntu 24.04 (“noble”) and hosts the Landscape services. Landscape 26.04 also runs Ubuntu 26.04 LTS (“resolute”).

You’ll also need certain PostgreSQL extensions to setup Landscape. If you’re using a managed PostgreSQL solution, check with your provider to make sure these extensions are available.

Note that manually setting up a Landscape Server Debian package deployment is a long process with many configuration steps.

If you want a Juju-managed, charmed deployment, you can install Landscape Server with Juju. See How to install Landscape Server with Juju or How to install and configure Landscape for high-availability deployments.

If you’re not setting up a real, production deployment and don’t require scaling to a large number of client machines, you can instead install the landscape-server-quickstart package. For details, visit How to install Landscape Server with quickstart mode.

Prepare for the installation

What you’ll need:

  • Ubuntu server install media for the version of Ubuntu you’re using

  • An Ubuntu Pro subscription for access to Landscape and other Pro services. See How to attach your Ubuntu Pro subscription for attaching tokens.

  • Server X509 certificate and key, signed by a publicly known Certificate Authority, and issued for the FQDN hostname of the application server.

  • Custom (internal) CAs can be used, but this process isn’t documented here in depth because many parts of that process take place outside of Landscape. Administrators deploying custom CAs generally know what needs to be done, but there is some guidance throughout this document.

Install the database server

After having installed the basic server profile of Ubuntu Server, you need to install the PostgreSQL database and configure it for use by Landscape.

Install PostgreSQL and required libraries

Run one of the following commands to install the database software.

For an Ubuntu 22.04 (“jammy”) database server:

sudo apt install postgresql postgresql-14-debversion postgresql-plpython3-14 postgresql-contrib

For an Ubuntu 24.04 (“noble”) database server:

sudo apt install postgresql postgresql-16-debversion postgresql-plpython3-16 postgresql-contrib

For an Ubuntu 26.04 (“resolute”) database server:

sudo apt install postgresql postgresql-18-debversion postgresql-plpython3-18 postgresql-contrib

Create a superuser Landscape can use

Landscape needs a database superuser in order to create the lower privilege users it needs to perform routine tasks and access the data, as well as alter the database schema whenever needed:

sudo -u postgres createuser --createdb --createrole --superuser --pwprompt landscape_superuser

You should use a strong password.

Note

Warning! Don’t use an @ symbol in the password.

If this database is going be shared with other services, it’s recommended that another cluster is created instead for those services (or for Landscape). Refer to the PostgreSQL documentation for guidance.

Configure PostgreSQL

Now allow the application server to access this database server. Landscape uses several users for this access, so you’ll need to allow them all. Edit the /etc/postgresql/<VERSION>/main/pg_hba.conf file (where <VERSION> is the installed version of PostgreSQL for example /etc/postgresql/12/...) and add the following to the end:

host all landscape,landscape_maintenance,landscape_superuser <IP-OF-APP> md5

Replace <IP-OF-APP> with the IP address of the application server, followed by /32. Alternatively, you can specify the network address using the CIDR notation. Some examples of valid values:

  • 192.168.122.199/32: the IP address of the APP server

  • 192.168.122.0/24: a network address

Now come changes to the main PostgreSQL configuration file. Edit /etc/postgresql/<VERSION>/main/postgresql.conf and:

  • Find the listen_addresses parameter, which is probably commented, and change it to:

    listen_addresses = '*'
    
  • Set max_prepared_transactions to the same value as max_connections. For example:

    max_connections = 400
    ...
    max_prepared_transactions = 400
    

Finally, restart the database service:

sudo systemctl restart postgresql

Tune PostgreSQL

It’s strongly recommended to fine tune this PostgreSQL installation according to the hardware of the server. Keeping the default settings (especially of max_connections) is known to be problematic. For more information, visit PostgreSQL’s guide on tuning your PostgreSQL server.

Landscape-specific tips for tuning PostgreSQL

The following parameters at a minimum should be touched:

A good starting value for max_connections is 400, even on modest hardware. As your needs grow, this number should be adjusted and re-evaluated carefully. It may be helpful to use a tuning tool like pgtune.

When you adjust max_connections, you’re likely to overrun shared memory allowed by the kernel (per process) and may need to increase the SHMMAX parameter.

If the tuning changed the value of max_connections, make sure you also change max_prepared_transactions to the same value.

Install the application server

The application server will host the following Landscape services:

  • application server

  • message server

  • ping server

  • job handler

  • async-frontend

  • combo loader

  • api server

  • package upload service

  • package search

Additionally, other services needed by Landscape will also be running on this machine, such as:

  • apache

  • rabbitmq-server

Attach your Ubuntu Pro token

If you have an Ubuntu Pro subscription, attach your Pro token to each machine that will host Landscape Server components. For guidance, see How to attach your Ubuntu Pro subscription.

Add the Landscape package archive

Landscape is distributed in a public PPA. You can add it to the system with these commands, replacing <LANDSCAPE_PPA> with the appropriate repository:

sudo add-apt-repository <LANDSCAPE_PPA>

<LANDSCAPE_PPA>: The PPA for the specific Landscape installation you’re using. The PPA for the most recent recommended Landscape LTS is: ppa:landscape/self-hosted-26.04. The PPA for Landscape’s stable rolling release is: ppa:landscape/latest-stable. We recommend using an LTS for production deployments.

Install the server package

Install the server package and its dependencies:

sudo apt-get install landscape-server rabbitmq-server apache2

(If needed) Install the (legacy) license file

Most Landscape 24.04 LTS and later deployments use Ubuntu Pro entitlements instead of a legacy license file. If you were given a legacy license file, copy it to /etc/landscape/license.d:

sudo cp license.txt /etc/landscape/license.d

Make sure it’s readable by the landscape user and root.

If you don’t have a legacy license file, Landscape will manage client machines with Ubuntu Pro subscriptions associated with them.

Configure rabbitmq

Note

You may want to change the default timeout of 30 minutes in RabbitMQ. See How to configure RabbitMQ for Jammy 22.04 (or later).

Run the following commands, replacing <PASSWORD> with a password of your choice. You’ll need it for later.

sudo rabbitmqctl add_user landscape <PASSWORD>
sudo rabbitmqctl add_vhost landscape
sudo rabbitmqctl set_permissions -p landscape landscape ".*" ".*" ".*"
sudo rabbitmqctl add_vhost landscape-hostagent
sudo rabbitmqctl set_permissions -p landscape-hostagent landscape ".*" ".*" ".*"

To make RabbitMQ listen only on the loopback interface (127.0.0.1), edit the file /etc/rabbitmq/rabbitmq-env.conf with the following content:

NODE_IP_ADDRESS=127.0.0.1

Then restart RabbitMQ:

sudo systemctl restart rabbitmq-server

Configure database and broker access

Make the following configuration changes to the /etc/landscape/service.conf file to tell Landscape how to use some other services:

Section [stores]:

  • host: the IP or hostname of the database server. If not the default PostgreSQL port (5432), add a :NNNN port definition after the hostname (e.g., 10.0.1.5:3232)

  • Ensure a strong password is set for user landscape (this differs from landscape_superuser password from earlier and will be created when setup script is executed)

Section [broker]:

  • Replace the password value with the password chosen above when configuring rabbitmq

Section [schema]:

  • Change the value of store_user to the landscape super user you created above during the DB installation

  • Add an entry for store_password with the password that was chosen in that same step

Section [landscape]:

  • Add an entry for secret-token and set it as a random string. You can set any string you want, but it should be reasonably long. You can use openssl to create a random string. For example, openssl rand -base64 128 | tr -d '\n'. Note that Landscape Server 24.04 LTS uses percent signs % for templated configuration. If you must include a percent sign in a configuration value, it can be escaped as %% so that it is interpreted as %.

If you want the services to allow only certain interfaces, you can set allowed_interfaces in each of the services listed in the configuration file. These must be space-separated IP addresses or host names. For example, to only allow connections on localhost, you may have a configuration like the following:

allowed_interfaces = localhost 127.0.0.1 ::1

Run the Landscape setup script

This script will bootstrap the databases Landscape needs to work and setup the rest of the configuration:

sudo setup-landscape-server

Note

Depending on the hardware, this may take several minutes to complete.

Configure Landscape services and schema upgrades

Enable the Landscape services now. Edit /etc/default/landscape-server and change the RUN_ALL line to yes:

RUN_ALL="yes"

Note

If more performance and availability is needed from Landscape Server, it’s possible to spread out the services amongst several machines. In that case, for example, you could run message servers on one machine, application servers on another, etc.

The message, application, and ping services can be configured to run multiple instances. If your hardware has several cores and enough memory (4GB or more), running two or more of each will improve performance. To run multiple instances of a service, set the value in the respective RUN_* line to the number of instances. For example, if you want to run two message servers, set:

RUN_MSGSERVER="2"

Note

To take advantage of this multiple-instances setting, you need to configure a load balancer or proxy. See the README.multiple-services file in the landscape-server package documentation directory for an example using Apache’s proxy_loadbalancer module.

In the same /etc/default/landscape-server file, review the UPGRADE_SCHEMA option. If set to yes, whenever the package landscape-server is updated, it will attempt to update the database schema too. It’s a convenient setting, but consider the following before enabling it:

  • Schema updates can take several minutes

  • If the package is updated while the database is offline, or unreachable, the update will fail

  • You should have a backup of the database before updating the package

Without this setting enabled, a package update might result in services that won’t start anymore because of a needed schema change. In that case:

  • Stop all the Landscape services

  • Backup your database

  • Update the schema on the application server:

    sudo setup-landscape-server
    
  • Start all Landscape services again

Configure web server

Landscape uses Apache to redirect requests to each service and provide SSL support. The usual way to do this in Ubuntu is to create a Virtual Host for Landscape.

Below is a suggested configuration file that does just that. Install it as /etc/apache2/sites-available/landscape.conf and change the following values:

  • @hostname@: The FQDN of the hostname the clients (browser and machines) will use to connect to Landscape Server. This is what will be in the URL, and it needs to be resolvable via DNS. For example, landscape.example.com

  • @certfile@: The full filesystem path to where the SSL certificate for this server is installed. For example, /etc/ssl/certs/landscape_server.pem

  • @keyfile@: The full filesystem path to where the corresponding private key of that certificate is installed. For example, /etc/ssl/private/landscape_server.key

If you’re using a custom certificate authority for your SSL certificate, then you must put the CA public certificate in the /etc/ssl/certs/landscape_server_ca.crt file and uncomment the SSLCertificateChainFile /etc/ssl/certs/landscape_server_ca.crt line.

Make sure the www-data user can read those files. Also, make sure the private key can only be read by root and the ssl-cert group.

<VirtualHost *:80>

    # This Hostname is the HTTP/1.1 hostname that users and Landscape clients will access
    # It must be the same as your SSL Certificate's CommonName
    # And the DNS Hostname for this machine
    # It is not recommended that you use an IP address here...
    ServerName @hostname@
    ServerAdmin webmaster@@hostname@
    ErrorLog /var/log/apache2/landscape_error.log
    CustomLog /var/log/apache2/landscape_access.log combined
    DocumentRoot /opt/canonical/landscape/canonical/landscape

    # Set a Via header in outbound requests to the proxy, so proxied apps can
    # know who the actual client is
    ProxyVia on
    ProxyTimeout 10

    <Directory "/">
      Options +Indexes
      Order deny,allow
      Allow from all
      Require all granted
      Satisfy Any
      ErrorDocument 403 /offline/unauthorized.html
      ErrorDocument 404 /offline/notfound.html
    </Directory>

    Alias /offline /opt/canonical/landscape/canonical/landscape/offline
    Alias /static /opt/canonical/landscape/canonical/static
    Alias /repository /var/lib/landscape/landscape-repository


    <Location "/repository">
      Order deny,allow
      Deny from all
      ErrorDocument 403 default
      ErrorDocument 404 default
    </Location>
   <LocationMatch "/repository/[^/]+/[^/]+/(dists|pool)/.*">
     Allow from all
   </LocationMatch>
   <Location "/icons">
        Order allow,deny
        Allow from all
   </Location>
   <Location "/ping">
        Order allow,deny
        Allow from all
    </Location>

    <Location "/message-system">
        Order allow,deny
        Allow from all
    </Location>

   <Location "/static">
      Header always append X-Frame-Options SAMEORIGIN
   </Location>

   <Location "/r">
      FileETag none
      ExpiresActive on
      ExpiresDefault "access plus 10 years"
      Header append Cache-Control "public"
   </Location>

    RewriteEngine On

    RewriteRule ^/r/([^/]+)/(.*) /$2

    RewriteRule ^/ping$ http://localhost:8070/ping [P]

    RewriteCond %{REQUEST_URI} !^/icons
    RewriteCond %{REQUEST_URI} !^/static/
    RewriteCond %{REQUEST_URI} !^/offline/
    RewriteCond %{REQUEST_URI} !^/repository/
    RewriteCond %{REQUEST_URI} !^/message-system

    # Replace the @hostname@ with the DNS hostname for this machine.
    # If you change the port number that Apache is providing SSL on, you must change the
    # port number 443 here.
    RewriteRule ^/(.*) https://@hostname@:443/$1 [R=permanent]
</VirtualHost>

<VirtualHost *:443>
    ServerName @hostname@
    ServerAdmin webmaster@@hostname@

    ErrorLog /var/log/apache2/landscape_error.log
    CustomLog /var/log/apache2/landscape_access.log combined

    DocumentRoot /opt/canonical/landscape/canonical/landscape

    SSLEngine On
    SSLCertificateFile @certfile@
    SSLCertificateKeyFile @keyfile@
    # If you have either an SSLCertificateChainFile or, a self-signed CA signed certificate
    # uncomment the line below.
    # Note: Some versions of Apache will not accept the SSLCertificateChainFile directive.
    # Try using SSLCACertificateFile instead in that case.
    # SSLCertificateChainFile /etc/ssl/certs/landscape_server_ca.crt
    # Disable to avoid POODLE attack
    SSLProtocol all -SSLv3 -SSLv2 -TLSv1
    SSLHonorCipherOrder On
    SSLCompression Off
    SSLCipherSuite EECDH+AESGCM+AES128:EDH+AESGCM+AES128:EECDH+AES128:EDH+AES128:ECDH+AESGCM+AES128:aRSA+AESGCM+AES128:ECDH+AES128:DH+AES128:aRSA+AES128:EECDH+AESGCM:EDH+AESGCM:EECDH:EDH:ECDH+AESGCM:aRSA+AESGCM:ECDH:DH:aRSA:HIGH:!MEDIUM:!aNULL:!NULL:!LOW:!3DES:!DSS:!EXP:!PSK:!SRP:!CAMELLIA:!DHE-RSA-AES128-SHA:!DHE-RSA-AES256-SHA:!aECDH

    # Try to keep this close to the storm timeout. Not less, maybe slightly
    # more
    ProxyTimeout 305

    <Directory "/">
      Options -Indexes
      Order deny,allow
      Allow from all
      Require all granted
      Satisfy Any
      ErrorDocument 403 /offline/unauthorized.html
      ErrorDocument 404 /offline/notfound.html
    </Directory>

    <Location "/ajax">
      Order allow,deny
      Allow from all
    </Location>

    Alias /offline /opt/canonical/landscape/canonical/landscape/offline
    Alias /config /opt/canonical/landscape/apacheroot
    Alias /hash-id-databases /var/lib/landscape/hash-id-databases

    ProxyRequests off
    <Proxy *>
       Order deny,allow
       Allow from all
       ErrorDocument 403 /offline/unauthorized.html
       ErrorDocument 500 /offline/exception.html
       ErrorDocument 502 /offline/unplanned-offline.html
       ErrorDocument 503 /offline/unplanned-offline.html
    </Proxy>

    ProxyPass /robots.txt !
    ProxyPass /favicon.ico !
    ProxyPass /offline !
    ProxyPass /static !

    ProxyPreserveHost on


   <Location "/r">
      FileETag none
      ExpiresActive on
      ExpiresDefault "access plus 10 years"
      Header append Cache-Control "public"
   </Location>

   <Location "/static">
      Header always append X-Frame-Options SAMEORIGIN
   </Location>

    RewriteEngine On

    RewriteRule ^/.*\+\+.* / [F]
    RewriteRule ^/r/([^/]+)/(.*) /$2

    # See /etc/landscape/service.conf for a description of all the
    # Landscape services and the ports they run on.
    # Replace the @hostname@ with the DNS hostname for this machine.
    # If you change the port number that Apache is providing SSL on, you must change the
    # port number 443 here.
    RewriteRule ^/message-system http://localhost:8090/++vh++https:@hostname@:443/++/ [P,L]

    RewriteRule ^/ajax http://localhost:9090/ [P,L]
    RewriteRule ^/combo(.*) http://localhost:8080/combo$1 [P,L]
    RewriteRule ^/api/(.*) http://localhost:9080/api/$1 [P,L]
    RewriteRule ^/attachment/(.*) http://localhost:8090/attachment/$1 [P,L]
    RewriteRule ^/upload/(.*) http://localhost:9100/$1 [P,L]
    RewriteRule ^/(new_dashboard.*) http://localhost:8080/$1 [P,L]
    RewriteRule ^/(assets.*) http://localhost:8080/$1 [P,L]

    RewriteCond %{REQUEST_URI} !^/robots.txt$
    RewriteCond %{REQUEST_URI} !^/favicon.ico$
    RewriteCond %{REQUEST_URI} !^/offline/
    RewriteCond %{REQUEST_URI} !^/(r/[^/]+/)?static/
    RewriteCond %{REQUEST_URI} !^/config/
    RewriteCond %{REQUEST_URI} !^/hash-id-databases/

    # Replace the @hostname@ with the DNS hostname for this machine.
    # If you change the port number that Apache is providing SSL on, you must change the
    # port number 443 here.
    RewriteRule ^/(.*) http://localhost:8080/++vh++https:@hostname@:443/++/$1 [P]

    <Location /message-system>
      Order allow,deny
      Allow from all
    </Location>

    <Location />
        # Insert filter
        SetOutputFilter DEFLATE

        # Don't compress images or .debs
        SetEnvIfNoCase Request_URI \
        \.(?:gif|jpe?g|png|deb)$ no-gzip dont-vary

        # Make sure proxies don't deliver the wrong content
        Header append Vary User-Agent env=!dont-vary
    </Location>

</VirtualHost>

Listen 6554

<VirtualHost *:6554>
  ServerName @hostname@
  ServerAdmin webmaster@@hostname@

  ErrorLog /var/log/apache2/landscape_error.log
  CustomLog /var/log/apache2/landscape_access.log combined

  SSLEngine On
  SSLCertificateFile @certfile@
  SSLCertificateKeyFile @keyfile@
  # Disable to avoid POODLE attack
  SSLProtocol all -SSLv3 -SSLv2 -TLSv1
  SSLHonorCipherOrder On
  SSLCompression Off
  SSLCipherSuite EECDH+AESGCM+AES128:EDH+AESGCM+AES128:EECDH+AES128:EDH+AES128:ECDH+AESGCM+AES128:aRSA+AESGCM+AES128:ECDH+AES128:DH+AES128:aRSA+AES128:EECDH+AESGCM:EDH+AESGCM:EECDH:EDH:ECDH+AESGCM:aRSA+AESGCM:ECDH:DH:aRSA:HIGH:!MEDIUM:!aNULL:!NULL:!LOW:!3DES:!DSS:!EXP:!PSK:!SRP:!CAMELLIA:!DHE-RSA-AES128-SHA:!DHE-RSA-AES256-SHA:!aECDH
  # If you have either an SSLCertificateChainFile or, a self-signed CA signed certificate
  # uncomment the line below.
  # Note: Some versions of Apache will not accept the SSLCertificateChainFile
  # directive. Try using SSLCACertificateFile instead
  # SSLCertificateChainFile /etc/ssl/certs/landscape_server_ca.crt
 
  ProxyPass / h2c://localhost:50052/
  ProxyPassReverse / http://localhost:50052/
</VirtualHost>

Enable the following modules:

for module in rewrite proxy_http ssl headers expires proxy_http2; do sudo a2enmod $module; done

Unless you require it and take necessary steps to secure that endpoint, it’s recommended to disable the mod_status module:

sudo a2dismod status

Disable the default site:

sudo a2dissite 000-default

Finally, enable the new site:

sudo a2ensite landscape.conf
sudo systemctl restart apache2.service

Start Landscape services

Use lsctl:

sudo lsctl restart

(Landscape 26.04 only) Install the outbox snap

Install the landscape-outbox snap on the same machine as your Landscape Server installation.

sudo snap install landscape-outbox

landscape-outbox is configured to work automatically with an existing Landscape Server by default. Confirm that the snap service is running.

sudo snap services landscape-outbox

The output should show the outbox service as active:

Service                  Startup  Current  Notes
landscape-outbox.outbox  enabled  active   -

To view outbox logs, run:

sudo snap logs landscape-outbox -n 50

(Landscape 26.04 only) Install the debarchive snap

The landscape-debarchive snap is required for repository management from Landscape 26.04 LTS onwards. Follow the instructions in the dedicated guide.

Create the first user

The first user that’s created in Landscape automatically becomes the administrator of the “standalone” account. To create your first user, go to https://<SERVER_NAME> and complete the requested information.

Configure the first client

Install and configure Landscape Client using the dedicated guides: How to install Landscape Client and How to configure Landscape Client.

If your self-hosted Landscape server uses a self-signed or custom CA certificate, see Register a client machine on a self-hosted server with a self-signed certificate.

(Optional) Add an email alias

You can configure Postfix to handle Landscape Server email notifications and alerts. To ensure that important system emails get attention, you can also add an alias for Landscape on your local environment. For details, see How to configure Postfix for emails.