Gunicorn/Flask reject identical SSL certificate that works fine with Apache

Cerin asked:

What would cause a Gunicorn server running a Flask app to report a "sslv3 alert certificate unknown" error in the browser, when an Apache server running a WSGI app, using the exact same certificate on the exact same machine, reports no problems?

The Gunicorn service is hosting from the domain https://mysub.example.com:1234 while the Apache service hosts from the standard port 80 at https://mysub.example.com.

Both services are hosted on the same physical server, and load the wildcard SSL certificate located at /etc/ssl/certs.

The logs from Gunicorn/Flask aren’t providing much feedback and are simply showing:

[2021-06-23 12:55:34 -0500] [2320785] [DEBUG] Error processing SSL request.
[2021-06-23 12:55:34 -0500] [2320785] [DEBUG] Invalid request from ip=123.45.678.90: [SSL: SSLV3_ALERT_CERTIFICATE_UNKNOWN] sslv3 alert certificate unknown (_ssl.c:2633)

The Gunicorn server is run via Supervisor with as user www-data the command:

/usr/local/alphabuyer/.env/bin/gunicorn --certfile=/etc/ssl/certs/example.com.crt --keyfile=/etc/ssl/certs/example.com.key --bind 0.0.0.0:1234 server:app

Meanwhile, the SSL settings for Apache config are:

SSLEngine On
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/certs/example.com.key
SSLCACertificateFile /etc/ssl/certs/example.com.intermediate.crt
SSLProtocol all
SSLCipherSuite HIGH:MEDIUM

I’ve checked the permissions in /etc/ssl/certs, and they appear to be correct. Everything’s owned by user www-data chmoded to 600.

I don’t see any reason why the certificate would be served correctly by Apache but not by Gunicorn. The error message suggests it’s not necessarily anything Gunicorn is serving, but an error or some supported feature with the request the browser is making. What am I missing here?

My answer:


Gunicorn (and virtually everything else that does TLS except Apache) expects your TLS certificate to be concatenated with the intermediate certificates in a single file.

Create the concatenated file:

cat /etc/ssl/certs/example.com.crt /etc/ssl/certs/example.com.intermediate.crt > /etc/ssl/certs/example.com.chain.crt

Now use it in your command line.

.... --certfile=/etc/ssl/certs/example.com.chain.crt ....

View the full question and any other answers on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.