Skip to content

v0.12.0 — request history, new portal, IPv6 range bans

Latest

Choose a tag to compare

@timothydodd timothydodd released this 24 Sep 02:10
· 1 commit to main since this release

A big one: searchable long-term request history, a rebuilt admin portal, IPv6 range bans, and a round of reliability and security fixes.

Overview

New

  • Request history on disk (stats.archive) — hourly JSONL segments, gzipped and indexed when the hour closes, kept retention_days (default 30). The writer never blocks the proxy; IP lookups read only the hours an index says matter.
  • Admin portal rebuilt — overview with 1h/24h/7d/30d traffic, status mix and top IPs/paths; a Requests tab searchable by IP/CIDR, text, outcome, status and range; an IP panel with ban status, activity summary and latest requests; a ban dialog with durations; blacklist search/filter/sort, export/import (JSON or one-IP-per-line blocklists) and a whitelist view.
  • IPv6 range bans — honeypot hits and temp-bans of an IPv6 client cover its /64 (ipv6_ban_prefix), and strikes are counted per range.
  • Temp-ban escalation — temp_ban.escalate_after makes repeat offenders permanent.
  • Temp bans from the portal/API (duration), live config reload (SIGHUP, Settings, or POST /admin/reload), and Prometheus /metrics on the admin port.
  • Request log records country (Cf-Ipcountry) and user agent.

Fixed

  • Concurrent bans could corrupt blacklist.json, which then silently reloaded empty. Writes are now serialized and a corrupt file is moved aside, never overwritten.
  • An empty or / honeypot banned every visitor; honeypots matching the site root are now rejected.
  • Whitelisting an already-banned IP didn't unban it; expired bans lingered in the list; an expiry race could delete a fresh permanent ban.
  • Honeypots are matched case-insensitively and against the cleaned path (//wp-admin, /x/../wp-admin), and unclean paths no longer get a 301 before the blacklist check.
  • IPs are canonicalized; tarpits release on shutdown; upstream connections are pooled.
  • Admin login is rate-limited (429 + Retry-After), request bodies are capped, and a password change signs out other sessions.
  • Permanent bans no longer serialize a bogus 0001-01-01 expiry.

Upgrade notes

  • Unknown config keys are now an error — check your config for typos before rolling out.
  • An install still on admin/admin is locked to a set-a-new-password screen on first login; passwords need 8+ characters.
  • IPv6 automatic bans now cover the /64 by default — set "ipv6_ban_prefix": 128 for the old single-address behaviour.
  • /metrics is unauthenticated on the admin port; disable with "admin": {"disable_metrics": true}.
  • To use the archive, add "stats": {"archive": {"dir": "/data/requests"}} and size the volume accordingly (the k3s manifest now requests 1Gi).
  • admin.Handler now takes an Options struct (only relevant if you embed the package).

Image: ghcr.io/timothydodd/thorngate:v0.12.0 (amd64 + arm64).