Portainer is a web UI for Docker: see every container, volume and network, view logs, exec into a shell, and update an image with a button press. If you host more than a handful of services, it pays for itself in the first afternoon.
What it is
A visual Docker manager with stack templates, container recreation, volume browsing, and registry management. The free Community Edition covers everything a self-hoster needs: stacks, logs, exec, and container health. Portainer's paid tiers add RBAC and multi-node, which most home servers don't need.
Before you start
- It mounts
/var/run/docker.sock, which is root on the host. Anyone with a Portainer admin account has your machine. Two-factor auth is not optional. - The default admin password is
portainerfor about five minutes. The UI nags you to change it; don't ignore the nag. - Portainer stacks and plain
docker composefiles fight over the same containers. Pick one source of truth or you'll get "orphan container" warnings forever.
1 — Write the compose file
services:
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: always
ports:
- "127.0.0.1:9443:9443"
- "127.0.0.1:8000:8000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
- /var/lib/docker/volumes:/var/lib/docker/volumes
environment:
TZ: UTC
healthcheck:
test: ["CMD", "/portainer", "--healthcheck"]
interval: 10s
timeout: 5s
retries: 5
volumes:
portainer_data:
name: portainer_data
2 — Start it
mkdir -p ~/services/portainer
cd ~/services/portainer
docker compose up -d
docker compose logs -f portainer | grep -i "portainer is ready\|error"
3 — First-run setup
- Open
http://yourhost:9443and set the admin password immediately. The port is 9443 for the modern UI; 8000 exists for the legacy one and the API, and you can leave it alone. - Turn on two-factor authentication under User settings. With Docker socket access, this is the difference between a leaked password and a compromised server.
- Import your existing stacks. Stacks → Add stack → Upload compose file works, but for anything you manage on the command line, it's cleaner to leave them as-is and use Portainer only for logs, exec and resource views.
- Set up a user with no
dockergroup equivalent — i.e. don't grant them Environment management — for read-only observation. - Check Settings → Local volumes to confirm your named and bind-mounted volumes appear. If the volume list is empty, the
/var/lib/docker/volumesmount is wrong for your Docker data root.
4 — Useful daily moves
# container update with log inspection - what the GUI button does
docker compose pull
docker compose up -d --remove-orphans
docker compose logs --tail=50
# confirm nothing auto-restarted in a crash loop
docker ps -a --filter "status=restarting" --format '{{.Names}}'
/ into a new container and read every file on the machine. Don't expose 9443 to the internet, don't reuse a password you've typed elsewhere, and keep 2FA on. If you need remote access, put it behind WireGuard or Tailscale.