Problem
awf-squid fails to start with a fatal error on any Docker host whose daemon has ipv6: false (the default on vanilla Docker installs). Config parsing aborts before any log file is opened, so the only evidence is in docker logs awf-squid before AWF's cleanup removes the container.
Full docker logs awf-squid stderr:
2026/04/21 15:53:16| WARNING: BCP 177 violation. Detected non-functional IPv6 loopback.
2026/04/21 15:53:16| aclIpParseIpData: IPv6 has not been enabled.
2026/04/21 15:53:16| aclIpParseIpData: IPv6 has not been enabled.
2026/04/21 15:53:16| aclIpParseIpData: IPv6 has not been enabled.
2026/04/21 15:53:16| Processing Configuration File: /etc/squid/squid.conf (depth 0)
2026/04/21 15:53:16| FATAL: http_port: IPv6 is not available.
2026/04/21 15:53:16| Not currently OK to rewrite swap log.
2026/04/21 15:53:16| storeDirWriteCleanLogs: Operation aborted.
2026/04/21 15:53:16| FATAL: Bungled /etc/squid/squid.conf line 74: http_port [::]:3128
2026/04/21 15:53:16| Squid Cache (Version 6.13): Terminated abnormally.
Line 74 is http_port [::]:3128, which was added in #1544 as dual-stack defense-in-depth for #1543.
The agent container then fails the dependency healthcheck with dependency failed to start: container awf-squid exited (1), and the whole gh-aw run fails at Execute Codex CLI (exit 1). Timeline from docker inspect:
StartedAt: 2026-04-21T15:53:16.126925664Z
FinishedAt: 2026-04-21T15:53:16.141058894Z # ~15ms lifetime
ExitCode: 1
OOMKilled: false
Root cause
Why Squid rejects http_port [::]:3128
Docker daemons default to ipv6: false. When that's set, Docker applies sysctl net.ipv6.conf.all.disable_ipv6=1 to every container's network namespace, including awf-squid's. Squid 6.13's startup probe of AF_INET6 then fails, and Squid treats http_port [::]:3128 as FATAL (not a warning, no fallback to IPv4-only listening) during config parse — before opening log files.
Why this is an undocumented implicit requirement
The http_port [::]:3128 line is emitted unconditionally by src/squid-config.ts:
// Listen on both IPv4 and IPv6 as defense-in-depth (see #1543)
let portConfig = `http_port ${port}\nhttp_port [::]:${port}`;
and in the SSL-bump path:
// Listen on both IPv4 and IPv6 as defense-in-depth (see: gh-aw-firewall issue #1543)
http_port 3128 ssl-bump ...
http_port [::]:3128 ssl-bump ...
Nothing in docs/architecture.md, docs/compatibility.md, or docs/troubleshooting.md documents the implicit "Docker daemon must have IPv6 enabled" requirement this creates. docs/compatibility.md lists "Docker Engine 20.10+" without noting that ipv6: true is required on the daemon config.
Per the fix analysis in #1543: "Fix 2 … However, Fix 1 alone should be sufficient since there's no reason for IPv6 in the isolated container network." So the listener is strictly defense-in-depth on top of the agent-side IPv6-disable work done in PR #1544 — but it's currently preventing a whole class of self-hosted runner users from running AWF at all.
Reproduction
-
Provision a Linux host with a default Docker daemon (no "ipv6": true in /etc/docker/daemon.json). Reproduced on Amazon Linux 2023 / m7i-flex.2xlarge EC2 instance, Docker Engine installed via dnf install docker.
-
Register as a self-hosted GitHub Actions runner.
-
Run any gh-aw workflow with sandbox.agent: awf (the default). Minimal example:
---
on:
pull_request:
runs-on: [self-hosted, your-label]
engine:
id: codex
network:
allowed: [defaults]
---
Say hello.
-
gh aw compile && git push → observe the agent job fail at Execute Codex CLI with the stderr above.
Workaround
Enable IPv6 on the Docker daemon. Add to /etc/docker/daemon.json:
{
"ipv6": true,
"fixed-cidr-v6": "fd00:d0c::/64"
}
…then systemctl restart docker. This prevents Docker from injecting net.ipv6.conf.all.disable_ipv6=1 into container namespaces, which allows Squid to bind [::]:3128. The AWF agent-namespace IPv6 disable from PR #1544 is orthogonal and continues to work — the agent container still has IPv6 disabled via sysctl after this change.
Proposed fixes (preferred → fallback)
-
Make http_port [::]:… conditional. In the Squid entrypoint, probe whether IPv6 is available in the container namespace before appending the dual-stack listener:
if [ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6 2>/dev/null || echo 1)" = "0" ]; then
# IPv6 available — keep http_port [::]:3128 for defense-in-depth
:
else
# IPv6 disabled by Docker daemon — remove listener to avoid fatal startup error
sed -i '/^http_port \[::\]:/d' /etc/squid/squid.conf
fi
exec squid -N -f /etc/squid/squid.conf
Keeps the defense-in-depth intent on runners that have IPv6, while being resilient to the default case.
-
Retry without the IPv6 listener on failure. Start Squid normally; if it exits with the IPv6 is not available FATAL, strip the [::]:… lines and restart. Slightly more complex but avoids a runtime sysctl probe.
-
At minimum, document the requirement. Add an entry to docs/compatibility.md ("Docker daemon must be configured with ipv6: true"), and add the exact FATAL stderr and the daemon.json workaround to docs/troubleshooting.md so operators can find it via search.
Impact
- Affected: any gh-aw workflow targeting a self-hosted runner whose Docker daemon is not explicitly configured with
ipv6: true — the default on most Linux distros (Debian, Ubuntu, Amazon Linux, RHEL, etc.).
- Severity: high for affected users — AWF cannot start at all. The only currently usable workaround is
sandbox.agent: false, which the strict-mode compiler in v0.68.3 rejects unless strict: false is also set, effectively disabling the firewall entirely.
- GitHub-hosted runners: not affected (their daemons have IPv6 enabled).
Environment
- AWF container:
ghcr.io/github/gh-aw-firewall/squid:0.25.20 (also agent:0.25.20, api-proxy:0.25.20)
- gh-aw compiler: v0.68.3
- Runner OS: Amazon Linux 2023
- Docker: installed via
dnf install docker (Docker CE 25.x, default daemon config — no /etc/docker/daemon.json)
- Instance type:
m7i-flex.2xlarge, self-hosted on AWS EC2
- Architecture: x86_64
References
Problem
awf-squidfails to start with a fatal error on any Docker host whose daemon hasipv6: false(the default on vanilla Docker installs). Config parsing aborts before any log file is opened, so the only evidence is indocker logs awf-squidbefore AWF's cleanup removes the container.Full
docker logs awf-squidstderr:Line 74 is
http_port [::]:3128, which was added in #1544 as dual-stack defense-in-depth for #1543.The agent container then fails the dependency healthcheck with
dependency failed to start: container awf-squid exited (1), and the whole gh-aw run fails atExecute Codex CLI(exit 1). Timeline fromdocker inspect:Root cause
Why Squid rejects
http_port [::]:3128Docker daemons default to
ipv6: false. When that's set, Docker appliessysctl net.ipv6.conf.all.disable_ipv6=1to every container's network namespace, includingawf-squid's. Squid 6.13's startup probe ofAF_INET6then fails, and Squid treatshttp_port [::]:3128as FATAL (not a warning, no fallback to IPv4-only listening) during config parse — before opening log files.Why this is an undocumented implicit requirement
The
http_port [::]:3128line is emitted unconditionally bysrc/squid-config.ts:and in the SSL-bump path:
Nothing in
docs/architecture.md,docs/compatibility.md, ordocs/troubleshooting.mddocuments the implicit "Docker daemon must have IPv6 enabled" requirement this creates.docs/compatibility.mdlists "Docker Engine 20.10+" without noting thatipv6: trueis required on the daemon config.Per the fix analysis in #1543: "Fix 2 … However, Fix 1 alone should be sufficient since there's no reason for IPv6 in the isolated container network." So the listener is strictly defense-in-depth on top of the agent-side IPv6-disable work done in PR #1544 — but it's currently preventing a whole class of self-hosted runner users from running AWF at all.
Reproduction
Provision a Linux host with a default Docker daemon (no
"ipv6": truein/etc/docker/daemon.json). Reproduced on Amazon Linux 2023 /m7i-flex.2xlargeEC2 instance, Docker Engine installed viadnf install docker.Register as a self-hosted GitHub Actions runner.
Run any gh-aw workflow with
sandbox.agent: awf(the default). Minimal example:gh aw compile && git push→ observe theagentjob fail atExecute Codex CLIwith the stderr above.Workaround
Enable IPv6 on the Docker daemon. Add to
/etc/docker/daemon.json:{ "ipv6": true, "fixed-cidr-v6": "fd00:d0c::/64" }…then
systemctl restart docker. This prevents Docker from injectingnet.ipv6.conf.all.disable_ipv6=1into container namespaces, which allows Squid to bind[::]:3128. The AWF agent-namespace IPv6 disable from PR #1544 is orthogonal and continues to work — the agent container still has IPv6 disabled via sysctl after this change.Proposed fixes (preferred → fallback)
Make
http_port [::]:…conditional. In the Squid entrypoint, probe whether IPv6 is available in the container namespace before appending the dual-stack listener:Keeps the defense-in-depth intent on runners that have IPv6, while being resilient to the default case.
Retry without the IPv6 listener on failure. Start Squid normally; if it exits with the
IPv6 is not availableFATAL, strip the[::]:…lines and restart. Slightly more complex but avoids a runtime sysctl probe.At minimum, document the requirement. Add an entry to
docs/compatibility.md("Docker daemon must be configured withipv6: true"), and add the exact FATAL stderr and the daemon.json workaround todocs/troubleshooting.mdso operators can find it via search.Impact
ipv6: true— the default on most Linux distros (Debian, Ubuntu, Amazon Linux, RHEL, etc.).sandbox.agent: false, which the strict-mode compiler in v0.68.3 rejects unlessstrict: falseis also set, effectively disabling the firewall entirely.Environment
ghcr.io/github/gh-aw-firewall/squid:0.25.20(alsoagent:0.25.20,api-proxy:0.25.20)dnf install docker(Docker CE 25.x, default daemon config — no/etc/docker/daemon.json)m7i-flex.2xlarge, self-hosted on AWS EC2References
http_port [::]:3128listenersrc/squid-config.ts— lines emittinghttp_port [::]:3128unconditionally