SSL certificate errors
Yours or the site’s. The proxy does not touch TLS on a tunnelled HTTPS request.
- Usually from
- Your client config, or the site’s certificate
- Try first
- Write the proxy URL with http:// and update your CA bundle
What a certificate error means through a proxy
Two kinds of error get lumped together here. Verification errors (CERTIFICATE_VERIFY_FAILED, ERR_CERT_AUTHORITY_INVALID, unable to get local issuer certificate) mean your client did not trust the site’s certificate. Handshake errors such as WRONG_VERSION_NUMBER usually mean your client tried to speak TLS to something speaking plain HTTP.
The classic handshake mistake is a proxy URL written as https://. That tells the client to open TLS to the proxy itself. The gateway expects plain HTTP on its port, and the tunnel it opens to the site is encrypted end to end anyway.
An error on one site only is that site’s certificate: expired, missing an intermediate, or issued for another name. Browsers can fetch a missing intermediate on their own, which is why a site can look fine in Chrome and fail in a script.
Your credentials, the proxy, or the target?
Yours or the site’s. The proxy does not touch TLS on a tunnelled HTTPS request.
Your credentials
Not the cause. Credentials are checked on the CONNECT, before any TLS.
The proxy
Not directly: it passes TLS through untouched. The one proxy-shaped cause is an
https://proxy URL, and that is a config fix on your side.The target site
An expired certificate, a missing intermediate or a name mismatch. It fails the same way without the proxy.
How to tell
WRONG_VERSION_NUMBERstraight away: check the scheme in the proxy URL before anything else.- The same error with and without the proxy: it is the site or your CA bundle.
openssl s_clientagainst the site, without the proxy, shows its chain and expiry directly.- Only one tool on the machine fails: that tool carries its own, older CA bundle.
Fixes, in the order to try them
- Costs nothing
Write the proxy URL with http://
For both the
httpandhttpskeys, in every tool. The site traffic is still HTTPS inside the tunnel. - Costs nothing
Update the CA bundle
pip install -U certififor Python, a current Node release for Node, and your OS updates orupdate-ca-certificatesfor curl. - Costs nothing
Look at the site’s certificate
Check its expiry, the names it covers and whether the chain is complete. A broken chain is the site owner’s to fix; you can tell them.
- Costs nothing
Disable verification for one test run only
-k,verify=Falseandignore_https_errorsconfirm a diagnosis. Left in a script, they remove the only check that the page came from the real site. - Costs some time
Point your tool at your network’s CA
If your machine sits behind a firewall that inspects TLS, your tool needs that firewall’s CA:
REQUESTS_CA_BUNDLE,NODE_EXTRA_CA_CERTSor--cacert.
See the real status and headers
Each sample shows the handshake with the site, or the exact certificate error, with verification left on.
curl
# -v shows the tunnel opening, then the TLS handshake with the site
curl -sv -o /dev/null -x http://USER:[email protected]:8000 https://example.com/ 2>&1 \
| grep -E 'CONNECT|HTTP/1.1 200|SSL|TLS|subject|expire|issuer'
# the site's certificate, checked without the proxy
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -enddatePython Requests
import certifi
import requests
PROXY = "http://USER:[email protected]:8000"
print("CA bundle:", certifi.where())
try:
r = requests.get("https://example.com/", proxies={"http": PROXY, "https": PROXY}, timeout=30)
print(r.status_code)
except requests.exceptions.SSLError as err:
print(err)Both keys use http://. An https:// proxy URL is the usual source of WRONG_VERSION_NUMBER.
Scrapy
# settings.py: pin one TLS version when a single old site fails the handshake
DOWNLOADER_CLIENT_TLS_METHOD = "TLSv1.2"
# in the spider
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(url, errback=self.on_error)
def on_error(self, failure):
self.logger.error("%s: %r", failure.request.url, failure.value)Scrapy does not verify certificates by default, so what reaches the errback here is a handshake failure with the site.
Playwright
from playwright.sync_api import Error, sync_playwright
PROXY = {"server": "http://resi.proxymonkey.io:8000", "username": "USER", "password": "PASS"}
with sync_playwright() as p:
browser = p.chromium.launch(proxy=PROXY)
page = browser.new_page()
try:
page.goto("https://example.com/")
except Error as err:
print(err.message.splitlines()[0])
browser.close()
# net::ERR_CERT_DATE_INVALID the certificate has expired
# net::ERR_CERT_COMMON_NAME_INVALID issued for a different name
# net::ERR_CERT_AUTHORITY_INVALID not signed by a CA Chromium trustsNode.js
import { fetch, ProxyAgent } from "undici";
const dispatcher = new ProxyAgent("http://USER:[email protected]:8000");
try {
await fetch("https://example.com/", { dispatcher });
} catch (err) {
console.error(err.cause?.code, err.cause?.message);
}
// CERT_HAS_EXPIRED the certificate has expired
// ERR_TLS_CERT_ALTNAME_INVALID issued for a different name
// UNABLE_TO_VERIFY_LEAF_SIGNATURE the site's chain is incomplete
// behind a TLS-inspecting firewall: NODE_EXTRA_CA_CERTS=./ca.pem node tls.mjsThe samples use the residential gateway, resi.proxymonkey.io:8000. For an ISP or datacenter IP, use USER:PASS@IP:PORT for the address you rented. Your dashboard lists the host and port for every order, and where it differs from this page, the dashboard is right.
Will a different proxy line fix it?
When switching helps
Switching line does not change which certificate your client checks. On an HTTPS site it is always the site’s own.
When it will not
Buying ISP or datacenter to get rid of a certificate error changes the address the site sees. The certificate check still happens on your machine, the same way.
Is a failed request billed?
We bill for request bytes and response bytes, including headers and protocol overhead on the tunnelled connection. Connections that fail before transferring data are not billed. Retries that you initiate are billed and appear as separate entries in your usage log.
The terms count protocol overhead on the tunnelled connection as billed bytes, and say connections that fail before transferring data are not billed. A handshake that fails inside an open tunnel has moved some bytes, and the terms do not describe that case on its own. Check the row in your usage log and ask in Discord if it looks wrong.
Residential is billed per GB of that traffic. ISP and datacenter addresses are charged per IP for their term, and where a plan includes a traffic allowance, traffic past it is billed per GB under the same rule. The usage log in your dashboard has one row per request with bytes in, bytes out and cost, so you can look up the failed request yourself.
Questions people ask about a certificate error
Can the proxy see my HTTPS traffic?
No. For an HTTPS site the proxy opens a tunnel and passes encrypted bytes through. It sees the host and port you asked for and how many bytes moved, which is what the meter counts. It cannot read the pages or swap the certificate.
Why does the site work in my browser and fail in Python?
Browsers ship their own trust store and can fetch a missing intermediate certificate by themselves. Python uses the certifi bundle and fails where the site’s chain is incomplete or the bundle is old. Update certifi, then check the site’s chain.
Is verify=False safe?
For one test run to confirm the diagnosis, it does no harm. Left in a scraper, it means anyone in the path could hand you a fake page and your code would accept it.
What does WRONG_VERSION_NUMBER mean?
Your client started a TLS handshake and got plain HTTP back. Through a proxy that nearly always means the proxy URL starts with https://. Change it to http://; the site traffic stays encrypted inside the tunnel.
Errors that travel with this one
- ECONNREFUSED
Connection refused
Something said no before any HTTP happened. Usually the host or port you gave for the proxy.
Work it out → - TIMEOUT
Connection timeout
Nothing came back in time. Find out which leg stalled before you raise the limit.
Work it out → - 407
407 Proxy Authentication Required
The proxy did not accept your login. Nearly always the credentials, or the way your tool sends them.
Work it out →
Still stuck on a certificate error?
Paste your error in the Discord: the full message plus the command or the few lines that set up the proxy, with the password taken out. Someone there has seen it before.
Join the Discord4,200+monkeys in the Discord
Help from humans
Post your error, get an answer. Usually in minutes, usually from someone who has hit the same wall.
A status bot that tells on us
Pool health, incidents and maintenance posted automatically. Including the bad days.
Deals and free traffic
Bonus GB drops, early access to new pools, and the occasional giveaway for a good bug report.