Skip to content

Squid aborts with "FATAL: http_port: IPv6 is not available" on runners with IPv6 disabled on the Docker daemon #2139

@Rubyj

Description

@Rubyj

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

  1. 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.

  2. Register as a self-hosted GitHub Actions runner.

  3. 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.
  4. 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)

  1. 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.

  2. 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.

  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions