使用requests与certifi遭遇CERTIFICATE_VERIFY_FAILED问题求助
Let's break down what's happening here, step by step—this is a common point of confusion with how requests handles SSL verification, especially across different environments.
Core Default Behavior for Requests 2.18.4 + Certifi 2018.1.18
By default, requests relies on the certifi package's bundled CA certificate store, not your system's native CA certificates. This is because requests uses urllib3 under the hood, and in this specific version stack, urllib3 is configured to prioritize certifi's cacert.pem file over system-level stores unless explicitly told otherwise.
That’s why your local Ubuntu 16.04 virtual environment works fine: requests is using certifi’s valid (for your target sites) CA bundle, regardless of your system’s cert state (though in your case, local system certs are probably up to date).
Why the Remote Server Throws CERTIFICATE_VERIFY_FAILED
The key issue is that your remote server’s requests instance is not using certifi’s bundle—it’s falling back to your expired system CA certificates instead. Here are the most likely causes:
- Environment Variable Override: The remote server has the
REQUESTS_CA_BUNDLEenvironment variable set. This forces requests to use a specific CA bundle path (usually pointing to the system’s expired/etc/ssl/certs/ca-certificates.crtor similar) instead of certifi’s. - Virtual Environment Isolation Failure: The remote venv isn’t properly activated, so requests is actually using the system-wide Python installation’s libraries (which might lack certifi or be configured to use system certs).
- Custom Configuration: Someone modified the requests/urllib3 config on the remote server (e.g., code that sets
verifyto a system path by default, or adjusted urllib3’scert_reqssettings).
Steps to Diagnose & Fix
Check for the REQUESTS_CA_BUNDLE Variable
In your remote venv, run:echo $REQUESTS_CA_BUNDLEIf you get a path output, that’s the culprit—unset it with
unset REQUESTS_CA_BUNDLEand test your request again.Verify Which CA Bundle Requests is Using
Run this Python snippet in your remote venv:import requests print(requests.utils.DEFAULT_CA_BUNDLE_PATH)This should point to a file inside your venv’s certifi directory (e.g.,
/your/venv/lib/python3.5/site-packages/certifi/cacert.pem). If it points to a system path like/etc/ssl/certs/ca-certificates.crt, your venv isn’t working as expected or config is overridden.Test Explicitly Using Certifi's Bundle
Force requests to use certifi’s bundle directly to confirm:import certifi import requests try: response = requests.get("https://your-target-site.com", verify=certifi.where()) print("Success!") except Exception as e: print(f"Error: {e}")If this works, you know the problem is that requests isn’t using certifi by default on the remote server.
Confirm Venv Activation
Runwhich pythonandpip listin the remote shell—ensure the Python path points to your venv, and thatrequests==2.18.4andcertifi==2018.1.18are listed. If not, reactivate your venv properly.
Final Notes
Keep in mind that certifi 2018.1.18 is an old release—many CA certificates in that bundle are now expired. While it works for your target sites today, you might run into issues with newer sites down the line. But for your current problem, the core fix is ensuring requests uses certifi’s bundle instead of the expired system certs on your remote server.
内容的提问来源于stack exchange,提问作者Robert Townley

