Skip to content

Changelog ​

All notable changes to this project are documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning. Entries are generated by release-please from Conventional Commits.

0.7.11 (2026-11-13) ​

Bug Fixes ​

  • abort file writes when permissions cannot be set (a230a5e)
  • align exact query explanations with resolution order (0cfc1ec)
  • align redirect diagnostics with browser and matcher behavior (b4d0bfd)
  • avoid full table scans for session activity updates (575f4e5)
  • bind rate limit refunds to their original windows (1abaff6)
  • correct OAuth discovery paths and enforce collision tests (d514f3c)
  • detect redirect loops by repeated request states (b4cba00)
  • make rate limit admission safe during concurrent resets (56c5717)
  • measure coverage only for current source modules (4e41054)
  • preserve active log permissions after rotation (1607573)
  • preserve audit permissions during atomic rotation (2c647f0)
  • preserve existing paths during configuration probes (64dd6f9)
  • preserve file order for tied query rules (509d926)
  • preserve permissions during atomic log compression (4dc695e)
  • preserve secret contents when trimming CRLF files (22a6214)
  • protect existing atomic write temporary paths (b818fbe)
  • quarantine hit counts outside native counter bounds (782f2b1)
  • rank Unicode prefixes by consumed request path (b5c9342)
  • redact URL fragments before query delimiters in access logs (1478aa5)
  • refresh recently modified API client cache entries (62f78f8)
  • replace upstream dates removed by connection filtering (09fe4e5)
  • restore audit archives when rotation publication fails (96a9a50)
  • track session activity without stale updates (6ffa6d8)
  • verify permissions after raced log reopening (6117e5a)

Dependencies ​

