arbret: our side of running it on vipy

prd-arbret was folded into vipy. arbret itself (app, worker, Postgres, timers,
its backup dump) is deployed by its owner's own repo; this repo owns the
shared host's side of it. arbret_handoff.md documents the split, the Gatus
push API and the backup contract.

- services/arbret: arbret.com -> localhost:3100, www redirects to the apex,
  port 4117 allowed on tailscale0 only, /opt/backups/arbret pre-created to
  the contract so the pull job is green before the first dump.
- headscale ACL: framie may reach prd-vipy:4117.
- vipy: arbret-server, arbret-worker and postgresql in the unit checks.
- 402: DNS and HTTP checks for arbret.com, www, and /api/health with
  [BODY].status == ok. Entries may now name an fqdn outside root_domain and
  add conditions.
- 403: probes arbret-analytics (hourly, 130m window) and arbret-beancount
  (daily, 26h), pushing with the dedicated arbret token.
- backups: pull from backup-pull@prd-vipy:/opt/backups/arbret/, and a
  backup-dump_arbret endpoint.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
counterweight 2026-10-19 22:10:26 +02:00
parent 3be5e7934c
commit 5447e03d1f
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
8 changed files with 554 additions and 8 deletions

View file

@ -35,6 +35,11 @@
- {sub: "{{ subdomains.monero_explorer }}", host: vipy}
- {sub: "{{ subdomains.music }}", host: vipy}
- {sub: "{{ subdomains.jar_lid_archive_staging }}", host: vipy}
# Not under root_domain, so named in full. arbret.com's zone is NOT in
# Porkbun (mynymdns) - this is the check that would have caught it still
# pointing at prd-arbret's recycled IP after the 2026-10-17 rebuild.
- {fqdn: arbret.com, host: vipy}
- {fqdn: www.arbret.com, host: vipy}
# A public resolver on purpose: this must test what the internet sees, not
# what a local cache or the tailnet's MagicDNS happens to answer.
@ -68,6 +73,13 @@
# tailnet hop, gunicorn, and the database and bucket behind it (503 if
# either is down). "/" would only prove the login redirect works.
- {name: jars-staging, sub: "{{ subdomains.jar_lid_archive_staging }}", path: "/health/", status: 200}
# arbret (runs on vipy since 2026-10-17; deployed by the arbret repo, not
# this one). /api/health answers 200 + "status":"ok" when healthy and 503
# "degraded" otherwise, DB down included - per the arbret owner. The body
# condition guards against a 200 that is not actually healthy.
- {name: arbret, fqdn: arbret.com, path: "/", status: 200}
- {name: arbret-health, fqdn: arbret.com, path: "/api/health", status: 200,
conditions: ['[BODY].status == ok']}
# Ports published from the edge host by socket_proxy.
public_tcp:
@ -107,11 +119,11 @@
- name: Build the DNS endpoints
ansible.builtin.set_fact:
dns_endpoints: "{{ dns_endpoints | default([]) + [{
'name': item.sub ~ '.' ~ root_domain,
'name': (item.fqdn if item.fqdn is defined else item.sub ~ '.' ~ root_domain),
'group': 'dns',
'url': dns_resolver,
'interval': item.interval | default('6h'),
'dns': {'query-type': 'A', 'query-name': item.sub ~ '.' ~ root_domain},
'dns': {'query-type': 'A', 'query-name': (item.fqdn if item.fqdn is defined else item.sub ~ '.' ~ root_domain)},
'conditions': ['[DNS_RCODE] == NOERROR',
'[BODY] == ' ~ hostvars[item.host].ansible_host],
'alerts': [{'type': 'signal', 'failure-threshold': 1,
@ -128,10 +140,11 @@
http_endpoints: "{{ http_endpoints | default([]) + [{
'name': item.name,
'group': 'public',
'url': 'https://' ~ item.sub ~ '.' ~ root_domain ~ item.path,
'url': 'https://' ~ (item.fqdn if item.fqdn is defined else item.sub ~ '.' ~ root_domain) ~ item.path,
'interval': item.interval | default('5m'),
'conditions': ['[STATUS] == ' ~ item.status,
'[CERTIFICATE_EXPIRATION] > 168h'],
'[CERTIFICATE_EXPIRATION] > 168h']
+ item.conditions | default([]),
'alerts': [{'type': 'signal', 'failure-threshold': item.threshold | default(3),
'success-threshold': 2, 'send-on-resolved': true,
'minimum-reminder-interval': '6h'}]}] }}"