Lizmap 3.9 on Ubuntu 24.04 on Azure User Guide
Overview
Lizmap turns a QGIS desktop project into an interactive web map. A cartographer styles layers, popups, print layouts and attribute tables in QGIS Desktop, saves the project, and Lizmap publishes it in the browser - layer tree, legend, search, feature identification, attribute tables, printing and per-group access control already wired up. There is no re-authoring step and no second styling language to learn: the map your GIS team designed is the map your users get.
Lizmap is the web client half of a two-part architecture; the rendering half is QGIS Server, the OGC map server of the QGIS project. This cloudimg image ships the whole stack assembled and proven, so there is nothing to wire together:
- Lizmap Web Client 3.9.9 (3Liz, MPL-2.0) on PHP 8.3-FPM behind nginx
- QGIS Server 3.44 LTR (GPL-2.0-or-later) as two persistent FastCGI workers, plus the mandatory Lizmap QGIS Server plugin
- PostgreSQL 16 with PostGIS 3.4, holding both Lizmap's own account database and the map data
- A working demo QGIS project, published and rendering on first boot
Security is designed in rather than bolted on. QGIS Server has no authentication of its own, so this image never exposes it: the OGC endpoint listens on 127.0.0.1 only and Lizmap is its sole client. Access control is Lizmap's own user, group and repository model, which is what you actually configure. Lizmap's documented default account (admin/admin) is deleted during the build, so the image ships with zero accounts; the administrator and the PostgreSQL password are both generated uniquely on the first boot of your VM. Backed by 24/7 cloudimg support.

What is included:
- Lizmap Web Client 3.9.9 installed from the official 3Liz release archive, with the version and SHA-256 recorded at
/etc/cloudimg-lizmap-version - QGIS Server 3.44 LTR from the official QGIS apt repository (
qgis.org/ubuntu-ltr), verified at build time to have come from that repository - The Lizmap QGIS Server plugin 2.14.1, with the
QGIS_SERVER_LIZMAP_REVEAL_SETTINGSgate already enabled - PostgreSQL 16 and PostGIS 3.4, tuned for 4 GiB alongside the map renderers, listening on localhost only
- Two persistent QGIS Server FastCGI workers, one per vCPU, reachable only over local unix sockets
- A per-VM Lizmap administrator (
lizmapadmin) and a per-VM PostgreSQL password, both generated at first boot - A demo QGIS project with PostGIS-backed layers, published in the
demorepository and rendering out of the box /usr/local/sbin/lizmap-selftest.sh, an end-to-end check you can re-run at any time- A dedicated Azure data disk at
/srv/lizmapcarrying both the published projects and the PostgreSQL cluster - An unauthenticated
/healthzendpoint for Azure Load Balancer health probes - 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is the recommended size and is what the three memory-hungry tiers are tuned for; scale up if you publish large raster projects or expect heavy concurrent tile traffic. NSG inbound: allow 22/tcp from your management network, 80/tcp for Lizmap, and 443/tcp if you add TLS. The appliance serves plain HTTP on port 80; for production, terminate TLS with your own domain and restrict access to trusted IP ranges (see Maintenance).
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Lizmap by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Review the dedicated data disk on the Disks tab, then Review + create followed by Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name lizmap \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name lizmap --port 80 --priority 1010
Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 - Confirm every tier is running
Lizmap is a four-tier appliance. All four services should report active.
systemctl is-active postgresql php8.3-fpm qgis-server@1 qgis-server@2 nginx
cat /etc/cloudimg-lizmap-version /etc/cloudimg-qgis-server-version \
/etc/cloudimg-lizmap-server-plugin-version /etc/cloudimg-lizmap-postgis-version

Step 5 - Confirm first boot completed
First boot generates the per-VM secrets, publishes the demo project and proves an end-to-end map render before it writes its sentinel. If the sentinel is present, all of that succeeded.
test -f /var/lib/cloudimg/lizmap-firstboot.done && echo "first boot complete"
sudo systemctl is-active lizmap-firstboot.service
Step 6 - Retrieve your per-VM credentials
The image contains no accounts at all. Your administrator account and your database password were generated on this VM, on its first boot, and exist nowhere else.
sudo cat /root/lizmap-credentials.txt

