Self-Hosting pgAdmin 4 with Docker Compose
What Is pgAdmin?
pgAdmin 4 is the leading open-source management tool for PostgreSQL. It provides a web-based GUI for managing databases, running SQL queries, monitoring server activity, and configuring replication — replacing the need for command-line-only database administration. If you self-host any app that uses PostgreSQL (Nextcloud, Immich, Authentik, dozens more), pgAdmin gives you visibility into what’s happening inside those databases.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 512 MB of free RAM (1 GB recommended)
- At least one PostgreSQL instance to manage (can be on the same server or remote)
Docker Compose Configuration
Create a directory for pgAdmin and add a docker-compose.yml:
mkdir -p ~/pgadmin && cd ~/pgadmin
services:
pgadmin:
image: dpage/pgadmin4:9.13
container_name: pgadmin
environment:
# CHANGE THESE — used for initial admin login
PGADMIN_DEFAULT_EMAIL: [email protected]
PGADMIN_DEFAULT_PASSWORD: ChangeThisPassword123!
# Disable built-in Postfix mail server (not needed for most setups)
PGADMIN_DISABLE_POSTFIX: "true"
ports:
- "5050:80"
volumes:
- pgadmin-data:/var/lib/pgadmin
restart: unless-stopped
networks:
- pgadmin-net
volumes:
pgadmin-data:
networks:
pgadmin-net:
Start the stack:
docker compose up -d
pgAdmin will be available at http://your-server:5050. Log in with the email and password you set in the environment variables.
Connecting pgAdmin to Your PostgreSQL Databases
Once logged in, click Add New Server in the dashboard. For a PostgreSQL instance running on the same Docker network:
| Field | Value |
|---|---|
| Name | Any label (e.g., “Nextcloud DB”) |
| Host | Container name or IP of your PostgreSQL container |
| Port | 5432 (default) |
| Username | Your PostgreSQL user |
| Password | Your PostgreSQL password |
If your PostgreSQL is in a different Docker Compose stack, create an external network both stacks share, or use the host IP address.
Pre-Loading Server Connections
To skip manual setup, create a servers.json file:
{
"Servers": {
"1": {
"Name": "Local PostgreSQL",
"Group": "Self-Hosted",
"Host": "postgres",
"Port": 5432,
"Username": "postgres",
"SSLMode": "prefer",
"MaintenanceDB": "postgres"
}
}
}
Mount it in your Compose file by adding to the volumes section:
volumes:
- pgadmin-data:/var/lib/pgadmin
- ./servers.json:/pgadmin4/servers.json:ro
Restart pgAdmin and the server appears automatically — you still need to enter the password on first connection.
Running pgAdmin Alongside PostgreSQL
Most self-hosters already run PostgreSQL for other apps. Here’s a complete stack with both pgAdmin and a fresh PostgreSQL instance:
services:
postgres:
image: postgres:17.3
container_name: postgres
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: StrongDatabasePassword!
POSTGRES_DB: default
volumes:
- postgres-data:/var/lib/postgresql/data
restart: unless-stopped
networks:
- db-net
pgadmin:
image: dpage/pgadmin4:9.13
container_name: pgadmin
environment:
PGADMIN_DEFAULT_EMAIL: [email protected]
PGADMIN_DEFAULT_PASSWORD: ChangeThisPassword123!
PGADMIN_DISABLE_POSTFIX: "true"
ports:
- "5050:80"
volumes:
- pgadmin-data:/var/lib/pgadmin
restart: unless-stopped
depends_on:
- postgres
networks:
- db-net
volumes:
postgres-data:
pgadmin-data:
networks:
db-net:
In this setup, pgAdmin connects to PostgreSQL using the hostname postgres (the container name) on port 5432.
Configuration
Key Environment Variables
| Variable | Description | Default |
|---|---|---|
PGADMIN_DEFAULT_EMAIL | Admin login email (required) | — |
PGADMIN_DEFAULT_PASSWORD | Admin login password (required) | — |
PGADMIN_DISABLE_POSTFIX | Disable built-in mail server | false |
PGADMIN_LISTEN_PORT | Port inside container | 80 |
PGADMIN_ENABLE_TLS | Enable HTTPS inside container | false |
GUNICORN_THREADS | Worker threads for performance | 25 |
File Permissions
pgAdmin runs as user pgadmin (UID 5050, GID 5050) inside the container. If you use bind mounts instead of named volumes, set ownership:
sudo chown -R 5050:5050 /path/to/pgadmin-data
Reverse Proxy
Behind Nginx Proxy Manager, Traefik, or Caddy, point your domain to port 5050. No special headers are required — pgAdmin works behind reverse proxies without additional configuration.
For HTTPS termination at the proxy level, keep PGADMIN_ENABLE_TLS disabled (the default) and let your reverse proxy handle SSL.
See Reverse Proxy Setup for full configuration.
Backup
The pgAdmin data volume (/var/lib/pgadmin) stores user sessions, saved queries, server definitions, and preferences. Back it up with your standard volume backup approach:
docker run --rm -v pgadmin_pgadmin-data:/data -v $(pwd):/backup alpine tar czf /backup/pgadmin-backup.tar.gz /data
For backing up the actual PostgreSQL databases managed through pgAdmin, use pg_dump — pgAdmin’s GUI provides a point-and-click backup tool under Tools > Backup for each database.
See Backup Strategy for a comprehensive approach.
Troubleshooting
Permission Denied on Volume Mount
Symptom: pgAdmin fails to start with permission errors on /var/lib/pgadmin.
Fix: The container runs as UID 5050. Set ownership on host-mounted directories:
sudo chown -R 5050:5050 /path/to/pgadmin-data
Cannot Connect to PostgreSQL Container
Symptom: “Connection refused” when adding a server.
Fix: Ensure both containers are on the same Docker network. Use the container name (not localhost) as the host. Check that PostgreSQL is accepting connections (pg_hba.conf allows the pgAdmin container’s subnet).
Slow Initial Load
Symptom: First page load takes 10-15 seconds.
Fix: This is normal — pgAdmin initializes its internal SQLite database on first access. Subsequent loads are faster. Increase GUNICORN_THREADS to 50 if managing many servers.
Resource Requirements
- RAM: ~150 MB idle, 300-500 MB under active use with multiple queries
- CPU: Low (spikes during large query execution)
- Disk: ~100 MB for the application, plus space for query history and session data
Verdict
pgAdmin is the standard PostgreSQL GUI — mature, full-featured, and actively maintained. If you run any self-hosted apps backed by PostgreSQL, pgAdmin belongs in your stack. The web UI makes database inspection, query writing, and backup management accessible without memorizing psql commands.
For MySQL/MariaDB databases, look at phpMyAdmin or Adminer instead. If you want a multi-database GUI that handles PostgreSQL, MySQL, SQLite, and more, consider CloudBeaver — though it lacks pgAdmin’s depth for PostgreSQL-specific features.
Frequently Asked Questions
Can pgAdmin manage multiple PostgreSQL servers?
Yes. pgAdmin supports connecting to unlimited PostgreSQL servers simultaneously. Add each server through the UI or pre-configure them using a servers.json file mounted into the container. You can organize servers into groups and switch between them in the tree view. This makes it ideal for managing databases across multiple self-hosted applications.
How does pgAdmin compare to Adminer?
pgAdmin is a full-featured tool specifically for PostgreSQL — it includes visual query plans, server monitoring dashboards, backup/restore wizards, and role management. Adminer is a lightweight, multi-database tool that supports PostgreSQL, MySQL, SQLite, and more from a single PHP file. Choose pgAdmin for deep PostgreSQL administration. Choose Adminer if you manage multiple database types and want a simple, unified interface.
Can I run pgAdmin alongside my existing PostgreSQL containers?
Yes. Add pgAdmin to the same Docker network as your PostgreSQL containers. Use the PostgreSQL container name as the hostname when adding a server in pgAdmin. No additional port exposure is needed — containers communicate directly over the shared Docker network.
Does pgAdmin support two-factor authentication?
Yes, pgAdmin 4 supports two-factor authentication using TOTP (Time-based One-Time Password) apps like Google Authenticator or Authy. Enable it in the pgAdmin settings after initial login. This is important if you expose pgAdmin through a reverse proxy.
How much disk space does pgAdmin use?
The Docker image is roughly 400 MB. pgAdmin stores session data, query history, and its internal SQLite database in the data volume, which rarely exceeds 100 MB for typical use. The main disk consideration is your PostgreSQL databases themselves, not pgAdmin.
Can I use pgAdmin to back up and restore databases?
Yes. pgAdmin includes graphical backup and restore wizards that wrap pg_dump and pg_restore. You can create full, schema-only, or data-only backups in custom, tar, or plain SQL formats. For automated backups, use a cron job with pg_dump directly — pgAdmin’s backup tool is best for ad-hoc operations.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments