Commit graph

105 commits

Author SHA1 Message Date
394f2519ff
age backups everywhere 2026-09-12 16:20:42 +02:00
27e036eccd
backup stuff 2026-09-12 16:02:00 +02:00
01b83a80ec
ip tricks 2026-09-12 15:32:17 +02:00
a8a2815c5f
inventory 2026-09-12 15:14:47 +02:00
cea2523e15
caddy: close out Plan 4
All five close-out greps return nothing: no sites-enabled handling outside
roles/, no `systemctl reload caddy`, no caddy_sites_dir self-reference, no
inline proxy unit writes. 37 playbooks syntax clean. The 14 Caddy site files
and 6 proxy units on the hosts are byte-identical to the Stage 0 baseline.

Seven play names still said "on vipy" while the play targeted a group. Renamed
to "on the edge host" - the last place a play claimed a hostname after Plan 2.

Documented the four vhosts in /etc/caddy/sites-enabled that no playbook writes
(uptime-kuma, arbretstaging, bitcoininfra, scriberr) in the caddy_site README.
None deleted.

uptime-kuma.conf was going to be deleted as dead config. It is not dead: the
louislam/uptime-kuma container is STILL RUNNING on watchtower - created
2026-02-07, restart=unless-stopped, healthy - and uptime.contrapeso.xyz returns
302, not the 502 a dead backend would give. The "decommissioning" retired the
Ansible code and the vault credentials, not the service. PLAN_3 claimed "the
tokens died with the server"; that is corrected there.

The Caddyfile.* backups are kept: one per host, Nov-Dec 2025, not churning, and
the only record of each Caddyfile before the import line was added.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:53:09 +02:00
c4094b692f
bitcoin-knots, fulcrum, datum-gateway: add and use the socket_proxy role
Three near-identical hosts: edge plays become one role plus three short
calls. 183 lines removed, 34 added, plus a 111-line role.

Verified before touching any playbook: all six live units on vipy reproduced
byte-identically. Then --limit edge --check per playbook - bitcoin-knots and
fulcrum changed=0; datum-gateway changed=2, both attributable to the already
known caddy_site comment line and the Reload caddy handler it triggers.
The 6 units and 14 Caddy files on the hosts are byte-identical afterwards.

PLAN_4 claimed these three plays had "no behavioural drift at all". That was
wrong - it came from a diff truncated by head -60. The live bitcoin-p2p-proxy
units carry four settings this playbook never wrote:

  .socket   Documentation=, FreeBind=true
  .service  Documentation=, TimeoutStopSec=5,
            StandardOutput=journal, StandardError=journal

FreeBind is the one that matters: it lets the socket bind to an address that
is not up yet, so without it the socket can fail to start on boot. Running
the bitcoin-knots playbook would have stripped it. Same class of hazard as
headscale. The role expresses all four; bitcoin-p2p is the only caller that
passes any.

Also: UFW treats the rule comment as part of the rule. datum-stratum's live
comment is "DATUM Gateway Stratum public access" but the role's derived
default produced "DATUM Stratum public access", which rewrote the rule.
Caught in the dry-run; datum now passes the comment explicitly.

Two deliberate differences from the original, both documented in the README:
ignore_errors: yes on the upstream check became failed_when: false, and the
handler restarts the .socket, which drops connections open through it - it
fires only when a unit file actually changes.

The inert Uptime Kuma TCP monitor blocks stay in the playbooks rather than
being pulled into a new role (12/12/18 guarded tasks).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:50:15 +02:00
16cbd189b8
ntfy, datum-gateway, headscale: use the caddy_site role
Completes Stage 3. No hand-rolled Caddy plumbing remains anywhere:
`grep sites-enabled` outside roles/ returns nothing, and so does
`grep "systemctl reload caddy"`.

ntfy uses caddy_site_body for its plain-HTTP listener and @httpget redirect.
Verified ok/unchanged against watchtower; the one other changed task is a
pre-existing "Update APT cache".

datum-gateway keeps a whole-Caddyfile validate after the role call. The role
validates its own fragment, but only a whole-file validate catches a conflict
between two sites, and this playbook was the only one that ever had it. Its
two debug tasks that echoed command output are gone with the commands.

headscale is the one that mattered. Its playbook wrote
`reverse_proxy localhost:8080`, but spacey is actually running a /admin*
route in front of Headplane behind Caddy basic auth. Running that playbook
would have deleted the admin route and its auth - a hazard that predates this
work. It now renders the config that is really there, verified ok/unchanged
via --start-at-task (the play cannot reach Caddy in check mode: "Install
headscale package" fails because the .deb is not really downloaded, before
and after this edit alike).

Supporting changes for headscale:
  - headscale_ui_password_hash added to infra_secrets.yml and the identical
    group_vars/all/vault.yml, read from the live config on spacey. The vault
    already had headscale_ui_username (= counterweight, confirmed) and
    headscale_ui_password; I did not verify the password is the plaintext of
    this hash.
  - headplane_port added to headscale_vars.yml.
  - The role's handler now sets become: true. Handlers do not inherit become
    from the task that notified them, and this play runs become: no.
  - The include uses `apply: become: yes`; `become:` on an include_role is
    rejected outright.

All 14 site files on all 3 hosts still byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:37:38 +02:00
82fca48b08
lnbits, memos, mempool: use the caddy_site role
lnbits is the header_up shape; memos and mempool are the Tailscale MagicDNS
shape. 108 lines removed, 25 added.

mempool was the one playbook already reloading Caddy correctly
(systemd: state: reloaded rather than command: systemctl reload caddy), so
its end marker differed - the role's handler does the same thing.

Verified:
  - lnbits: full --check, site task ok, byte-identical to the live file
  - memos, mempool: --check --diff via --limit edge shows exactly one added
    line each, the standardised MagicDNS comment. Both playbooks fail earlier
    in check mode on their VM play ("Extract memos binary", the same
    download-does-not-happen-in-check-mode artifact as forgejo), but the edits
    are confined to the hosts: edge play - memos at line 169+, play 2 starts
    at 159; mempool at 617+, play 2 starts at 606.

The added comment means the next real run of memos/mempool rewrites one
comment line. Those two host files were already stale against their
playbooks before this change.

All 14 site files on all 3 hosts still byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:29:06 +02:00
4bee182978
ntfy-emergency-app, vaultwarden, forgejo: use the caddy_site role
The plain reverse_proxy shape. All three removed a byte-identical 23-line
block (verified by md5 of the diff with the service name normalised) and
gained the same 7-line include_role call. The caddy_sites_dir self-reference
goes with it.

Verified in check mode, nothing applied to the hosts yet:
  - ntfy-emergency-app: site task ok, changed=0
  - vaultwarden: site task ok; the one changed task is a pre-existing
    always-restarts fail2ban step, identical before the edit
  - forgejo: check mode cannot run this playbook at all - get_url does not
    download in check mode so the next task fails on "Source /tmp/forgejo not
    found". Confirmed identical before the edit. Covered instead by the
    Stage 2 dry-run, which ran the role against vipy with forgejo's real
    parameters and reported ok/unchanged.

All 14 site files on all 3 hosts still byte-identical. Real runs for these
three are still outstanding.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:24:57 +02:00
39a1b43577
personal-blog: use the caddy_site role
First service on the role. 31 lines of copy-pasted Caddy plumbing become 7.

Verified: --check before and after the edit reports the same three unrelated
tasks as changed, so the edit introduces nothing. Real run leaves all 14 site
files on all 3 hosts byte-identical, and the blog still answers HTTP 200. A
second consecutive run reports the site task ok with the handler not firing.

Side effect worth noting: the playbook no longer has a perpetually-changed
task. `command: systemctl reload caddy` always reported changed; the role's
handler only fires when the file actually moves.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:19:01 +02:00
cc9340b7cc
caddy: add the caddy_site role
Replaces the four-task Caddy vhost block currently copy-pasted into 10
playbooks. Nothing calls it yet; this commit only adds the role.

Verified by rendering all 10 sites through the template and diffing against
what the current playbooks produce: 9 of 10 byte-identical. The tenth is
datum-gateway, where the resolvers comment is standardised, rewriting one
comment line Caddy ignores.

Then dry-run against the live hosts (--check, nothing written):
  - vipy: forgejo, vaultwarden, lnbits, personal-blog, ntfy-emergency-app
    all report ok/unchanged against the real files
  - watchtower: ntfy renders identical via caddy_site_body, blank line and
    {host}{uri} placeholders intact
  - spacey: headscale renders identical when given the config that is
    actually running
  - memos, mempool, datum-gateway report changed - the comment, as expected
All 14 site files on all 3 hosts confirmed unchanged afterwards.

Two things the build turned up:

- Ansible does not template dict *keys*, so caddy_site_basic_auth is a list
  of {user, hash}. As a dict, a Jinja username passes through literally.
  The assert refuses a mapping.
- `caddy validate` does accept a single site fragment - rc=0 on a good one,
  rc=1 with a line number on a broken one. This was the plan's one untested
  claim. A failed validate leaves the live file untouched.

The reload is now a handler, so it fires once at end of play rather than
immediately; anything needing the new config live mid-play must
flush_handlers first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:10:43 +02:00
b07ed72a92
caddy: add a [caddy] role group and target it
services/caddy_playbook.yml was the one play still targeting a location
group (vps) rather than a role group. The two coincide today — vps is
exactly vipy, watchtower and spacey, the three hosts with
/etc/caddy/sites-enabled — but adding a fourth VPS that does not run
Caddy would have silently pulled it into the play.

[caddy:children] is edge + monitoring + vpn_control. Verified the play
selects the same three machines before and after.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 23:03:25 +02:00
8a3fddbe49
docs: mark Uptime Kuma as decommissioned
README, both setup guides and the forgejo-runner notes now point at
archive/uptime_kuma/ instead of describing a live service.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 22:43:56 +02:00
338f2ae636
uptime-kuma: annotate config and drop the unused collection
lucasheld.uptime_kuma was pinned but never used - every monitor was created by
hand-rolled Python. The uptime subdomain stays because the deprecated blocks
still template it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 22:43:56 +02:00
b5b028c356
uptime-kuma: deprecation banners on the monitoring-only plays
These five plus the ntfy notification playbook assert on the credentials, so
they now fail immediately instead of running — deliberately, before anything is
installed. The banner says so and points at archive/uptime_kuma/.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 22:43:55 +02:00
2dabc6ad62
uptime-kuma: add uptime_kuma_enabled flag and make monitoring blocks inert
Removing the credentials would otherwise break these playbooks mid-deploy: they
template uptime_kuma_password with no assert to stop them first. 100 tasks are
now guarded by uptime_kuma_enabled (false), so deployments run normally and the
monitoring sections skip. A further 28 tasks were already self-guarding on
monitor_setup/push_url being defined; verified that a skipped task's registered
variable makes those skip cleanly rather than error.

The blocks are kept on purpose — the health-check logic is the durable part and
should be rewired to whatever replaces Uptime Kuma.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 22:43:55 +02:00
80c9e6f3e3
uptime-kuma: remove credentials from the vaults
Drops uptime_kuma_username/password from infra_secrets.yml and its group_vars
copy and example, plus a dead push token in nodito_secrets.yml that nothing
referenced. They remain in git history — rotation is what actually retires them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 22:43:15 +02:00
79942525b1
archive: record Uptime Kuma monitors and setup before decommissioning
Captured from the live instance rather than the repo: the playbooks created 17
monitors, the server had 75. The rest existed only in the UI. Push tokens are
excluded deliberately — they are live credentials.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 22:43:15 +02:00
b0f14ea365
vars 2026-09-11 22:17:13 +02:00
3c2aacad46
vars: derive remote_host_name from role groups instead of hostnames
Resolved values verified unchanged: same host, IP, user, key and port for all 8.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 22:00:43 +02:00
ed99e17aae
backups: target control group instead of lapy
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:24 +02:00
ceb5c4ad27
infra/nodito: target hypervisor group instead of nodito_host/nodito
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:24 +02:00
4349006d51
datum-gateway: target bitcoin and edge groups instead of hostnames
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:15 +02:00
52d4a377f7
bitcoin-knots: target bitcoin and edge groups instead of hostnames
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:15 +02:00
a6c621e95c
fulcrum: target electrum and edge groups instead of hostnames
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:15 +02:00
fd7803755b
mempool: target mempool and edge groups instead of hostnames
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:14 +02:00
8d402b64fc
phoenixd: target edge group instead of vipy
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:14 +02:00
9ae0cc36d8
lnbits: target edge group instead of vipy
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:14 +02:00
900a0b4826
headscale: target vpn_control group instead of spacey
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:14 +02:00
f3ff1169db
forgejo-runner: target ci_runner group instead of forgejo_runner_local
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:13 +02:00
6680918fb7
forgejo: target edge group instead of vipy
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:13 +02:00
cc1aecd098
vaultwarden: target edge group instead of vipy
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:13 +02:00
791f6f3b69
ntfy: target monitoring group instead of watchtower
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:13 +02:00
31efa8365b
uptime_kuma: target monitoring group instead of watchtower
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:12 +02:00
007fdb43af
memos: target memos and edge groups instead of hostnames
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:12 +02:00
a26c0eca46
ntfy-emergency-app: target edge group instead of vipy
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:12 +02:00
e63fa1ff11
personal-blog: target edge group instead of vipy
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 21:56:12 +02:00
28a0bb2806
new groups, stop using all 2026-09-11 21:51:50 +02:00
acb8f9d82f
remove old example password 2026-09-11 21:32:56 +02:00
123107b7fb
track inventory 2026-09-11 21:32:23 +02:00
5e06021938
secrets note in readme 2026-09-11 20:08:19 +02:00
9db0b0ae84
now using password 2026-09-11 17:59:41 +02:00
6029317f3b
ansible: vault encrypt secrets 2026-09-11 17:53:12 +02:00
c3f5e47559
add ansible.cfg 2026-09-11 17:42:49 +02:00
d0bfc2650d
phoenixd upgrade 2026-08-08 15:19:11 +02:00
ba4ba504d0
stuffy stuff 2026-08-08 12:00:27 +02:00
0736f29f79
little thingies 2026-03-22 21:25:08 +01:00
c6e1a01167
thingies 2026-02-08 18:22:31 +01:00
08281ce349
ups playbook 2026-01-11 22:43:27 +01:00
fe321050c1
monitor zfs 2026-01-04 23:19:19 +01:00