MakerFLOSS_Troubleshooting/docs/superpowers/plans/2026-06-28-tappaas-vps-publishing.md
sjat 2e3f38cb3a plan: TaPPaaS VPS-side publishing implementation
Bite-sized tasks for the AnsibleBaobabV4 changes: flossfw wg1 peer +
keypair, *.tappaas wildcard cert, catch-all delegate route, public DNS.
VPS-side deliverable = valid-TLS 502; end-to-end gated on TaPPaaS-side plan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 10:33:10 +02:00

14 KiB
Raw Blame History

TaPPaaS VPS Publishing (VPS side) — Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Wire the makerfloss VPS to publish *.tappaas.makerfloss.eu — add a wg1 peer for the TaPPaaS FLOSSFirewall, issue the wildcard cert, add the catch-all route to the backend, and publish the public DNS — reusing the proven mf01 pattern.

Architecture: All changes are additive edits to AnsibleBaobabV4/host_vars/makerfloss.yml (plus one vault entry), deployed with the repo's existing plays. TLS terminates at the VPS; a catch-all Traefik router forwards plain HTTP over wg1 to the FLOSSFirewall/Caddy backend at 10.13.0.9:80. This plan delivers the VPS edge only — end-to-end 200 awaits the separate TaPPaaS-side plan, so the success criterion here is a valid-TLS 502 (route works, backend not yet up).

Tech Stack: Ansible (baobab roles baobab.wireguard_server, baobab.traefik, baobab.gandi_dns), Traefik (Gandi DNS-01 ACME), WireGuard, wireguard-tools.

Global Constraints

  • Target repo/branch: changes land in ~/Projects/AnsibleBaobabV4 on main. That repo currently has unrelated WIP on feat/loki-review-staleness-alert — before starting, get these commits onto main cleanly (stash/commit the WIP, or branch off main and fast-forward main when done). Do not mix this work into the loki feature branch.
  • All ansible commands run from ~/Projects/AnsibleBaobabV4 (repo root) using .venv/bin/ansible-playbook.
  • Inventory + limit always: -i inventories/prod/hosts.yml --limit makerfloss.
  • Vault is auto-loaded from ~/.ansible/vault-keys/prod.txt via ansible.cfg (vault_identity_list = prod@...). Never pass --vault-id manually; never print vault plaintext into a commit or log.
  • Idempotency (repo rule): every deploy task runs the play twice; the second run must report changed=0.
  • Peer naming/addressing (decided): peer name flossfw, wg1 IP 10.13.0.9/32 (confirmed free; taken = .1 .2 .3 .5 .6 .8).
  • Test hostname: use whoami.tappaas.makerfloss.eu throughout — any label under the wildcard works; nothing needs to exist at the backend for the VPS-side checks.
  • Reach path: all verification targets the public VPS (makerfloss.eu / 88.99.32.236, SSH :7576) — no makerspace tunnel needed (access.md path B2).
  • Never commit secrets. The keypair lives only in the encrypted vault.

File Structure

  • ~/Projects/AnsibleBaobabV4/group_vars/all/90-secrets.vault.yml (modify, encrypted) — adds flossfw keypair under vault_wireguard_makerfloss_peers.
  • ~/Projects/AnsibleBaobabV4/host_vars/makerfloss.yml (modify) — adds, in four distinct sections: the wg1 peer, the wildcard cert set, the catch-all dynamic route, and the public DNS records.

No new files; no TaPPaaS-side files (separate plan).


Task 1: Generate the FLOSSFirewall WireGuard keypair and store it in the vault

Files:

  • Modify: ~/Projects/AnsibleBaobabV4/group_vars/all/90-secrets.vault.yml (encrypted)

Interfaces:

  • Produces: vault var vault_wireguard_makerfloss_peers.flossfw.public_key (and .private_key), referenced by Task 2.

  • Step 1: Ensure wg is available

Run:

command -v wg || sudo apt-get install -y wireguard-tools

Expected: a path like /usr/bin/wg.

  • Step 2: Generate the keypair (private never leaves tmpfs until vaulted)

Run:

umask 077
wg genkey | tee /dev/shm/flossfw.key | wg pubkey > /dev/shm/flossfw.pub
echo "PRIV=$(cat /dev/shm/flossfw.key)"
echo "PUB=$(cat /dev/shm/flossfw.pub)"

Expected: two base64 strings (44 chars ending =).

  • Step 3: Add the entry to the vault

Run:

cd ~/Projects/AnsibleBaobabV4
.venv/bin/ansible-vault edit group_vars/all/90-secrets.vault.yml

Under the existing vault_wireguard_makerfloss_peers: mapping, add (paste the real values from Step 2 in place of PRIV/PUB):

  flossfw:
    private_key: "PRIV"
    public_key:  "PUB"

Save and close the editor.

  • Step 4: Verify the entry decrypts and parses

Run:

cd ~/Projects/AnsibleBaobabV4
.venv/bin/ansible-vault view group_vars/all/90-secrets.vault.yml | grep -A3 'flossfw:'

Expected: the flossfw: block with private_key/public_key printed. (This is local stdout only — do not redirect to a file.)

  • Step 5: Shred the tmp keys

Run:

shred -u /dev/shm/flossfw.key /dev/shm/flossfw.pub 2>/dev/null; rm -f /dev/shm/flossfw.key /dev/shm/flossfw.pub

Expected: files gone (ls /dev/shm/flossfw.* → no such file). The keys now live only in the vault.

  • Step 6: Commit
cd ~/Projects/AnsibleBaobabV4
git add group_vars/all/90-secrets.vault.yml
git commit -m "secrets: add flossfw wireguard keypair for tappaas wg1 peer"

Task 2: Add the FLOSSFirewall as a wg1 peer and deploy

Files:

  • Modify: ~/Projects/AnsibleBaobabV4/host_vars/makerfloss.yml (wireguard_server_peers)

Interfaces:

  • Consumes: vault_wireguard_makerfloss_peers.flossfw.public_key (Task 1).

  • Produces: VPS wg1 allows 10.13.0.9/32 — the backend address Task 4 routes to.

  • Step 1: Add the peer entry

In host_vars/makerfloss.yml, append to the wireguard_server_peers: list (after the mf01 entry), matching the existing style exactly:

  - name: "flossfw"
    public_key: "{{ vault_wireguard_makerfloss_peers.flossfw.public_key }}"
    allowed_ips: "10.13.0.9/32"
    managed: true
    description: "TaPPaaS FLOSSFirewall (Caddy reverse proxy, split-tunnel)"
    generate_config: false  # client config deployed on the TaPPaaS side
  • Step 2: Deploy the WireGuard server config

Run:

cd ~/Projects/AnsibleBaobabV4
.venv/bin/ansible-playbook play_setup.yml -i inventories/prod/hosts.yml --limit makerfloss -t wireguard-server,firewall

Expected: PLAY RECAP with failed=0, changed>=1.

  • Step 3: Confirm idempotence (run again)

Run the exact command from Step 2 again. Expected: PLAY RECAP changed=0.

  • Step 4: Verify the peer is live on the VPS

Run:

ssh -p 7576 sjat@makerfloss.eu "sudo wg show wg1 allowed-ips" | grep -F '10.13.0.9/32'

Expected: one line containing the flossfw public key and 10.13.0.9/32. (No handshake yet — the FLOSSFirewall isn't up; that's expected.)

  • Step 5: Commit
cd ~/Projects/AnsibleBaobabV4
git add host_vars/makerfloss.yml
git commit -m "wg1: add flossfw peer (10.13.0.9) for tappaas publishing"

Task 3: Add the *.tappaas wildcard cert set and issue it

Files:

  • Modify: ~/Projects/AnsibleBaobabV4/host_vars/makerfloss.yml (traefik_wildcard_sets)

Interfaces:

  • Produces: a valid *.tappaas.makerfloss.eu cert on the VPS Traefik, used by Task 4's router (tls: {}).

  • Step 1: Add the wildcard set

In host_vars/makerfloss.yml, append to traefik_wildcard_sets: (after the mf01 entry):

  - main: "tappaas.makerfloss.eu"
    sans: ["*.tappaas.makerfloss.eu"]
  • Step 2: Deploy Traefik (triggers ACME via the anchor router)

Run:

cd ~/Projects/AnsibleBaobabV4
.venv/bin/ansible-playbook play_containers.yml -i inventories/prod/hosts.yml --limit makerfloss -t traefik

Expected: PLAY RECAP failed=0; the traefik container is recreated.

  • Step 3: Confirm idempotence (run again)

Run the Step 2 command again. Expected: PLAY RECAP changed=0.

  • Step 4: Watch ACME issue the cert

Run (wait up to ~90s for DNS-01 to complete):

ssh -p 7576 sjat@makerfloss.eu "docker logs traefik 2>&1 | grep -i tappaas | tail -20"

Expected: ACME log lines referencing tappaas.makerfloss.eu / *.tappaas.makerfloss.eu with no error; eventually a "certificate obtained" style entry.

  • Step 5: Verify the served cert (by IP + SNI — no DNS needed yet)

Run:

echo | openssl s_client -connect 88.99.32.236:443 -servername whoami.tappaas.makerfloss.eu 2>/dev/null | openssl x509 -noout -ext subjectAltName

Expected: SAN list contains *.tappaas.makerfloss.eu.

  • Step 6: Commit
cd ~/Projects/AnsibleBaobabV4
git add host_vars/makerfloss.yml
git commit -m "traefik: add *.tappaas.makerfloss.eu wildcard cert set"

Task 4: Add the catch-all delegate route to the backend and deploy

Files:

  • Modify: ~/Projects/AnsibleBaobabV4/host_vars/makerfloss.yml (traefik_extra_dynamic_files)

Interfaces:

  • Consumes: the wildcard cert (Task 3) via tls: {}; the 10.13.0.9 peer (Task 2).

  • Produces: VPS routes *.tappaashttp://10.13.0.9:80.

  • Step 1: Add the dynamic route file

In host_vars/makerfloss.yml, add a new key under traefik_extra_dynamic_files: (sibling of mf01-delegate.yml). Keep the regex single-quoted — a YAML error here breaks the whole file provider:

  tappaas-delegate.yml: |
    http:
      routers:
        tappaas-wildcard:
          rule: 'HostRegexp(`^.+\.tappaas\.makerfloss\.eu$`)'
          entryPoints:
            - websecure
          service: tappaas-backend
          tls: {}
      services:
        tappaas-backend:
          loadBalancer:
            passHostHeader: true
            servers:
              - url: "http://10.13.0.9:80"
  • Step 2: Deploy Traefik

Run:

cd ~/Projects/AnsibleBaobabV4
.venv/bin/ansible-playbook play_containers.yml -i inventories/prod/hosts.yml --limit makerfloss -t traefik

Expected: PLAY RECAP failed=0.

  • Step 3: Confirm idempotence (run again)

Run the Step 2 command again. Expected: PLAY RECAP changed=0.

  • Step 4: Verify the dynamic file parsed (no file-provider error)

Run:

ssh -p 7576 sjat@makerfloss.eu "docker logs traefik 2>&1 | grep -iE 'error|tappaas-delegate' | tail -20"

Expected: no parse/error lines mentioning tappaas-delegate.yml.

  • Step 5: Verify the route matches (502 = success here)

Run:

curl -sk -o /dev/null -w '%{http_code}\n' -H 'Host: whoami.tappaas.makerfloss.eu' https://88.99.32.236/

Expected: 502 (or 504). The router matched and tried the backend; 10.13.0.9:80 isn't up yet, which is the expected VPS-side end state. A 404 would mean the route didn't match — investigate before committing.

  • Step 6: Commit
cd ~/Projects/AnsibleBaobabV4
git add host_vars/makerfloss.yml
git commit -m "traefik: route *.tappaas to flossfw backend over wg1"