Store the values somewhere safe. LIZMAP_ADMIN_USERNAME is lizmapadmin and LIZMAP_ADMIN_PASSWORD is a 24-character random string.
Step 7 - Confirm the health endpoint
/healthz is static, unauthenticated and served by nginx, which makes it a safe Azure Load Balancer probe target.
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/healthz
Step 8 - Confirm QGIS Server is not exposed
QGIS Server has no authentication of its own. On this appliance it is bound to the loopback interface, so it is unreachable from the network and Lizmap is its only client. PostgreSQL is bound the same way.
ss -lnt | grep -E ':(80|8081|5432)\s'
Port 80 listens on all interfaces; 8081 (QGIS Server) and 5432 (PostgreSQL) must show 127.0.0.1 only.
Step 9 - Run the end-to-end self-test
This is the same check first boot runs. It signs in with the per-VM password, asks Lizmap for a rendered map image, and asserts the returned raster is a picture of something rather than a blank tile. It also asserts that a wrong password is refused and that the service is still alive afterwards. It prints OK and nothing else on success.
sudo /usr/local/sbin/lizmap-selftest.sh
sudo -u postgres psql -d lizmap -c 'SELECT f_table_name, type, srid FROM geometry_columns ORDER BY 1'

Step 10 - Sign in to Lizmap
Open http://<vm-public-ip>/ in a browser. Choose Connect and sign in with the username and password from Step 6.

Step 11 - Open the demo map
The landing page lists every project you are allowed to see, grouped by repository. The bundled cloudimg demo repository contains one project.

Choose Load the map. Lizmap asks QGIS Server for tiles, QGIS Server reads the layers from PostGIS, and the map draws with the symbology defined in the QGIS project - categorised region fills, dashed routes and site markers. Use the layer tree on the left to toggle layers, and the zoom controls or your scroll wheel to move around; every movement re-renders server side, so the labelling and styling stay correct at every scale.
Step 12 - Read the attribute table
The attribute table is a Lizmap feature that QGIS Server alone does not provide. Choose the table icon in the left toolbar, then Detail next to cloudimg_regions. The rows come straight from PostGIS, and selecting one highlights the matching feature on the map.

Step 13 - Review the administration interface
Choose Administration in the header. Server information reports the Lizmap version, the QGIS Server version and the plugins QGIS Server has loaded - the fastest way to confirm the two halves of the stack agree after any upgrade.

Users and Rights are where you add colleagues. Lizmap ships three groups: admins (full administration), publishers (may see the project list in the admin panel) and users (ordinary viewers). All three can already view the demo repository; anonymous visitors cannot, which is why the landing page is empty until you sign in.
Step 14 - Add a user
Add accounts from the administration interface, or from the command line. Replace the example login, email and password.
cd /var/www/lizmap && sudo -u www-data php lizmap/console.php \
jcommunity:user:create --no-error-if-exist mapviewer viewer@example.com 'ChangeThisPassword123' >/dev/null 2>&1
sudo -u postgres psql -tAd lizmap -c "SELECT usr_login, usr_email FROM jlx_user WHERE usr_login='mapviewer'"
cd /var/www/lizmap && sudo -u www-data php lizmap/console.php acl2user:addgroup mapviewer users >/dev/null 2>&1
sudo -u postgres psql -tAd lizmap -c "SELECT id_aclgrp FROM jacl2_user_group WHERE login='mapviewer'"
Note the option is --no-error-if-exist (singular) on console.php. Redirecting stdout to /dev/null matters: the command echoes the account's password back to the terminal, which you do not want in your shell history or in a log.
The new account can sign in immediately and will see every repository the users group has been granted.
Step 15 - Publish your own QGIS project
A Lizmap project is two files that live together in a repository directory: the QGIS project (.qgs) and its Lizmap configuration (.qgs.cfg), which the Lizmap plugin for QGIS Desktop writes when you choose Publish in Lizmap. Copy both into a repository directory under /srv/lizmap/projects/ and the project appears immediately - no restart.
# from your workstation
scp my-project.qgs my-project.qgs.cfg azureuser@<vm-public-ip>:/tmp/
sudo install -o www-data -g qgis -m 0640 /dev/null /srv/lizmap/projects/demo/.keep && echo "repository writable"
Your layers must be readable by the appliance. Layers stored in a GeoPackage or Shapefile simply need to sit under /srv/lizmap with group qgis. Layers stored in the bundled PostGIS database are read as the read-only qgis role over the local socket, which authenticates by operating system identity rather than a password, so your project file never has to carry a credential.
sudo -u postgres psql -d lizmap -c "\du qgis"
To add a second repository - useful for separating teams, since rights are granted per repository - create the directory, register it, and grant a group access to it.
sudo install -d -o www-data -g qgis -m 0750 /srv/lizmap/projects/team-b && echo "directory created"
cd /var/www/lizmap && sudo -u www-data php lizmap/console.php repository:create team-b "Team B" team-b >/dev/null 2>&1
grep -c '^\[repository:team-b\]' /var/www/lizmap/lizmap/var/config/lizmapConfig.ini.php
Registering a repository does not grant anyone access to it - Lizmap gates every repository behind the lizmap.repositories.view right, scoped to that repository. Until you grant it, the repository is invisible to everyone.
cd /var/www/lizmap && sudo -u www-data php lizmap/console.php acl2:add users lizmap.repositories.view team-b >/dev/null 2>&1
sudo -u postgres psql -tAd lizmap -c "SELECT id_aclgrp FROM jacl2_rights WHERE id_aclsbj='lizmap.repositories.view' AND id_aclres='team-b'"
Both commands are written to attempt the change and then prove the result, so they are safe to re-run: repository:create and acl2:add both refuse loudly if the repository or the right already exists.
Step 16 - Confirm the dedicated data volume
Everything that is yours - the published projects and the whole PostgreSQL cluster - lives on a dedicated Azure data disk, not on the OS disk. That keeps your data on its own volume that you can snapshot and grow independently.
df -h /srv/lizmap
sudo -u postgres psql -tAc 'SHOW data_directory'

