Files
alembic/docker-compose.snippet.yml
T
andrew b135f11557 Security hardening and first-run/portability improvements
Security (P0):
- Remove committed session-secret default; auto-generate and persist a
  random secret to the config volume when SESSION_SECRET is unset
  (prevents forgeable session cookies / auth bypass).
- Validate playlist names to a safe charset and render sldl configs via
  literal Python substitution instead of sed (closes a command-injection
  and path-traversal path through playlist names).
- shlex-quote credential values written to shell-sourced env files, and
  strip newlines from values patched into .conf files.
- Render playlist .conf files 0600; warn at startup if the master key is
  co-located with the config volume; document keeping it separate.

Portability:
- Configurable timezone via TZ (default UTC) instead of hardcoded Edmonton.
- Remove personal defaults (navidrome user "andrew", ephemeral.club URLs).
- Ship generic example seeds; move the cross-album dedup keep-list and the
  legacy playlist import to editable config files; drop the personal
  _upgrade.csv.
- Generic VPN reference in docker-compose.snippet.yml.

First-run experience:
- Redirect to /setup instead of 500 when OIDC is unconfigured; surface a
  missing master key inline; entrypoint exits with an actionable message
  when the config folder is not writable.
- Add unauthenticated /health (JSON) and /setup (checklist) diagnostics.

Docs:
- Write docs/ARCHITECTURE.md and docs/MIGRATION.md (previously referenced
  but missing); expand README with ownership, backups, advanced settings,
  and migration guidance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 14:25:55 -06:00

52 lines
2.2 KiB
YAML

# Optional: route Soulseek traffic through a VPN container (gluetun).
#
# This is a reference, not a drop-in file. Most people can ignore it and use
# the plain `ports:` mapping shown in the README. Use this pattern only if you
# want alembic's outbound traffic to leave through a VPN.
#
# The idea: instead of giving alembic its own network, you attach it to a
# gluetun container's network with `network_mode: "service:gluetun"`. All of
# alembic's traffic then exits through the VPN gluetun maintains.
#
# When you do this, three things change compared to the README example:
# 1. alembic no longer publishes its own port. Publish 8420 on the gluetun
# service instead (add `- 8420:8420` to gluetun's `ports:`).
# 2. gluetun's firewall must allow alembic to reach your other containers
# (Navidrome, etc). Add your Docker bridge subnet to gluetun's
# FIREWALL_OUTBOUND_SUBNETS, for example:
# FIREWALL_OUTBOUND_SUBNETS=192.168.0.0/24,172.18.0.0/16
# Find your subnet with: docker network inspect <your-compose-project>_default
# 3. If you use a reverse proxy, point it at gluetun's host/port, not
# alembic's. Once alembic shares gluetun's network it has no container
# hostname of its own.
alembic:
image: alembic:latest
container_name: alembic
network_mode: "service:gluetun"
depends_on:
gluetun:
condition: service_healthy
env_file:
# Your OIDC settings (POCKETID_ISSUER, POCKETID_CLIENT_ID,
# POCKETID_CLIENT_SECRET) and any other env vars.
- /path/to/alembic-config/alembic.env
volumes:
- /path/to/your/music:/data/music:rw
- /path/to/alembic-config:/config:rw
secrets:
- alembic_master_key
restart: unless-stopped
# Add alongside the existing top-level `secrets:` block (create one if this
# compose file doesn't have one yet).
#
# Keep master.key OUTSIDE the config volume. The key decrypts every stored
# credential, and the encrypted database lives in the config volume, so if the
# key sits in there too then a single leaked backup exposes both halves and the
# encryption buys you nothing. Put it in its own directory that your config
# backup does not include:
# secrets:
# alembic_master_key:
# file: /path/to/alembic-secrets/master.key