Gitea returns HTTP 200 on a failed web login (the page is simply
re-rendered with an error), so the existing traefik-auth jail, which
matches on DownstreamStatus, is structurally blind to brute force on
the login form. Adds a dedicated gitea-auth jail reading the
forwarded application log (routed by the new 50-gitea.conf on top of
#20's generic receiver), plus a Traefik-side rate limit on
/user/login, /user/sign_up and /user/forgot_password as a second
layer.
[DEFAULT] ignoreip in jail.local guards every jail (not just
gitea-auth) so a misconfigured X-Forwarded-For chain can't ban the
tailnet itself — this must be in place before the jail, since the
whole point is to make that failure mode structurally impossible
rather than caught after the fact.
conf.d/gitea.yml gains a highest-priority router that denies public
access to /metrics (ipAllowList limited to loopback) while leaving it
reachable on the tailnet, where Gitea's own tailscale serve answers
directly. The backend also moves to https://gitea.taila5ad8.ts.net
(443, no port) — the result of #19's tailscale serve --https=443 —
which is NOT compatible with the previous :3000 backend of the old
community-scripts deployment; only apply once the data migration has
actually happened.
Verified with real fail2ban/rsyslog/Traefik v3 in disposable
containers: the gitea filter matches real failure log lines and
misses the normal login-page line; 5 failed logins from an external
IP bans it while 5 from the Tailscale CGNAT range never do (ignoreip
in effect); a forwarded "gitea"-tagged message lands in
/var/log/gitea/gitea.log; Traefik loads all three routers, both
middlewares, and the stated priorities without error.
Closes#21
A fail2ban jail running inside a service's own LXC only ever sees this
proxy's tailnet IP as the connection source, so it would end up
banning the proxy itself. Detection needs to stay at the service's
application log; banning needs to happen here, at the edge where
public connections terminate.
Adds a generic imtcp listener (port RSYSLOG_PORT, default 5514) that
routes anything unclaimed by a later 50-<service>.conf into
/var/log/remote/<sender-hostname>.log, plus logrotate with
copytruncate so fail2ban never loses its file descriptor. No
service-specific routing yet — that's one 50-<service>.conf per
service, documented here for the next issue to follow.
Refs #20