pbs-projects/Tech/Reference/staging-environment-setup.md

3.9 KiB

project type status path tags created updated
staging-environment-setup reference active Tech/Reference
pbs
infrastructure
staging
traefik
cloudflare
docker
2026-04-15 2026-04-15

Staging Environment — Architecture Reference

Reference doc for how the PBS staging environment is structured. Captured retroactively from the original Feb 24 build session, before the n8n email pipeline existed.

Note on path: Filed under a proposed new Tech/Reference folder for evergreen architecture docs (vs. Tech/Sessions for point-in-time notes or Tech/Projects for active work). Flag if you'd rather move it.

Domain & DNS Strategy

Staging lives at staging.plantbasedsoutherner.com, with all supporting tools nested as further subdomains under it.

staging.plantbasedsoutherner.com           ← WordPress
n8n.staging.plantbasedsoutherner.com       ← n8n
portainer.staging.plantbasedsoutherner.com ← Portainer
status.staging.plantbasedsoutherner.com    ← Uptime Kuma
db.staging.plantbasedsoutherner.com        ← phpMyAdmin
gitea.staging.plantbasedsoutherner.com     ← Gitea

Cloudflare DNS uses a wildcard A record so new subdomains require zero DNS work:

Type: A
Name: *.staging
Value: 
Proxy: DNS only (grey cloud)

The wildcard must remain DNS only (grey cloud) for Let's Encrypt HTTP challenges to succeed. With Cloudflare proxy on, ACME hits Cloudflare's IP instead of the origin and TLS handshake fails.

SSL / Traefik

Traefik handles all routing and SSL via Let's Encrypt HTTP challenge (not TLS challenge — TLS challenge is incompatible with Cloudflare in front).

Each container declares its hostname via Traefik labels; Traefik handles cert issuance and renewal automatically per hostname.

Migration Pattern (Prod → Staging Clone)

The original staging build used a full prod clone. Key gotchas:

  • Database URL replacement: Use WP-CLI search-replace (not raw SQL) to handle serialized Elementor data correctly. Run from inside the wordpress container.
  • Avoid "staging.staging" loops: Replace plantbasedsoutherner.com staging.plantbasedsoutherner.com in one direction only; double-check existing staging references before running.
  • Redis password: Must be present in the container env for both prod and staging — easy to forget when moving env vars between .env files.
  • DB user recreation: Fresh MySQL inits won't carry over user grants from the prod dump.

Resource Sizing

Staging started on a 1GB Linode Nanode and was upgraded to 2GB after hitting memory ceilings during full-stack runs (WordPress + MySQL + Redis + n8n + Traefik + monitoring). 2GB is the practical minimum for the full stack.

Healthchecks

All Docker containers have healthchecks defined. A few patterns learned:

  • Traefik requires an IPv6 loopback target in some configurations.
  • Containers without curl (slim images, Gitea, Python slim) need alternative healthcheck commands — wget, a Python one-liner, or the application's own CLI.
  • Gitea healthcheck on /api/v1/version returns 404 before the setup wizard completes, blocking initial Traefik routing. Remove the healthcheck for first-time setup, then add it back.

Inventory & Ansible (added later)

The Ansible inventory eventually evolved to keep staging and production strictly separated — see the GitHub deploy key project for the final structure with bootstrap_staging, bootstrap_production, staging, and production groups (no meta-groups that could hit both environments).

Open Items

  • Confirm Tech/Reference is the right folder for this kind of doc, or move to Tech/Sessions / Tech/Projects
  • Cross-link this from the GitHub deploy key project plan once both are in the vault
  • GitHub private repo + Ansible inventory restructure (April 2026)
  • PBS Security Hardening (Crowdsec + Authelia, staged on staging first)
  • WP-Cron / Supercronic deploy (March 2026)

...sent from Jenny & Travis