PG Back Web on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and operation of PG Back Web on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. PG Back Web gives PostgreSQL backups a user interface. Instead of hand written pg_dump scripts scattered across cron tabs, you register each database once, describe when it should be backed up and where the dump should go, and then watch every run succeed or fail from a single dashboard, with retention, one click restores and webhook notifications built in.
The image runs PG Back Web v0.5.1, built reproducibly from source at build time from the exact upstream commit that release tag points at. Both the release tag and the source commit are recorded in /opt/pgbackweb/VERSION, and the running server reports the same version on its About page.
Everything sensitive on this appliance is generated for your machine alone, on its first boot. PG Back Web stores the connection string of every database it backs up, and the access key and secret key of every object store destination, inside its own PostgreSQL database. Those values are encrypted with a key held in PBW_ENCRYPTION_KEY. If that key were baked into the image, every deployment of the image would share it, and anyone holding a copy of the image could decrypt the stored credentials of every other deployment. It is therefore never baked: your instance mints 32 random bytes on first boot, and the service refuses to start at all if that key is empty, is still the cloudimg placeholder, or matches a value published in upstream's own documentation.
The administrator account is treated the same way. PG Back Web ships with no seeded account and, on a stock deployment, presents a "Create first user" page to anyone who reaches it, which on an internet facing server means the first stranger to arrive becomes the administrator. This image closes that window: first boot creates the administrator with a password unique to your VM before port 80 is ever opened, and the account creation route is then closed at the reverse proxy because it has no further legitimate use.
What is included:
-
PG Back Web v0.5.1, built from source at a pinned upstream commit, running under systemd as the unprivileged
pgbackwebsystem user -
PostgreSQL 18 as PG Back Web's own metadata store, bound to loopback only with
scram-sha-256authentication and notrustmethod anywhere in its configuration -
The
pg_dumpandpsqlclient tools for every supported PostgreSQL major version, 13 through 18, so you can back up and restore servers of any of those versions from one appliance -
nginx on port
80as the only network facing surface, reverse proxying to PG Back Web on127.0.0.1:8085 -
A per VM administrator password and a per VM encryption key, both generated on first boot and never shared between instances
-
A
/healthzendpoint served by nginx and PG Back Web's own/api/v1/healthendpoint, both unauthenticated, for load balancer and uptime probes -
A built in self test at
/usr/local/sbin/pgbackweb-selftest.shthat proves the per VM credentials really authenticate through the public listener -
The complete AGPL-3.0 corresponding source on disk with a checksum manifest, licence text and written offer
-
Ubuntu 24.04 LTS base with the latest security patches applied at build time and unattended security updates enabled
-
Azure Linux Agent for seamless cloud integration and SSH key injection
-
24/7 cloudimg support with guaranteed 24 hour response SLA
Prerequisites
-
An Azure subscription with permission to deploy virtual machines
-
An SSH key pair for administrative access to the VM as the
azureuseraccount -
A Network Security Group allowing inbound TCP
80from the networks that should reach the web interface, and22(SSH) from your management network only -
Network reachability from this VM to each PostgreSQL server you intend to back up, and to your object store endpoint if you use one
-
A recommended size of
Standard_B2s(2 vCPU, 4 GB RAM) or larger
Step 1 — Deploy the virtual machine
Create the VM from the cloudimg Azure Marketplace image. Adjust the resource group, region and size to suit your environment.
az vm create \
--resource-group my-resource-group \
--name pgbackweb-01 \
--image cloudimg:pgbackweb-ubuntu-24-04:default:latest \
--size Standard_B2s \
--storage-sku StandardSSD_LRS \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
# Open port 80 to the networks that should reach the interface. Keep port 22
# restricted to your management network only.
az vm open-port --resource-group my-resource-group --name pgbackweb-01 --port 80 --priority 1001
Step 2 — Read the credentials generated for your instance
First boot generates the administrator password and the encryption key, writes them where only root can read them, and only then opens port 80. Connect over SSH and read them.
sudo cat /root/pgbackweb-credentials.txt
You will see the sign in URL, the administrator email address and the password generated for this machine. The file is mode 0600 and owned by root, and its contents are unique to this VM.
sudo stat -c '%a %U:%G %n' /root/pgbackweb-credentials.txt
Expected output:
600 root:root /root/pgbackweb-credentials.txt
The encryption key that protects everything you will store lives separately, in the service environment file, readable only by root and the pgbackweb service account.
sudo stat -c '%a %U:%G %n' /etc/pgbackweb/pgbackweb.env
sudo sed -n 's/^PBW_ENCRYPTION_KEY=//p' /etc/pgbackweb/pgbackweb.env | wc -c
The key is 64 hexadecimal characters (the wc -c count includes a trailing newline, so it reports 65).

