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.12.0
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.12.0
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.
Related
Get self-hosting tips in your inbox
New guides, comparisons, and setup tutorials — delivered weekly. No spam.