Squid3 listens only on IPv6 after reboot — how to diagnose and fix it

Squid3 listens only on IPv6 after reboot — how to diagnose and fix it

Context. After a server reboot, Squid3 accepted connections only over IPv6. IPv4 clients timed out when connecting to the proxy. Root cause: no explicit IPv4 bind in the Squid configuration, so Squid listened on [::]:3128 only.

Symptoms

  • IPv4 client requests time out:
curl -4 -x http://<SERVER_IPV4>:3128 http://icanhazip.com -v
# ... -> connect timeout
  • Listening sockets show IPv6 only:
ss -ltnp | grep 3128
# LISTEN ... :::3128 ...
  • No IPv4 listener:
ss -ltnp4 | grep 3128
# (no output)

Root cause

On many systems, an IPv6 socket does not also accept IPv4 (e.g., due to net.ipv6.bindv6only=1). If Squid binds only to [::]:3128, IPv4 connections to <SERVER_IPV4>:3128 fail.

Diagnosis checklist

  1. Confirm where Squid is listening

    ss -ltnp4 | grep 3128   # IPv4
    ss -ltnp6 | grep 3128   # IPv6
    
  2. Watch logs while you test

    sudo tail -f /var/log/squid3/access.log /var/log/squid3/cache.log
    
  3. Verify traffic reaches the host

    sudo tcpdump -n -i any tcp port 3128
    # No SYNs → upstream/provider firewall
    # SYNs but no accept → local firewall or Squid not bound to IPv4
    

The fix (make it explicit)

  1. Bind explicitly to IPv4 (and optionally IPv6)
    Edit /etc/squid3/squid.conf (or /etc/squid/squid.conf):

    # IPv4 listener (required)
    http_port 0.0.0.0:3128
    
    # Optional: separate IPv6 listener
    # http_port [::]:3128
    

    Alternative (if supported by your build):

    http_port [::]:3128 ipv6only=off
    

    However, two explicit lines are the most predictable on older systems.

  2. Minimal, safe ACLs

    acl localhost src 127.0.0.1/32
    acl myclient  src <YOUR_TEST_SERVER_IP>/32
    
    acl SSL_ports port 443
    acl Safe_ports port 80
    acl Safe_ports port 443
    acl CONNECT method CONNECT
    
    http_access allow localhost
    http_access allow myclient
    http_access deny CONNECT !SSL_ports
    http_access deny all
    
    visible_hostname squid-proxy
    
  3. Validate and restart

    sudo squid3 -k parse   # or: sudo squid -k parse
    sudo service squid3 restart
    
  4. Verify listeners

    ss -ltnp4 | grep 3128   # expect 0.0.0.0:3128 (or your server IP)
    ss -ltnp6 | grep 3128   # (optional) [::]:3128
    

Firewall hardening

UFW

sudo ufw allow 3128/tcp
# tighter (recommended during testing):
# sudo ufw allow from <YOUR_TEST_SERVER_IP> to any port 3128 proto tcp

iptables (IPv4)

# allow only your test IP, drop the rest
sudo iptables -I INPUT -p tcp -s <YOUR_TEST_SERVER_IP> --dport 3128 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 3128 -j DROP

Note: Avoid http_access allow all in production. If you temporarily use it for debugging, enforce source-IP restrictions at the OS/provider firewall.

Testing

  1. HTTP smoke test (avoids TLS variables)

    curl -4 -x http://<SERVER_IPV4>:3128 http://icanhazip.com -v
    
  2. HTTPS via CONNECT

    curl -4 -x http://<SERVER_IPV4>:3128 https://ipinfo.io/ip -L -v
    # In access.log, success appears as: TCP_TUNNEL/200
    

Handy test script

Save as test_squid.sh, make executable (chmod +x test_squid.sh), run with your server IP.

#!/usr/bin/env bash
PROXY_IP="${1:?Usage: $0 <proxy_ipv4>}"
PORT="${2:-3128}"

echo "[1] Sockets:"
ss -ltnp4 | grep "$PORT" || echo "IPv4 not listening on :$PORT"
ss -ltnp6 | grep "$PORT" || echo "IPv6 not listening on :$PORT"

echo -e "\n[2] HTTP smoke test:"
curl -4 -x "http://$PROXY_IP:$PORT" http://icanhazip.com -sS || echo "HTTP via proxy failed"

echo -e "\n[3] HTTPS test:"
curl -4 -x "http://$PROXY_IP:$PORT" https://ipinfo.io/ip -L -sS || echo "HTTPS via proxy failed (TLS/ACL?)"

echo -e "\n[4] Recent logs:"
sudo tail -n 5 /var/log/squid3/access.log 2>/dev/null || true
sudo tail -n 5 /var/log/squid3/cache.log 2>/dev/null || true

Prevention

  • Always bind IPv4 explicitly: http_port 0.0.0.0:3128.
  • Keep UFW/iptables/provider firewall rules restrictive and persistent.
  • Include a config validation step in provisioning: squid3 -k parse.
  • Optional: add monitoring/alerts on TCP/3128 and on Squid errors.

Conclusion

The issue stemmed from a missing explicit IPv4 binding. By adding http_port 0.0.0.0:3128, setting sane ACLs, and tightening the firewall, the proxy works reliably again—across reboots—without exposing you as an open proxy.

Comments