Step 3 — Confirm the appliance is healthy
Check that every service reached the running state and that nothing except SSH and nginx is listening on a routable address.
systemctl is-active pgbackweb-firstboot.service pgbackweb.service postgresql@18-main.service nginx.service
Expected output:
active
active
active
active
ss -ltn
PG Back Web itself is bound to 127.0.0.1:8085 and PostgreSQL to 127.0.0.1:5432. Neither is reachable from the network; nginx on :80 is the only public entry point.

Both health endpoints answer without authentication, which makes them suitable for a load balancer probe.
curl -s http://127.0.0.1/api/v1/health
echo
curl -s http://127.0.0.1/healthz
Expected output:
{"server_healthy":true}
ok
Step 4 — Sign in to the web interface
Browse to the URL from your credentials file, which is http://<your-vm-public-ip>/, and sign in with the administrator email address and password from that same file.

After signing in you land on the Summary dashboard, which counts your databases, destinations, backup tasks, executions and restorations, and colours each ring by health.

You can prove the same credentials work from the command line, exactly as a browser does, using a session cookie rather than a bare token.
sudo /usr/local/sbin/pgbackweb-selftest.sh
Expected output:
SELFTEST_OK: cookie-authenticated dashboard access verified for <PGBACKWEB_ADMIN_EMAIL>
Change the administrator email address and password to your own from Profile in the navigation rail once you have signed in for the first time.
Step 5 — Register a database to back up
Open Databases and choose Add database. Give the connection a name you will recognise, pick the major version of the server you are connecting to (this is what decides which pg_dump binary PG Back Web uses), and paste a standard PostgreSQL connection string.
postgresql://backup_user:<your-database-password>@<your-database-host>:5432/orders?sslmode=require
PG Back Web tests the connection when you save it and shows a green indicator when it is healthy. The connection string is encrypted with your instance's own key before it is written to disk, and the interface only ever shows it masked.

The role you connect as needs permission to read everything you want in the dump. A role that cannot read a table will cause pg_dump to stop with a permission error, and PG Back Web will record the run as failed with that message attached, so failures are visible rather than silent.
Step 6 — Choose where dumps are written
PG Back Web writes each dump either to a Local directory on this VM or to any S3 compatible object store.
Local destinations are written under /backups, which is owned by the pgbackweb service account and readable only by it.
sudo stat -c '%a %U:%G %n' /backups
Expected output:
750 pgbackweb:pgbackweb /backups
Local dumps share the operating system disk, so for anything beyond light use either attach and mount a data disk at /backups or send dumps to object storage instead.
For an S3 compatible destination, open Destinations, choose Add destination, and supply the bucket name, region, endpoint, access key and secret key. Azure Blob Storage is reachable this way through its S3 compatible gateways, as are AWS S3, MinIO, Backblaze B2 and Cloudflare R2. The access key and secret key are encrypted with your instance's own key before being stored.
Step 7 — Create a backup task and run it
Open Backup tasks and choose Create backup task. Select the database, choose the destination, name the task, and give it a cron schedule and a time zone. Retention in days controls how long PG Back Web keeps each dump before deleting it. The pg_dump option switches on the same form map directly onto the corresponding pg_dump flags.

You do not have to wait for the schedule. Use the row menu and choose Run manually to take a backup immediately. Executions then records every run, whether started by the scheduler or by hand, with its status, the database and destination it used, when it started and finished, how long it took and the size of the dump it wrote.

