Managing Docker Compose stacks by hand gets old fast. You SSH into the box, edit a compose.yaml in vim, run docker compose up -d, then tail logs in a second terminal to see whether anything caught fire. Dockge folds all of that into one web page: edit the compose file in the browser, deploy it, and watch the container logs stream live on the same screen.
This guide walks through how to install Dockge on Ubuntu, create the first admin account, deploy a real stack, and put the whole thing behind Nginx with HTTPS. Dockge comes from the developer behind Uptime Kuma, and it shows: the interface is light, fast, and does one job well instead of trying to manage every corner of your Docker host like Portainer does.
Ran through this on Ubuntu 26.04 in September 2026 with Docker Engine 29.8 and Dockge 1.5. The same steps apply on 24.04, since the Docker repo carries both releases.
Where Dockge fits next to Portainer and Komodo
Dockge is not trying to be a full container platform. It manages Compose stacks that live as plain compose.yaml files on disk, and that is the whole point. Your stacks stay readable and portable, so if you ever drop Dockge, the files still work with a bare docker compose up -d. That is a real difference from tools that store stack definitions in their own database.
| Item | Dockge | Portainer | Komodo |
|---|---|---|---|
| Scope | Compose stacks only | Full Docker + Swarm + K8s | Multi-server builds and deploys |
| Stack storage | Plain files in /opt/stacks | Internal database | Git repos + database |
| In-browser compose editing | First-class | Limited | Yes |
| Footprint | Tiny (one container) | Medium | Medium, plus agents |
| Best for | Homelab and single-host stacks | Broad Docker management | GitOps across many hosts |
If you run a handful of Compose stacks on one or two hosts, Dockge is the leaner fit. For fleet-wide GitOps, Komodo is the heavier tool built for that job.
Prerequisites
You need an Ubuntu 26.04 or 24.04 host with a sudo user, Docker Engine with the Compose plugin (installed below), and TCP port 5001 free for the web UI. If you already run Docker from the Docker and Compose setup, skip straight to installing Dockge.
Dockge itself is cheap to run. The container is a small Node service with a SQLite database, so it sips RAM. What actually sizes the box is the stacks you point it at, not Dockge. A host that comfortably runs your containers already has the headroom for Dockge on top. The lab here used 2 vCPU and 4 GB of RAM, which is a floor for following along rather than a target to plan production around.
1. Install Docker Engine
Dockge ships as a container, so Docker Engine and the Compose plugin come first. Add Docker’s official repository, which carries the current engine rather than the older build in the Ubuntu archive. Set up the keyring and repo:
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
Add the repository. The line below resolves your release codename automatically, which is why the exact same command works on 26.04 and 24.04. Docker publishes both, so nothing needs hard-coding:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Refresh the index and pull in the engine, CLI, containerd, and the Compose plugin:
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Confirm the engine and Compose plugin are both present:
docker --version
docker compose version
Both print a version and the service reports active:
Docker version 29.8.1, build 4a63305
Docker Compose version v5.5.1
Add your user to the docker group so you can run Compose without sudo. Log out and back in (or run newgrp docker) for the group change to take effect:
sudo usermod -aG docker $USER
2. Install Dockge
Dockge keeps two directories: one for its own compose file and data, and one that holds every stack it manages. Create both. The stacks path must be a full, absolute path, and the same path has to appear on both sides of the volume mount later, so /opt/stacks is the sane default:
sudo mkdir -p /opt/stacks /opt/dockge
cd /opt/dockge
Pull the official compose file into the Dockge directory:
sudo curl -fsSL https://raw.githubusercontent.com/louislam/dockge/master/compose.yaml --output compose.yaml
Look at what it defines before starting it:
cat compose.yaml
The important lines are the Docker socket mount, the data volume, and the stacks directory, which is passed to Dockge through an environment variable:
services:
dockge:
image: louislam/dockge:1
restart: unless-stopped
ports:
- 5001:5001
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/app/data
- /opt/stacks:/opt/stacks
environment:
- DOCKGE_STACKS_DIR=/opt/stacks
That socket mount is how Dockge talks to Docker, and it is also the reason Dockge effectively has root on the host. Keep the UI behind authentication and off the public internet. Bring it up:
sudo docker compose up -d
Docker pulls the image and starts the container. Check that it is healthy and listening on 5001:
docker compose ps
The container shows as up and healthy with the port published:
NAME IMAGE STATUS PORTS
dockge-dockge-1 louislam/dockge:1 Up 6 minutes (healthy) 0.0.0.0:5001->5001/tcp
Here is the engine, the Compose plugin, and the running Dockge container together on the test box:

