Skip to content

Test server (10.1.1.20) and pptx-remediate recovery

Server split

ServerRoleNotes
test (10.1.1.20)Ephemeral test/staging β€” Supabase, LocalStack, MinIO, Caddy, deployed apps under test4 vCPU / 15 GB / 98 GB. Safe to reset any service.
staging (10.1.1.17)Shared observability + future production4 vCPU / 31 GB / 937 GB. Hosts pptx-remediate and the Loki/Grafana/Kuma stack. Don’t wipe.

Naming is historical: .17 is called β€œstaging” in DNS but is not the staging box anymore β€” .20 (alias test) is. The .17 box is shared infrastructure.

How I use the test server

Deploying an app for a test release

From the root of any app repo:

  1. Add a .staging-deploy manifest:

    APP_NAME=foo # becomes foo.test.lan
    APP_PORT=3000 # the port your container listens on
    DOCKERFILE=Dockerfile # default
    ENV_FILE=.env.staging # optional
  2. Add "stage": "deploy-to-staging" to package.json.

  3. Run npm run stage. The CLI (installed at /usr/local/bin/deploy-to-staging from ~/Projects/staging-server-setup) builds the image locally, streams it to test over SSH, writes a Caddy route, and brings the container up. The app is live at https://foo.test.lan.

The CLI defaults to SSH alias test and domain test.lan. Override with --host, --domain, or env vars STAGING_SSH / STAGING_DOMAIN.

Accessing services

All TLS-trusted via the mkcert CA (already in the Mac System keychain):

  • https://studio.test.lan β€” Supabase Studio
  • https://supabase.test.lan β€” Supabase REST / Auth / Kong
  • https://localstack.test.lan β€” LocalStack edge (AWS API emulation)
  • https://minio.test.lan β€” MinIO S3 API
  • https://minio-console.test.lan β€” MinIO web UI
  • https://grafana.test.lan β€” Grafana (runs on .17, proxied through .20’s Caddy). Login: admin / admin β€” change it.
  • https://kuma.test.lan β€” Uptime Kuma (runs on .17, proxied through .20’s Caddy)

SSH: ssh test (passwordless, uses ~/.ssh/id_ed25519).

Resetting a service on the test box

Terminal window
# Reset LocalStack to pristine state
ssh test 'cd /srv/staging/localstack && docker compose down && sudo rm -rf data/* && docker compose up -d'
# Reset Supabase (wipes the DB)
ssh test 'cd /srv/staging/supabase && docker compose down -v && docker compose up -d'
# Restart MinIO
ssh test 'cd /srv/staging/minio && docker compose restart'
# Restart the test app (replace foo)
ssh test 'cd /srv/staging/apps/foo && docker compose restart'

Log flow

Promtail on .20 ships container logs to Loki on http://10.1.1.17:3100. View them at https://grafana.test.lan β†’ Explore β†’ Loki β†’ {container=~".+"}. Logs from .17’s own containers (including pptx-remediate) are also in the same Loki instance β€” one dashboard, all servers.

Bringing up a fresh test box

If .20 is rebuilt from scratch:

Terminal window
# On the Mac
rsync -az --delete ~/Projects/staging-server-setup/ test:~/staging-server-setup/
# On the server
ssh test
cd ~/staging-server-setup
# Edit staging.env β€” set STAGING_DOMAIN=test.lan, confirm LAN_CIDR
# Skip stage 07-backup.sh unless B2 creds are set
sudo -E bash install.sh
# On the Mac, after install finishes
scp test:/srv/staging/caddy/ca/rootCA.pem /tmp/test-rootCA.pem
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/test-rootCA.pem
echo "10.1.1.20 localstack.test.lan supabase.test.lan studio.test.lan grafana.test.lan kuma.test.lan minio.test.lan minio-console.test.lan apps.test.lan" | sudo tee -a /etc/hosts

Then fix the two known install quirks:

  • The Caddyfile is templated with staging.lan hardcoded β€” sed -i 's/\.staging\.lan/.test.lan/g' /srv/staging/caddy/Caddyfile && docker compose exec -T caddy caddy reload --config /etc/caddy/Caddyfile
  • Rewrite /srv/staging/observability/docker-compose.yml to drop the Loki/Grafana/Kuma/Redis services (they live on .17), leaving only the Promtail shipper. Update /srv/staging/observability/promtail-config.yml to push to http://10.1.1.17:3100/loki/api/v1/push. Update /srv/staging/caddy/Caddyfile so grafana.test.lan and kuma.test.lan reverse_proxy 10.1.1.17:3000 and 10.1.1.17:3001 respectively.

pptx-remediate recovery (on .17)

Where it lives

  • Source of truth: services/pptx-remediate/ in the accessible monorepo (tracked in git). Not at apps/remediate/ β€” that path is taken by a separate Next.js frontend (@accessible-pdf/remediate-app).
  • Deployed copy on .17: ~/services/pptx-remediate/ β€” a detached snapshot, not a git checkout. Matches the monorepo contents.
  • Declarative compose (on .17): ~/services/pptx-remediate/docker-compose.yml
  • Image tarball backup (on .17): ~/services/pptx-remediate/pptx-remediate-image.tar.gz (~4 GB)
  • Port: 5003 (bound to 0.0.0.0 on the host)
  • Restart policy: unless-stopped
  • Consumers: API nodes on 10.1.1.4 reach it via PPTX_REMEDIATE_URL=http://10.1.1.17:5003

Health check

Terminal window
curl -sI http://10.1.1.17:5003/ | head -1 # expect 404 (app up, no / route)
ssh 10.1.1.17 'docker ps --filter name=pptx-remediate --format "{{.Status}}"'

Recovery scenarios

Container stopped / crashed:

Terminal window
ssh 10.1.1.17 'cd ~/services/pptx-remediate && docker compose up -d'

Container + image deleted (image still in local Docker cache? no):

Terminal window
ssh 10.1.1.17 'cd ~/services/pptx-remediate && docker load < pptx-remediate-image.tar.gz && docker compose up -d'

Everything deleted including the tarball:

Terminal window
# Rebuild from source β€” Dockerfile and Python code are still in ~/services/pptx-remediate/
ssh 10.1.1.17 'cd ~/services/pptx-remediate && docker build -t pptx-remediate:latest . && docker compose up -d'
# Then re-snapshot for future recovery:
ssh 10.1.1.17 'docker save pptx-remediate:latest | gzip > ~/services/pptx-remediate/pptx-remediate-image.tar.gz'

Entire .17 server rebuilt from scratch:

  1. Clone the monorepo (or rsync from a Mac checkout) and copy the service tree to the new host:
    Terminal window
    rsync -az ~/Projects/accessible/services/pptx-remediate/ 10.1.1.17:~/services/pptx-remediate/
    Then add a docker-compose.yml next to it (see contents in reference_server_layout.md memory, or just copy the existing one from the Mac).
  2. ssh 10.1.1.17 'cd ~/services/pptx-remediate && docker build -t pptx-remediate:latest . && docker compose up -d'
  3. If the service uses API keys (Gemini / Anthropic / Deepgram / HuggingFace), populate ~/services/pptx-remediate/.env. The .env file seeded during this migration is empty β€” match whatever values were live before, from password manager or prior .env backup.

API keys note

docker inspect pptx-remediate shows GEMINI_API_KEY=, ANTHROPIC_API_KEY=, DEEPGRAM_API_KEY=, HF_TOKEN= with empty values in the running container as of 2026-04-23. Either the service doesn’t use them, or they were supposed to be set and never were. If features start failing, populate ~/services/pptx-remediate/.env with real values and docker compose up -d to pick them up.

Before pptx-remediate goes to production

  • Wire up proper deploy from the monorepo: add a .staging-deploy manifest in services/pptx-remediate/. Since this is a Python service with no package.json, invoke the deploy CLI directly: cd services/pptx-remediate && deploy-to-staging. That rebuilds the image from the Dockerfile and redeploys to .17 (adjust --host if production needs a different target), replacing the current detached-snapshot workflow.
  • Add the service to the nightly backup on .3 (see ~/.claude/scripts/server-backup.sh on 10.1.1.3).
  • Add a Caddy route (pptx.anglinai.internal or similar) with TLS rather than exposing :5003 directly.
  • Add an Uptime Kuma monitor hitting a real health endpoint (not /).
  • Point real API keys in via .env.