To grow it, resize the disk in the Azure Portal (the VM must be deallocated), then extend the filesystem online.
sudo resize2fs /dev/disk/azure/scsi1/lun0
Maintenance
Add TLS before exposing this VM on the public internet. Lizmap serves plain HTTP on port 80, so sessions and passwords cross the network in clear text. Point a DNS record at the VM, allow 443/tcp in the NSG, and issue a certificate.
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d maps.example.com --redirect --agree-tos -m you@example.com
Patching. Every component is package-managed, so ordinary updates cover the whole stack: Lizmap's PHP runtime, QGIS Server (from the QGIS repository), PostgreSQL and PostGIS, and nginx. Unattended security upgrades are enabled by default.
sudo apt-get update && sudo apt-get -s dist-upgrade | tail -3
Upgrading Lizmap itself. Lizmap is the one component installed from an upstream release archive rather than a package. Back up first, then follow 3Liz's upgrade notes - unpack the new release over /var/www/lizmap, re-run php lizmap/install/installer.php as www-data, and keep lizmap/var/config/ intact.
Back up the database and the projects. Both live on the data disk; the projects are plain files and the database has everything else.
sudo -u postgres pg_dump -Fc lizmap > /tmp/lizmap-backup.dump && ls -lh /tmp/lizmap-backup.dump
Logs. Lizmap writes application errors to its own log; the map renderers and the web tier use the journal.
sudo tail -n 5 /var/www/lizmap/lizmap/var/log/errors.log 2>/dev/null || echo "no application errors"
sudo journalctl -u nginx -u php8.3-fpm -u 'qgis-server@*' --no-pager -n 10
Resetting the administrator password. If you lose it, set a new one from the command line.
cd /var/www/lizmap && sudo -u www-data php lizmap/console.php \
jcommunity:password:change --force lizmapadmin 'YourNewPassword'
Scaling. The two QGIS Server workers are sized one per vCPU for Standard_B2s. On a larger VM, add worker instances and matching nginx upstream entries, and raise pm.max_children in /etc/php/8.3/fpm/pool.d/www.conf.
grep -E '^(pm|pm.max_children) ' /etc/php/8.3/fpm/pool.d/www.conf
Support
cloudimg provides 24/7 support for this image. Lizmap is a product of 3Liz; QGIS and QGIS Server are products of the QGIS project; PostgreSQL and PostGIS are products of their respective projects. cloudimg is not affiliated with, endorsed by or sponsored by any of them. For questions about the image, contact cloudimg support. For questions about Lizmap itself, see the Lizmap documentation.