ISP SNI Filtering Blocking Caddy Reverse Proxy¶
Some ISPs — including Google Fiber — silently block TLS handshakes for certain hostnames at the network level. The connection reaches your server, TCP completes, but the TLS handshake never finishes. The symptom looks identical to a misconfigured Caddy setup or a missing certificate, which makes it a frustrating thing to debug.
What Happened¶
Deployed a new Caddy vhost for wiki.majorshouse.com on a Google Fiber residential connection. Everything on the server was correct:
- Let's Encrypt cert provisioned successfully
- Caddy validated clean with
caddy validate curl --resolve wiki.majorshouse.com:443:127.0.0.1 https://wiki.majorshouse.comreturned 200 from loopback- iptables had ACCEPT rules for ports 80 and 443
- All other Caddy vhosts on the same IP and port worked fine externally
But from any external host, curl timed out with no response. ss -tn showed SYN-RECV connections piling up on port 443 — the TCP handshake was completing, but the TLS handshake was stalling.
The Debugging Sequence¶
Step 1: Ruled out Caddy config issues
caddy validate --config /etc/caddy/Caddyfile
curl --resolve wiki.majorshouse.com:443:127.0.0.1 https://wiki.majorshouse.com
Both clean. Loopback returned 200.
Step 2: Ruled out certificate issues
ls /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/wiki.majorshouse.com/
openssl x509 -in wiki.majorshouse.com.crt -noout -text | grep -E "Subject:|Not Before|Not After"
Valid cert, correct subject, not expired.
Step 3: Ruled out firewall
Ports open, Caddy listening on *:443.
Step 4: Ruled out hairpin NAT
Testing curl https://wiki.majorshouse.com from the server itself returned "No route to host" — the server can't reach its own public IP. This is normal for residential connections without NAT loopback. It's not the problem.
Step 5: Confirmed external connectivity on port 443
# From an external server (majormail)
curl -sk -o /dev/null -w "%{http_code}" https://git.majorshouse.com # 200
curl -sk -o /dev/null -w "%{http_code}" https://wiki.majorshouse.com # 000
Same IP, same port, same Caddy process. git works, wiki doesn't.
Step 6: Tested a different subdomain
Added notes.majorshouse.com as a new Caddyfile entry pointing to the same upstream. Cert provisioned via HTTP-01 challenge successfully (proving port 80 is reachable). Then:
curl -sk -o /dev/null -w "%{http_code}" https://notes.majorshouse.com # 200
curl -sk -o /dev/null -w "%{http_code}" https://wiki.majorshouse.com # 000
notes worked immediately. wiki still timed out.
Conclusion: Google Fiber is performing SNI-based filtering and blocking TLS connections where the ClientHello contains wiki.majorshouse.com as the server name.
The Fix¶
Rename the subdomain. Use anything that doesn't trigger the filter. notes.majorshouse.com works fine.
# Remove the blocked entry
sed -i '/^wiki\.majorshouse\.com/,/^}/d' /etc/caddy/Caddyfile
systemctl reload caddy
Update mkdocs.yml or whatever service's config references the domain, add DNS for the new subdomain, and done.
How to Diagnose This Yourself¶
If your Caddy vhost works on loopback but times out externally:
- Confirm other vhosts on the same IP and port work externally
- Test the specific domain from multiple external networks (different ISP, mobile data)
- Add a second vhost with a different subdomain pointing to the same upstream
- If the new subdomain works and the original doesn't, the hostname is being filtered
# Quick external test — run from a server outside your network
curl -sk -o /dev/null -w "%{http_code}" --max-time 10 https://your-domain.com
If you get 000 (connection timeout, not a TLS error like curl: (35)), the TCP connection isn't completing — pointing to network-level blocking rather than a Caddy or cert issue.
Gotchas & Notes¶
curl: (35) TLS erroris different from000. A TLS error means TCP connected but the handshake failed — usually a missing or invalid cert. A000timeout means TCP never completed — a network or firewall issue.- SYN-RECV in
ss -tnmeans TCP is partially open. If you see SYN-RECV entries for your domain but the connection never moves to ESTAB, something between the client and your TLS stack is dropping the handshake. - ISP SNI filtering is uncommon but real. Residential ISPs sometimes filter on SNI for terms associated with piracy, proxies, or certain categories of content. "Wiki" may trigger a content-type heuristic.
- Loopback testing isn't enough. Always test from an external host before declaring a service working. The server can't test its own public IP on most residential connections.
See Also¶
- [[setting-up-caddy-reverse-proxy]]
- [[linux-server-hardening-checklist]]
- [[tailscale-homelab-remote-access]]