Bind 0.0.0.0 to IPv4 only (closes #528)
check / check (push) Waiting to run

Go listens on any unspecified address with one socket that answers
IPv4 and IPv6, so BIND_ADDRESS=0.0.0.0 also bound every IPv6 address,
which the README says it does not. The listener now uses tcp4 for an
IPv4 address; :: still binds both. The server's start hook suppresses
contextcheck, as the other start hooks do.

The image's health check asked for localhost, which wget reached over
::1 only, so it now asks for 127.0.0.1. The README says what that
means for a loopback bind in a container, drops the bindv6only
condition from :: (Go sets that socket option itself), and names an
ss check.

Model: opus-5-5
This commit is contained in:
2026-10-15 08:20:43 +00:00
parent 573f7f986a
commit 615ba5bf72
5 changed files with 112 additions and 12 deletions
+10 -10
View File
@@ -316,10 +316,9 @@ The value must be an IP address literal:
- `127.0.0.1` — loopback only (the binary's default). Use this with a reverse
proxy on the same host.
- `0.0.0.0` — every IPv4 address. The image's default; on a bare host, only
behind a firewall on the port.
- `::` — every address, IPv6 and (on Linux, with the default
`net.ipv6.bindv6only=0`) IPv4 as well.
- `0.0.0.0` — every IPv4 address and no IPv6 address. The image's default; on a
bare host, only behind a firewall on the port.
- `::` — every IPv6 address and every IPv4 address.
- A specific address such as `10.0.0.5` — that interface only.
An **empty** value is treated as unset, as everywhere else here, and takes the
@@ -340,7 +339,8 @@ machine that has no such interface — is a valid literal, so it reaches the
listener and fails there. The process logs the bind error and exits non-zero
rather than staying up with nothing listening. The effective value is in the
`bindAddress` field of the startup log line, which is the way to check what a
running deployment actually bound.
running deployment actually bound. On a bare host, `ss -ltn` lists the socket
itself as `0.0.0.0:8080` for a `0.0.0.0` bind and as `*:8080` for `::`.
#### Metrics credentials
@@ -667,10 +667,10 @@ Either set a literal or leave the variable out entirely.
Overriding `BIND_ADDRESS` to a loopback address in a container — by that route
or deliberately — makes the container unreachable from outside its namespace
even with `-p`. The published port answers nothing, and the health check fails
too: it requests `http://localhost:8080`, `localhost` resolves to `::1` first,
and a `127.0.0.1` bind is not listening there. The container then goes
`unhealthy` about **65 seconds** after start — from
even with `-p`. The published port answers nothing. The health check requests
`http://127.0.0.1:8080` from inside the container, so a `127.0.0.1` bind passes
it and the container stays `healthy`. A `::1` bind fails it, and the container
goes `unhealthy` about **65 seconds** after start — from
`HEALTHCHECK --start-period=5s --interval=30s --retries=3`, so failing probes at
5s, 35s and 65s, and `unhealthy` on the third. (Docker's probe cadence during
the start period has changed between versions; re-derive from those three values
@@ -726,7 +726,7 @@ the credentials.
address (directly, or through anything that can rewrite source addresses,
such as NAT or a published container port). The `remoteIP` field of the
`http request` log line for a request that came through the proxy shows
that address; the health check's own lines show `::1`. See
that address; the health check's own lines show `127.0.0.1`. See
[Trusted proxies](#trusted-proxies).
- Leave `BIND_ADDRESS` and `DATA_DIR` unset: the image sets `BIND_ADDRESS`
to `0.0.0.0`, and `DATA_DIR` defaults to `/var/lib/webhooker`.