Ramblings of an aging IT geek
← Ramblings of an aging IT geek
homelab

one docker-compose file to rule the homelab

Consolidating a sprawl of hand-started containers into a single declarative Compose stack with a reverse proxy and shared network.

A server rack with networking gear

The homelab had reached the stage where I no longer knew what was running. Containers started by hand months ago, half of them with the run command lost to shell history, port numbers I had to docker ps to remember. The day I rebooted the host and spent twenty minutes reconstructing what was meant to come back up, I admitted it had to become a file.

Everything now lives in one docker-compose.yml. Not because Compose is clever, it's deliberately not, but because the whole stack being declared in one place I can read, diff, and commit to git is worth more than any feature. The host can burn down and I can bring the entire house back with one command.

The pattern that made it click was putting a reverse proxy in front of everything and giving the services a shared network. Traefik watches the Docker socket and configures itself from labels on each container, so adding a new service is a few lines, no editing a central config, no remembering which port was free.

A homelab setup

version: "3.7"

services:
  traefik:
    image: traefik:v2.0
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - web

  grafana:
    image: grafana/grafana
    restart: unless-stopped
    volumes:
      - grafana-data:/var/lib/grafana
    labels:
      - traefik.enable=true
      - traefik.http.routers.grafana.rule=Host(`grafana.house`)
    networks:
      - web

networks:
  web:

volumes:
  grafana-data:

A few things I learned the boring way. Name your volumes and never bind-mount data into a path you might docker-compose down -v by accident, because that flag deletes volumes and it does not ask twice. Set restart: unless-stopped on everything you want surviving a reboot, but not always, or a container in a crash loop will fight you. And pin image tags. latest is a promise that something will silently change underneath you on a Tuesday, and you will spend the evening working out which thing.

The real win isn't any one service, it's that the config is now reviewable. When I add Pi-hole or swap a database image, it's a commit with a diff I can read before applying. The homelab stopped being a pile of pets I tended by hand and became a thing I could describe in a file, which means future me can understand it without archaeology. That, more than uptime, is what self-hosting at home should buy you.