diff --git a/.claude/skills/homelab-ssh/SKILL.md b/.claude/skills/homelab-ssh/SKILL.md index 1142951..cf19b16 100644 --- a/.claude/skills/homelab-ssh/SKILL.md +++ b/.claude/skills/homelab-ssh/SKILL.md @@ -19,10 +19,10 @@ The first `Bash` command of a session is gated by a GateGuard hook — state the ## docker-compose via the `dc` alias -The stack is Docker Compose **v1.27.4** (`docker-compose`, hyphenated — `docker compose` v2 is not installed). On the server, `dc` is aliased in `~/.bashrc` to: +The stack uses Docker Compose v2 (`docker compose` plugin, installed via apt). On the server, `dc` is aliased in `~/.bashrc` to: ``` -docker-compose -f ~/htpc-download-box/docker-compose.yml --env-file ~/htpc-download-box/.env +docker compose -f ~/htpc-download-box/docker-compose.yml --env-file ~/htpc-download-box/.env ``` It's a shell alias, so it only exists in an interactive shell. Invoke it with `bash -ic`: @@ -42,7 +42,7 @@ Use the compose **service name** (`sonarr`, `caddy`, `app`, …). Without `bash - `~/htpc-download-box/docker-compose.yml`, `~/htpc-download-box/.env` — stack definition - `/config/caddy/Caddyfile` — Caddy config (mounted into the `caddy` container at `/etc/caddy/Caddyfile`) - `/config//` — per-service persisted config; `/storage1/` — media & data; plus named Docker volumes -- `~/htpc-download-box/` also holds unrelated legacy files (`*.bak`, old `.git`, `README.md`, `Vagrantfile`) — don't modify them +- `~/htpc-download-box/` contains only `docker-compose.yml` and `.env` — the legacy cruft has been cleaned out ## Notes diff --git a/CLAUDE.md b/CLAUDE.md index b174355..001ddec 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,7 +16,7 @@ Tracked files ↔ where they live on valhalla: `.env` is committed **intentionally** — the GitHub repo `ginnoir/homelabstack` is private and the stack's secrets are versioned with it. Do not scrub or gitignore it. -The server's `~/htpc-download-box/` also holds unrelated legacy files (`*.bak`, a 2020 `.git`, an old 42 KB `README.md`, `Vagrantfile`, `apache/`, `proxy/`): this stack was grafted onto the original *htpc-download-box* project. Leave that cruft alone — only the three files above are managed from here. +The server's `~/htpc-download-box/` contains only `docker-compose.yml` and `.env` — the legacy cruft from the original *htpc-download-box* project has been cleaned out. ## The core workflow @@ -43,7 +43,7 @@ SSH is key-based and works from this Windows host directly. In automation, pass All compose operations go through the **`dc` alias** in the server's `~/.bashrc`: ``` -dc = docker-compose -f ~/htpc-download-box/docker-compose.yml --env-file ~/htpc-download-box/.env +dc = docker compose -f ~/htpc-download-box/docker-compose.yml --env-file ~/htpc-download-box/.env ``` It's a shell alias, so it only exists in an **interactive** shell — invoke it over SSH with `bash -ic`: @@ -59,8 +59,8 @@ Address services by their **compose service name** (`sonarr`, `caddy`, `app`, ## docker-compose.yml — read before editing -- **Compose v1.27.4.** The binary is hyphenated `docker-compose`; `docker compose` (v2) is **not** installed. Project name is `htpc-download-box` (from the directory). -- **Container names:** services with an explicit `container_name:` (most of the media stack, `owncloud_*`, `ntfy`, `freshrss`, `hbbr`/`hbbs`) use that literal name. Services without one get the v1 pattern `htpc-download-box__1` (e.g. `caddy`, `foundry`, `app`, `postgres`, the `authentik-*`/`famapp-*` sets). Prefer `dc ` so you don't have to track which is which. +- **Compose v2** (`docker compose`, space), installed as the `docker-compose-plugin` apt package and kept current via apt. Project name is `htpc-download-box` (from the directory — inconsequential since every service now has an explicit `container_name:`). +- **Container names:** every service has an explicit `container_name:`. Disambiguated duplicates use `type_context` naming: `postgres_resume`, `postgres_famapp`, `postgres_authentik`, `minio_resume`, `minio_famapp`, `redis_authentik`. Always use the compose **service name** with `dc` commands — container names are just for `docker ps` readability. - **`${ROOT}`** (`.env`, default `/`) prefixes some media-stack volume mounts; other services hardcode `/config` and `/storage1`. Both forms resolve to the same real paths. - **Networks segment the stack:** `foundry`, `media`, `media_external`, `owncloud`, `resume`, `famapp`, `authentik`. `caddy` is the only container on all of them — a new service that Caddy must proxy has to share a network with `caddy`. - **Persistence lives on the server, not in this repo:** container state is in `/config/` bind mounts, under `/storage1`, or in named volumes (`postgres_data`, `minio_data`, `authentik_db_data`, `garden_uploads`, …). diff --git a/docker-compose.yml b/docker-compose.yml index 6ca0b76..c99e21b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,7 @@ services: # FOUNDRY VTT # ============================================================ foundry: + container_name: foundry image: felddy/foundryvtt:latest hostname: valhalla-primary init: true @@ -29,6 +30,7 @@ services: - "30000:30000" foundry2: + container_name: foundry2 image: felddy/foundryvtt:latest hostname: valhalla-secondary init: true @@ -62,6 +64,7 @@ services: # - caddy-dynamicdns (keeps DNS records current if WAN IP changes) # ============================================================ caddy: + container_name: caddy image: serfriz/caddy-cloudflare-ddns:latest restart: unless-stopped networks: @@ -404,6 +407,7 @@ services: # REACTIVE RESUME STACK # ============================================================ postgres: + container_name: postgres_resume image: postgres:16-alpine restart: unless-stopped networks: @@ -421,6 +425,7 @@ services: retries: 5 resume-minio: + container_name: minio_resume image: minio/minio:latest restart: unless-stopped networks: @@ -442,6 +447,7 @@ services: start_period: 30s chrome: + container_name: chrome image: ghcr.io/browserless/chromium:latest restart: unless-stopped networks: @@ -454,6 +460,7 @@ services: - PRE_REQUEST_HEALTH_CHECK=true app: + container_name: resume image: amruthpillai/reactive-resume:latest restart: unless-stopped networks: @@ -547,6 +554,7 @@ services: - FRESHRSS_USER=--api-password ${FRESHRSS_API_PASSWORD} --email ${FRESHRSS_EMAIL} --password ${FRESHRSS_PASSWORD} --user ginnoir vigilant: + container_name: vigilant image: ghcr.io/verifiedjoseph/vigilant:latest restart: unless-stopped environment: @@ -590,6 +598,7 @@ services: # UTILITIES # ============================================================ 5etools: + container_name: 5etools image: ghcr.io/5etools-mirror-3/5etools-src:latest restart: unless-stopped networks: @@ -598,6 +607,7 @@ services: - "9009:80" watchtower: + container_name: watchtower image: containrrr/watchtower:latest restart: unless-stopped environment: @@ -610,6 +620,7 @@ services: # FAMAPP # ============================================================ famapp: + container_name: famapp image: ${FAMAPP_IMAGE:-ghcr.io/ginnoir/famapp:latest} pull_policy: ${FAMAPP_PULL_POLICY:-always} restart: unless-stopped @@ -645,6 +656,7 @@ services: condition: service_healthy famapp-db: + container_name: postgres_famapp image: postgres:16-alpine restart: unless-stopped networks: @@ -662,6 +674,7 @@ services: retries: 5 famapp-minio: + container_name: minio_famapp image: minio/minio:latest command: server /data --console-address ":9003" restart: unless-stopped @@ -686,6 +699,7 @@ services: # AUTHENTIK # ============================================================ authentik-server: + container_name: authentik_server image: ghcr.io/goauthentik/server:${AUTHENTIK_IMAGE_TAG:-2024.12.3} restart: unless-stopped command: server @@ -708,6 +722,7 @@ services: condition: service_healthy authentik-worker: + container_name: authentik_worker image: ghcr.io/goauthentik/server:${AUTHENTIK_IMAGE_TAG:-2024.12.3} restart: unless-stopped command: worker @@ -728,6 +743,7 @@ services: condition: service_healthy authentik-db: + container_name: postgres_authentik image: postgres:16-alpine restart: unless-stopped networks: @@ -749,6 +765,7 @@ services: retries: 5 authentik-redis: + container_name: redis_authentik image: redis:7-alpine restart: unless-stopped networks: