monitoring: track arbret.com expiry too

Domains are now a list in group_vars/all (monitored_domains) rather than the
single root_domain hardcoded in the playbook, so adding one is a line of data
instead of a change to the task.

arbret.com resolves to prd-arbret (167.99.242.62) and its RDAP record exposes
an expiry of 2027-02-18, so the check reads real data rather than silently
passing on a missing field - verified against rdap.verisign.com before wiring
it up.

Both domains checked daily with two weeks of runway, because registration
renewal is a manual act at the registrar and losing a domain is not recoverable
the way losing a host is.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
counterweight 2026-09-14 09:53:15 +02:00
parent efa9eb55ca
commit 99760dfd46
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
2 changed files with 31 additions and 18 deletions

View file

@ -58,3 +58,17 @@ subdomains:
# group covers them, so these are global rather than group_vars/<group>. # group covers them, so these are global rather than group_vars/<group>.
ntfy_topic: alerts ntfy_topic: alerts
headscale_namespace: counter-net headscale_namespace: counter-net
# ─────────────────────────────────────────────────────────────────────────────
# Domains whose registration expiry is monitored (infra/402_public_monitoring).
#
# Registration renewal is a manual act at the registrar, and losing a domain is
# not recoverable in the way losing a host is - so these are checked daily and
# alarm with two weeks of runway.
#
# root_domain is the estate's own domain; the rest are domains we own that are
# served from it or from a host in the inventory.
# ─────────────────────────────────────────────────────────────────────────────
monitored_domains:
- "{{ root_domain }}"
- arbret.com

View file

@ -61,25 +61,24 @@
tasks: tasks:
# ── Domain expiry ──────────────────────────────────────────────────────── # ── Domain expiry ────────────────────────────────────────────────────────
- name: Build the domain endpoint # Each domain needs a URL SCHEME: Gatus derives the endpoint type from the
# prefix (endpoint.Type()), so a bare "example.com" is UNKNOWN and the whole
# config is rejected. No status is asserted, only the WHOIS/RDAP expiry, so
# whatever the apex serves - a real site, or the registrar's parking page -
# is irrelevant.
#
# 24h, and upstream enforces a 5m minimum for DOMAIN_EXPIRATION anyway
# because it uses a free whois service that must not be hammered.
# 336h = 14 days of runway, because renewal is a manual act at the registrar.
- name: Build the domain endpoints
ansible.builtin.set_fact: ansible.builtin.set_fact:
domain_endpoints: domain_endpoints: "{{ domain_endpoints | default([]) + [{
- name: "{{ root_domain }}" 'name': item,
group: domain 'group': 'domain',
# Needs a scheme: Gatus derives the endpoint TYPE from the URL prefix 'url': 'https://' ~ item,
# (endpoint.Type()), and a bare domain is UNKNOWN and rejected. The 'interval': '24h',
# apex points at the registrar's parking page, which is irrelevant - 'conditions': ['[DOMAIN_EXPIRATION] > 336h']}] }}"
# the only condition here is the WHOIS expiry, and no status check is loop: "{{ monitored_domains }}"
# asserted, so what the page serves does not matter.
url: "https://{{ root_domain }}"
# 24h, and upstream enforces a 5m minimum for DOMAIN_EXPIRATION
# anyway because it uses a free whois service that must not be
# hammered and whose data updates slowly.
interval: 24h
# 336h = 14 days. Renewal is manual at the registrar, so this needs
# enough runway to act on.
conditions:
- "[DOMAIN_EXPIRATION] > 336h"
# ── DNS ────────────────────────────────────────────────────────────────── # ── DNS ──────────────────────────────────────────────────────────────────
- name: Build the DNS endpoints - name: Build the DNS endpoints