If ufw is active on this host, open the port so you can reach the UI from your LAN. A fresh Ubuntu server image usually has ufw disabled, in which case you can skip this:
sudo ufw allow 5001/tcp
3. Create your admin account
Open http://SERVER_IP:5001 in a browser. On first load Dockge sends you to a setup page to create the single admin account. There is no default password to change and no email step, just a username and a password you pick.

Pick a strong password (this account can start and stop anything on the Docker host) and submit. Dockge logs you straight in to the home view, which shows your stack counts and a live tile for active, exited, and inactive stacks.

The home screen also has a handy trick: paste a long docker run command into the Docker Run box, click Convert to Compose, and Dockge turns it into a compose file you can save as a stack. It is the fastest way to migrate a one-off container into something version controlled.
4. Deploy your first stack
Click Compose in the top left to start a new stack. Give it a name (that name becomes a folder under /opt/stacks), then paste a compose definition into the editor. A small two-service stack is enough to see how it behaves, an Nginx web server plus a Redis cache:
services:
web:
image: nginx:alpine
restart: unless-stopped
ports:
- "8080:80"
cache:
image: redis:alpine
restart: unless-stopped
Hit Deploy. Dockge writes the file to /opt/stacks/webapp/compose.yaml, runs the equivalent of docker compose up -d, and flips the stack to active. The stack page then shows each container with its state and published ports, the compose file on the right, and a terminal panel streaming the live logs.

