Self-Host Portainer: Manage All Your Docker Containers from One Dashboard in 15 Minutes
If you're running more than a couple of Docker containers, you know the pain: docker ps gives you a wall of text, docker logs requires you to remember container names, and inspecting resource usage means parsing JSON output. Portainer solves this by giving you a clean, powerful web UI to manage everything Docker — containers, images, volumes, networks, and even Docker Swarm or Kubernetes clusters.
In this guide, you'll deploy Portainer CE (Community Edition) on any Docker host and get a centralized dashboard up and running in about 15 minutes.
Why Self-Host Portainer?
- Unified view: See all containers, images, volumes, and networks across multiple Docker environments
- Easy management: Start, stop, restart, inspect, and delete containers with a few clicks
- Stack deployments: Deploy multi-container applications using docker-compose files directly from the UI
- User management: Create teams and control who can access what (CE supports local users; BE adds LDAP/OAuth)
- Lightweight: Runs in a single container with minimal resource overhead
- No vendor lock-in: Open-source (zlib license), self-hosted, your data stays local
Prerequisites
- A VPS or server with Docker installed (Ubuntu 22.04/24.04, Debian 12, or similar)
- Minimum 1 CPU, 1GB RAM (2GB+ recommended for the host)
- Docker Engine 20.10+ and Docker Compose plugin
- A domain pointing to your server (optional, for reverse proxy setup)
- Ports 9000 (HTTP) and 9443 (HTTPS) available
Step 1: Create the Docker Compose File
Create a directory for Portainer and a docker-compose.yml file:
mkdir -p ~/portainer && cd ~/portainer
Paste this into docker-compose.yml:
version: "3.8"
services:
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: unless-stopped
security_opt:
- no-new-privileges:true
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- portainer_data:/data
ports:
- "8000:8000"
- "9443:9443"
- "9000:9000"
environment:
- TZ=UTC
volumes:
portainer_data:
What this does:
- portainer-ce:latest: The community edition image (stable, regularly updated)
- docker.sock: Gives Portainer access to the Docker daemon (required for management)
- portainer_data: Persistent volume for Portainer's database and settings
- 9443: HTTPS web UI (recommended)
- 9000: HTTP web UI (useful for local access or reverse proxy)
- 8000: Edge agent tunnel (for managing remote Docker hosts)
- no-new-privileges: Security hardening to prevent privilege escalation
Step 2: Deploy Portainer
Start the container:
docker compose up -d
Verify it's running:
docker ps --filter name=portainer
You should see output like:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 portainer/portainer-ce:latest "/portainer" 5 seconds ago Up 3 seconds 0.0.0.0:8000->8000/tcp, 0.0.0.0:9000->9000/tcp, 0.0.0.0:9443->9443/tcp portainer
Step 3: Initial Setup
Open your browser and navigate to:
https://your-server-ip:9443
Note: You'll see a browser warning about the self-signed certificate. Click "Advanced" → "Proceed" (or add an exception). This is normal for the initial setup.
On first launch:
- Create admin user: Enter a username (or leave as
admin) and a strong password (minimum 12 characters recommended) - Connect to Docker: Select
Get Started→Docker(local environment) - Done! You'll land on the Portainer dashboard
Step 4: Verify Everything Works
Once logged in, you should see:
- Dashboard: Overview of your Docker environment (running/stopped containers, image count, volume usage)
- Containers: List of all containers with start/stop/restart/delete actions
- Images: All pulled images with prune options
- Networks: Docker networks with create/manage options
- Volumes: Persistent volumes with browse and cleanup tools
Try these quick tests:
- View container logs: Click any running container →
Logstab — much nicer thandocker logs -f - Open a shell: Container →
Console→Connect— instant web-based exec - Check stats: Container →
Stats— real-time CPU, memory, network, and disk I/O - Deploy a stack:
Stacks→Add stack→ paste a docker-compose file →Deploy
Step 5: (Optional) Secure with a Reverse Proxy
For production, put Portainer behind Traefik or Nginx Proxy Manager with a valid TLS certificate. Here's a Traefik example:
# Add labels to the portainer service in docker-compose.yml
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.yourdomain.com`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
Then access Portainer at https://portainer.yourdomain.com with a valid certificate.
Next Steps
Now that Portainer is running, consider these follow-ups:
- Add remote environments: Use the Portainer Edge Agent to manage other Docker hosts from one dashboard
- Set up stacks: Convert your docker-compose files into Portainer stacks for one-click deployments
- Enable notifications: Configure webhook notifications for container events
- Explore Portainer BE: If you need LDAP, OAuth, or role-based access control, check out the Business Edition (free for up to 5 users)
- Backup Portainer data: The
portainer_datavolume contains your config — add it to your backup strategy
Related Guides
- Self-Host Traefik: The Ultimate Reverse Proxy for Your Homelab
- Self-Host Uptime Kuma: Monitor All Your Services
- Self-Host Coolify: Your Own Vercel/Netlify Alternative
With Portainer managing your Docker fleet, you'll spend less time memorizing CLI flags and more time shipping. Deploy it once, and you'll wonder how you managed containers without it.