Skip to main content
Docker & Infrastructure

Dockge Docker Compose Setup: My Complete Homelab Config

· · 8 min read

I’ve been managing Docker containers across my homelab for three years now. For most of that time, I just SSH’d into machines and ran docker-compose commands directly. It worked fine until it didn’t—usually at 2 AM when I needed to restart something and couldn’t remember which directory I kept the YAML files in. Dockge, the Docker Compose manager from the creator of Uptime Kuma, isn’t flashy, but it solves a real problem: giving you one place to see, edit, and control all your stacks without leaving your browser. I’ve been running it for about four months, and I’m still skeptical of some design choices, but I’m not going back to the old workflow either.

🎯 Not sure if this will run on your hardware?Use our free Local LLM Hardware Checker — pick your GPU and RAM, see which models will run with real tokens/sec estimates.
Check my hardware →

Why I Chose Dockge and What It Actually Does

There are other Docker Compose managers out there. Portainer is the big one—it’s feature-rich and well-established. But Portainer wants to manage your entire Docker infrastructure, and for a homelab where you mostly just need to start, stop, and occasionally tweak stacks, that’s overkill. Dockge is lighter. It does one thing: let you manage Compose stacks through a web interface with an integrated editor and terminal. No agent overhead, no complex permission systems to debug.

The interface is actually thoughtful. You get a file editor for your compose YAML, a real-time terminal for watching logs, and buttons to up/down your stacks without guessing which directory you’re in. The interactive editor validates your YAML as you type, which has saved me from syntax errors at least twice. That said, the UI is functional, not pretty. It looks like something built to work, not to impress. That’s honest, at least.

Prerequisites and Hardware

Dockge runs in Docker itself, which is both elegant and slightly recursive. You need Docker and Docker Compose installed on the machine where you’re running it. I’m running it on an old Intel NUC with 8GB of RAM and an SSD, alongside about fifteen other containers. It uses maybe 50-100MB of RAM at idle, so it won’t stress your hardware.

For reverse proxy access, I’m using Caddy, but Nginx or Traefik work fine too. You’ll want HTTPS; running this over plain HTTP would be asking for trouble. I also recommend putting it behind some form of authentication—Caddy’s basicauth is serviceable for a home network, or use your reverse proxy’s built-in auth if it supports it.

My Docker Compose Configuration

Here’s what I’m actually running. This goes in a file I keep at /opt/dockge/docker-compose.yml:

version: '3.8'

services:
  dockge:
    image: louislam/dockge:1.4.2
    container_name: dockge
    restart: unless-stopped
    ports:
      - "5001:5001"
    environment:
      - DOCKGE_STACKS_DIR=/opt/stacks
      - SQLITE_PATH=/opt/dockge/data
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/dockge/data:/opt/dockge/data
      - /opt/stacks:/opt/stacks
    networks:
      - dockge_net

networks:
  dockge_net:
    driver: bridge

Let me break down the choices here:

  • Image tag (1.4.2): I pin versions explicitly. Using latest in a homelab is asking for unplanned breaks. Check the Dockge releases page for the current stable version.
  • DOCKGE_STACKS_DIR: This tells Dockge where to look for your Compose files. I keep all my stacks in /opt/stacks with subdirectories for each application. Dockge reads from this directory and lets you manage them through the UI.
  • SQLITE_PATH: Dockge uses SQLite to store state about your stacks (status, last update time, etc.). Binding this to a persistent volume means your data survives container restarts. This matters if you care about the history tab.
  • Docker socket binding: The ro flag means read-only. Dockge needs to talk to Docker, but you don’t want it to have write access to the socket unless absolutely necessary. In practice, Dockge needs some write permissions to start and stop containers, so full read-only access is a bit of a security theater, but it’s better than nothing.
  • Network: I put Dockge on its own bridge network. This is mostly habit; it doesn’t really matter for a single-machine homelab, but it keeps things organized.

Reverse Proxy Setup with Caddy

I don’t expose Dockge directly to port 5001. Instead, I put it behind Caddy. Here’s the relevant snippet from my Caddyfile:

dockge.home.lab {
    reverse_proxy localhost:5001 {
        header_up X-Forwarded-For {http.request.remote.host}
        header_up X-Forwarded-Proto {http.request.proto}
    }
    basicauth / {
        mustafa $2a$14$...[bcrypt hash here]
    }
}

A few things worth noting. The header_up directives tell Dockge the real IP and protocol of the original request. This matters for logging and for Dockge’s internal logic around forwarded connections. The basicauth block uses bcrypt-hashed credentials. You can generate a hash with caddy hash-password.

One small frustration: Dockge doesn’t have built-in support for trusting reverse proxy headers by default, so if you check the IP logs in Dockge, it’ll show the Caddy container’s IP, not your real client IP. This is a minor thing, but it bugged me enough to mention it. Portainer handles this more gracefully out of the box.

Directory Structure and Stack Organization

Here’s how I organize my stacks on disk:

/opt/stacks/
├── immich/
│   ├── docker-compose.yml
│   ├── .env
│   └── data/
├── ollama/
│   ├── docker-compose.yml
│   └── models/
├── uptime-kuma/
│   ├── docker-compose.yml
│   └── data/
└── vaultwarden/
    ├── docker-compose.yml
    ├── .env
    └── data/