Because the file lives at a real path on disk, you can edit it in the browser or in vim on the server, and both stay in sync. The Edit, Restart, Update, and Stop buttons map to the Compose commands you already know, so nothing about the stack is locked inside Dockge.
If you drop compose files into /opt/stacks from the shell, use the Scan Stacks Folder item in the top-right menu and Dockge picks them up.
5. Put Dockge behind Nginx with HTTPS
Port 5001 over plain HTTP is fine on a trusted LAN, but anything that can start containers deserves TLS and a real hostname. Put Dockge behind Nginx as a reverse proxy and let certbot handle the certificate. Set two shell variables first so the rest of the step pastes as-is:
export DOCKGE_DOMAIN="dockge.example.com"
export ADMIN_EMAIL="[email protected]"
Point an A record for that hostname at the server’s IP, then install Nginx:
sudo apt-get install -y nginx
Create the site file. Dockge drives its live terminal and log streaming over WebSockets, so the proxy has to pass the Upgrade and Connection headers, otherwise those features break even though the page itself loads:
sudo vim /etc/nginx/sites-available/dockge
Add the following server block. Leave DOCKGE_DOMAIN_HERE as a literal placeholder for now; a sed command in a moment swaps in your real hostname:
server {
listen 80;
server_name DOCKGE_DOMAIN_HERE;
location / {
proxy_pass http://127.0.0.1:5001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Substitute your hostname, enable the site, drop the default one, and test the config:
sudo sed -i "s/DOCKGE_DOMAIN_HERE/${DOCKGE_DOMAIN}/g" /etc/nginx/sites-available/dockge
sudo ln -sf /etc/nginx/sites-available/dockge /etc/nginx/sites-enabled/dockge
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
A clean config reports the syntax is ok and the test is successful:
nginx: configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Reload Nginx, then let certbot issue the certificate and rewrite the vhost for HTTPS. The --nginx plugin uses the HTTP-01 challenge, which works with any DNS provider as long as port 80 is reachable from the internet:
sudo systemctl reload nginx
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d "${DOCKGE_DOMAIN}" --non-interactive --agree-tos --redirect --no-eff-email -m "${ADMIN_EMAIL}"
Certbot installs the certificate, adds the 443 server block, and sets up the HTTP to HTTPS redirect. Confirm renewal is wired up:
sudo certbot renew --dry-run
Open port 443 (and 80 for the redirect and future renewals) if a firewall is in front of the box, and reach Dockge at https://dockge.example.com with a valid certificate.
Issuing the certificate without a public port 80
If the server sits on a private LAN behind NAT with no inbound port 80, or you want a wildcard certificate, use the DNS-01 challenge instead. It proves domain ownership through a DNS TXT record, so no inbound HTTP is needed. Certbot has a plugin per provider:
| DNS provider | Certbot plugin |
|---|---|
| Cloudflare | python3-certbot-dns-cloudflare |
| Route 53 | python3-certbot-dns-route53 |
| DigitalOcean | python3-certbot-dns-digitalocean |
| Google Cloud DNS | python3-certbot-dns-google |
| Linode | python3-certbot-dns-linode |
| RFC2136 (BIND) | python3-certbot-dns-rfc2136 |
Substitute your provider’s plugin below. This shows Cloudflare, where you store a scoped API token in a credentials file and point certbot at it:
sudo apt-get install -y python3-certbot-dns-cloudflare
echo "dns_cloudflare_api_token = your-scoped-token" | sudo tee /etc/letsencrypt/cloudflare.ini
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d "${DOCKGE_DOMAIN}" --non-interactive --agree-tos -m "${ADMIN_EMAIL}"
Unlike the --nginx plugin, certonly only fetches the certificate. It does not edit your Nginx config, so the TLS server block is on you. Swap the plain-HTTP site created earlier for an HTTPS version:
sudo vim /etc/nginx/sites-available/dockge
Replace the contents with the block below. It terminates TLS on 443, redirects plain HTTP to HTTPS, and keeps the same WebSocket headers so the live terminal survives the switch. Leave DOCKGE_DOMAIN_HERE as a placeholder again:
server {
listen 80;
server_name DOCKGE_DOMAIN_HERE;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name DOCKGE_DOMAIN_HERE;
ssl_certificate /etc/letsencrypt/live/DOCKGE_DOMAIN_HERE/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/DOCKGE_DOMAIN_HERE/privkey.pem;
location / {
proxy_pass http://127.0.0.1:5001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Substitute the hostname across the file, test the config, and reload:
sudo sed -i "s/DOCKGE_DOMAIN_HERE/${DOCKGE_DOMAIN}/g" /etc/nginx/sites-available/dockge
sudo nginx -t
sudo systemctl reload nginx
Certbot’s systemd timer renews the certificate on its own. A renewal only swaps the files on disk, so pair it with an Nginx reload hook or a periodic sudo systemctl reload nginx to pick up the fresh certificate.
6. Update Dockge
Updates pin to the 1 major tag, so a pull grabs the latest release in that line without a surprise major bump. From the Dockge directory:
cd /opt/dockge
sudo docker compose pull
sudo docker compose up -d
Compose recreates the container only if the image changed, and your stacks keep running untouched because they are separate Compose projects. You can also trigger this from the UI with the Update button on the Dockge container itself.
Fixing the problems you will hit
The live terminal and logs are blank behind a reverse proxy
This is the one that trips people up. Dockge’s terminal and log streaming run over a WebSocket, and a proxy without the upgrade headers refuses the connection. In testing, a WebSocket handshake through a correct vhost returns 101 Switching Protocols, while the same request through a vhost missing proxy_http_version 1.1 and the Upgrade and Connection headers returns 400 Bad Request. The page loads either way, which is what makes it confusing. If your logs panel is empty, the fix is the three proxy lines from the vhost above.
Error: “permission denied while trying to connect to the Docker daemon socket”
Dockge shows this when its container cannot read /var/run/docker.sock. It almost always means the socket mount is missing from the compose file or the host socket has non-default permissions. Confirm the /var/run/docker.sock:/var/run/docker.sock line is present, then recreate the container with sudo docker compose up -d --force-recreate.
A stack you created on disk does not appear
Dockge only lists stacks under the directory it was told about, which is /opt/stacks from DOCKGE_STACKS_DIR. A stack elsewhere, or one added while Dockge was running, will not show until you use Scan Stacks Folder. If a stack still refuses to appear, check that its file is named compose.yaml inside its own subfolder, because a loose file in the root of the stacks directory is ignored.