diff --git a/DEV.md b/DEV.md index 632e68c..f6dfe04 100644 --- a/DEV.md +++ b/DEV.md @@ -269,39 +269,53 @@ fi ## Docker Compose / ScaleTail -The installer clones [ScaleTail](https://github.com/tailscale-dev/ScaleTail) templates to `/usr/local/share/linux_post_install/scale-tail/` — 119+ self-hosted services with a Tailscale sidecar pattern. +The installer clones [ScaleTail](https://github.com/tailscale-dev/ScaleTail) templates to `/usr/local/share/linux_post_install/scale-tail/` — 119+ self-hosted services with a Tailscale sidecar pattern. Each service gets a `tail-xxxxx.ts.net` URL via `network_mode: service:tailscale`. -### Deployed Layout +### Config Strategy — Three Layers + +Values cascade from least to most specific: ``` -/usr/local/share/linux_post_install/scale-tail/ # Templates (git repo) -└── services// - ├── compose.yaml - └── .env - -~/.config/linux_post_install/compose.env # Global defaults - -/srv// # Active deployment - ├── compose.yaml # Refreshed on update (preserves .env) - ├── .env # Your config — preserved across updates - ├── config/ - └── data/ +Template .env (per-service defaults from ScaleTail) + ↓ +Global config (~/.config/linux_post_install/compose.env) + ↓ +Per-service .env (/srv//.env) — created on first deploy, NEVER overwritten ``` +On first `pos docker compose up `: +1. Template `.env` is copied to `/srv//.env` +2. Matching keys from global config are filled in +3. If `TS_AUTHKEY` is still empty, you're prompted to enter it +4. After that, the per-service `.env` is **never touched** — not even by `update` + +### Layout + +| Path | Purpose | Mutability | +|------|---------|------------| +| `/usr/local/share/linux_post_install/scale-tail/services//` | ScaleTail templates (git repo) | Read-only | +| `~/.config/linux_post_install/compose.env` | Your global defaults | Edit via `config set` or `config edit` | +| `/srv//` | Active deployment | Per-service `.env` preserved forever | + ### Key Commands | Command | Behaviour | |---------|-----------| -| `pos docker compose up ` | Deploys to `$SERVICES_BASE//`, creates `config/` + `data/`, generates `.env` | +| `pos docker compose up ` | Deploys to `$SERVICES_BASE//`, creates `config/` + `data/`, generates `.env` from global defaults | | `pos docker compose down ` | Stops the stack | -| `pos docker compose update` | `git pull` templates + refreshes `compose.yaml` for all deployed services | -| `pos docker compose config set K=V` | Sets global default in `~/.config/linux_post_install/compose.env` | +| `pos docker compose update` | `git pull` templates + refreshes `compose.yaml` for all deployed services (`.env` untouched) | +| `pos docker compose config set K=V` | Sets a global default in `~/.config/linux_post_install/compose.env` | +| `pos docker compose config show` | Displays current global config and `SERVICES_BASE` | +| `pos docker compose config edit` | Opens global config in `$EDITOR` | -### .env Design +### Global Config Keys -- **Global config**: `~/.config/linux_post_install/compose.env` — one place for `TS_AUTHKEY`, `TZ`, `DNS_SERVER`, `SERVICES_BASE` -- **Per-service**: `//.env` — generated from template, filled from global config -- **Updates**: `compose.yaml` refreshes from template but `.env` is never overwritten +| Key | Required | Default | Purpose | +|-----|----------|---------|---------| +| `TS_AUTHKEY` | Yes | — | Tailscale auth key for sidecar networking | +| `TZ` | No | `Europe/Amsterdam` | Timezone for services | +| `DNS_SERVER` | No | `9.9.9.9` | Custom DNS server | +| `SERVICES_BASE` | No | `/srv` | Root directory for all deployments | --- diff --git a/README.md b/README.md index 9f4cd69..069e745 100755 --- a/README.md +++ b/README.md @@ -76,23 +76,63 @@ pos network scan 192.168.8.0/24 # Fast parallel ping sweep ```bash pos docker ps # List containers with health, IPs, ports pos docker health # Health dashboard (exits 1 if unhealthy) -pos docker compose ls # List 119+ available services -pos docker compose up jellyfin # Deploy with Tailscale HTTPS -pos docker compose down actual-budget # Stop a stack -pos docker compose logs home-assistant -f # Tail logs -pos docker compose update # Pull latest templates -pos docker compose config set TS_AUTHKEY=x # Set global defaults ``` -**First run with compose:** +#### Compose (ScaleTail — 119+ self-hosted services) + +Each service runs with a Tailscale sidecar and gets its own `tail-xxxxx.ts.net` URL. + +**Quick start:** ```bash +# 1. Set your Tailscale auth key (required once) pos docker compose config set TS_AUTHKEY=tskey-auth-xxxxx + +# 2. Deploy a service pos docker compose up jellyfin -# Open https://jellyfin.tail-xxxxx.ts.net + +# 3. Open https://jellyfin.tail-xxxxx.ts.net ``` -Services are deployed to `/srv//` by default. +**All commands:** + +```bash +pos docker compose ls # List available service templates +pos docker compose installed # List deployed services +pos docker compose up jellyfin # Deploy or start a service +pos docker compose down actual-budget # Stop a service +pos docker compose logs home-assistant -f # Tail logs +pos docker compose restart home-assistant # Restart a service +pos docker compose update # Pull latest templates + refresh deployed compose files +pos docker compose config # Show current configuration +pos docker compose config set TZ=Asia/Tokyo # Set a global default +pos docker compose config edit # Open config in editor +``` + +**Config strategy — three layers:** + +| Layer | File | Purpose | +|-------|------|---------| +| Template defaults | `/usr/local/share/linux_post_install/scale-tail/services//.env` | Per-service defaults from ScaleTail | +| Global config | `~/.config/linux_post_install/compose.env` | Your defaults — applies to all services | +| Per-service | `/srv//.env` | Actual config — created on first deploy, **never overwritten** | + +Set global defaults once, then every `up` fills them into the new service's `.env`. + +**Paths:** + +- Templates: `/usr/local/share/linux_post_install/scale-tail/services/` +- Deployments: `/srv//` (configurable via `SERVICES_BASE`) +- Global config: `~/.config/linux_post_install/compose.env` + +**Config keys:** + +| Key | What it does | +|-----|-------------| +| `TS_AUTHKEY` | Tailscale auth key (required for sidecar networking) | +| `TZ` | Timezone for the service | +| `DNS_SERVER` | Custom DNS server | +| `SERVICES_BASE` | Where services are deployed (default: `/srv`) ### VBox (disposable Docker containers) diff --git a/bin/pos-docker-compose b/bin/pos-docker-compose index d96b885..f00308f 100755 --- a/bin/pos-docker-compose +++ b/bin/pos-docker-compose @@ -7,24 +7,60 @@ CONFIG_ENV="${HOME}/.config/linux_post_install/compose.env" usage() { cat < Deploy a service - pos docker compose down Stop a service - pos docker compose restart Restart a service - pos docker compose logs [-f] View service logs - pos docker compose update Pull latest ScaleTail + refresh compose files - pos docker compose config Show global config - pos docker compose config set KEY=VALUE Set a global config value - pos docker compose config edit Open global config in editor - -h, --help Show this help +Usage: pos docker compose [args] + +Commands: + ls List all available ScaleTail service templates + installed List services already deployed on this machine + up Deploy or start a service + down Stop and remove a deployed service + restart Restart a running service + logs [-f] View logs (use -f to follow) + update Pull latest ScaleTail templates + refresh all deployed compose files + config Show current global configuration + config set KEY=VALUE Set a global default (e.g. TS_AUTHKEY, TZ, SERVICES_BASE) + config edit Open global config in your editor (\$EDITOR) + +─── Config Strategy ────────────────────────────────────────── + + Three layers — each overrides the one above: + + 1. Template defaults + /usr/local/share/linux_post_install/scale-tail/services//.env + + 2. Global config (your defaults — set once, applies to all services) + ~/.config/linux_post_install/compose.env + Keys: TS_AUTHKEY | TZ | DNS_SERVER | SERVICES_BASE + + 3. Per-service config (created on first deploy, preserved forever) + /srv//.env (or \$SERVICES_BASE//.env) + + On first "up", the service .env is generated from the template + and filled with values from your global config. After that, the + per-service .env is never overwritten — even by "update". + +─── Paths ──────────────────────────────────────────────────── + + Templates: /usr/local/share/linux_post_install/scale-tail/services/ + Deployments: \$SERVICES_BASE// (default: /srv//) + Global conf: ~/.config/linux_post_install/compose.env + +─── Quick Start ────────────────────────────────────────────── + + 1. Set your Tailscale auth key (required): + pos docker compose config set TS_AUTHKEY=tskey-auth-xxxxx + + 2. Deploy a service: + pos docker compose up jellyfin + + 3. Open https://jellyfin.tail-xxxxx.ts.net Examples: pos docker compose up jellyfin pos docker compose down actual-budget pos docker compose logs home-assistant -f - pos docker compose config set TS_AUTHKEY=tskey-auth-xxxxx + pos docker compose config set TZ=Asia/Tokyo + pos docker compose config set SERVICES_BASE=/data EOF exit 0 } @@ -122,7 +158,7 @@ cmd_up() { target=$(service_dir "$svc") if [ ! -d "$target" ]; then - log "Creating $svc at $target" + log "Deploying $svc to $target" mkdir -p "$target/config" "$target/data" if [ -f "$SCALE_DIR/$svc/compose.yaml" ]; then cp "$SCALE_DIR/$svc/compose.yaml" "$target/" @@ -249,16 +285,17 @@ cmd_config() { case "$action" in show) load_global_config + echo "${CYAN}Global compose config${RESET}" + echo "${DIM}File: $CONFIG_ENV${RESET}" + echo "${BLUE}────────────────────────────────────────${RESET}" if [ -f "$CONFIG_ENV" ]; then - echo "${CYAN}Global compose config:${RESET}" - echo "${BLUE}────────────────────────────────────────${RESET}" cat "$CONFIG_ENV" - echo "${BLUE}────────────────────────────────────────${RESET}" - echo "SERVICES_BASE=$SERVICES_BASE" else - warn "No config file found at $CONFIG_ENV" - echo "Default SERVICES_BASE=/srv" + echo "(no global config set — using defaults)" fi + echo "${BLUE}────────────────────────────────────────${RESET}" + echo "SERVICES_BASE=$SERVICES_BASE (deployment directory)" + echo "${DIM}Set with: pos docker compose config set SERVICES_BASE=/srv${RESET}" ;; set) local pair="${1:-}" @@ -277,13 +314,18 @@ cmd_config() { mkdir -p "$(dirname "$CONFIG_ENV")" if [ ! -f "$CONFIG_ENV" ]; then cat > "$CONFIG_ENV" <<-EOF +# Linux_post_install — global Docker Compose config +# Each key is optional; empty values prompt on first deploy. TS_AUTHKEY= TZ=Europe/Amsterdam DNS_SERVER=9.9.9.9 SERVICES_BASE=/srv EOF + log "Created default config at $CONFIG_ENV" fi + log "Opening $CONFIG_ENV in ${EDITOR:-nano}..." "${EDITOR:-nano}" "$CONFIG_ENV" + log "Config saved" ;; *) usage