Task 5: Publish the public DNS records and deploy

Files:

  • Modify: ~/Projects/AnsibleBaobabV4/host_vars/makerfloss.yml (gandi_dns_records)

Interfaces:

  • Produces: public A records tappaas and *.tappaas88.99.32.236.

  • Step 1: Add the records

In host_vars/makerfloss.yml, append to gandi_dns_records: (after the *.mf01 entry), matching the existing style:

  - name: "tappaas"
    type: A
    ttl: 300
    values: ["88.99.32.236"]
  - name: "*.tappaas"
    type: A
    ttl: 300
    values: ["88.99.32.236"]
  • Step 2: Deploy DNS

Run:

cd ~/Projects/AnsibleBaobabV4
.venv/bin/ansible-playbook play_dns.yml -i inventories/prod/hosts.yml --limit makerfloss -t gandi-dns

Expected: PLAY RECAP failed=0; task output shows the two records added.

  • Step 3: Confirm idempotence (run again)

Run the Step 2 command again. Expected: PLAY RECAP changed=0 (records already present).

  • Step 4: Verify resolution

Run (allow up to the 300s TTL to propagate):

dig +short whoami.tappaas.makerfloss.eu @1.1.1.1
dig +short tappaas.makerfloss.eu @1.1.1.1

Expected: both return 88.99.32.236.

  • Step 5: Commit
cd ~/Projects/AnsibleBaobabV4
git add host_vars/makerfloss.yml
git commit -m "dns: publish tappaas + *.tappaas A records to the VPS"

Task 6: VPS-side integration verification (no code change)

Files: none — verification gate.

  • Step 1: End-to-end VPS edge check

Run:

curl -sk -o /dev/null -w 'http=%{http_code} cert_subject=%{ssl_verify_result}\n' https://whoami.tappaas.makerfloss.eu/
echo | openssl s_client -connect whoami.tappaas.makerfloss.eu:443 -servername whoami.tappaas.makerfloss.eu 2>/dev/null | openssl x509 -noout -ext subjectAltName | grep -F '*.tappaas.makerfloss.eu'

Expected: real public DNS resolves to the VPS, TLS validates against the *.tappaas wildcard, and HTTP returns 502/504 (backend not yet up). This is the completed VPS-side deliverable.

  • Step 2: Record the result

Note in the session/PR: VPS edge ready; 200 OK is gated on the TaPPaaS-side plan (FLOSSFirewall WireGuard client + Caddy plain-HTTP backend on 10.13.0.9:80 + internal DNS). That plan is blocked on identifying the TaPPaaS config repo (spec Open items). Optionally add a short note to MakerFLOSS_Troubleshooting/runbooks/ pointing at this pattern (mirror of publishing-services-mf01.md).


Self-Review

Spec coverage (VPS scope):

  • Component A.1 wg1 peer → Task 2 ✓ (keypair prereq → Task 1 ✓)
  • A.2 wildcard cert → Task 3 ✓
  • A.3 catch-all route → Task 4 ✓
  • A.4 public DNS → Task 5 ✓
  • Phasing steps 13 (tunnel VPS-end, edge, DNS) → Tasks 25 ✓; integration gate → Task 6 ✓
  • Isolation: split-tunnel/AllowedIPs and the tcp/80 from 10.13.0.1 firewall are TaPPaaS-side — correctly deferred to the other plan, not in scope here.
  • Phasing steps 45 (internal DNS, makerspace LAN) → TaPPaaS-side plan, out of scope. Noted gap by design.

Placeholder scan: No TBD/TODO/"handle errors" placeholders; PRIV/PUB in Task 1 are explicitly real-value substitutions generated in-step. ✓

Type/name consistency: peer name flossfw, IP 10.13.0.9, vault path vault_wireguard_makerfloss_peers.flossfw.public_key, service tappaas-backend, router tappaas-wildcard, dynamic file tappaas-delegate.yml, hostname whoami.tappaas.makerfloss.eu — all consistent across tasks. ✓