Reading time: ~18 minutes Audience: Homelabbers who want a web UI to manage Docker containers
What Is Portainer?
Overview
Portainer is a lightweight web UI for managing Docker, Docker Swarm, Kubernetes, and Nomad environments. It turns complex CLI commands — docker run, docker network create, docker volume inspect — into clickable buttons. For homelabbers, it is the fastest way to deploy, update, and monitor containers without memorizing flags.
Portainer CE (Community Edition) is free and open-source. It supports up to 5 nodes in the free version, which is more than enough for most homelabs.
Key Benefits
- Stack deployment: Paste a
docker-compose.ymlinto the UI and deploy it in one click. - Container logs: Stream logs in real-time from the browser.
- Image management: Pull, inspect, and delete images without touching the CLI.
- Volume browser: Browse files inside named volumes — useful for debugging config files.
- User management: Create multiple users with role-based access control (RBAC).
- App templates: One-click deploy popular apps (NGINX, MySQL, Redis, WordPress).
Prerequisites
Hardware Requirements
- A Linux server (x86_64 or ARM64) with Docker installed.
- Minimum 2 GB RAM (4 GB recommended if running multiple stacks).
- 20 GB free storage for images and volumes.
Software Requirements
- Docker Engine 20.10+ and Docker Compose plugin.
- A user with
dockergroup membership (or root access). - Optional: A domain name and DNS A record pointing to your server.
Knowledge Prerequisites
- Basic familiarity with Docker concepts (images, containers, volumes, networks).
- Comfortable editing YAML files.
- Understanding of reverse proxies (Traefik or Nginx Proxy Manager) for HTTPS.
| Component | Minimum | Recommended |
|---|---|---|
| CPU | 2 cores | 4 cores |
| RAM | 2 GB | 4 GB |
| Storage | 20 GB | 50 GB+ |
| Network | 1 GbE | 2.5 GbE |
Step 1: Install Docker and Docker Compose
Objective
Prepare the host with Docker Engine and the Compose plugin. Ensure the Docker daemon is running and the user has correct permissions.
Step-by-Step Instructions
# Update system
sudo apt update && sudo apt upgrade -y
# Install prerequisites
sudo apt install -y ca-certificates curl gnupg lsb-release
# Add Docker's official GPG key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# Add the repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Add user to docker group
sudo usermod -aG docker $USER
newgrp docker
# Verify
docker --version
docker compose version
Step 2: Deploy Portainer CE
Objective
Run Portainer as a Docker container with persistent data storage and restart policies.
Step-by-Step Instructions
# Create a volume for Portainer data
docker volume create portainer_data
# Run Portainer
docker run -d \
-p 8000:8000 \
-p 9443:9443 \
--name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
Access Portainer at https://your-server-ip:9443. Create the initial admin account.
Optional: Docker Compose for Portainer
version: "3.8"
services:
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: always
ports:
- "8000:8000"
- "9443:9443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
volumes:
portainer_data:
Deploy:
docker compose up -d
Step 3: Deploy a Reverse Proxy Stack
Objective
Set up Traefik as a reverse proxy so all services get HTTPS certificates and domain-based routing.
Step-by-Step Instructions
Create a project directory:
mkdir -p ~/homelab/traefik && cd ~/homelab/traefik
Create docker-compose.yml:
version: "3.8"
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: always
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email=admin@yourdomain.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
networks:
- proxy
whoami:
image: traefik/whoami
container_name: whoami
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.yourdomain.com`)"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
networks:
- proxy
networks:
proxy:
external: false
Deploy via Portainer:
1. In Portainer, go to Stacks → Add stack.
2. Name it traefik.
3. Paste the Compose YAML.
4. Click Deploy the stack.
Verify:
curl -I https://whoami.yourdomain.com
Step 4: Deploy a Monitoring Stack
Objective
Add Prometheus, Grafana, and cAdvisor to monitor container metrics and system performance.
Step-by-Step Instructions
Create a new stack in Portainer named monitoring:
version: "3.8"
networks:
proxy:
external: true
monitoring:
driver: bridge
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: always
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
networks:
- monitoring
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: always
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin
networks:
- monitoring
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.yourdomain.com`)"
- "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
restart: always
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker:/var/lib/docker:ro
- /dev/disk:/dev/disk:ro
networks:
- monitoring
volumes:
prometheus_data:
grafana_data:
Create prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
Deploy the stack in Portainer. Access Grafana at https://grafana.yourdomain.com.
Step 5: Add a Database Stack
Objective
Deploy PostgreSQL and Redis as reusable backing services for apps like Nextcloud, Immich, and Authelia.
Step-by-Step Instructions
Create a database stack in Portainer:
version: "3.8"
networks:
backend:
driver: bridge
services:
postgres:
image: postgres:16-alpine
container_name: postgres
restart: always
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=changeme-strong-password
- POSTGRES_DB=postgres
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- backend
ports:
- "5432:5432"
redis:
image: redis:7-alpine
container_name: redis
restart: always
networks:
- backend
volumes:
- redis_data:/data
ports:
- "6379:6379"
volumes:
postgres_data:
redis_data:
Security note: Do not expose PostgreSQL and Redis to the internet. Use the backend network for internal communication only. If you must expose ports, restrict them with UFW or iptables.
Pro Tips
Tip 1: Use Portainer’s Environment Variables
Store secrets in Portainer’s Environment Variables section when creating a stack. This keeps passwords out of your Git repository.
Tip 2: Enable Stack GitOps
Portainer can poll a Git repository for docker-compose.yml changes and auto-deploy. This turns your homelab into a GitOps workflow:
1. Push a new Compose file to GitHub.
2. Portainer detects the change and redeploys.
Tip 3: Use Agent Mode for Remote Hosts
If you have multiple homelab servers, install the Portainer Agent on each:
docker run -d \
-p 9001:9001 \
--name portainer_agent \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /var/lib/docker/volumes:/var/lib/docker/volumes \
portainer/agent:latest
Then add the agent endpoint in your main Portainer UI.
Tip 4: Backup Portainer Data
Portainer’s database is in its named volume. Back it up with:
docker run --rm -v portainer_data:/data -v $(pwd):/backup alpine \
tar czf /backup/portainer-backup.tar.gz -C /data .
Troubleshooting Common Issues
Problem 1: Portainer Shows “Unable to Retrieve Containers”
Cause: The Docker socket is not mounted or Portainer lacks permissions. Fix:
docker stop portainer
docker rm portainer
docker run -d ... -v /var/run/docker.sock:/var/run/docker.sock ...
Problem 2: Traefik Not Generating Certificates
Cause: Port 80 is not reachable from the internet, or the DNS record is wrong.
Fix: Ensure your router forwards port 80 and 443 to the Docker host. Verify DNS with dig yourdomain.com.
Problem 3: Stack Deploy Fails with “Network Not Found”
Cause: The stack references an external network (e.g., proxy) that does not exist.
Fix: Create the network first:
docker network create proxy
Or set external: false in the Compose file.
Conclusion
Summary
Portainer transforms Docker from a CLI-only tool into a visual platform. With a single UI, you can manage reverse proxies, monitoring, databases, and dozens of apps. The stack-based deployment model keeps your homelab organized, reproducible, and version-controlled.
Next Steps
- Add apps: Deploy Nextcloud, Jellyfin, Immich, and Pi-hole as separate stacks.
- Set up HTTPS: Ensure every public service has a valid Let’s Encrypt certificate via Traefik.
- Monitor: Use the Grafana stack to track CPU, memory, and container health.
- Automate: Enable GitOps or Watchtower for automatic image updates.
Affiliate Opportunities
- Mini PCs: Beelink, Minisforum for running the Docker host.
- Storage: Samsung 990 Pro NVMe, WD Red SATA SSDs.
- Networking: TP-Link Omada or UniFi for managed switches.
- UPS: APC Back-UPS for protecting the Docker host.
Internal Linking Strategy
prerequisites→docker-compose-for-beginners— “learn Docker Compose basics first”step-3→immich-reverse-proxy— “configure Traefik for Immich”step-4→docker-monitoring-grafana-prometheus— “deep dive into homelab monitoring”step-5→nextcloud-self-hosted— “connect Nextcloud to PostgreSQL”conclusion→best-self-hosted-apps-2026— “apps to deploy in your Portainer stacks”
CTA
- What’s in your Portainer stack? Share your Compose templates in the comments.
- Subscribe for Docker Compose recipes, Portainer tips, and homelab automation guides.