pgAdmin 4
Overview
pgAdmin 4 is the most widely used open source administration and development platform for PostgreSQL. From an ordinary browser it gives you an object explorer over servers, databases, schemas, tables, functions and roles, a Query Tool with syntax highlighting, explain plans and result grids, a graphical ERD designer, import and export, backup, restore and maintenance jobs, and live dashboards showing sessions, locks, transactions and server activity.
This SecureAnyCloud image runs pgAdmin on its own, in server mode, which is the multi-user web deployment that upstream provides for teams. It is not bundled with a database. You point it at the PostgreSQL instances you already run: Azure Database for PostgreSQL Flexible Server, a self-managed cluster on your own virtual machines, or any reachable PostgreSQL endpoint from version 13 through 18.
No PostgreSQL server runs on this VM, and no connection details ship in the image. The image also contains no administrator account and no configuration database. A one-shot service creates them on first boot, with secrets unique to that VM.
What you get:
- pgAdmin 4 version 9.17 in server mode, installed from the official pgAdmin APT repository, served by Apache with mod_wsgi and managed by systemd, on a hardened Ubuntu 24.04 LTS base patched at build time
- PostgreSQL client tooling for every supported major version (13 through 18), wired into pgAdmin so backup, restore and maintenance jobs always run a version-matched
pg_dump,pg_restoreandpsqlagainst whichever server you are connected to - A per-VM administrator account and password generated on first boot and recorded in a root-only file
- Session signing and password salting secrets generated per VM, never baked into the image
- A bootstrap gate: Apache refuses to serve until first boot has finished, so a partially initialised console is never exposed
- No saved server connections, hostnames or database passwords anywhere in the image
- An Apache configuration that is an explicit allowlist, so application source, configuration and the configuration database are never served
apache2.serviceandpgadmin-firstboot.serviceas enabled systemd units- An unauthenticated
/healthzendpoint for Azure Load Balancer health probes - 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting size. Move up to Standard_D2s_v3 if many people use the console at once or you run large backup jobs from it.
Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 80/tcp for the console. Also allow 443/tcp if you terminate TLS on the VM.
This VM must be able to reach every PostgreSQL server you intend to manage, normally on 5432/tcp. Those servers must allow connections from this VM's address.
Step 1 - Deploy from the Azure Marketplace
In the Azure portal, choose Create a resource, search for pgAdmin 4 on Ubuntu 24.04 LTS by SecureAnyCloud, and select Create.
Pick your subscription, resource group and region, and choose the Standard_B2s size. Select SSH public key authentication with the username azureuser, and allow inbound 22 and 80.
pgAdmin keeps only its own small configuration database on this VM, so you do not need to attach an extra disk.
Step 2 - Deploy from the Azure CLI
You launch the image like any other Marketplace VM. The commands below accept the Marketplace terms, create the VM and open the web ports. Adjust the names to match your subscription.
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:pgadmin-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name pgadmin \
--image sac1647283583153:pgadmin-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name pgadmin --port 80,443Step 3 - Confirm the service is running
SSH to the VM as azureuser and confirm that Apache and the first-boot service are both active. Apache serves on port 80. Nothing listens on 5432, because this appliance runs no local database.
systemctl is-active apache2 pgadmin-firstbootcurl -s -o /dev/null -w 'healthz: %{http_code}\n' http://127.0.0.1/healthzcurl -s -o /dev/null -w 'console: %{http_code}\n' http://127.0.0.1/pgadmin4/loginpgAdmin uses version-matched PostgreSQL client tooling for backup, restore and maintenance. The tooling is installed under /usr/lib/postgresql, with one directory per supported server major version:
ls /usr/lib/postgresqlStep 4 - Retrieve the per-VM administrator password
The first-boot service generates an administrator password unique to your VM and writes it to a root-only file. Read it over SSH:
sudo cat /root/pgadmin-credentials.txtPGADMIN_URL is the VM's own address as seen from inside the VM. Azure does not expose the public IP to the instance, so this is usually the private address. The public IP shown in the Azure portal works identically.
Step 5 - Sign in
Browse to http://<vm-ip>/. It redirects to the console at /pgadmin4/. Sign in with the email address and password from the credentials file.
Change the password right away from the user menu in the top right (admin@secureanycloud.com > Change Password). Then add named accounts for your colleagues, as described in the Multi-user access section.
Step 6 - Register your first PostgreSQL server
pgAdmin manages servers you already run, so the object explorer starts empty. Choose Add New Server on the Welcome page, or Object > Register > Server from the menu.
On the General tab, give the connection a name. On the Connection tab, enter the host name or address, the port (normally 5432), the maintenance database, and the user name and password that pgAdmin should connect with.
For Azure Database for PostgreSQL Flexible Server, use the server's fully qualified name as the host and your administrator login as the user name. Set SSL mode to require on the Parameters tab. First add this VM's address to the flexible server's firewall rules, or place both in the same VNet.
Leave Save password off unless you want pgAdmin to store the database password. If you turn it on, pgAdmin asks you to set a master password first. The master password encrypts any stored connection passwords and is never written to disk, so a stolen disk image does not yield your database credentials.
When you save, pgAdmin connects, and the server dashboard starts plotting live activity for that server: sessions, transactions per second, tuples in and out, and block I/O.
Step 7 - Browse objects and run SQL
Expand the tree to walk the server: Databases, then a database, then Schemas, public and Tables. Select an object to see its Properties, SQL, Statistics, Dependencies and Dependents in the panel on the right. All of it is read live from the server.
To run SQL, select a database and choose Tools > Query Tool. Type a statement and press F5 or the execute button. Results appear in the Data Output grid below, with the row count and elapsed time in the status bar. Export them to CSV from the grid toolbar.
The Explain tab next to Data Output renders a graphical query plan for the statement in the editor. It is the fastest way to see why a query is slow.
Step 8 - Backup, restore and maintenance
Right-click a database or table to open Backup..., Restore... and Maintenance.... They run pg_dump, pg_restore and VACUUM or ANALYZE on your behalf.
These tools must match the major version of the server being dumped. This image therefore installs the client tooling for every supported major version and wires each one into pgAdmin explicitly. You can see the mapping in the system configuration:
sudo grep -E "'pg-1[3-8]'" /etc/pgadmin/config_system.pyA backup of a PostgreSQL 18 server therefore runs the version 18 pg_dump, and a backup of a version 15 server runs the version 15 one, with no configuration from you. Backup files are written to the pgAdmin storage area for your user, and you can download them from the browser.
Step 9 - No known or default credentials
Nothing in this image is a shared secret. The image contains no administrator account and no configuration database. pgAdmin keeps its session signing key, password salt and CSRF key in the keys table of its configuration database and generates them when that database is first created. Because the image ships no database, every VM gets its own secrets.
pgadmin-firstboot.service runs once, before Apache is allowed to start. It creates the configuration database, which generates those three secrets. It then creates the administrator with a fresh random password, writes the root-only credentials file, and only then creates the bootstrap ready marker that releases Apache.
Apache carries a ConditionPathExists drop-in for that marker. On any boot where bootstrap has not completed, the web server does not serve at all.
systemctl cat pgadmin-firstboot.service | sed -n '1,12p'cat /etc/systemd/system/apache2.service.d/10-sac-pgadmin-gate.confYou can verify that the per-VM administrator is the only login that works. The check below signs in through the real pgAdmin login form with the password from the credentials file. It then confirms that a blank password, common weak guesses and unknown user names are all rejected:
sudo bash /usr/local/sbin/pgadmin-cred-roundtrip.shStep 10 - How the web server is locked down
The Apache virtual host is an explicit allowlist rather than a catch-all. Exactly three URL spaces are served: / redirects into the console, /healthz is a static document for load balancer probes, and /pgadmin4 is the application.
Everything else ends in a 404. The document root is a permanently empty directory that denies everything, and the application directory denies everything except the single WSGI entry point. Application source, the system configuration and the configuration database are therefore not reachable over HTTP:
for p in /config.py /pgadmin4/config.py /etc/pgadmin/config_system.py /pgadmin4.db /server-status; do printf '%-34s ' "$p"; curl -s -o /dev/null -w '%{http_code}\n' "http://127.0.0.1$p"; doneThe Server response header is set to Apache with no version or distribution, and directory listings are off. Every response carries the X-Content-Type-Options, X-Frame-Options and Referrer-Policy headers.
Adding your own domain and TLS
The console ships on HTTP so that it works the moment the VM boots. pgAdmin carries database credentials, so put it behind TLS before real use.
Point a DNS record at the VM and open 443/tcp in the NSG. Then install a certificate with certbot, which edits the shipped virtual host in place:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-apache
sudo certbot --apache -d pgadmin.your-domain.exampleAlternatively, terminate TLS on an Azure Application Gateway or Load Balancer in front of the VM. Keep the VM itself on the private network, with the NSG allowing 80/tcp only from the gateway subnet.
Multi-user access
pgAdmin runs in server mode, so it supports named accounts, each with its own registered servers and preferences. To add colleagues, use File > Preferences, or choose Users from the user menu to open the user management screen. Give each person their own login with the Administrator or User role.
You can also list users from the command line:
sudo /usr/pgadmin4/venv/bin/python3 /usr/pgadmin4/web/setup.py get-usersShared servers let one administrator publish a connection to everyone. Configure them per server with the Shared? switch in the Register Server dialog.
Backing up pgAdmin's own configuration
pgAdmin's registered servers, users and preferences live in one small SQLite file. Back it up with Apache stopped, or copy it with the SQLite backup API, and keep the copy outside the VM. Check the file:
sudo ls -l /var/lib/pgadmin/pgadmin4.dbTo restore, stop Apache, replace the file, restore its 0600 www-data:www-data ownership and start Apache again. Your database contents are never on this VM, so this file is the only pgAdmin state worth backing up.
Server components
Component Version Notes
pgAdmin 4 9.17 Server mode, from the official pgAdmin APT repository
Apache HTTP Server 2.4.58 Serves the console through mod_wsgi at /pgadmin4
mod_wsgi Python 3 build Runs pgAdmin in a dedicated daemon process group
Python 3.12.3 Bundled pgAdmin virtual environment at /usr/pgadmin4/venv
PostgreSQL client tooling 13, 14, 15, 16, 17, 18 Version matched pg_dump, pg_restore and psql
Ubuntu 24.04 LTS Patched at build time, unattended security upgrades enabled
Filesystem layout
Path Size Purpose
/ 29 GB Root filesystem
/boot 881 MB Operating system kernel files
/boot/efi 105 MB UEFI boot partition (Gen2 Hyper V)
/mnt varies Azure temporary resource disk
Key directories:
Path Purpose
/usr/pgadmin4/web The pgAdmin application and its WSGI entry point
/usr/pgadmin4/venv The bundled Python virtual environment
/etc/pgadmin/config_system.py System configuration, loaded last, survives package upgrades
/var/lib/pgadmin Configuration database, sessions and per user storage, mode 0700
/var/lib/pgadmin/pgadmin4.db The configuration database, mode 0600 www-data
/etc/apache2/sites-available/sac-pgadmin.conf The allowlist virtual host
/usr/lib/postgresql/<major>/bin Version matched PostgreSQL client tooling
Scripts and log files
Path Purpose
/usr/local/sbin/pgadmin-firstboot.sh First boot bootstrap: config database, per VM secrets, administrator account
/usr/local/sbin/pgadmin-cred-roundtrip.sh Proves the per VM administrator authenticates and weak credentials do not
/root/pgadmin-credentials.txt The per VM administrator login, mode 0600 root:root
/var/lib/sac/data/pgadmin-firstboot.done First boot sentinel, stops the bootstrap re running
/var/lib/sac/data/pgadmin-ready Bootstrap ready marker that releases Apache
/var/log/pgadmin-firstboot.log First boot bootstrap log
/var/log/pgadmin/pgadmin4.log pgAdmin application log
/var/log/apache2/pgadmin-access.log Console access log
/var/log/apache2/pgadmin-error.log Console error log
Troubleshooting
The console does not answer and Apache is inactive. Bootstrap has not completed, so the gate is holding Apache back by design. Check the first-boot log and the marker:
sudo tail -20 /var/log/pgadmin-firstboot.logsystemctl status pgadmin-firstboot --no-pager --lines=20The login page loads but the password is rejected. Confirm that you are using the email address from the credentials file, not a user name. pgAdmin locks an account after three failed attempts. The round-trip script in Step 9 clears that counter as part of its check.
A server will not connect. The cause is almost always on the network or server side, not in pgAdmin. Confirm that this VM can reach the database host and port, and that the database server accepts connections from this VM's address:
/usr/lib/postgresql/18/bin/psql --versionFor Azure Database for PostgreSQL Flexible Server, check the firewall rules or VNet integration, and set SSL mode to require.
Backup or restore fails with a version mismatch. pgAdmin picks the client tooling from the mapping in /etc/pgadmin/config_system.py. If you connect to a server newer than version 18, add the matching client package and a corresponding pg-<major> entry to that file.
Security notes
- Change the administrator password immediately. Create a named account per person instead of sharing one login.
- Encrypt web traffic. Put the console behind TLS before real use, because it carries database credentials.
- Restrict network access. Limit
80/tcpand443/tcpin the NSG to the networks that need the console, and keep22/tcplimited to your management network. - Protect stored passwords. Leave Save password off, or set a master password so any stored connection passwords are encrypted at rest.
- Keep the VM patched. The image ships with unattended security upgrades enabled, so later security updates are applied automatically.
Trademark
pgAdmin and PostgreSQL are trademarks of their respective holders. SecureAnyCloud is not affiliated with, endorsed by, or sponsored by the pgAdmin Development Team or the PostgreSQL Global Development Group. All product and company names are trademarks or registered trademarks of their respective holders.
Support
SecureAnyCloud provides 24/7 technical support for this image by email at sales@secureanycloud.com and by live chat. We help with deployment, connecting to Azure Database for PostgreSQL and self-managed clusters, network and firewall configuration, TLS setup, multi-user administration, upgrades and troubleshooting. Critical issues receive a one hour average response time.
Deploy on Azure
Launch pgAdmin 4 on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com