Commit Graph
6 Commits
Author SHA1 Message Date
ced4568 67e172c800 feat(cicd): Gitea Actions pipeline, deterministic image tagging
Automatic test/build/tag/staging-deploy on push to main; production
promotion stays a manual, human-run step (deploy-production.sh) - never
automated. SHA-tagged images always, semantic tags only on deliberate
release, never :latest alone in staging/production. No paid CI provider or
registry required (uses Gitea's own). Real regression job installs all
services, applies real migrations against a service Postgres, runs the
infra validation scripts.

Validated as real YAML (python3 yaml parse).
2026-08-18 17:13:25 -05:00
ced4568 b1b22b9285 feat(backup): encrypted Postgres backup/restore + off-host adapter
pg_dump -> gzip -> gpg AES-256 symmetric encryption, plaintext deleted
immediately, optional off-host rsync-over-SSH copy (Hetzner Storage Box or
any SSH target), retention pruning, Prometheus textfile-collector metrics
for backup success/age/size.

Genuinely tested end-to-end, not just written: real production migrations
(17 total, correct cross-service order) applied to a disposable Postgres,
sample data inserted, backed up, restored into a second disposable
Postgres, verified table-for-table and byte-for-byte. Exit 0.
2026-08-18 17:13:19 -05:00
ced4568 4e8fa1d413 feat(observability): Prometheus/Alertmanager/Grafana/Loki stack
Self-hosted, no paid SaaS. Host/container/Postgres metrics, uptime probes
against the new /healthz endpoints, alert rules split critical (pages) vs
warning (informational), one starter Grafana dashboard. Deliberately
separate from the application's instructor learning analytics (Phase 3B) -
different audience, different data.

Validated: promtool check config (valid), promtool check rules (11 rules,
valid), amtool check-config (1 inhibit rule, 2 receivers, valid).
2026-08-18 17:13:14 -05:00
ced4568 d2280d0f0d feat(security): production Compose topology, firewall rulesets, Docker mTLS
Named-bridge-network production Compose (not host networking, unlike dev)
for rn-platform-01; egress-proxy + agents for rn-lab-host-01. Caddy reverse
proxy, single public origin, Grafana restricted to management_cidr.
iptables-restore firewall rulesets for all three hosts (Proxmox host,
rn-platform-01, rn-lab-host-01) codifying the Platform/Lab-Host boundary:
no student-to-student traffic, no direct Proxmox exposure, no direct
Postgres/Provisioner exposure from the Lab Host.

Mutual TLS for the Provisioner<->Lab Host Docker connection: certificate
generation/verification scripts, dockerd TLS config, firewall-restricted
port 2376. Application support already existed since Phase 1; this is
purely the operational half.

Validated: docker compose config, caddy validate, firewall structural lint,
and a real openssl s_server/s_client mTLS handshake proving the cert chain
and mutual-auth rejection (legitimate client verified, rogue client
correctly rejected with verify code 19).
2026-08-18 17:13:09 -05:00
ced4568 507ac4c5d3 feat(ansible): idempotent role-based host config for both production VMs
common/firewall/docker-tls/platform/lab-host/monitoring-agent/backup roles,
orchestrated by site.yml with the ordering that matters (firewall/TLS land
before the services that depend on them). Ansible Vault for secrets, no new
tool introduced for this project's modest secret surface. Explicit
dev/staging/production environment separation, no secrets committed
(.gitignore covers vault plaintext, TLS keys, Terraform state, *.env).

Validated: ansible-playbook --syntax-check clean.
2026-08-18 17:13:01 -05:00
ced4568 cbf81b09e7 feat(proxmox): Proxmox VM template + Terraform/OpenTofu VM creation
Manual, documented bare-metal Proxmox install + cloud-init template build
(deliberately not automated — a fragile one-time step). Terraform/OpenTofu
config creates rn-platform-01/rn-lab-host-01 from that template via the
bpg/proxmox provider, with configurable (not hardcoded) VM sizing.

Validated: tofu fmt, tofu init -backend=false (real provider download),
tofu validate -> Success. No paid state backend required (local state).
2026-08-18 17:12:55 -05:00