[{"data":1,"prerenderedAt":19},["ShallowReactive",2],{"blog:post:en:debugging-proxy-tls-failures":3},{"slug":4,"lang":5,"title":6,"summary":7,"date":8,"tags":9,"tag_slugs":14,"thumbnail_url":15,"translations":16,"body":17,"asset_base":18},"debugging-proxy-tls-failures","en","Debugging Proxy TLS Failures: SNI, ALPN, and Certificates","Learn to separate TCP, TLS, certificate, SNI, and ALPN failures, then fix proxy trust and handshake configuration with curl, Python, and browser checks.","2026-09-14",[10,11,12,13],"proxies","tls","troubleshooting","networking",[10,11,12,13],"https://blog-api.ro-proxy.com/api/blog/posts/debugging-proxy-tls-failures/thumbnail.svg?lang=en",[5],"## Locate the failure layer\n\nA failed request through a proxy can look like a generic timeout, a 502 response, or a browser certificate warning. Those symptoms often come from different layers. Before changing rotation settings or headers, identify where the request stops.\n\nCheck the layers in this order:\n\n1. **TCP connection:** Can the client reach the proxy and its port?\n2. **Proxy tunneling:** Did the proxy accept the `CONNECT` request for an HTTPS URL?\n3. **TLS handshake:** Did the client and server agree on a protocol, version, and cipher?\n4. **Certificate validation:** Is the presented certificate trusted and intended for the destination?\n5. **ALPN and application protocol:** Did the connection select `h2`, `http/1.1`, or another negotiated protocol?\n6. **HTTP response:** Is the problem now an origin response, authentication issue, or rate limit?\n\nThis distinction matters. A certificate error is not an IP ban, and a 502 caused by a failed TLS termination is not necessarily an origin server outage.\n\n## Establish direct and proxy baselines\n\nTest the same URL directly and through the proxy. Replace the proxy address with the endpoint supplied by your provider.\n\n```bash\ncurl -v --max-time 20 'https://example.com/'\ncurl -v --proxy 'http://127.0.0.1:8080' --max-time 20 'https://example.com/'\n```\n\nLook for these signals:\n\n- `Trying... Connected` confirms that the client reached the proxy.\n- `Connected to` identifies the proxy host that handled the request.\n- `CONNECT example.com:443` shows that the HTTP proxy opened a tunnel to the destination.\n- `SSL connection using` reveals the negotiated TLS version and cipher.\n- `ALPN protocol` shows the selected application protocol.\n- `subject:` and `issuer:` identify the certificate presented to the client.\n\nIf the direct request succeeds but the proxied request fails, focus on the proxy path, its TLS policy, and its certificate trust chain. If both fail, investigate the destination, local DNS, firewall rules, or the client environment before rotating proxies.\n\nDo not use `curl --insecure` as a permanent fix. It disables certificate validation and can expose credentials, cookies, and request data to an attacker.\n\n## Verify CONNECT, SNI, and ALPN\n\nFor an HTTPS request through an HTTP proxy, the sequence is:\n\n1. Open a TCP connection to the proxy.\n2. Send `CONNECT destination:443`.\n3. Receive a successful tunnel response.\n4. Start TLS inside that tunnel.\n5. Send the TLS Server Name Indication, or SNI, value.\n6. Negotiate ALPN and HTTP/2 or HTTP/1.1.\n\nSNI is not the same thing as the HTTP `Host` header. It is sent during the TLS handshake and helps the server select the correct certificate when one IP hosts multiple domains. Most clients set it automatically from the URL. Do not manually add `Host`, `X-Forwarded-Host`, or custom SNI headers unless your proxy product specifically requires it.\n\nCompare a direct TLS handshake with a proxied one:\n\n```bash\nopenssl s_client -connect example.com:443 -servername example.com -alpn h2\nopenssl s_client -proxy 127.0.0.1:8080 -connect example.com:443 -servername example.com -alpn h2\n```\n\nIf the proxied command shows a different certificate, a handshake alert, or no expected ALPN result, inspect the proxy configuration and logs. Confirm that the proxy is receiving the destination hostname rather than an IP address or a generic placeholder. Also verify that the proxy is configured for HTTPS tunneling rather than only plain HTTP forwarding.\n\nIf the proxy terminates TLS, it becomes the TLS peer from the client's perspective. In that design, the proxy must have the correct certificate, support the required TLS versions and ALPN values, and present a chain trusted by the client. If the proxy only tunnels traffic, it does not need to decrypt or understand the encrypted HTTP/2 frames.\n\n## Fix certificate trust without weakening production\n\nA message such as `certificate verify failed` or a browser warning beginning with `NET::ERR_CERT_AUTHORITY_INVALID` usually indicates a trust-chain problem. Compare the certificate issuer with the direct request. If the direct certificate is issued by the website owner but the proxied certificate is issued by a gateway or interception appliance, the proxy is probably performing TLS inspection.\n\nThe correct fix is to install the interception organization's root or intermediate certificate in the operating system and browser trust stores. Use the certificate supplied by your security or proxy administrator, and verify its source before installing it.\n\nFor a controlled test, point `curl` at a known certificate authority file:\n\n```bash\ncurl -v --proxy 'http://127.0.0.1:8080' --cacert '/path/to/company-ca.pem' 'https://example.com/'\n```\n\nThe same principle applies to Python. The `verify` option should point to the trusted CA bundle, not be disabled globally.\n\n```python\nimport requests\n\nurl = 'https://example.com/'\nproxies = {\n    'http': 'http://127.0.0.1:8080',\n    'https': 'http://127.0.0.1:8080',\n}\n\nresponse = requests.get(\n    url,\n    proxies=proxies,\n    timeout=(5, 20),\n    verify='/etc/ssl/certs/company-ca.pem',\n)\nprint(response.status_code, response.url)\n```\n\nDisabling verification can be useful for a short, isolated diagnostic in a lab, but it is not a production configuration. It makes man-in-the-middle attacks possible and can cause secrets in headers, cookies, and query strings to be exposed. Never copy that setting into a shared scraper, CI job, or customer-facing service.\n\n## Test ALPN and protocol fallback\n\nALPN lets the client and server agree on the application protocol during the TLS handshake. A server may prefer HTTP/2 while the client or proxy negotiates HTTP/1.1. This is often a compatibility issue rather than a failure of the proxy itself.\n\nTry explicit protocol tests:\n\n```bash\ncurl -v --proxy 'http://127.0.0.1:8080' --http1.1 'https://example.com/'\ncurl -v --proxy 'http://127.0.0.1:8080' --http2 'https://example.com/'\n```\n\nIf HTTP/1.1 succeeds while the default request fails, check whether the proxy or TLS-terminating gateway supports the protocol expected by the origin. A transparent CONNECT tunnel can carry HTTP/2 without the proxy decrypting it. A terminating proxy must negotiate ALPN correctly and either forward the selected protocol or emulate the origin's behavior.\n\nDo not force an obsolete protocol merely to make a test pass. Prefer enabling a supported modern protocol, updating the proxy software, or selecting a compatible proxy endpoint.\n\n## Check TLS versions and cipher policy\n\nAn outdated proxy may reject a modern client, or a security policy may disable a cipher required by an older origin. Test the minimum and maximum versions deliberately:\n\n```bash\ncurl -v --proxy 'http://127.0.0.1:8080' --tlsv1.2 --tls-max 1.3 'https://example.com/'\nopenssl s_client -proxy 127.0.0.1:8080 -connect example.com:443 -servername example.com -tls1_2\n```\n\nUse these commands to gather evidence, not to weaken security. If the origin only supports TLS 1.0 or 1.1, the durable solution is to update the origin or proxy rather than enabling insecure protocols across an entire application.\n\n## Collect browser evidence\n\nBrowser Developer Tools provide useful evidence without changing application code. Open the Network panel, reproduce the request, and inspect:\n\n- the failure stage and status code;\n- the request and response headers;\n- the certificate issuer, validity period, and SAN values;\n- whether the request used the expected proxy;\n- whether another tab or clean browser profile produces the same result.\n\nExtensions can inject certificates, alter headers, or terminate TLS. Test with extensions disabled and with a clean profile before changing the proxy. Browser certificate caches can also preserve an old result, so restart the browser after installing a trusted CA or changing proxy settings.\n\n## Use a small Python diagnostic loop\n\nA diagnostic loop makes it easy to compare direct and proxied behavior while keeping the test repeatable. Keep logs limited to the stage, status, final URL, and elapsed time; do not log authorization headers or tokens.\n\n```python\nimport time\nimport requests\n\nurl = 'https://example.com/'\nproxy = 'http://127.0.0.1:8080'\n\ncases = [\n    ('direct', {}),\n    ('proxy', {'http': proxy, 'https': proxy}),\n]\n\nfor name, proxies in cases:\n    started = time.monotonic()\n    try:\n        response = requests.get(\n            url,\n            proxies=proxies,\n            timeout=(5, 20),\n            verify=True,\n        )\n        print(name, response.status_code, response.url, f'{time.monotonic() - started:.2f}s')\n    except Exception as error:\n        print(name, type(error).__name__, str(error))\n```\n\nIf the direct case succeeds and the proxy case raises `SSLError`, inspect the certificate chain. If it raises a connection exception, check the proxy port and firewall. If it returns an HTTP response, move the investigation to the proxy access policy, origin response, and application-level rate limits.\n\n## Apply fixes one variable at a time\n\nUse this evidence-based checklist:\n\n- **No TCP connection:** Verify the proxy hostname, port, firewall, and proxy type.\n- **`CONNECT` returns 403 or 407:** Check proxy authorization and access rules.\n- **Handshake alert:** Compare TLS versions, cipher suites, and proxy software.\n- **Certificate authority error:** Install the correct trusted CA or remove unnecessary TLS interception.\n- **Unexpected certificate:** Confirm SNI, hostname verification, and the proxy's certificate mapping.\n- **ALPN mismatch:** Enable the required protocol or use a compatible proxy endpoint.\n- **HTTP response problem:** Treat it separately from TLS and investigate authentication, origin rules, and rate limits.\n\nRecord the proxy version, endpoint, destination, timestamp, and sanitized response code. Change one setting per test, rerun the baseline, and keep the direct comparison. This approach finds the actual failure layer without turning a TLS problem into a broader scraper or networking incident.\n","https://blog-api.ro-proxy.com/api/blog/posts/debugging-proxy-tls-failures/assets",1790057932514]