Provisions a LAN-only browser code editor (Atheos) in an Alpine 3.23 LXC on the scotty PVE node, with armistace/blog cloned and ready to edit. Built via the AI-DLC workflow; the full process trail is in aidlc-docs/. Deliverables - scripts/provision.sh rebuild the guest from scratch (re-runnable) - scripts/update-atheos.sh move Atheos to latest upstream and RE-PIN - scripts/build-and-test.sh captures evidence for every acceptance criterion - files/atheos.conf nginx vhost (socket path byte-matches the FPM pool) - files/ssh-config ~atheos/.ssh/config deploy-key alias - RUNBOOK.md operational guide (START AT STEP 1) - docs/security-notes.md credential model + wider-web hardening TODOs - docs/resiliency-notes.md what a non-PoC deployment would need Design decisions - D1 no git identity is configured by the agent; the operator sets it. Git will refuse the first commit until then, which is deliberate (requirement FR-11). - D2 Atheos pinned to commit f90cd18 (build 611) with a verified tarball sha256, plus update-atheos.sh as the deliberate escape hatch. - D3 nginx :80, web root /var/www/atheos, php-fpm over a unix socket. - D6 git auth is a per-repository DEPLOY KEY scoped to armistace/blog, not a personal access token (a PAT's write:repository scope reaches every repo the account can write). Verified on the live guest (40 checks, 0 failures) - AC-2 Atheos served over HTTP 200 by nginx+php-fpm; socket paths byte-match - AC-3 20 posts + themes/cleanblog present; owned by the php-fpm user - AC-4 all five writable paths writable as the service user - AC-5 remote targets armistace/blog; deploy key authenticates over SSH - AC-6 survival proven with a real container restart, marker byte-identical - AC-8 no python/pelican/pip/make and no DB engine - scope boundary enforced - FR-11 git identity is empty; deploy key mode 600 owned by the service user Traps documented in the RUNBOOK (each cost real debugging time) - The Gitea SSH user is `gitea`, NOT `git` (app.ini SSH_USER=gitea). With `git`, sshd answers "Invalid user git" and rejects before reading authorized_keys, which is indistinguishable from a bad key. - The Gitea SSH endpoint is the LAN address (:22 is not forwarded publicly). - `uptime` and `free` report the PVE HOST inside an LXC without lxcfs, so a container that just restarted can claim days of uptime.
4.9 KiB
4.9 KiB
Application Design (consolidated) — atheos-blog-lxc
Stage: INCEPTION — Application Design (minimal depth) · Date: 2026-09-29
Deploy target: Proxmox LXC 136 on node scotty (.69) — Alpine 3.23 · LAN-only
1. What this system is
A small, single-purpose guest whose only job is to put a browser editor in front of the
armistace/blog working copy. It is deliberately not a build environment.
┌───────────────────────── LXC 136 (scotty) ─────────────────────────┐
Browser (LAN) │ │
http://<ip>/ ────┼──► nginx :80 ──unix socket──► php-fpm (php83) ──► Atheos (PHP) │
│ │ │
│ ├──► workspace/blog/** (rw) │
│ └──► git CLI ──► local commit│
└────────────────────────────────────────────────────────────────────┘
│
(operator, later) SSH identity + SSH remote
▼
Gitea git.aridgwayweb.com
2. Components
| ID | Component | Role |
|---|---|---|
| C1 | LXC 136 on scotty, Alpine 3.23 |
isolated runtime, OpenRC, 20 GB root, onboot |
| C2 | nginx :80 | HTTP front end; sends *.php to C3 |
| C3 | php-fpm php83 |
PHP runtime; ZIP/OPENSSL/MBSTRING; allow_url_fopen=On |
| C4 | Atheos (pinned SHA) | the editor; git via its codegit component |
| C5 | /var/www/atheos/workspace |
project storage (writable) |
| C6 | git CLI | VCS; safe.directory set; no identity (operator-owned) |
| C7 | blog working copy |
clone of armistace/blog on master |
| C8 | Gitea (external) | clone source; agent never pushes |
| C9 | Operator (external) | owns SSH key, git identity, Atheos admin, remote switch |
3. Key interfaces
- nginx → php-fpm:
fastcgi_pass unix:<FPM_SOCKET>must equal the pool'slisten =. Mismatch ⇒ 502. - Atheos → filesystem: writable
config.php,data/,workspace/,plugins/,themes/. Failure ⇒ installer dependency error. - Atheos → git: needs
giton PATH andsafe.directoryfor the workspace (else dubious ownership). Identity intentionally unset. - git → Gitea: HTTPS clone (public); operator later switches to SSH.
- OpenRC:
nginx+php-fpm83enabled atdefaultrunlevel — otherwise first reboot breaks service (AC-6).
4. Design decisions (from the gate)
| # | Decision | Source |
|---|---|---|
| D1 | No git identity configured by the agent. user.name/user.email left unset; RUNBOOK instructs the operator to set them first. |
Q1=B |
| D2 | Atheos pinned to a resolved commit SHA, with an additional update script that re-clones at latest and re-pins. | Q2 |
| D3 | Web root /var/www/atheos; workspace /var/www/atheos/workspace; nginx :80; php-fpm via unix socket. |
Q3 |
| D4 | Atheos served at the site root. | assumed, accepted |
| D5 | Operator completes Atheos's first-run installer; agent seeds no users. | FR-11 / Q2 of requirements |
| D6 | Credential = a per-repository Gitea deploy key scoped to armistace/blog, write-enabled (read_only:false), owned by the php-fpm user, aliased via ~/.ssh/config with IdentitiesOnly yes. Not a PAT (account-wide scopes) and not a dedicated Gitea user (no blast-radius reduction for blog). Private key generated on the guest; public half handed to the operator to add in-repo. |
Andrew, 2026-09-29 (security review) |
5. Scope guards (each is a testable negative)
- No database installed
- No Python / pelican /
make— the presence of Python is a defect (AC-8) - No NPM proxy host / DNS / port-forward (FR-10)
- No
armistacecredential, SSH key, or git identity created by the agent (FR-11)
6. Design-level risks handed to Infrastructure Design
- C-1 Atheos on Alpine is under-documented → resolve the FPM socket and extension package names from the installed system, not from upstream docs.
- C-2 OpenRC, not systemd → all service work uses
rc-service/rc-update. - C-3 Alpine template must be downloaded on scotty first (
pveam update+download). - C-4 The installer needs a writable web root before it will run.
7. Unit mapping
U1 guest (C1) · U2 web stack (C2,C3) · U3 Atheos (C4,C5) · U4 git + clone (C6,C7) · U5 docs + script (all)