Skip to content

fix(devcontainer): fix claude login hanging + replace npm with install script#27306

Closed
Convl wants to merge 2 commits intoanthropics:mainfrom
Convl:fix/devcontainer-oauth-ipv6-binding
Closed

fix(devcontainer): fix claude login hanging + replace npm with install script#27306
Convl wants to merge 2 commits intoanthropics:mainfrom
Convl:fix/devcontainer-oauth-ipv6-binding

Conversation

@Convl
Copy link
Copy Markdown

@Convl Convl commented Feb 21, 2026

Problem

Two issues make the reference devcontainer broken out of the box:

1. claude login hangs indefinitely after clicking Authorize

Claude Code's OAuth callback server calls getaddrinfo("localhost") and binds to whichever address is returned first. Ubuntu containers list ::1 before 127.0.0.1 in /etc/hosts, so the server ends up on [::1]:PORT. VS Code port forwarding connects via IPv4 (127.0.0.1) and never reaches it — the browser shows "Waiting for localhost…" forever.

Setting NODE_OPTIONS=--dns-result-order=ipv4first does not fix this because Claude Code ships a self-contained binary with a bundled Node.js runtime that ignores environment-level Node.js flags.

The fix is to remove ::1 entries from /etc/hosts at container startup, which forces getaddrinfo to return only 127.0.0.1 for localhost. This works at the C library level, which all Node.js runtimes call regardless of how they are bundled.

Note: sed -i cannot be used here because Docker mounts /etc/hosts as a bind mount that does not support the atomic rename sed -i relies on; grep + cat is used instead.

Additionally, claude.ai and platform.claude.com must be in the firewall allowlist. After receiving the OAuth callback, Claude Code makes outbound requests to these domains to complete the token exchange. Without them the browser hangs waiting for a response from the local callback server even after the /etc/hosts fix.

Finally, ipset add is changed to ipset add -exist throughout. claude.ai resolves to IPs already covered by the GitHub CIDR ranges added earlier, causing the script to crash with "Element cannot be added to the set: it's already added" and exit before the firewall is fully configured.

Fixes #9376

2. Claude Code installation via npm no longer works

The npm package (@anthropic-ai/claude-code) is no longer the supported install method. The Dockerfile is updated to use the official install script (curl -fsSL https://claude.ai/install.sh | bash), and /home/node/.local/bin is added to PATH since that is where the script installs the binary for non-root users.

Changes

  • .devcontainer/init-firewall.sh: remove ::1 from /etc/hosts at startup; add claude.ai and platform.claude.com to allowlist; use ipset add -exist to handle duplicate IPs
  • .devcontainer/Dockerfile: replace npm install -g @anthropic-ai/claude-code with curl -fsSL https://claude.ai/install.sh | bash; add /home/node/.local/bin to PATH

Claude Code's OAuth callback server resolves "localhost" via getaddrinfo()
and binds to whichever address is returned first. Ubuntu containers list ::1
before 127.0.0.1 in /etc/hosts, so the server ends up on [::1]:PORT.
VS Code port forwarding connects via IPv4 (127.0.0.1) and never reaches it,
causing `claude login` to hang indefinitely after the user clicks Authorize.

Three changes to init-firewall.sh:

1. Remove ::1 entries from /etc/hosts so getaddrinfo("localhost") returns
   only 127.0.0.1. This fixes the binding at the C library level, which all
   Node.js runtimes (including Claude Code's bundled one) use underneath.
   Note: sed -i cannot be used on /etc/hosts in Docker because it is a bind
   mount that does not support atomic rename; grep + cat is used instead.

2. Add claude.ai and platform.claude.com to the firewall allowlist. After
   receiving the OAuth callback, Claude Code makes outbound requests to these
   domains to complete the token exchange. Without them the request is blocked
   and the browser hangs waiting for a response from the local callback server.

3. Use `ipset add -exist` instead of `ipset add` to silently skip duplicate
   entries. claude.ai resolves to IPs already covered by the GitHub CIDR
   ranges, causing the script to crash with "Element cannot be added to the
   set: it's already added" and exit before completing setup.

Fixes: #9376
…all script

The npm package (@anthropic-ai/claude-code) is no longer the supported
installation method. Replace it with the official install script:

  curl -fsSL https://claude.ai/install.sh | bash

The install script drops the binary in ~/.local/bin rather than the npm
global bin directory, so add /home/node/.local/bin to PATH.
@Convl Convl closed this by deleting the head repository Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] OAuth callback server hangs after authorization - setup-token and /login both fail

1 participant