Replace the remaining deploy procedures with CTXD runbook pointers
CI / ci (push) Successful in 5m27s
CI / ci (pull_request) Successful in 5m41s

The repository still carried operating steps from the deleted runbook:
secret creation and permission commands in deploy/.env.example, build,
restart and restore steps in deploy/compose.yaml, a direct
"docker compose up -d" in mealquest-firewall.service, a manual run in
mealquest-media-backup.service and a dev start command in
compose.dev.yaml. Replace each with a pointer to the named section of
CTXD project mealquest, RUNBOOKS.MD, keeping every variable, path,
owner, mode, port and mount description.

Maestro task e81ed994-a510-48e6-9cf6-e76d5d81f56c.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 09:19:29 -04:00
co-authored by Claude Opus 5.5
parent 89574333e8
commit fd05d51ebf
6 changed files with 35 additions and 44 deletions
+13 -18
View File
@@ -1,20 +1,15 @@
# MealQuest production environment. Copy to deploy/.env (never committed) # MealQuest production environment: the template for deploy/.env (never
# and replace the placeholders. The service fails fast: a missing or invalid # committed). The service fails fast: a missing or invalid required variable
# required variable stops it at boot with the variable named. # stops it at boot with the variable named. Creating deploy/.env: CTXD
# project mealquest, RUNBOOKS.MD "Stack and first deploy" > "3. Environment
# file".
# #
# Secrets are never set here. They live in deploy/secrets/ (never committed), # Secrets are never set here. They live in deploy/secrets/ (never committed),
# one value per file, owned by the container user and readable only by it: # one value per file, owned by the container user 10001:10001 with mode
# # 0600: secret_key, oidc_client_secret and google_client_secret. SearXNG's
# mkdir -p deploy/secrets && chmod 700 deploy/secrets # searxng.env is the exception: compose reads it itself, so it is owned by
# head -c 32 /dev/urandom | base64 > deploy/secrets/secret_key # the host account that runs compose, mode 0600. Creating them: CTXD project
# printf '%s\n' '<Authentik client secret>' > deploy/secrets/oidc_client_secret # mealquest, RUNBOOKS.MD "Stack and first deploy" > "4. Secrets".
# printf '%s\n' '<Google OAuth client secret>' > deploy/secrets/google_client_secret
# sudo chown 10001:10001 deploy/secrets/* && sudo chmod 600 deploy/secrets/*
#
# SearXNG's secret key is the exception: compose reads it itself, so it
# stays owned by you (mode 0600). Create it after the chown above:
#
# (umask 077; printf 'SEARXNG_SECRET=%s\n' "$(openssl rand -hex 32)" > deploy/secrets/searxng.env)
# #
# deploy/compose.yaml mounts them at /run/secrets/<name> and points the # deploy/compose.yaml mounts them at /run/secrets/<name> and points the
# *_FILE variables at them. # *_FILE variables at them.
@@ -42,8 +37,7 @@ MEALQUEST_TRUSTED_PROXY=10.60.1.33
# IANA zone the household settings are created with on first boot. Required # IANA zone the household settings are created with on first boot. Required
# until those settings exist; ignored afterwards (change the zone in # until those settings exist; ignored afterwards (change the zone in
# household settings instead). Confirm the household's zone before the first # household settings instead).
# deploy.
MEALQUEST_DEFAULT_TZ=America/New_York MEALQUEST_DEFAULT_TZ=America/New_York
# --- Authentik OIDC ---------------------------------------------------------- # --- Authentik OIDC ----------------------------------------------------------
@@ -88,7 +82,8 @@ MEALQUEST_SESSION_MAX=4320h
# #
# Added to deploy/compose.yaml and this file by the features that use them. # Added to deploy/compose.yaml and this file by the features that use them.
# #
# Web Push (Feature 19). Generate the key pair with cmd/vapidgen. # Web Push (Feature 19). Key pair: CTXD project mealquest, RUNBOOKS.MD
# "VAPID keys (Web Push)".
# MEALQUEST_VAPID_PUBLIC_KEY=<base64url VAPID public key> # MEALQUEST_VAPID_PUBLIC_KEY=<base64url VAPID public key>
# MEALQUEST_VAPID_PRIVATE_KEY_FILE=/run/secrets/vapid_private_key # MEALQUEST_VAPID_PRIVATE_KEY_FILE=/run/secrets/vapid_private_key
# MEALQUEST_VAPID_SUBJECT=mailto:<owner address> # MEALQUEST_VAPID_SUBJECT=mailto:<owner address>
+4 -5
View File
@@ -1,8 +1,7 @@
# Development override: publishes SearXNG on the dev machine's loopback so # Development override layered on deploy/compose.yaml: publishes SearXNG
# it can be queried directly, e.g. # on the dev machine's loopback (127.0.0.1:8888) so it can be queried
# # directly. Using it: CTXD project mealquest, RUNBOOKS.MD "Local
# docker compose -f deploy/compose.yaml -f deploy/compose.dev.yaml up -d searxng # development".
# curl 'http://127.0.0.1:8888/search?q=chicken+tikka+masala+recipe&format=json'
# #
# Loopback only, never a LAN address. Never used in production: the # Loopback only, never a LAN address. Never used in production: the
# systemd unit starts deploy/compose.yaml alone. # systemd unit starts deploy/compose.yaml alone.
+10 -13
View File
@@ -1,18 +1,16 @@
# Production stack for MealQuest on 10.60.1.14 (D-018). Build on the host, # Production stack for MealQuest on 10.60.1.14 (D-018). Building, deploying
# then start through systemd: # and operating it: CTXD project mealquest, RUNBOOKS.MD "Stack unit" and
# # "Routine deploy and rollback".
# docker compose -f deploy/compose.yaml build
# sudo systemctl restart mealquest
# #
# The services use restart: "no" on purpose: Docker must not start them # The services use restart: "no" on purpose: Docker must not start them
# before the DOCKER-USER firewall is applied. deploy/systemd/mealquest.service # before the DOCKER-USER firewall is applied. deploy/systemd/mealquest.service
# owns start and stop and requires mealquest-firewall.service first. # owns start and stop and requires mealquest-firewall.service first.
# #
# Configuration comes from deploy/.env (copy deploy/.env.example) and secrets # Configuration comes from deploy/.env (template: deploy/.env.example) and
# from deploy/secrets/; neither is committed. Compose bind-mounts file secrets # secrets from deploy/secrets/; neither is committed. Compose bind-mounts
# with their host owner and mode, so each file in deploy/secrets/ must be # file secrets with their host owner and mode, so each file in
# owned by the container user 10001:10001 with mode 0600 (except # deploy/secrets/ must be owned by the container user 10001:10001 with mode
# searxng.env, read by compose itself; see the searxng service). # 0600 (except searxng.env, read by compose itself; see the searxng service).
name: mealquest name: mealquest
services: services:
@@ -65,9 +63,8 @@ services:
# the app's own user (owner of the volume) with a read-only root # the app's own user (owner of the volume) with a read-only root
# filesystem, no privilege escalation and no Linux capabilities. # filesystem, no privilege escalation and no Linux capabilities.
# #
# Restore: follow "Restore the database" in the CTXD project mealquest, # Restoring the database: CTXD project mealquest, RUNBOOKS.MD "Restore
# RUNBOOKS.MD (stop the stack, move the database with its -wal and -shm # the database".
# aside, restore, check).
litestream: litestream:
image: litestream/litestream:0.5.17 image: litestream/litestream:0.5.17
user: "10001:10001" user: "10001:10001"
+3 -2
View File
@@ -5,8 +5,9 @@
# are one-way: a failure here fails this unit visibly and never fails # are one-way: a failure here fails this unit visibly and never fails
# docker.service. # docker.service.
# #
# Start MealQuest only after this unit has succeeded: # mealquest.service requires this unit and starts the stack only after it
# systemctl start mealquest-firewall && docker compose up -d # has succeeded. Installing and operating both: CTXD project mealquest,
# RUNBOOKS.MD "Host firewall" and "Stack unit".
[Unit] [Unit]
Description=Restrict MealQuest port 8090 to Traefik (DOCKER-USER) Description=Restrict MealQuest port 8090 to Traefik (DOCKER-USER)
After=docker.service After=docker.service
@@ -1,8 +1,7 @@
# Runs the nightly MealQuest media backup (/usr/local/sbin/mealquest-media-backup). # Runs the nightly MealQuest media backup (/usr/local/sbin/mealquest-media-backup).
# Triggered by mealquest-media-backup.timer; run by hand with # Triggered by mealquest-media-backup.timer; output goes to the journal.
# systemctl start mealquest-media-backup # Installing it and running it by hand: CTXD project mealquest,
# and read the result with # RUNBOOKS.MD "Media — nightly rsync".
# journalctl -u mealquest-media-backup
# #
# The script runs as the app's user (10001, host user "mealquest") with no # The script runs as the app's user (10001, host user "mealquest") with no
# capabilities. systemd, as root, only bind-mounts the data volume's root # capabilities. systemd, as root, only bind-mounts the data volume's root
+2 -2
View File
@@ -16,8 +16,8 @@
# directory are copied as links (-a), never followed. # directory are copied as links (-a), never followed.
# #
# The media directory is created at deploy time (CTXD project mealquest, # The media directory is created at deploy time (CTXD project mealquest,
# RUNBOOKS.MD). If it is missing the job fails; it is never treated as # RUNBOOKS.MD "Media — nightly rsync"). If it is missing the job fails; it
# "nothing to back up". # is never treated as "nothing to back up".
# #
# rsync mirrors into .../mealquest-backups/media/ only: the target ends in # rsync mirrors into .../mealquest-backups/media/ only: the target ends in
# a slash, so --delete removes files from that directory and nothing # a slash, so --delete removes files from that directory and nothing