You can read the same record from the command line, along with the file that was written.
sudo -u postgres psql -w -tA -d pgbackweb -c "SELECT status, coalesce(message,''), pg_size_pretty(file_size), path FROM executions ORDER BY updated_at DESC NULLS LAST LIMIT 1"
Step 8 — Restore
Every successful execution can be restored from the Executions page. Use the row menu and choose the restore action, then pick the database to restore into. PG Back Web streams the stored dump back through the psql binary matching that database's version and records the attempt under Restorations, so restores are auditable in the same place as backups.
Because the appliance carries the client tools for every supported major version, you can restore a dump taken from one server into a different server of a different major version, as long as the target version is one PostgreSQL itself accepts.
ls -1 /usr/lib/postgresql/*/bin/pg_dump

Step 9 — Back up the encryption key
This is the single most important operational step on this appliance.
PBW_ENCRYPTION_KEY in /etc/pgbackweb/pgbackweb.env is what decrypts every database connection string and every object store credential PG Back Web holds. If you rebuild this VM, or restore its disk without that file, PG Back Web will start but will be unable to decrypt anything it previously stored, and every registered database and destination will have to be entered again.
Copy the key somewhere your team already keeps secrets, such as Azure Key Vault, before you rely on the instance.
sudo sed -n 's/^PBW_ENCRYPTION_KEY=//p' /etc/pgbackweb/pgbackweb.env
Treat the value exactly as you would a password manager master key.
Step 10 — Security notes for production
The image is hardened before it reaches you, and it is worth knowing what that covers and what remains yours.
The service refuses to start on a weak encryption key. You can see the guard that enforces it, which runs before the application on every start.
systemctl cat pgbackweb.service | grep -E 'ExecStartPre|ConditionPathExists'
The account creation route that upstream leaves reachable is closed at the proxy, because this appliance creates its administrator during first boot and the route has no further legitimate use.
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/auth/create-first-user
Expected output:
404
The login form is rate limited by client address, and nginx replaces any client supplied X-Forwarded-For header with the real peer address, so a client cannot forge a fresh rate limit bucket or a false address in the authentication log.
Two things remain yours to decide:
-
Terminate TLS. The appliance serves plain HTTP on port
80. Put it behind Azure Application Gateway, Azure Front Door or a load balancer with your own certificate, or install a certificate directly into nginx, before exposing it beyond a trusted network. Passwords and session cookies should not cross an untrusted network in clear text. -
Restrict who can reach port 80. Keep the Network Security Group as tight as your environment allows.
Step 11 — Licence and source
PG Back Web is free software under the GNU Affero General Public License, version 3. Section 13 of that licence requires that anyone interacting with the program over a network is offered its corresponding source, so this image carries it on disk rather than relying on a remote location. It is the exact tree the shipped binary was built from, and you can verify it against its manifest.
cd /usr/share/pgbackweb/source && sudo sha256sum -c SHA256SUMS
Expected output:
pgbackweb-v0.5.1-source.tar.gz: OK

The full licence text is at /usr/share/pgbackweb/LICENSE and the written offer is in /usr/share/pgbackweb/README.source. cloudimg is not affiliated with or endorsed by the PG Back Web project.
Troubleshooting
The web interface does not answer on port 80. Check that first boot completed. Until it has written the per VM encryption key and created the administrator, both PG Back Web and nginx deliberately stay stopped.
systemctl is-active pgbackweb-firstboot.service
sudo journalctl -u pgbackweb-firstboot.service --no-pager -n 30
PG Back Web will not start. The startup guard refuses a missing, empty, placeholder or published default encryption key, and says which condition failed.
sudo journalctl -u pgbackweb.service --no-pager -n 30 -b
A backup run failed. The failure reason from pg_dump is recorded against the execution and shown in the interface. The most common cause is a role that lacks read permission on a table in the target database.
sudo -u postgres psql -w -tA -d pgbackweb -c "SELECT status, coalesce(message,'') FROM executions ORDER BY updated_at DESC NULLS LAST LIMIT 3"
A database shows as unhealthy. PG Back Web tests each registered connection periodically. Confirm this VM can reach the server and that the credentials and sslmode in the connection string are correct.
You have lost the administrator password. A password reset tool ships with the appliance and generates a new random password for an existing account.
sudo systemctl show -p Environment pgbackweb.service >/dev/null 2>&1; echo "run: sudo -u pgbackweb env \$(sudo grep -v '^#' /etc/pgbackweb/pgbackweb.env | xargs) /opt/pgbackweb/change-password"
Run the printed command, enter the account email address when prompted, and it prints a new password.
Support
cloudimg images are backed by 24/7 support with a guaranteed 24 hour response SLA. Contact support through the Azure Marketplace listing or at www.cloudimg.co.uk.