--- name: homelab-ssh description: Connect to and run commands on the valhalla homelab server (ginnoir@valhalla) over SSH. Use when inspecting the live per-domain stacks, tailing logs, restarting a container, reloading Caddy, or checking container/network/volume state. There is no `dc` alias anymore — services are addressed by container name with plain `docker` commands. --- # homelab-ssh The production homelab runs on a headless Ubuntu host reachable at `ssh ginnoir@valhalla` (key-based auth; resolves and works from this Windows host directly). ## Connect (non-interactive / safe for automation) Always pass `-o BatchMode=yes` so a missing key or password prompt fails fast instead of hanging: ```powershell ssh -o BatchMode=yes -o ConnectTimeout=8 ginnoir@valhalla "" ``` The first `Bash` of a session is gated by a GateGuard hook — state the user request + what the command does, then retry. ## The estate is now 11 Portainer-managed stacks + the management plane | Stack (Portainer project name) | Containers | |---|---| | `proxy` | `caddy` | | `media` | `deluge`, `nzbget`, `sonarr`, `radarr`, `bazarr`, `prowlarr`, `overseerr`, `tautulli`, `qbittorrent`, `whisparr`, `stash` | | `foundry` | `foundry`, `foundry2`, `5etools` | | `owncloud` | `owncloud_server`, `owncloud_mariadb`, `owncloud_redis` | | `resume` | `resume`, `postgres_resume`, `minio_resume`, `chrome` | | `famapp` | `famapp`, `postgres_famapp`, `minio_famapp` | | `authentik` | `authentik_server`, `authentik_worker`, `postgres_authentik`, `redis_authentik` | | `notify` | `ntfy`, `freshrss`, `vigilant` | | `monitoring` | `uptime_kuma`, `homarr` | | `remote` | `hbbr`, `hbbs` | | `dev` | `gitea`, `code_server`, `bookstack`, `mariadb_bookstack`, `dbx`, `registry`, `postgres_gitea`, `postgres_plane`, `redis_plane`, `plane_minio`, `plane_api`, `plane_web`, `plane_worker`, `plane_beat`, `plane_create_bucket` | | management plane (raw compose at `~/valhalla-lab/portainer-compose.yml`, project name `valhalla-lab`) | `portainer`, `vault`, `github_runner`, `watchtower` | ## Common ops by container name There's no umbrella `dc` alias. Use plain `docker`: ```powershell ssh -o BatchMode=yes ginnoir@valhalla "docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Label \"com.docker.compose.project\"}}'" ssh -o BatchMode=yes ginnoir@valhalla "docker logs --tail 200 -f " ssh -o BatchMode=yes ginnoir@valhalla "docker restart " ssh -o BatchMode=yes ginnoir@valhalla "docker exec " ssh -o BatchMode=yes ginnoir@valhalla "docker exec caddy caddy reload --config /etc/caddy/Caddyfile" ``` ## Per-stack `docker compose` operations Each Portainer git stack lives at `/data/compose//stacks//docker-compose.yml` (Portainer chooses the `` when the stack is created). To inspect a stack's resolved config or run a one-off compose op: ```powershell # Pick the stack file from its label ssh ginnoir@valhalla "docker inspect --format '{{ index .Config.Labels \"com.docker.compose.project.config_files\"}}'" # Then point compose at it ssh ginnoir@valhalla "docker compose -f /data/compose/14/stacks/owncloud/docker-compose.yml ps" ``` For management plane only: ```powershell ssh ginnoir@valhalla "docker compose -f ~/valhalla-lab/portainer-compose.yml --env-file ~/valhalla-lab/.env ps" ``` ## Key paths on the server - `~/valhalla-lab/portainer-compose.yml` + `~/valhalla-lab/.env` — management plane (raw compose, applied via `apply-compose.ps1 -Portainer`) - `/config/caddy/Caddyfile` — Caddy config (mounted into `caddy` at `/etc/caddy/Caddyfile`) - `/config//` — per-service persisted config (SSD tier: configs + Postgres + Redis) - `/storage1/labdata//` — high-density data on the ZFS pool (MinIO buckets, registry layers, gitea repos) - `/storage1/` — media library (Books, Tabletop, etc.) - `/data/compose//stacks//` — Portainer's working copy of each stack (Portainer auto-pulls these from git every 5 min) ## Networks - `edge` — shared reverse-proxy network. `caddy` + every service Caddy proxies. Anything new that needs to be public must join this. - `` (e.g. `media`, `authentik`, `dev`) — per-stack private network for intra-stack traffic (app ↔ its db/cache/minio). - `portainer_proxy`, `valhalla-lab_default` — management-plane networks (legacy names, kept). - `bridge`, `host`, `none` — Docker defaults. ## Notes - Read-only exploration of `/config`, `/storage1`, and container state is fine for answering questions. - For destructive ops (`docker rm -f`, network/volume pruning), get explicit confirmation first. - To deploy config changes, use the `homelab-apply` skill (per-domain stacks → git push; mgmt plane / Caddyfile → `apply-compose.ps1`). - `htpc-download-box_*` and `valhalla-lab_*` named volumes still exist as a data safety net from the pre-split monolith — every per-domain stack uses bind mounts now, so those orphans can be reaped once you're confident in the new persistence.