Gunicorn gevent CERTIFICATE_VERIFY_FAILED error

I have a Django website running in a Docker container (Debian), which I deploy with the following command:

    gunicorn core.wsgi:application --bind 0.0.0.0:8000 --workers 33 --worker-class gevent --timeout 1200

I created a simple view with an outgoing request:

    def my_view(request):
        import requests
        requests.get('https://website.domain.com', verify='/etc/ssl/certs/mycert.cer')
        return HttpResponse('Success')

Which throws the error:

    requests.exceptions.SSLError: HTTPSConnectionPool(host='website.domain.com', port=443): 
    Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] 
    certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)')))

What could be the reason for such behavior? What is special about how the gevent worker handles SSL certificates?

What I found out for now:

  • The script works fine when I use --worker-class sync or deploy with python manage.py runserver
  • The script works fine when executed via python console or via python manage.py shell (from a running docker container)
  • The certificate is correct (otherwise, it didn't work for cases above)
  • Unsetting REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE, SSL_CERT_FILE or setting them to current location of my cert file doesn't help
  • PYTHONHTTPSVERIFY=0 seems to have no effect
  • verify=False and verify=True have no effect
  • Adding monkey.patch_all() in the script has no effect
  • Adding gunicorn.conf.py with monkey.patch_all() in it has no effect
  • The certificate is definitely being used. Because if I set verify parameter to incorrect path it throws the corresponding error
  • update-ca-certificates have no effect

Python packages (some of them):

Python 3.11.7
amqp 5.3.1
asgiref 3.8.1
bcrypt 4.3.0
billiard 4.2.1
certifi 2025.6.15
cffi 1.17.1
cryptography 45.0.5
distlib 0.3.8
Django 5.2.4
filelock 3.15.4
gevent 25.5.1
greenlet 3.2.3
gssapi 1.9.0
gunicorn 23.0.0
hvac 2.3.0
krb5 0.5.1
pip 25.1.1
pip_system_certs 5.2
psutil 7.0.0
pykerberos 1.2.4
requests 2.32.4
requests-kerberos 0.15.0

The full text of an error:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/urllib3/connectionpool.py", line 464, in _make_request
    self._validate_conn(conn)
  File "/usr/local/lib/python3.11/site-packages/urllib3/connectionpool.py", line 1093, in _validate_conn
    conn.connect()
  File "/usr/local/lib/python3.11/site-packages/urllib3/connection.py", line 790, in connect
    sock_and_verified = _ssl_wrap_socket_and_match_hostname(
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/connection.py", line 969, in _ssl_wrap_socket_and_match_hostname
    ssl_sock = ssl_wrap_socket(
               ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/util/ssl_.py", line 480, in ssl_wrap_socket
    ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/util/ssl_.py", line 524, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/gevent/ssl.py", line 122, in wrap_socket
    return self.sslsocket_class(
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/gevent/ssl.py", line 351, in __init__
    self.do_handshake()
  File "/usr/local/lib/python3.11/site-packages/gevent/ssl.py", line 740, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)  
During handling of the above exception, another exception occurred:  
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/urllib3/connectionpool.py", line 787, in urlopen
    response = self._make_request(
               ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/connectionpool.py", line 488, in _make_request
    raise new_e
urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)  
The above exception was the direct cause of the following exception:  
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/requests/adapters.py", line 667, in send
    resp = conn.urlopen(
           ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/connectionpool.py", line 841, in urlopen
    retries = retries.increment(
              ^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/urllib3/util/retry.py", line 519, in increment
    raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='website.domain.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)')))  
During handling of the above exception, another exception occurred:  
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/app/web/core/views.py", line 178, in my_view
    res = requests.get('https://website.domain.com', verify='/etc/ssl/certs/mycert.cer')
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/api.py", line 73, in get
    return request("get", url, params=params, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/api.py", line 59, in request
    return session.request(method=method, url=url, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/requests/adapters.py", line 698, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='website.domain.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)')))
Вернуться на верх