The plaintext listener bound `:PORT`, so it answered on every
interface with no way to say otherwise. That published the admin UI
and the unauthenticated receiver in cleartext beside whatever TLS
proxy was in front of them, reachable from any host that could route
to the machine.
BIND_ADDRESS now selects the address, defaulting to 127.0.0.1.
Loopback is the only default that does not silently expose that
listener; reaching webhooker from another host becomes a deliberate
act. A container must set BIND_ADDRESS=0.0.0.0, since a loopback bind
inside a network namespace is unreachable even with -p, and the
documented `docker run` does. Only IP address literals are accepted:
hostnames, host:port and CIDR blocks abort startup naming the variable
and the value, and a literal that is not an address of this host fails
at listen and exits non-zero.
The http.Server is now built in New rather than in the serving
goroutine. Two goroutines reached that field with nothing ordering
them — the serving goroutine assigning it, the fx stop hook calling
Shutdown on it — which is a data race the race detector reports as
soon as anything starts and stops the server, and a nil dereference if
a stop arrived first.
README gains a "Deployment behind a reverse proxy" section: a working
nginx server block, and the five things that are silent when wrong —
bind or firewall the app port, WEBHOOKER_ENVIRONMENT=prod,
TRUSTED_PROXIES, Host as $http_host rather than $host, and keeping the
proxy's access log because webhooker's own records only the proxy.
With no trusted proxies configured, every client behind the reverse proxy production requires shares one rate-limit bucket per limit, so five POSTs per minute from anywhere holds the login limit full and denies the admin login until restart. The default is still correct; it was the consequence that was invisible. Startup now warns, and the README no longer claims the login limit is per-IP unconditionally.
check / check (push) Superseded by a newer commit; never tested
Defaults now apply only to unset or empty environment variables; a set-but-
unparseable value aborts startup with an error naming the key and the value.
envInt is gone, envBool parses with strconv.ParseBool, and PORT is bounded.