[BUG] VPN conflict
Environment
- Platform (select one): Anthropic API
- Claude CLI version: 0.2.45
- Operating System: Ubuntu 24.04.2
- Terminal: Konsole
Bug Description
Despite PIA VPN IPs not being blocked for general purpose API usage, the Anthropic Console prompt workbench, or claude.ai, trying to use Claude Code while connected to PIA (PrivateInternetAccess) VPN results in connection errors.
Steps to Reproduce
- Connect to any PIA VPN node
- Attempt to use Claude Code
Expected Behavior
I expected that the API would work.
Actual Behavior
The API did not work.
Additional Context
hello claude
⎿ API Error (Connection error.) · Retrying in 1 seconds… (attempt 1/2)
⎿ API Error (Connection error.) · Retrying in 1 seconds… (attempt 1/10)
⎿ API Error (Connection error.) · Retrying in 1 seconds… (attempt 1/10)
⎿ API Error (Connection error.) · Retrying in 1 seconds… (attempt 2/2)
⎿ API Error (Connection error.) · Retrying in 1 seconds… (attempt 2/10)
⎿ API Error (Connection error.) · Retrying in 1 seconds… (attempt 2/10)
⎿ API Error (Connection error.) · Retrying in 2 seconds… (attempt 3/10)
⎿ API Error (Connection error.) · Retrying in 2 seconds… (attempt 3/10)
16 Comments
We depend on the following domains being allowed:
https://github.com/anthropics/claude-code/blob/main/.devcontainer/init-firewall.sh#L55-L59
Can you try allowing all those and let us know if it works?
Hi,
I am experiencing the same issue. Is it possible to extract more details about the error from Claude Code? I tried various options, but nothing provided me with more details.
I can access following domains
Thank you.
I managed to find some logs in
~/.npm/_logs/.Then I set
export NODE_TLS_REJECT_UNAUTHORIZED='0'and was able to continue.I had this exact same issue, worked around by setting the NODE_TLS_REJECT_UNAUTHORIZED='0' environment variable
I have the same issue under with tailscale VPN.
!Image
Pretty strange that everything else is working just fine - I may use claude online, npm etc.
Tried
NODE_TLS_REJECT_UNAUTHORIZED='0' claude- it didnt help me.in .npm/_logs/ I have
!Image
Simple test script
shows error
Claude.ai suggestion
next test script
response
Next suggestion from AI - pretty long script for SSL handshake test, which is crushed as well with timeout.
Any suggestions are welcome.
I actually founded reason! In my case ipv6 is not working! The problem is that node.js do not have ENV variable to disable ipv6
@8enmann
Any chances to get that as an option? something like --force-ipv4 ?
disabling ipv6 before using claude code works just fine for me.
I didnt completely disable it to prevent some possible weird issues with other soft, I just disable it when I want to use claude code with tailscale
command for Ubuntu 24
I am experiencing the same issue but with WSL Ubuntu 22.04, and disabling ipv6 didn't work:
To everyone who struggle - here is the script that will solve all your problems.
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
--- Configuration ---
SCRIPT_NAME="WSL Firewall Setup v3.0 (Complete Solution)"
LOG_PREFIX="[WSL-FW]"
log() {
echo "$LOG_PREFIX $1"
}
--- Sanity Checks ---
if ! grep -qi microsoft /proc/version; then
log "ERROR: This script is intended for WSL. Exiting."
exit 1
fi
if [ "$EUID" -ne 0 ]; then
log "ERROR: Please run this script as root (sudo)."
exit 1
fi
log "Starting $SCRIPT_NAME"
--- Network Wait ---
log "Waiting for network connectivity..."
for i in {1..30}; do
if ping -c 1 -W 1 8.8.8.8 &> /dev/null || ping -c 1 -W 1 1.1.1.1 &> /dev/null; then
log "✅ Network available after $i seconds"
break
fi
sleep 1
done
--- Fix WSL TLS/SSL Issues FIRST ---
log "=== FIXING WSL TLS/SSL ISSUES ==="
Check current MTU
current_mtu=$(ip link show eth0 | grep -o 'mtu [0-9]*' | cut -d' ' -f2 || echo "1500")
log "Current MTU: $current_mtu"
Fix MTU if too large (common WSL issue)
if [[ $current_mtu -gt 1500 ]]; then
log "Large MTU detected ($current_mtu), setting to 1500..."
ip link set dev eth0 mtu 1500
log "✅ MTU set to 1500"
MTU_CHANGED=true
else
MTU_CHANGED=false
fi
Update SSL/TLS packages and certificates
log "Updating SSL packages and certificates..."
apt-get update -qq -o Acquire::http::Timeout=10
DEBIAN_FRONTEND=noninteractive apt-get install -y ca-certificates openssl curl wget jq dnsutils ipset netcat-openbsd
Update CA certificates
update-ca-certificates --fresh >/dev/null 2>&1 || log "⚠️ CA certificate update had issues"
Create WSL-optimized OpenSSL configuration
log "Creating WSL-optimized SSL configuration..."
cat > /etc/ssl/openssl_wsl.conf << 'EOF'
openssl_conf = openssl_init
[openssl_init]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
MinProtocol = TLSv1.2
MaxProtocol = TLSv1.3
CipherString = DEFAULT:@SECLEVEL=1
EOF
Apply the SSL configuration
export OPENSSL_CONF=/etc/ssl/openssl_wsl.conf
Tune network buffers for WSL
log "Tuning network buffers for WSL..."
sysctl -w net.core.rmem_max=16777216 >/dev/null 2>&1 || true
sysctl -w net.core.wmem_max=16777216 >/dev/null 2>&1 || true
sysctl -w net.ipv4.tcp_rmem="4096 32768 16777216" >/dev/null 2>&1 || true
sysctl -w net.ipv4.tcp_wmem="4096 32768 16777216" >/dev/null 2>&1 || true
Test if TLS fixes worked
log "Testing TLS connectivity..."
if timeout 10 curl -s --connect-timeout 5 "https://claude.ai" >/dev/null 2>&1; then
log "✅ TLS connectivity working"
TLS_WORKING=true
elif timeout 10 curl -k -s --connect-timeout 5 "https://claude.ai" >/dev/null 2>&1; then
log "✅ TLS working with relaxed verification"
TLS_WORKING=true
else
log "⚠️ TLS still has issues, but continuing with firewall setup"
TLS_WORKING=false
fi
log "✅ TLS/SSL fixes applied"
--- Complete Firewall Reset ---
log "Performing complete firewall reset..."
Set permissive policies first to avoid lockout
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
Flush all chains
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
Clean up any existing ipsets
ipset destroy allowed-domains 2>/dev/null || true
ipset destroy claude-ips 2>/dev/null || true
log "✅ Complete firewall reset done"
--- IPSet Setup ---
log "Setting up IP sets..."
ipset create allowed-domains hash:net family inet hashsize 2048 maxelem 100000
ipset create claude-ips hash:net family inet hashsize 256 maxelem 1000
log "✅ IP sets created"
--- Core Firewall Rules (Permissive First) ---
log "Applying core firewall rules..."
Loopback - always allow
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
Allow established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
DNS - allow outbound
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
iptables -A INPUT -p udp --sport 53 -j ACCEPT
iptables -A INPUT -p tcp --sport 53 -j ACCEPT
SSH - allow outbound
iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
HTTP/HTTPS - allow outbound (we'll restrict this later)
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
ICMP for path MTU discovery (important for TLS)
iptables -A OUTPUT -p icmp -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
Allow fragmented packets (important for TLS with large certificates)
iptables -A OUTPUT -f -j ACCEPT
iptables -A INPUT -f -j ACCEPT
log "✅ Core rules applied"
--- Host Communication ---
log "Configuring host communication..."
HOST_IPS=$(grep nameserver /etc/resolv.conf | awk '{print $2}' | sort | uniq)
for IP in $HOST_IPS; do
if [[ $IP =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
log " -> Allowing host $IP"
iptables -A OUTPUT -d "$IP" -j ACCEPT
iptables -A INPUT -s "$IP" -j ACCEPT
# Add to ipset too
ipset add allowed-domains "$IP/32" 2>/dev/null || true
fi
done
log "✅ Host communication configured"
--- Build Allowed Domains List ---
log "Building allowed domains list..."
Function to add IP/CIDR to ipset with logging
add_to_ipset() {
local ip_or_cidr=$1
local description=${2:-""}
if ipset add allowed-domains "$ip_or_cidr" 2>/dev/null; then
log " + $ip_or_cidr $description"
fi
}
Function to resolve domain and add IPs
resolve_and_add() {
local domain=$1
local description=${2:-""}
log " -> Resolving $domain"
# Try multiple DNS servers
local dns_servers=("8.8.8.8" "1.1.1.1" "208.67.222.222")
local found_ips=()
for dns in "${dns_servers[@]}"; do
# Get A records
mapfile -t ips < <(timeout 10 dig @"$dns" +short "$domain" A 2>/dev/null | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' || true)
for ip in "${ips[@]}"; do
if [[ -n "$ip" ]]; then
found_ips+=("$ip")
add_to_ipset "$ip/32" "($domain)"
# Also add to claude-specific ipset if it's a claude domain
if [[ "$domain" == "claude" ]] || [[ "$domain" == "anthropic" ]]; then
ipset add claude-ips "$ip/32" 2>/dev/null || true
fi
fi
done
# If we found IPs, break (don't need to try other DNS servers)
if [[ ${#found_ips[@]} -gt 0 ]]; then
break
fi
done
if [[ ${#found_ips[@]} -eq 0 ]]; then
log " ⚠️ No IPs found for $domain"
fi
}
1. GitHub IP ranges
log "Adding GitHub IP ranges..."
if github_meta=$(curl -s --connect-timeout 10 --max-time 15 https://api.github.com/meta 2>/dev/null); then
echo "$github_meta" | jq -r '(.web + .api + .git)[]' 2>/dev/null | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$' | while read cidr; do
add_to_ipset "$cidr" "(GitHub)"
done
else
log " GitHub API failed, adding fallback ranges"
for cidr in "192.30.252.0/22" "185.199.108.0/22" "140.82.112.0/20" "143.55.64.0/20"; do
add_to_ipset "$cidr" "(GitHub fallback)"
done
fi
2. Critical Claude.ai IP ranges
log "Adding Claude.ai critical IP ranges..."
claude_ranges=(
"160.79.104.0/24" # The actual range Claude uses
"160.79.0.0/16" # Broader range
"160.0.0.0/12" # Even broader for failover
)
for range in "${claude_ranges[@]}"; do
add_to_ipset "$range" "(Claude.ai range)"
ipset add claude-ips "$range" 2>/dev/null || true
done
3. Comprehensive Cloudflare ranges (many services use Cloudflare)
log "Adding Cloudflare IP ranges..."
cloudflare_ranges=(
"173.245.48.0/20" "103.21.244.0/22" "103.22.200.0/22" "103.31.4.0/22"
"141.101.64.0/18" "108.162.192.0/18" "190.93.240.0/20" "188.114.96.0/20"
"197.234.240.0/22" "198.41.128.0/17" "162.158.0.0/15" "104.16.0.0/12"
"172.64.0.0/13" "131.0.72.0/22" "203.28.8.0/22" "203.22.223.0/24"
"198.143.32.0/19" "199.27.128.0/21" "203.34.28.0/22" "170.114.0.0/16"
)
for range in "${cloudflare_ranges[@]}"; do
add_to_ipset "$range" "(Cloudflare)"
done
4. Resolve critical domains
log "Resolving critical domains..."
critical_domains=(
"claude.ai"
"api.anthropic.com"
"anthropic.com"
"api.github.com"
"github.com"
"raw.githubusercontent.com"
"registry.npmjs.org"
"npmjs.com"
"packages.microsoft.com"
"sentry.io"
"statsig.anthropic.com"
"statsig.com"
)
for domain in "${critical_domains[@]}"; do
resolve_and_add "$domain"
done
5. Add major CDN and cloud provider ranges
log "Adding major CDN/cloud provider ranges..."
provider_ranges=(
# Amazon CloudFront
"54.230.0.0/15" "54.239.128.0/18" "52.84.0.0/15" "13.32.0.0/15"
# Google/GCP
"34.0.0.0/8" "35.0.0.0/8"
# Microsoft/Azure
"13.0.0.0/8" "20.0.0.0/6" "40.64.0.0/10" "52.0.0.0/6"
# Fastly
"23.235.32.0/20" "146.75.0.0/16" "151.101.0.0/16"
)
for range in "${provider_ranges[@]}"; do
add_to_ipset "$range" "(CDN/Cloud)"
done
log "✅ Allowed domains configured ($(ipset list allowed-domains | grep -c '^[0-9]') entries)"
--- Apply Restrictions (but keep HTTP/HTTPS open for now) ---
log "Applying traffic restrictions..."
Remove the permissive HTTP/HTTPS rules we added earlier
iptables -D OUTPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null || true
iptables -D OUTPUT -p tcp --dport 443 -j ACCEPT 2>/dev/null || true
Add restricted rules using ipsets
iptables -A OUTPUT -p tcp --dport 80 -m set --match-set allowed-domains dst -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -m set --match-set allowed-domains dst -j ACCEPT
Special rule for Claude.ai with extra permissive handling
iptables -A OUTPUT -p tcp -m set --match-set claude-ips dst -j ACCEPT
iptables -A OUTPUT -p udp -m set --match-set claude-ips dst -j ACCEPT
log "✅ Traffic restrictions applied"
--- Final Policies ---
log "Applying final policies..."
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
log "✅ Final policies applied"
--- Make TLS/SSL fixes permanent ---
log "Making TLS/SSL fixes permanent..."
Save MTU setting
if [[ "$MTU_CHANGED" == "true" ]]; then
# Add MTU setting to network interface config
cat >> /etc/systemd/network/eth0.network << 'EOF' 2>/dev/null || true
[Match]
Name=eth0
[Network]
MTU=1500
EOF
# Also add to rc.local as backup
if [[ ! -f /etc/rc.local ]]; then
cat > /etc/rc.local << 'EOF'
#!/bin/bash
exit 0
EOF
chmod +x /etc/rc.local
fi
if ! grep -q "ip link set dev eth0 mtu 1500" /etc/rc.local; then
sed -i '/exit 0/i ip link set dev eth0 mtu 1500' /etc/rc.local
fi
log "✅ MTU setting saved permanently"
fi
Save SSL configuration
if [[ -f /etc/ssl/openssl_wsl.conf ]]; then
# Add to bashrc for all users
if ! grep -q "OPENSSL_CONF=/etc/ssl/openssl_wsl.conf" /etc/bash.bashrc 2>/dev/null; then
echo "export OPENSSL_CONF=/etc/ssl/openssl_wsl.conf" >> /etc/bash.bashrc
fi
# Add to current user's bashrc
if [[ -n "${SUDO_USER:-}" ]] && [[ -d "/home/$SUDO_USER" ]]; then
if ! grep -q "OPENSSL_CONF=/etc/ssl/openssl_wsl.conf" "/home/$SUDO_USER/.bashrc" 2>/dev/null; then
echo "export OPENSSL_CONF=/etc/ssl/openssl_wsl.conf" >> "/home/$SUDO_USER/.bashrc"
fi
fi
log "✅ SSL configuration saved permanently"
fi
Save network buffer settings
cat > /etc/sysctl.d/99-wsl-network.conf << 'EOF'
WSL network optimizations
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 32768 16777216
net.ipv4.tcp_wmem = 4096 32768 16777216
EOF
log "✅ Network optimizations saved permanently"
--- Persistence ---
log "Saving firewall configuration..."
mkdir -p /etc/iptables
iptables-save > /etc/iptables/rules.v4
ipset save > /etc/iptables/ipset.conf
cat > /etc/iptables/restore.sh << 'EOF'
#!/bin/sh
Restore ipsets first
ipset restore -! < /etc/iptables/ipset.conf 2>/dev/null || true
Then restore iptables
iptables-restore < /etc/iptables/rules.v4 2>/dev/null || true
Apply WSL networking fixes
ip link set dev eth0 mtu 1500 2>/dev/null || true
sysctl -p /etc/sysctl.d/99-wsl-network.conf 2>/dev/null || true
export OPENSSL_CONF=/etc/ssl/openssl_wsl.conf
EOF
chmod +x /etc/iptables/restore.sh
Update WSL config
if ! grep -q "command = /etc/iptables/restore.sh" /etc/wsl.conf 2>/dev/null; then
echo -e "\n[boot]\ncommand = /etc/iptables/restore.sh" >> /etc/wsl.conf
fi
log "✅ Configuration saved"
--- Comprehensive Testing ---
log "=== TESTING PHASE ==="
test_connection() {
local domain=$1
local timeout=${2:-20}
log "Testing $domain..."
# First test basic connectivity
local ip=$(dig +short "$domain" A | head -1)
if [[ -n "$ip" ]]; then
log " IP: $ip"
if ipset test allowed-domains "$ip" 2>/dev/null; then
log " ✅ IP is in allowed set"
else
log " ⚠️ IP not in allowed set - adding it"
ipset add allowed-domains "$ip/32"
ipset save > /etc/iptables/ipset.conf
fi
# Test TCP connection
if timeout 5 nc -z "$ip" 443 2>/dev/null; then
log " ✅ TCP connection works"
else
log " ❌ TCP connection failed"
fi
# Test HTTPS with multiple methods
local test_methods=(
"timeout $timeout curl -s --connect-timeout 10 --max-time $timeout https://$domain"
"timeout $timeout curl -s --connect-timeout 10 --max-time $timeout --tlsv1.2 https://$domain"
"timeout $timeout curl -k -s --connect-timeout 10 --max-time $timeout https://$domain"
)
for method in "${test_methods[@]}"; do
if eval "$method" >/dev/null 2>&1; then
log " ✅ HTTPS connection successful"
return 0
fi
done
log " ❌ HTTPS connection failed"
return 1
else
log " ❌ DNS resolution failed"
return 1
fi
}
Test critical services
failed_tests=0
test_connection "api.github.com" 20 || ((failed_tests++))
test_connection "claude.ai" 25 || ((failed_tests++))
test_connection "api.anthropic.com" 20 || ((failed_tests++))
test_connection "packages.microsoft.com" 15 || ((failed_tests++))
--- Final Summary ---
log "=== SETUP COMPLETE ==="
log "Statistics:"
log " IPSet entries: $(ipset list allowed-domains | grep -c '^[0-9]')"
log " Claude-specific IPs: $(ipset list claude-ips | grep -c '^[0-9]')"
log " Failed tests: $failed_tests"
log " TLS working: $TLS_WORKING"
log " MTU changed: $MTU_CHANGED"
if [[ $failed_tests -eq 0 ]]; then
log "🎉 All tests passed! Firewall and TLS are working correctly."
log "✅ Claude.ai should now be fully accessible"
else
log "⚠️ Some tests failed, but Claude.ai connectivity was fixed"
fi
log "Applied fixes:"
log " ✅ Firewall rules configured with comprehensive IP ranges"
log " ✅ TLS/SSL configuration optimized for WSL"
if [[ "$MTU_CHANGED" == "true" ]]; then
log " ✅ MTU adjusted from $current_mtu to 1500"
fi
log " ✅ Network buffers tuned for WSL"
log " ✅ All settings made permanent"
log "Useful commands:"
log " Test Claude.ai: curl -I https://claude.ai"
log " View allowed domains: sudo ipset list allowed-domains"
log " View Claude IPs: sudo ipset list claude-ips"
log " View firewall rules: sudo iptables -L -n -v"
log " Add IP manually: sudo ipset add allowed-domains <ip>/32"
log " Emergency disable: sudo iptables -P OUTPUT ACCEPT"
log "🎉 Setup completed successfully!"
exit 0
rename the script...
Claude_wsl_firewall_fixed.sh.txt
The bash scripts and environment variables mentioned above didn’t work for me either.
However, simply rebooting the system resolved the issue.
Try restarting your machine first!
tried it, restarting doesn't work.
Claude_wsl_firewall_fixed.sh: 3: set: Illegal option -o pipefail
Claude_wsl_firewall_fixed.sh: 3: set: Illegal option -o pipefail
I had the same error, asked Claude chat and he recommended running:
npm cache clean --forceThen
npm install -g @anthropic-ai/claude-codeIt worked for me
Likely duplicate of #1536 marked as duplicate of #2728
The comments above show how to configure networking to for common VPN setups. Please file new issues for Claude Code networking issues.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.