← Back

Casa - My Home Lab

I run about 38 services on a single machine at home media streaming, home automation, ad blocking, password management, telegram bots, workflow automation - the works and managing all of that used to be a mess until I built casa

what is it

casa is a home lab management system built around Docker Compose every service gets its own directory with a compose.yml and optionally a .env file then there’s a central config.yaml that defines which services are active, their URLs, categories, and colors for the UI

the whole thing is a git repo, with secrets encrypted via git-crypt

the CLI

the core of casa is a CLI tool that wraps Docker Compose with some nice abstractions I went with Go for this because the compiled binary is tiny, it has zero runtime dependencies, and the code reads almost like pseudocode

casa up jellyfin        # start a service
casa down sonarr        # stop a service
casa status             # see what's running
casa log homeassistant  # tail logs
casa update jellyfin    # pull + restart
casa install seerr      # add a new service to config
casa reset transmission # wipe and start fresh

it reads config.yaml to know which services are active, parses each service’s compose.yml for metadata like URLs and ports, creates volume directories if they don’t exist, and restarts Caddy after config changes

nothing fancy - it just saves you from remembering which directory to cd into and which docker compose flags to pass

the services

here’s a taste of what’s running:

media

infrastructure

smart home

tools

bots

networking

every service gets a subdomain under home.shubapp.com - so Jellyfin lives at jellyfin.home.shubapp.com, Home Assistant at homeassistant.home.shubapp.com, and so on

the cool trick here (which I learned from Schniz) is that the domain just points to my server’s LAN IP so from outside my network it doesn’t resolve to anything - it’s basically a private domain that only works at home but you still get all the benefits of real DNS - proper subdomains, valid HTTPS certificates via Cloudflare DNS challenges, and no more typing IP addresses with port numbers

Caddy handles all the reverse proxying and TLS via Cloudflare DNS challenges the Caddyfile is generated automatically from config.yaml - a TypeScript script reads each service’s compose file, extracts port mappings and labels, and builds the full config

services either share a Docker network called caddy (so Caddy can reach them by container name) or run with host networking when they need direct access to the network (like Home Assistant for device discovery)

Pi-hole runs as the network DNS so every device on the LAN gets ad blocking for free

the setup

the entire system bootstraps with a single Ansible playbook

./run-ansible.sh

it walks you through an interactive config - picks your static IP, username, domain, which services to enable - then it installs Docker, configures the network with netplan, mounts your external drives, creates all the volume directories, generates the Caddyfile, and starts everything

all configs and data live on external USB drives mounted at /media/external/ this way the OS drive can die and you just plug the drives into a new machine and run the playbook again

/media/external/
├── configs/     # service configs (jellyfin, sonarr, caddy, etc.)
└── library/     # media and data
    ├── tv/
    ├── movies/
    ├── music/
    └── downloads/

adding a new service

adding a service is just creating a directory with a compose.yml:

services:
  myapp:
    image: some/image:latest
    labels:
      url: https://myapp.home.shubapp.com
      title: My App
      category: tools
      color: "#4A90D9"
    ports:
      - "8080:8080"
    networks:
      - caddy

networks:
  caddy:
    external: true

then casa install myapp adds it to the config, regenerates the Caddyfile, and you’re live

why not kubernetes

I tried k8s at home, I really did but for a single machine running personal services it’s just overkill Docker Compose gives you everything you need - declarative config, networking, volume management - without the operational overhead and when something breaks at 2am you want to debug a compose.yml, not a HelmRelease → Deployment → ReplicaSet → Pod chain

casa keeps the simplicity of compose but adds just enough tooling on top to make managing 38 services not feel like a chore