Each application gets its own subdirectory with its compose file and any local data or config files. When you open Dockge, it discovers these directories and lists them as separate stacks. You can edit, start, stop, or delete each one independently.

The .env files are important. Dockge will load them automatically when you bring up a stack, so you can keep secrets and configuration outside the YAML itself. I use `.env` for things like database passwords and API keys. Make sure these files aren’t world-readable if your homelab is accessible from untrusted networks.

Environment Variables and Secrets

Here’s a sample `.env` for one of my stacks (Vaultwarden):

DOMAIN=vaultwarden.home.lab
SMTP_HOST=mail.example.com
SMTP_PORT=587
[email protected]
[email protected]
SMTP_PASSWORD=your_password_here
DATABASE_URL=postgresql://user:pass@postgres:5432/vaultwarden
LOG_LEVEL=info

In the corresponding docker-compose.yml, I reference these with ${VARIABLE_NAME}. Dockge doesn’t have a built-in secret manager like Docker Swarm does, so this is as secure as I’m making it for a homelab. If you want encryption at rest, put your stacks directory on an encrypted volume, but honestly, if someone gets SSH access to your homelab, the .env files are the least of your problems.

First Run and Common Setup Issues

When you start Dockge for the first time, it’ll generate an admin user. The default username and password are both ‘admin’—change this immediately in the settings. The web interface walks you through it, no surprises there.

One thing that tripped me up initially: Dockge expects the stacks directory to already exist. If you point it to /opt/stacks but that directory doesn’t exist yet, it won’t error out loudly; it just won’t discover anything. Create the directory first, then start Dockge:

mkdir -p /opt/stacks /opt/dockge/data
docker-compose up -d

After that, you can create new stacks through the UI, and they’ll show up immediately. Dockge doesn’t restart when you add new subdirectories; it just discovers them on the fly. That’s actually nice.

The terminal feature is one of the reasons I’m still using this. When you click into a stack and then the ‘Terminal’ tab, you get a real-time shell into the container (whichever one you select from the dropdown). This is genuinely useful for debugging. The logs are color-coded and scrollable, which makes reading through pages of container output less painful than it used to be.

Backup and Disaster Recovery

Dockge stores its state in SQLite, but the real data—the actual compose files and .env files—lives in your stacks directory. If you lose /opt/stacks, you lose your configurations. I back this up to a second drive every night via rsync. It’s not sexy, but it works:

rsync -av /opt/stacks /mnt/backup/

The SQLite database in /opt/dockge/data isn’t critical—it’s just metadata about your stacks. If it gets corrupted, Dockge will recreate it on the next start. But your compose files are critical. Treat them like code, because they are.

I’ve been tempted to keep my stacks in git, but I haven’t done it yet because some of the .env files have actual secrets in them, and I’m paranoid about accidentally committing those. There are patterns for this (git-crypt, sealed secrets, etc.), but for a homelab with five machines and no CI/CD pipeline, rsync and weekly backups are honestly good enough.

What I Still Don’t Like About Dockge

It’s fair to admit what doesn’t work well. The YAML editor is functional but not great—it has syntax highlighting and validation, but autocomplete is nonexistent. If you’re writing complex compose files, you’ll probably end up editing them in VS Code anyway and pasting them in. That’s a minor thing, but it means the UI isn’t actually a replacement for knowing how to write Compose YAML by hand.

There’s also no built-in monitoring or alerting. It doesn’t tell you when a container dies or when a resource limit is hit. Uptime Kuma does this, and I use it in parallel, but Dockge itself is just a manager, not a monitor. If you need that, layer another tool on top.

Finally, multi-machine management is listed as a feature, but I haven’t gotten it working reliably. The idea is that you can manage Docker hosts remotely through Dockge, but the setup involves SSH keys and some configuration that felt fragile to me. I ended up running separate Dockge instances on each machine instead, which is simpler but less elegant.

These limitations don’t make Dockge bad. They just make it what it is: a focused tool that does one job well without trying to be everything to everyone. For a homelab with a handful of machines and a few dozen containers, that’s actually the right approach.

FAQ

Can I run Dockge on a Raspberry Pi?

Yes, but only on Pi 4 with at least 2GB of RAM. The Pi 3 is too slow. Just use the standard Docker install and run the same compose config; there’s an ARM image available. I haven’t tested it personally, but people have reported it working fine on Pi 4 with moderate stack counts.

How much RAM does Dockge use?

Roughly 50-150MB depending on how many stacks you’re managing and how often you’re checking logs. It’s lightweight compared to Portainer, which can balloon to 200-300MB. For most homelabs, this won’t be a constraint.

Is Dockge secure enough for production?

For a homelab, yes. For production, no. There’s no multi-tenancy, no advanced RBAC, no audit logging, and authentication is basic. If you’re running this on machines exposed to the internet, put it behind a reverse proxy with strong auth and definitely use HTTPS. Don’t expose it directly.

Can I manage stacks on remote Docker hosts?

Dockge has a remote hosts feature that works over SSH, but it’s not well-documented and I couldn’t get it stable. Running separate Dockge instances on each host is more reliable.

What happens if Dockge crashes?

Your containers keep running. Dockge is just a UI layer—it doesn’t manage the actual container lifecycle in a deep way. If Dockge goes down, your stacks stay up until you manually stop them. This is good design, even if it’s not obvious at first.

Explore Dockge in our AI Homelab Toolkit.

Share this article