refactor: pure env_file stack.env convention across all stacks

Every service now reads stack.env via env_file with container-exact var
names — no ${VAR} parse-time interpolation, no Portainer UI env vars
(except stacks/dev, kept on UI-env interpolation as documented exception).

- media: drop PUID/PGID/TZ env lines (env_file covers); resolve ${ROOT}
- foundry: secrets via env_file; FOUNDRY_PATCH_URLS -> CONTAINER_PATCH_URLS
- monitoring: HOMARR_SECRET_ENCRYPTION_KEY -> SECRET_ENCRYPTION_KEY
- notify: FRESHRSS_USER composed in stack.env; TZ via env_file
- owncloud: container-exact OWNCLOUD_*/MYSQL_* keys; runtime $$ healthcheck
- resume/famapp: composites (DATABASE_URL etc.) written out in stack.env
- authentik: container-exact keys; image tag pinned in compose
- notes: couchdb creds via env_file
- remote: gains stack.env (no secrets; convention completeness)
- CLAUDE.md: env convention, valhalla-lab registration-only note, correct
  on-host Portainer working-copy path (/config/portainer/compose/<id>)

Validated with docker compose config on valhalla for all 15 stacks.
This commit is contained in:
ginnoir
2026-06-09 16:03:47 -05:00
parent bb2bc6a20e
commit 7aa95fa00a
21 changed files with 114 additions and 175 deletions
+8 -3
View File
@@ -50,7 +50,7 @@ The runner workflow gate-filters on `paths: [Caddyfile, .github/workflows/deploy
| Path on valhalla | Purpose |
|---|---|
| `~/valhalla-lab/portainer-compose.yml` + `.env` | management plane (raw compose; project name `valhalla-lab`) |
| `/data/compose/<id>/stacks/<domain>/` | Portainer's working copy of each app stack (auto-pulled from git) |
| `/config/portainer/compose/<id>/stacks/<domain>/` | Portainer's working copy of each app stack (auto-pulled from git; `/data/compose/<id>/...` is the same path *inside* the portainer container, and root-owned on the host) |
| `/config/<service>/` | SSD-tier persistence: app configs, Postgres data, Redis data |
| `/storage1/labdata/<service>/` | ZFS-tier persistence: MinIO blob buckets, registry image layers, gitea repos/LFS |
| `/storage1/` | media library (Books, Tabletop, plex-style media) |
@@ -84,14 +84,14 @@ For per-stack compose ops, pick the file from the container's label:
```powershell
ssh ginnoir@valhalla "docker inspect <container> --format '{{ index .Config.Labels \"com.docker.compose.project.config_files\"}}'"
ssh ginnoir@valhalla "docker compose -f /data/compose/14/stacks/owncloud/docker-compose.yml ps"
ssh ginnoir@valhalla "docker compose -f /config/portainer/compose/14/stacks/owncloud/docker-compose.yml ps" # root-owned; needs sudo or a helper container
```
## Adding a service
1. Pick the stack it belongs to under `stacks/<domain>/` (or create a new stack and a new Portainer git stack for it).
2. Add the service to `stacks/<domain>/docker-compose.yml`. Configs → `/config/<svc>` bind. Blobs → `/storage1/labdata/<svc>` bind. Add `edge` to its `networks:` if Caddy must reach it; otherwise just the per-stack private net.
3. Add secrets to `stacks/<domain>/stack.env` (Portainer reads this file directly from the git repo on each redeploy).
3. Add secrets to `stacks/<domain>/stack.env` (Portainer reads this file directly from the git repo on each redeploy). **Env convention:** every service gets `env_file: stack.env`, and var names in `stack.env` are exactly what the container reads — no `${VAR}` interpolation, no Portainer UI env vars. Composite values (e.g. `DATABASE_URL`) are written out in full in `stack.env`; keep embedded components in sync on rotation. Exception: `stacks/dev` still uses `${VAR}` interpolation backed by Portainer UI env vars — when editing its `stack.env`, mirror the change in the stack's UI env vars too.
4. Add a site block to `Caddyfile` (`reverse_proxy <container_name>:<port>`); `import internal_only` for LAN-only.
5. Run `./scripts/gen-bookmarks.ps1` to regenerate `bookmarks-domains.html` + `bookmarks-ports.html` from the new Caddy block / published ports.
6. `git push`. Portainer redeploys the stack within 5 min; the runner reloads Caddy on the same push if `Caddyfile` changed.
@@ -104,6 +104,11 @@ ssh ginnoir@valhalla "docker compose -f /data/compose/14/stacks/owncloud/docker-
## Known quirks / gotchas
- Portainer stack #6 `valhalla-lab` is **registration-only** (visibility in the Portainer UI). It
has no auto-update and no git credentials on purpose — the management plane deploys via
`apply-compose.ps1 -Portainer`, never via Portainer git. Don't "fix" it by re-enabling polling,
and don't click *pull and redeploy* on it (its `docker-compose.yml` path no longer exists at
repo root).
- A **GateGuard hook** blocks the first use of `Bash`, and every `Write`/`Edit`, until you state the required facts (the user request + what the operation does/affects). State them, then retry the same call.
- `Caddyfile` proxies `matrix.ginnoir.com → localhost:8008`, but there is **no Matrix/Synapse service in compose** — it's external/legacy. Likewise `dev.ginnoir.com → 192.168.1.74:3000` points at a different LAN host.
- `watchtower` auto-updates `:latest` images, so a running image can drift ahead of what the last `apply` pulled.
+3 -19
View File
@@ -8,7 +8,7 @@
services:
authentik-server:
container_name: authentik_server
image: ghcr.io/goauthentik/server:${AUTHENTIK_IMAGE_TAG:-2024.12.3}
image: ghcr.io/goauthentik/server:2024.12.3
restart: unless-stopped
command: server
networks: [authentik, edge]
@@ -17,10 +17,6 @@ services:
environment:
AUTHENTIK_REDIS__HOST: authentik-redis
AUTHENTIK_POSTGRESQL__HOST: authentik-db
AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_DB_USER:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_DB_NAME:-authentik}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
ports:
- "9200:9000"
@@ -32,7 +28,7 @@ services:
authentik-worker:
container_name: authentik_worker
image: ghcr.io/goauthentik/server:${AUTHENTIK_IMAGE_TAG:-2024.12.3}
image: ghcr.io/goauthentik/server:2024.12.3
restart: unless-stopped
command: worker
networks: [authentik]
@@ -41,10 +37,6 @@ services:
environment:
AUTHENTIK_REDIS__HOST: authentik-redis
AUTHENTIK_POSTGRESQL__HOST: authentik-db
AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_DB_USER:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_DB_NAME:-authentik}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
depends_on:
authentik-db:
@@ -59,18 +51,10 @@ services:
networks: [authentik]
env_file:
- stack.env
environment:
POSTGRES_USER: ${AUTHENTIK_DB_USER:-authentik}
POSTGRES_PASSWORD: ${AUTHENTIK_DB_PASSWORD}
POSTGRES_DB: ${AUTHENTIK_DB_NAME:-authentik}
volumes:
- /config/authentik/postgres:/var/lib/postgresql/data
healthcheck:
test:
[
"CMD-SHELL",
"pg_isready -U ${AUTHENTIK_DB_USER:-authentik} -d ${AUTHENTIK_DB_NAME:-authentik}",
]
test: ["CMD-SHELL", "pg_isready -U authentik -d authentik"]
interval: 10s
timeout: 5s
retries: 5
+10 -5
View File
@@ -1,6 +1,11 @@
# authentik stack secrets
AUTHENTIK_IMAGE_TAG=2024.12.3
AUTHENTIK_DB_USER=authentik
AUTHENTIK_DB_PASSWORD=ebb7d34ecbc4fc8f95cd16ef491d2162cdf8
AUTHENTIK_DB_NAME=authentik
# authentik stack secrets — injected into all services via env_file.
# Var names are exactly what each container reads (no ${VAR} interpolation).
# AUTHENTIK_POSTGRESQL__* (server/worker) and POSTGRES_* (db) must stay in sync.
# Image tag is pinned in docker-compose.yml — bump it there via git.
AUTHENTIK_POSTGRESQL__USER=authentik
AUTHENTIK_POSTGRESQL__PASSWORD=ebb7d34ecbc4fc8f95cd16ef491d2162cdf8
AUTHENTIK_POSTGRESQL__NAME=authentik
AUTHENTIK_SECRET_KEY=C33S/oXOVOLrlLnWGMRYadgH9zfEC7Bm1vHtbczkFxHcTOj9j6io397c/OGb
POSTGRES_USER=authentik
POSTGRES_PASSWORD=ebb7d34ecbc4fc8f95cd16ef491d2162cdf8
POSTGRES_DB=authentik
+3 -28
View File
@@ -10,33 +10,15 @@
services:
famapp:
container_name: famapp
image: ${FAMAPP_IMAGE:-ghcr.io/ginnoir/famapp:latest}
pull_policy: ${FAMAPP_PULL_POLICY:-always}
image: ghcr.io/ginnoir/famapp:latest
pull_policy: always
restart: unless-stopped
networks: [famapp, edge]
env_file:
- stack.env
environment:
NODE_ENV: production
AUTH_URL: ${AUTH_URL}
DATABASE_URL: postgres://${FAMAPP_DB_USER}:${FAMAPP_DB_PASSWORD}@famapp-db:5432/${FAMAPP_DB_NAME}
AUTH_SECRET: ${FAMAPP_AUTH_SECRET}
AUTH_OIDC_ISSUER: ${AUTH_OIDC_ISSUER}
AUTH_OIDC_CLIENT_ID: ${AUTH_OIDC_CLIENT_ID}
AUTH_OIDC_CLIENT_SECRET: ${AUTH_OIDC_CLIENT_SECRET}
VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY}
VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY}
VAPID_SUBJECT: ${VAPID_SUBJECT}
NTFY_URL: ${NTFY_URL:-}
NTFY_TOPIC: ${NTFY_TOPIC:-}
LOG_LEVEL: ${LOG_LEVEL:-info}
RUN_MIGRATIONS: ${RUN_MIGRATIONS:-true}
MINIO_ENDPOINT: http://famapp-minio:9000
MINIO_ROOT_USER: ${famapp_MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${famapp_MINIO_ROOT_PASSWORD}
MINIO_BUCKET: ${famapp_MINIO_BUCKET}
OPENPLANTBOOK_CLIENT_ID: ${famapp_OPENPLANTBOOK_CLIENT_ID}
OPENPLANTBOOK_CLIENT_SECRET: ${famapp_OPENPLANTBOOK_CLIENT_SECRET}
ports:
- "3010:3000"
depends_on:
@@ -52,14 +34,10 @@ services:
networks: [famapp]
env_file:
- stack.env
environment:
POSTGRES_USER: ${FAMAPP_DB_USER}
POSTGRES_PASSWORD: ${FAMAPP_DB_PASSWORD}
POSTGRES_DB: ${FAMAPP_DB_NAME}
volumes:
- /config/famapp/postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${FAMAPP_DB_USER} -d ${FAMAPP_DB_NAME}"]
test: ["CMD-SHELL", "pg_isready -U famapp -d famapp"]
interval: 10s
timeout: 5s
retries: 5
@@ -72,9 +50,6 @@ services:
networks: [famapp]
env_file:
- stack.env
environment:
MINIO_ROOT_USER: ${famapp_MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${famapp_MINIO_ROOT_PASSWORD}
volumes:
- /storage1/labdata/famapp/minio:/data
ports:
+18 -13
View File
@@ -1,16 +1,21 @@
# famapp stack secrets
FAMAPP_IMAGE=ghcr.io/ginnoir/famapp:latest
FAMAPP_PULL_POLICY=always
# famapp stack secrets — injected into all services via env_file.
# Var names are exactly what each container reads (no ${VAR} interpolation,
# no Portainer UI env vars). POSTGRES_* (db) are embedded in DATABASE_URL
# (app) — keep them in sync on rotation. MINIO_ROOT_* are shared by the app
# and the minio server. Image tag is pinned in docker-compose.yml.
RUN_MIGRATIONS=true
LOG_LEVEL=info
AUTH_URL=https://fam.ginnoir.com
FAMAPP_DB_USER=famapp
FAMAPP_DB_PASSWORD=a9a999d16dd5cdc521bb62eff331265d3c24
FAMAPP_DB_NAME=famapp
# famapp Auth.js session secret (mapped to the container's AUTH_SECRET)
FAMAPP_AUTH_SECRET=CJsICgBs78YxxSdJfS8KU9Zn9k+QytRoVui9kVtuHtI=
# postgres (db container) + the composed URL the app reads
POSTGRES_USER=famapp
POSTGRES_PASSWORD=a9a999d16dd5cdc521bb62eff331265d3c24
POSTGRES_DB=famapp
DATABASE_URL=postgres://famapp:a9a999d16dd5cdc521bb62eff331265d3c24@famapp-db:5432/famapp
# famapp Auth.js session secret
AUTH_SECRET=CJsICgBs78YxxSdJfS8KU9Zn9k+QytRoVui9kVtuHtI=
# OIDC via Authentik (public URL through Caddy — no container dependency)
AUTH_OIDC_ISSUER=https://auth.ginnoir.com/application/o/famapp/
@@ -25,9 +30,9 @@ NTFY_URL=https://ntfy.ginnoir.com
NTFY_TOPIC=famapp
# MinIO object storage (plant/container image uploads)
famapp_MINIO_ROOT_USER=famapp
famapp_MINIO_ROOT_PASSWORD=d0fet0th3x
famapp_MINIO_BUCKET=garden
MINIO_ROOT_USER=famapp
MINIO_ROOT_PASSWORD=d0fet0th3x
MINIO_BUCKET=garden
famapp_OPENPLANTBOOK_CLIENT_ID=5JdQLab69RhVaF4er7b7D29BCrkf3fo3OEiDsOQa
famapp_OPENPLANTBOOK_CLIENT_SECRET=kxPTrdQPAVta7sjVuIRf5EGIJ1fKvlMlqRSJpQtFxRftJhg7oeGnXzwH7ls6tluQLFUYVDYRMwISiAuKZGZLvkuJzUwFGCwhZw7UtW8OvcTGy4717WeNUinvuCDSsNXP
OPENPLANTBOOK_CLIENT_ID=5JdQLab69RhVaF4er7b7D29BCrkf3fo3OEiDsOQa
OPENPLANTBOOK_CLIENT_SECRET=kxPTrdQPAVta7sjVuIRf5EGIJ1fKvlMlqRSJpQtFxRftJhg7oeGnXzwH7ls6tluQLFUYVDYRMwISiAuKZGZLvkuJzUwFGCwhZw7UtW8OvcTGy4717WeNUinvuCDSsNXP
-8
View File
@@ -17,9 +17,6 @@ services:
env_file:
- stack.env
environment:
- FOUNDRY_USERNAME=${FOUNDRY_USERNAME}
- FOUNDRY_PASSWORD=${FOUNDRY_PASSWORD}
- FOUNDRY_ADMIN_KEY=${FOUNDRY_ADMIN_KEY}
- CONTAINER_VERBOSE=true
- FOUNDRY_HOSTNAME=foundry.ginnoir.com
- FOUNDRY_PROXY_PORT=443
@@ -27,7 +24,6 @@ services:
- CONTAINER_PRESERVE_OWNER=/data/Data/storage
- FOUNDRY_UID=1000
- FOUNDRY_GID=1000
- CONTAINER_PATCH_URLS=${FOUNDRY_PATCH_URLS:-}
ports:
- "30000:30000"
@@ -45,9 +41,6 @@ services:
env_file:
- stack.env
environment:
- FOUNDRY_USERNAME=${FOUNDRY_USERNAME}
- FOUNDRY_PASSWORD=${FOUNDRY_PASSWORD}
- FOUNDRY_ADMIN_KEY=${FOUNDRY_ADMIN_KEY}
- CONTAINER_VERBOSE=true
- FOUNDRY_HOSTNAME=foundry2.ginnoir.com
- FOUNDRY_PROXY_PORT=443
@@ -55,7 +48,6 @@ services:
- CONTAINER_PRESERVE_OWNER=/data/Data/storage
- FOUNDRY_UID=1000
- FOUNDRY_GID=1000
- CONTAINER_PATCH_URLS=${FOUNDRY_PATCH_URLS:-}
ports:
- "30001:30000"
+3 -2
View File
@@ -1,8 +1,9 @@
# foundry stack secrets
# foundry stack secrets — injected into both Foundry services via env_file.
# Var names are exactly what the felddy/foundryvtt container reads.
FOUNDRY_USERNAME=ginnoir
FOUNDRY_PASSWORD=agt-UAU!uky_ykh3juy
FOUNDRY_ADMIN_KEY=fuckyouben
# NOTE: the old plutonium patch gist 404s (dead URL), which put Foundry into a
# crash/backoff loop. Disabled to restore service. To re-enable, set this to a
# CURRENT raw gist URL for the plutonium patch script.
FOUNDRY_PATCH_URLS=
CONTAINER_PATCH_URLS=
+22 -54
View File
@@ -2,6 +2,11 @@
# All config/data is bind-mounted to /config and /storage1 already (no named
# volumes to migrate). Services join the private `media` net for inter-app
# traffic (prowlarr<->sonarr/radarr) and `edge` so Caddy can proxy them.
#
# Env convention: every service gets stack.env via env_file; var names there are
# exactly what the containers read (PUID/PGID/TZ), so no ${VAR} interpolation
# and no Portainer UI env vars are needed. Service-specific settings stay in
# per-service environment blocks.
services:
deluge:
@@ -11,13 +16,9 @@ services:
networks: [media, edge]
env_file:
- stack.env
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- ${ROOT}/storage1/torrents:/downloads
- ${ROOT}/config/deluge:/config
- /storage1/torrents:/downloads
- /config/deluge:/config
ports:
- "8112:8112"
@@ -28,13 +29,9 @@ services:
networks: [media, edge]
env_file:
- stack.env
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- ${ROOT}/storage1/complete:/downloads
- ${ROOT}/config/nzbget:/config
- /storage1/complete:/downloads
- /config/nzbget:/config
ports:
- "6789:6789"
@@ -45,16 +42,12 @@ services:
networks: [media, edge]
env_file:
- stack.env
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- /etc/localtime:/etc/localtime:ro
- ${ROOT}/config/sonarr:/config
- ${ROOT}/storage1/Media/TV:/tv
- ${ROOT}/storage1/Media/Anime:/anime
- ${ROOT}/storage1/complete:/downloads
- /config/sonarr:/config
- /storage1/Media/TV:/tv
- /storage1/Media/Anime:/anime
- /storage1/complete:/downloads
ports:
- "8989:8989"
@@ -65,15 +58,11 @@ services:
networks: [media, edge]
env_file:
- stack.env
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- /etc/localtime:/etc/localtime:ro
- ${ROOT}/config/radarr:/config
- ${ROOT}/storage1/Media/Movies:/movies
- ${ROOT}/storage1/complete:/downloads
- /config/radarr:/config
- /storage1/Media/Movies:/movies
- /storage1/complete:/downloads
ports:
- "7878:7878"
@@ -85,15 +74,12 @@ services:
env_file:
- stack.env
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- UMASK_SET=022
volumes:
- ${ROOT}/config/bazarr:/config
- ${ROOT}/storage1/Media/Movies:/movies
- ${ROOT}/storage1/Media/TV:/tv
- ${ROOT}/storage1/Media/Anime:/anime
- /config/bazarr:/config
- /storage1/Media/Movies:/movies
- /storage1/Media/TV:/tv
- /storage1/Media/Anime:/anime
ports:
- "6767:6767"
@@ -105,10 +91,7 @@ services:
env_file:
- stack.env
environment:
- PUID=1000
- PGID=1000
- UMASK=002
- TZ=${TZ}
volumes:
- /config/prowlarr:/config
ports:
@@ -122,10 +105,7 @@ services:
env_file:
- stack.env
environment:
- PUID=1000
- PGID=1000
- UMASK=002
- TZ=${TZ}
volumes:
- /config/overseerr:/app/config
ports:
@@ -138,13 +118,9 @@ services:
networks: [media, edge]
env_file:
- stack.env
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- ${ROOT}/config/tautulli:/config
- ${ROOT}/storage1/PMS:/logs
- /config/tautulli:/config
- /storage1/PMS:/logs
ports:
- "8181:8181"
@@ -156,9 +132,6 @@ services:
env_file:
- stack.env
environment:
- PUID=1000
- PGID=1000
- TZ=${TZ}
- WEBUI_PORT=3232
- TORRENTING_PORT=6881
volumes:
@@ -177,10 +150,7 @@ services:
env_file:
- stack.env
environment:
- PUID=1000
- PGID=1000
- UMASK=002
- TZ=${TZ}
- WEBUI_PORTS=6969/tcp
volumes:
- /config/whisparr:/config
@@ -201,8 +171,6 @@ services:
env_file:
- stack.env
environment:
- PUID=1000
- PGID=1000
- STASH_STASH=/data/
- STASH_GENERATED=/generated/
- STASH_METADATA=/metadata/
+3 -2
View File
@@ -1,5 +1,6 @@
# media stack config
# media stack config — injected into every service via env_file.
# Var names are exactly what the containers read; no ${VAR} interpolation,
# no Portainer UI env vars needed.
TZ=America/Chicago
PUID=1000
PGID=1000
ROOT=/
-2
View File
@@ -21,8 +21,6 @@ services:
networks: [edge]
env_file:
- stack.env
environment:
- SECRET_ENCRYPTION_KEY=${HOMARR_SECRET_ENCRYPTION_KEY}
ports:
- "7575:7575"
volumes:
+2 -2
View File
@@ -1,3 +1,3 @@
# monitoring stack secrets
# monitoring stack secrets — injected via env_file; container-exact var names.
# Homarr config encryption key. Generate with: openssl rand -hex 32
HOMARR_SECRET_ENCRYPTION_KEY=98989838bf06c9e42d77944ce848963a22ab316b55a09b0d199652ef0934394f
SECRET_ENCRYPTION_KEY=98989838bf06c9e42d77944ce848963a22ab316b55a09b0d199652ef0934394f
+2 -3
View File
@@ -25,9 +25,8 @@ services:
image: couchdb:3
restart: unless-stopped
networks: [notes, edge]
environment:
COUCHDB_USER: ${COUCHDB_USER}
COUCHDB_PASSWORD: ${COUCHDB_PASSWORD}
env_file:
- stack.env
volumes:
- /config/couchdb/data:/opt/couchdb/data
- /config/couchdb/etc:/opt/couchdb/etc/local.d
-2
View File
@@ -16,7 +16,6 @@ services:
env_file:
- stack.env
environment:
- TZ=${TZ}
- NTFY_DEFAULT_HOST=https://ntfy.ginnoir.com
- NTFY_BASE_URL=https://ntfy.ginnoir.com
- NTFY_CACHE_FILE=/var/lib/ntfy/cache.db
@@ -63,7 +62,6 @@ services:
- CRON_MIN=3,33
- TRUSTED_PROXY=172.16.0.1/12 192.168.0.1/16
- FRESHRSS_INSTALL=--default-user ginnoir --api-enabled --base-url https://freshrss.ginnoir.com
- FRESHRSS_USER=--api-password ${FRESHRSS_API_PASSWORD} --email ${FRESHRSS_EMAIL} --password ${FRESHRSS_PASSWORD} --user ginnoir
vigilant:
container_name: vigilant
+4 -4
View File
@@ -1,5 +1,5 @@
# notify stack secrets
# notify stack secrets — injected via env_file; container-exact var names.
TZ=America/Chicago
FRESHRSS_API_PASSWORD=d0fet0th3x
FRESHRSS_PASSWORD=d0fet0th3x
FRESHRSS_EMAIL=3nigma.matt@gmail.com
# FreshRSS first-run user bootstrap (the container reads FRESHRSS_USER as the
# full CLI argument string for its install script).
FRESHRSS_USER=--api-password d0fet0th3x --email 3nigma.matt@gmail.com --password d0fet0th3x --user ginnoir
+2 -9
View File
@@ -19,14 +19,9 @@ services:
env_file:
- stack.env
environment:
- OWNCLOUD_DOMAIN=${OWNCLOUD_DOMAIN}
- OWNCLOUD_DB_TYPE=mysql
- OWNCLOUD_DB_NAME=owncloud
- OWNCLOUD_DB_USERNAME=${OWNCLOUD_DB_USER}
- OWNCLOUD_DB_PASSWORD=${OWNCLOUD_DB_PASSWORD}
- OWNCLOUD_DB_HOST=mariadb
- OWNCLOUD_ADMIN_USERNAME=${OWNCLOUD_ADMIN_USER}
- OWNCLOUD_ADMIN_PASSWORD=${OWNCLOUD_ADMIN_PASSWORD}
- OWNCLOUD_MYSQL_UTF8MB4=true
- OWNCLOUD_REDIS_ENABLED=true
- OWNCLOUD_REDIS_HOST=redis
@@ -49,13 +44,11 @@ services:
env_file:
- stack.env
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_USER=${OWNCLOUD_DB_USER}
- MYSQL_PASSWORD=${OWNCLOUD_DB_PASSWORD}
- MYSQL_DATABASE=owncloud
command: ["--max-allowed-packet=128M", "--innodb-log-file-size=64M"]
healthcheck:
test: ["CMD", "mariadb-admin", "ping", "-u", "root", "--password=${MYSQL_ROOT_PASSWORD}"]
# $$ defers expansion to container runtime (env_file supplies the value)
test: ["CMD-SHELL", "mariadb-admin ping -u root --password=\"$$MYSQL_ROOT_PASSWORD\""]
interval: 10s
timeout: 5s
retries: 5
+7 -3
View File
@@ -1,7 +1,11 @@
# owncloud stack secrets
# owncloud stack secrets — injected via env_file; container-exact var names.
# OWNCLOUD_* are read by owncloud/server, MYSQL_* by mariadb (cross-injection
# of the other service's vars is harmless — both images ignore unknown env).
OWNCLOUD_DOMAIN=files.ginnoir.com
OWNCLOUD_DB_USER=ginnoir
OWNCLOUD_DB_USERNAME=ginnoir
OWNCLOUD_DB_PASSWORD=d0fet0th3x
OWNCLOUD_ADMIN_USER=ginnoir
OWNCLOUD_ADMIN_USERNAME=ginnoir
OWNCLOUD_ADMIN_PASSWORD=d0fet0th3x
MYSQL_ROOT_PASSWORD=d0fet0th3x
MYSQL_USER=ginnoir
MYSQL_PASSWORD=d0fet0th3x
-2
View File
@@ -24,8 +24,6 @@ services:
- "443:443"
env_file:
- stack.env
environment:
- CF_API_TOKEN=${CF_API_TOKEN}
volumes:
- /config/caddy/Caddyfile:/etc/caddy/Caddyfile
- /config/caddy/site:/srv
+4
View File
@@ -8,6 +8,8 @@ services:
image: rustdesk/rustdesk-server:latest
command: hbbr
restart: unless-stopped
env_file:
- stack.env
ports:
- "21117:21117"
volumes:
@@ -18,6 +20,8 @@ services:
image: rustdesk/rustdesk-server:latest
command: hbbs
restart: unless-stopped
env_file:
- stack.env
ports:
- "21115:21115"
- "21116:21116"
+4
View File
@@ -0,0 +1,4 @@
# remote stack config — injected into hbbr/hbbs via env_file.
# No secrets today: the RustDesk key pair lives in /config/rustdesk/*/data on
# the host, not in env. Present for stack convention (every stack ships a
# stack.env). Candidate vars if ever needed: ALWAYS_USE_RELAY, RUST_LOG.
-10
View File
@@ -19,7 +19,6 @@ services:
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
interval: 10s
@@ -39,9 +38,6 @@ services:
- /storage1/labdata/resume/minio:/data
env_file:
- stack.env
environment:
- MINIO_ROOT_USER=${MINIO_ROOT_USER}
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live || exit 1"]
interval: 30s
@@ -59,7 +55,6 @@ services:
environment:
- TIMEOUT=10000
- CONCURRENT=10
- TOKEN=${CHROME_TOKEN}
- EXIT_ON_HEALTH_FAILURE=true
- PRE_REQUEST_HEALTH_CHECK=true
@@ -85,16 +80,11 @@ services:
- APP_URL=https://resume.ginnoir.com
- STORAGE_URL=https://storage.j-costa.com/default
- PRINTER_ENDPOINT=http://chrome:3000
- PRINTER_TOKEN=${CHROME_TOKEN}
- DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres
- AUTH_SECRET=${RESUME_AUTH_SECRET}
- MAIL_FROM=noreply@localhost
- STORAGE_ENDPOINT=resume-minio
- STORAGE_PORT=9000
- STORAGE_REGION=us-east-1
- STORAGE_BUCKET=default
- STORAGE_ACCESS_KEY=${MINIO_ROOT_USER}
- STORAGE_SECRET_KEY=${MINIO_ROOT_PASSWORD}
- STORAGE_USE_SSL=false
- STORAGE_SKIP_BUCKET_CHECK=false
+19 -4
View File
@@ -1,9 +1,24 @@
# resume stack secrets
# resume stack secrets — injected into all services via env_file.
# Var names are exactly what each container reads (no ${VAR} interpolation).
# Components are duplicated into composites (DATABASE_URL embeds
# POSTGRES_PASSWORD; STORAGE_* mirror MINIO_*) — keep them in sync on rotation.
# postgres
POSTGRES_PASSWORD=postgres
# minio (resume-minio service)
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin
CHROME_TOKEN=chrome_token
# Auth/JWT signing secret for Reactive Resume (the app reads ${RESUME_AUTH_SECRET}).
# browserless chrome auth token (chrome reads TOKEN, the app reads PRINTER_TOKEN)
TOKEN=chrome_token
PRINTER_TOKEN=chrome_token
# reactive-resume app
DATABASE_URL=postgresql://postgres:postgres@postgres:5432/postgres
STORAGE_ACCESS_KEY=minioadmin
STORAGE_SECRET_KEY=minioadmin
# Auth/JWT signing secret for Reactive Resume.
# Pinned to the running value so recreating the container keeps sessions valid.
# Rotate with: openssl rand -hex 64
RESUME_AUTH_SECRET=1b7e96f61f080d04d4bf673d9ea1d9349eb7693cddee5772b6c3f153c88032db5b97efd8570087bc6f340d2cd874aabc1e5c681bc22889921240d6a23738bc7f
AUTH_SECRET=1b7e96f61f080d04d4bf673d9ea1d9349eb7693cddee5772b6c3f153c88032db5b97efd8570087bc6f340d2cd874aabc1e5c681bc22889921240d6a23738bc7f