From ee3051f6e4a9f837c2cb9335fc2cc8b80e8592a8 Mon Sep 17 00:00:00 2001 From: Erik Simon Date: Sun, 23 Aug 2026 07:35:03 +0200 Subject: [PATCH] gitea: allow tailnet webhook targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Webhook delivery to the hermes relay was refused outright: Post "http://mars.orbit.sol:8645/gitea/gitea-pr-comments": dial tcp 100.64.0.6:8645: webhook can only call allowed HTTP servers (check your security.ALLOWED_HOST_LIST setting), deny 'mars.orbit.sol(100.64.0.6:8645)' ALLOWED_HOST_LIST defaults to `external`, documented as "a valid non-private unicast IP". Tailscale addresses come from 100.64.0.0/10 — RFC 6598 carrier-grade NAT space — which is not RFC1918 private but does not satisfy gitea's notion of external either, so every tailnet target is denied by default. Nothing about the relay or the URL was wrong; the request never left jupiter. Sets the tailnet CIDR explicitly and keeps `external`, so a future webhook to a public service still works without another edit here. Goes in [security], not [webhook]: the webhook-section key is deprecated in favour of this one and now merely falls back to it, and [security] is the name the delivery error itself reports. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01S94o42aQ8VkBmEWvDem5xa --- services/dev/gitea.nix | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/services/dev/gitea.nix b/services/dev/gitea.nix index ff21b02..7cdb25e 100644 --- a/services/dev/gitea.nix +++ b/services/dev/gitea.nix @@ -77,6 +77,23 @@ in service = { DISABLE_REGISTRATION = true; }; + security = { + # Gitea refuses to deliver a webhook to any host outside this list, + # which defaults to `external` — "a valid non-private unicast IP". + # Tailscale addresses are 100.64.0.0/10 (RFC 6598 carrier-grade NAT), + # which is neither RFC1918 private nor, as far as gitea's matcher is + # concerned, external — so the hermes relay on mars was refused with + # deny 'mars.orbit.sol(100.64.0.6:8645)' + # even though nothing here is private in the RFC1918 sense. Adding + # the tailnet CIDR is what makes tailnet-internal webhook targets + # deliverable at all; `external` is kept so a future webhook to a + # public service (discord, slack) still works without another edit. + # + # This lives in [security], not [webhook]: the webhook-section key is + # deprecated and now just falls back to this one, which is the name + # the delivery error itself reports. + ALLOWED_HOST_LIST = "external,100.64.0.0/10"; + }; actions = { ENABLED = true; };