Documentation ​

  • bump playwright from 1.64.1 to 1.65.0 in /docs in the docs group (#183) (8e73de5)

0.7.10 (2026-11-11) ​

⚠ BREAKING CHANGES ​

  • with trailing_slash = "ignore", a request whose host has a rule for the other trailing slash form now gets that rule instead of a matching *.parent or * rule.

Bug Fixes ​

  • matching precision, store reads that do not wait, and the Erlang helpers by area (#179) (a85ef93)
  • oidc: keep the metadata a provider outage falls back on (#180) (09488fc)

0.7.9 (2026-11-11) ​

⚠ BREAKING CHANGES ​

  • a proxy that sets the auth.header identity headers for the upstream must be listed in auth.header.trusted_proxies. Users now store credentials: an older version rewriting users.json drops them, which ends every admin session.

Bug Fixes ​

0.7.8 (2026-11-10) ​

⚠ BREAKING CHANGES ​

  • with api.require_if_match, PATCH without If-Match answers 428; imports refuse new ids that are not URL-safe; imports and bulk enabling refuse rules they add, change or enable that loop or can never apply.

Features ​

  • stricter checks on PATCH, imported ids, imports and bulk enabling (#174) (261ea89)

0.7.7 (2026-11-10) ​

Bug Fixes ​

  • proxy: listener edge cases after a hot upgrade or an early disconnect (#172) (2c075d9)

0.7.6 (2026-11-10) ​

Bug Fixes ​

  • audit fixes for logs, config, API and rule imports (#170) (5ffe2c7)

0.7.5 (2026-11-10) ​

Features ​

  • proxy: limit open connections per client address (#168) (d23e189)

0.7.4 (2026-11-10) ​

⚠ BREAKING CHANGES ​

  • OIDC sign-in with no allowed_emails, allowed_domains or allowed_groups does not start unless auth.oidc.allow_any_account = true; api.oauth.require_at_jwt defaults to true; without admin.metrics_token, /metrics answers 404 on a listener that is not on the loopback interface (as in the container image).

Bug Fixes ​

  • harden the listener, proxy, admin and API (#165) (7f96487)

Performance ​

  • less work per request on the redirect listener (#166) (ec50e42)

0.7.3 (2026-11-09) ​

Bug Fixes ​

  • auth: completed SSO logins do not count against their address's 30 SSO starts (eab5afe)
  • matcher: a prefix rule refused by its host guard leaves the request to a shorter prefix rule (eab5afe)
  • proxy: linger before closing a connection whose request body was not read (answered, rejected, or answered early by the upstream), so that the client gets the response (eab5afe)
  • proxy: repeated Connection headers are one list when answering, as when forwarding (eab5afe)
  • store: create the backups directory only when backups are kept, and rotate backup files only (eab5afe)
  • store: the redirect loop check follows rules that keep the query they matched (eab5afe)
  • tester: the URL tester follows preserved queries, ranks prefixes in bytes and tells requests apart by their query (eab5afe)

Security ​

  • auth: a login re-hashing a password no longer restores the old password over a reset made meanwhile (eab5afe)
  • proxy: drop a client's X-Forwarded-Host, -For and -Proto from untrusted peers, also for an HTTP/1.0 request without Host (eab5afe)
  • proxy: parse a request head again only when it may be complete, not at every new line, nor at every packet without one (eab5afe)

Documentation ​

  • api: document the 400 of non-object JSON bodies, and the token endpoint's 413 (64 KiB) and 415 (eab5afe)

0.7.2 (2026-11-08) ​

Bug Fixes ​

  • admin,cli: report a busy rules store (503 page, exit 1) instead of crashing (#156) (e908fa9)
  • csv: quote cells whose quote, comma or line break precedes a combining mark (#155) (7fcb9c4)
  • matcher: whole-segment prefixes ending with a slash match the paths below them (#152) (726d030)
  • proxy: harden the redirect listener against slow heads, connection floods, h2c and forged identity headers (#148) (ad6bd07)
  • store: keep held locks fresh, skip changes whose caller gave up, answer 503 when busy (#149) (42c40e1)

Performance ​

  • parse trusted proxy networks once and compare peer addresses as integers (#159) (112fe6c)
  • proxy: cheaper upstream forwarding: no reuse probe, one send per small response, fewer lowercasings (#158) (5bd17d2)

Documentation ​

  • migration from nginx and Apache, Kubernetes and Compose, trust settings, CLI reference (#150) (84c776c)

0.7.1 (2026-11-08) ​

Performance ​

  • a 20 KiB heap for busy connections, hibernation for idle ones (#143) (d38eaa8)
  • parse a request as it arrives instead of appending it to an empty buffer (#146) (0543a22)
  • send kept-alive responses without waiting for the driver's reply (#141) (ef2ddc3)

0.7.0 (2026-11-08) ​

Features ​

  • forward requests no rule answers to an upstream website (server.upstream) (#135) (fed99ac)

Performance ​

  • cut per-request work in the redirect handler (#129) (41804b0)
  • faster request parsing, a quarter less memory, lower tail latency (#131) (7c2583c)
  • serve the redirect listener with a dedicated HTTP/1.1 server (#127) (f5fbd68)

Documentation ​

  • compare with nginx, HAProxy, Caddy, Traefik and Apache, refreshed every week (#122) (5c919ce)
  • put redirect-proxy in front of the website, with nginx, HAProxy, Apache, Caddy and Traefik (#137) (f70b26d)

0.6.1 (2026-11-07) ​

Bug Fixes ​

  • admin: leave unknown dates and author out of a rule's details (#121) (e0dba6b)

Documentation ​

  • documentation site with generated screenshots, custos-style README (#119) (46d3f12)

0.6.0 (2026-11-07) ​

⚠ BREAKING CHANGES ​

  • admin: SSO and proxy-header users without a matching group or role header are viewers. To keep the previous behaviour, set default_role = "admin" in [auth.oidc] or [auth.header] (RP_AUTH_OIDC_DEFAULT_ROLE, RP_AUTH_HEADER_DEFAULT_ROLE), or better, set admin_groups or role_header.

Features ​

  • admin: optional bearer token for /metrics (#57) (599d631)
  • admin: single sign-on and proxy users are viewers by default (#66) (7b42ba6)
  • admin: viewer, editor and admin roles (#61) (11c40f7)
  • api: let clients choose the id of a new redirection, so retries are safe (#97) (49474d1)
  • api: stable problem codes, optional If-Match requirement, uniform paging (#100) (58296af)
  • audit: rotation, searches over the whole history, GET /api/audit (#60) (5864cd4)
  • metrics: latency buckets from 5 µs (#72) (7af1a29)
  • metrics: server.metrics_path for replicas (#73) (30312ec)
  • rules: ${host} and ${sub} placeholders in targets (#40) (aafba7a)
  • rules: import and export rules as CSV (#59) (424d40a)
  • rules: keep hit counts and last hit times across restarts (#42) (2448c25)
  • rules: match exact rules on query parameters (#43) (b98b714)
  • rules: starts_at and expires_at for scheduled redirects (#39) (cd1953d)
  • rules: tags to group and filter redirections (#58) (9f4880c)
  • rules: whole_segments option for prefix rules (#37) (7593452)
  • rules: with preserve_query, the target's own parameters win (#51) (16da88a)
  • server: health path, rules file watch, store restart safety, 414 (#32) (41f7a22)
  • server: https_redirect setting to upgrade plain HTTP requests (#41) (9bfd6d5)
  • sso: return to the requested page after SSO login, optional logout at the provider (#38) (ef52b3c)

Bug Fixes ​

  • admin,api: harden proxy sessions, client address, tokens and errors (#29) (635ca83)
  • admin: bulk actions refuse a rule set changed since the page was shown (#53) (c1d236a)
  • admin: exact import previews, history link for admins only, audit window text (#110) (a2f2604)
  • admin: name the list filters as in the API (#54) (ea7eaa1)
  • admin: the URL tester reads the published rules once (#76) (aa69e71)
  • api,admin: apply imports as previewed, conditional requests, config checks (#35) (ebde5ec)
  • api: 405 for other methods on export, import and bulk; one route table (#50) (a3d41f2)
  • api: a rule's GET always answers 200, with current hit counts (#52) (72e99fd)
  • api: take the OpenAPI scopes from the route table and name external scopes (#92) (f63c08f)
  • audit,admin,rules: findings of a review of the new features (#63) (b63340a)
  • auth,api: keep the last good provider keys during an outage (#69) (fac2b77)
  • auth: one session per proxy user and role, not one per cookie-less request (#95) (6008bbe)
  • cli: use the installed configuration by default, say which data a command changes (#111) (2023b46)
  • config: report unreadable metrics token files, bound timer and rotation settings (#107) (5482288)
  • csv: read and write CSV the way spreadsheets do (#109) (307969b)
  • log: truncate addresses in logged forwarding headers and 6to4 addresses (#108) (64e78ab)
  • matcher,store: malformed query params, hits while draining, host checks (#44) (04730dc)
  • matcher: refuse rules that never match, loop check with trailing slash (#27) (3d717f5)
  • ops: health check on bound addresses, real release SBOM, dependency reports (#46) (bd6c89c)
  • ops: replicas on a read-only data directory, documented (#56) (cd88a61)
  • reach rules whose id is not URL-safe, refuse ids that name routes (#106) (3c35fb0)
  • rules: refuse dates that do not exist instead of shifting them (#112) (1760665)
  • store: a file being written is not taken for two changes (#55) (8ec5c66)
  • store: keep hit counts right across deletes, a deleted file and a corrupt one (#115) (646d0ad)
  • store: take the time and file stamp before the first load, not after (#113) (254d277)
  • store: the watcher retries a valid file it could not load, and sees same-second edits (#114) (1299590)
  • users: change roles when there is no administrator at all (#116) (900f816)

Performance ​

  • bench: matcher microbenchmark in reductions, gated in CI (#75) (c3e2cdb)
  • matcher: a tree of prefix indexes, targets parsed once (#74) (0e5fafb)
  • matcher: byte scans for request hosts and redirect guards, fewer writes (#47) (0c96885)
  • matcher: index query rules by their first condition (#79) (720725b)
  • matcher: normalise request hosts with byte operations (#105) (f5b5058)
  • rules: parse CSV imports on bytes, cap their errors (#70) (099999e)
  • store: encode only the changed rules when rewriting the file (#104) (82e45ff)
  • store: faster loads and edits of large rule sets (#99) (957a499)
  • store: the schedule check compares two numbers while rules are unchanged (#78) (656a9ea)

Security ​

  • admin,api: throttle password changes, atomic failure counts, refuse ID tokens (#45) (d066892)
  • admin,api: throttling cannot lock owners out, IPv6 by /64 (#65) (2d5b96a)
  • admin: refuse control characters and backslashes in next (#64) (098b851)
  • api: name only existing clients as the actor of refused token requests (#89) (a4f8590)
  • api: optionally require typed access tokens, refuse tokens without a subject (#94) (51c2c59)
  • audit: failures without credentials cannot flush the log (#68) (5f7a56e)
  • auth: count login attempts before hashing, bound concurrent hashes (#87) (fc434c2)
  • auth: keep SSO logins in progress in the browser, not in a capped table (#96) (661dca6)
  • close request smuggling, throttle SSO and API tokens, namespace audit actors (#34) (eb6a9eb)
  • log: use a forwarded client address only if it is an IP address (#90) (7967e08)
  • matcher: bound what the regex rules of a host may cost one request (#93) (76115e3)
  • matcher: remove dot segments from request paths (#86) (58ba239)
  • store: files with secrets are created 0600 (#67) (2e08ec5)

Documentation ​

  • operations: a reference of every exported metric, checked by a test (#91) (73843b8)
  • split the README into docs/ (#62) (d4b0e8b)

0.5.0 (2026-11-06) ​

Features ​

  • admin,api: bulk actions, import preview, sorting, URL tester explanations (#25) (27e0a12)
  • matcher: wildcard hosts, equivalent paths, trailing slash option (#22) (cb48c6a)
  • observability: json logs, latency and reload metrics, richer audit (#24) (7ba625f)

Bug Fixes ​

  • admin: account safety, confirmations, accessibility (#26) (8630327)

0.4.0 (2026-11-06) ​

Features ​

  • detect redirect loops through prefix rules and across rules (#14) (4ff0a2e)

Bug Fixes ​

  • auth: close two authentication bypasses (#17) (0987272)
  • auth: tie sessions to the user, throttle per client, limit input (#18) (29b39f4)
  • close races and crash modes on the rules write path (#9) (3bb3357)
  • harden configuration, admin, API and CI (#20) (4171e8b)
  • ops: reject bad env values, drain on SIGTERM, fix packaging and release (#19) (2325623)
  • preserve the query before a fragment, ignore rule host ports (#13) (5acfbcb)

Performance ​

  • cache access log timestamps, anonymise peers without a string round trip (#11) (5b50d5e)
  • index prefix and regex rules, make hit counters lock-free (#10) (0d23bed)

0.3.0 (2026-11-06) ​

Features ​

  • add access logging for the redirect, admin and API listeners (#6) (1c60a6e)
  • make concurrent writes safe across processes (#7) (7f123c0)

Bug Fixes ​

  • keep capture substitutions on the target's host (#15) (6ce17a0)

0.2.0 (2026-11-05) ​

Features ​

  • add an OAuth-authenticated REST API (#3) (c3896ce)

0.1.1 (2026-11-05) ​

Bug Fixes ​

  • docker: install lksctp-tools to silence the socket NIF warning (4b0a159)

0.1.0 (2026-11-05) ​

Features ​

  • HTTP redirect server on the BEAM with lock-free rule lookups (persistent_term): exact, prefix and regular expression rules, per-host rules with a * wildcard, capture substitution ($1, ${n}), query string preservation and 301/302/303/307/308 statuses.
  • Rules persisted to a versioned JSON file with atomic writes, rotating backups, an append-only audit log and validated hot reload (SIGHUP or admin button).
  • ReDoS protection: catastrophic regular expressions are rejected and every match runs with a PCRE backtracking budget.
  • Administration backend (Bootstrap 6): CRUD, search and filters, enable / disable, URL tester, JSON import / export, local users, audit log.
  • Authentication: local accounts (PBKDF2-SHA256), OpenID Connect SSO (authorization code + PKCE) and trusted reverse-proxy headers; server-side sessions, CSRF tokens, origin checks and login throttling.
  • Prometheus metrics, health endpoints and a CLI (serve, check-config, user, rules).
  • Release bundles with the Erlang runtime, Debian/Ubuntu packages, multi-arch container images and a Homebrew formula.

Last updated:

Released under the MIT License.