diff --git a/Sources/Homelab/wordpress-install-staging-deploy.md b/Sources/Homelab/wordpress-install-staging-deploy.md new file mode 100644 index 0000000..ce33fd2 --- /dev/null +++ b/Sources/Homelab/wordpress-install-staging-deploy.md @@ -0,0 +1,71 @@ +--- +created: '2026-07-07' +path: Sources/Homelab +project: wordpress-install-staging-deploy +tags: +- pbs +- ansible +- docker +- traefik +- cloudflare +- tls +type: project-plan +--- + +Bring the `wordpress-install` Ansible stack up on the staging Linode, load the real site data on top of a fresh install, and confirm it serves — so PBS changes can be exercised under near-real-world conditions. Isolated from the herbylab target (thread 582) and from production. + +## Goal + +A running, data-loaded PBS WordPress stack on the staging Linode `pbs-staging`: +- Host: 139.144.16.8, user `tj57testadmin`, port 22, connect **only** via `~/.ssh/pbs-staging-site-ed25519`. +- Site: `pbs-staging.herbylab.dev` (Cloudflare-proxied, orange cloud; wildcard + apex A records already live → the Linode IP). +- Infra green: traefik, mariadb, wordpress core, docker networks, Let's Encrypt cert issued via HTTP-01, no Cloudflare redirect loop. +- Real content imported from the `20260622` non-sandbox dumps; site loads over HTTPS with wp-admin reachable and the membership / save-button changes present. + +**Done condition:** stack up and serving as above. App containers built from gitea source projects (pbs-api / pbs-video-manager, ssh-login-alerter, pbsii) that fail on their own code are logged and deferred — not blockers for done. + +## Locked Decisions + +- **Target is fresh + import** — clean WordPress install via the playbook, then restore the real DB and wp-content on top. No reuse of the earlier local-VM state. +- **Dumps: non-sandbox `20260622`** — `pbs_wordpress_dump_20260622.sql`, `pbs_automation_dump_20260622.sql`, and `pbs_wp-content_20260622.tar.gz` from `/opt/backups/pbs-wp/`. The `_sandbox` variants are not used. +- **Import is manual, run by hand** after the stack is green. The `scripts/restore-wordpress-backup.sh` helper is untested and stays untouched this run. +- **Source of truth is gitea, not github.** The current app code lives on the self-hosted gitea; nothing is pushed to github. The two `repo_url` entries in `playbook.yml` (`ssh-login-alerter`, `pbs-video-manager`) get repointed github → gitea. This edits the deploy repo only. +- **No changes to the gitea app projects — full stop.** Deploy them as-is. If a container will not start on its own code, that is fixed in a later project, after this install completes. +- **Cloudflare zone settings are out of scope.** If the cert path needs a Flexible → Full-strict change, halt and hand it back to Travis; do not touch the Cloudflare console. +- **Secrets:** the staging vault trust domain (`group_vars/staging/vault.yml`, `host_vars/pbs-staging/vault.yml`) decrypts with the `staging@/opt/backups/ansible/vault-staging.pass` id, isolated from the prod/global key. +- **Thread hygiene:** this is a new thread under the pbs node (608), kept separate from the herbylab thread (582). + +## Open Items + +- Cloudflare SSL/TLS mode for the zone is unconfirmed. Verify it is **Full (strict)**; if it is Flexible, the HTTPS redirect will loop behind the orange cloud. Detect the loop in verification and, if present, halt for Travis to change the zone mode. +- Target box has no git tooling / gitea auth yet — provisioned in Phase 1. +- The local-VM provisioning path is unexplained (it may have pulled from github despite "nothing on github"). Loose thread only; watch for a stale clone and flag if one appears. +- Local control-node resolver is split-horizon and does not resolve `pbs-staging.herbylab.dev`; verify via `--resolve` or from the target, not a bare curl on the control node. + +## Phases + +**P0 — Pre-flight (control node, no target changes).** Confirm control node is herbys-dev on a clean tree / correct branch (prep changes already committed by Travis). `ansible-galaxy install -r requirements.yml`. Confirm the staging vault files decrypt with the `staging@` id. `ansible-playbook --limit staging --list-hosts` returns **only** `pbs-staging` (guard against herbylab/prod). Confirm the inventory pins `ansible_ssh_private_key_file` to the ed25519 key and SSH to `tj57testadmin@139.144.16.8` succeeds through it. + +**P1 — Repoint sources + git-on-target.** On a feature branch, change the two `repo_url` values in `playbook.yml` from github to the gitea remotes. Provision git tooling and a gitea deploy key on the target so `ansible.builtin.git` can pull. Gate: a successful `git ls-remote` from the target against each gitea repo before any real deploy run. No edits to the app-project source. + +**P2 — Base setup.** `ansible-playbook -i inventory/inventories.yml playbook.yml --limit staging --tags base_setup` (manage_linux hardening + geerlingguy.docker). Verify docker is running, the deploy user is in the docker group, and ufw allows 22 / 80 / 443. + +**P3 — Dockers bring-up.** Run with `--tags dockers` plus the pbsii roles. Verify `docker compose ps` shows infra services healthy (network, traefik, wordpress + mariadb, redis). Confirm the Let's Encrypt cert is issued via the HTTP-01 challenge and there is no Cloudflare redirect loop. This is the highest-risk phase. App containers built from gitea source that fail on their own code get their logs captured and are deferred, not fixed. + +**P4 — Manual data import.** Into the green stack, by hand: load the WordPress dump and the automation dump into mariadb, extract the wp-content tarball into the wordpress content volume, fix ownership, run a wp-cli search-and-replace of the old domain to `pbs-staging.herbylab.dev`, and flush caches. Uses the `20260622` non-sandbox files. + +**P5 — Verify working.** Site loads over HTTPS with real content (via `--resolve` from the control node or curl from the target). wp-admin reachable, cert valid, no redirect loop. Spot-check the membership / save-button changes. Check the aux dashboards (portainer, uptime-kuma, traefik, hosted gitea). Any app-container failures are logged in the thread for a post-install follow-up. + +## Notes + +**Run contract (unattended, version-warrior + remote-infra override).** Full contract is written into the Trellis thread as the first checkpoint. Summary: + +- **Tier / Done:** version-warrior; done = stack up and serving per Goal. +- **Authority:** control node — edit within the wordpress-install repo, run ansible-playbook, manual import, commit + push to a feature branch on gitea. Target `pbs-staging` only — sudo/infra via ansible become (install git + docker, ufw, hardening, deploy key, compose up). Not permitted: any other host, push to main/prod, editing gitea app-project source, touching herbylab/prod inventory or vaults, opening PRs, changing Cloudflare zone settings. +- **Boundary:** in — the wordpress-install deploy repo (feature branch) and the pbs-staging Linode. Out — cloned app-repo source, herbylab box / thread 582, production, any other host. +- **Run policy:** work P0 → P5 in order, each gated by its verify step; halt and document on hard blockers (SSH/key failure, gitea clone-auth failure, infra-role task failure, a redirect-loop needing a zone change); app-container failures are captured and deferred; checkpoint the thread at each phase boundary. +- **Isolation:** feature branch for repo edits; the target is a disposable staging Linode, rebuildable from this playbook; import is one-way onto that throwaway box. + +**Key paths:** deploy repo `/opt/projects/pbs/wordpress-install`; backups `/opt/backups/pbs-wp/`; staging vault pass `/opt/backups/ansible/vault-staging.pass`; staging vault README `/opt/backups/ansible/README-vault-staging.md`; connection details `/opt/backups/pbs-wp/staging.md`. + +**References:** repo `CLAUDE.md` (Cloudflare HTTP-01 note, service list, troubleshooting), `disaster_recovery_plan.md`. Prior herbylab target work is trellis thread 582 (`wordpress-install-herbylab`). \ No newline at end of file