【问题标题】:Flask app with Apache proxy + Gunicorn not working on HTTPS带有 Apache 代理 + Gunicorn 的 Flask 应用程序无法在 HTTPS 上运行
【发布时间】:2021-12-24 11:53:15
【问题描述】:

更新在底部,我有点解决了,但不确定解决方案是否正确。


我在 CentOS 上运行 Apache,并使用代理到 ​​localhost 端口 8080,我使用 Gunicorn 运行 Flask 应用程序。此设置适用于 Apache 端口 80 (HTTP),我可以使用我的域 http://example.com 和浏览器连接到它,但现在我尝试设置 SSL/HTTPS,但它不起作用。

导航到https://example.com 尝试加载页面一段时间(比如 30 秒),然后显示 502 错误页面:

Proxy Error
The proxy server received an invalid response from an upstream server.
The proxy server could not handle the request GET /.
Reason: Error reading from remote server

Apache 错误日志:

[proxy_http:error] [pid 30209] (103)Software caused connection abort: [client xx.xxx.xxx.xxx:60556] AH01102: error reading status line from remote server localhost:8080
[proxy:error] [pid 30209] [client xx.xxx.xxx.xxx:60556] AH00898: Error reading from remote server returned by /

Gunicorn 错误日志(前 7 行来自 Gunicorn 启动,不知道为什么此信息在错误日志中,后 3 行是 HTTPS 请求返回 502 错误时):

[29478] [INFO] Listening at: http://127.0.0.1:8080 (29478)
[29478] [INFO] Using worker: sync
[29480] [INFO] Booting worker with pid: 29480
[29481] [INFO] Booting worker with pid: 29481
[29482] [INFO] Booting worker with pid: 29482
[29483] [INFO] Booting worker with pid: 29483
[29484] [INFO] Booting worker with pid: 29484
[29478] [CRITICAL] WORKER TIMEOUT (pid:29480)
[29480] [INFO] Worker exiting (pid: 29480)
[29554] [INFO] Booting worker with pid: 29554

适用于 HTTP (/etc/httpd/conf/httpd.conf) 的 Apache 配置:

Listen 80

#other default config values here

<VirtualHost *:80>
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
</VirtualHost>

IncludeOptional conf.d/*.conf

Apache 配置不适用于 HTTPS (/etc/httpd/conf.d/ssl.conf):

Listen 443 https

#other default config values here

<VirtualHost *:443>

#other default config values here too

SSLCertificateFile /etc/pki/tls/certs/cert.pem
SSLCertificateKeyFile /etc/pki/tls/private/cert.key

SSLProxyEngine on
ProxyPass / https://localhost:8080/
ProxyPassReverse / https://localhost:8080/

</VirtualHost>

如果我删除/评论 SSLProxyEngineProxyPassProxyPassReverse 行并重新启动 Apache,我会得到默认的 Apache 欢迎页面,并且 HTTPS 工作得很好,那么很明显问题出在代理中?

Flask 应用程序是由 Gunicorn 启动的:

gunicorn --config gunicorn_config.py app:app

gunicorn_config.py:

workers = 5
bind = '127.0.0.1:8080'
umask = 0o007
reload = True
accesslog = 'log_gunicorn_access.txt'
errorlog = 'log_gunicorn_error.txt'

app.py:

from flask import Flask

app = Flask(__name__)

@app.route('/')
    def hello_world():  
        return 'Hello world!'

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8080)

再一次,这在使用 HTTP 导航到我的域时有效,但在使用 HTTPS 时无效。

有什么帮助吗?


更新:

我设法得到另一个错误。现在导航到https://example.com 会立即加载并显示 500 错误页面:

Proxy Error
The proxy server could not handle the request GET /.
Reason: Error during SSL Handshake with remote server

Apache 错误日志:

[proxy:error] [pid 32385] (502)Unknown error 502: [client xx.xxx.xxx.xxx:50932] AH01084: pass request body failed to [::1]:8080 (localhost)
[proxy:error] [pid 32385] [client xx.xxx.xxx.xxx:50932] AH00898: Error during SSL Handshake with remote server returned by /
[proxy_http:error] [pid 32385] [client xx.xxx.xxx.xxx:50932] AH01097: pass request body failed to [::1]:8080 (localhost) from xx.xxx.xxx.xxx ()

Gunicorn 错误日志中不再有任何错误。

我在 gunicorn_config.py 中添加了这两行:

keyfile = '/etc/pki/tls/private/cert.key'
certfile = '/etc/pki/tls/certs/cert.pem'

并确保运行 Gunicorn 的用户可以访问这两个文件 (chmod o+r cert.key/pem)。

不知道我是否应该这样更改它,因为我认为流量应该是这样的:客户端 --https--> Apache,然后是 Apache --http--> Gunicorn。

此外,HTTP (http://example.com) 不再有效,并给出了之前的 502 错误页面,但我猜想使用证书配置运行 Gunicorn 不再允许 HTTP,需要使用不同的配置运行应用程序两次)。


更新 2:

我通过将此行添加到虚拟主机内的/etc/httpd/conf.d/ssl.conf 添加了更多 Apache 日志记录:

LogLevel info

现在我在 Apache 错误日志中获得了更多信息:

[ssl:info] [pid 3808] [remote 127.0.0.1:8080] AH02411: SSL Proxy: Peer certificate does not match for hostname localhost

然后我在虚拟主机内的/etc/httpd/conf.d/ssl.conf 中添加了新行:

SSLProxyCheckPeerName off

现在我遇到了另一个 Apache 错误:

[ssl:info] [pid 3999] [remote 127.0.0.1:8080] AH02005: SSL Proxy: Peer certificate CN mismatch: Certificate CN: example.com Requested hostname: localhost

在虚拟主机内的/etc/httpd/conf.d/ssl.conf 中添加了新行:

SSLProxyCheckPeerCN off

Aaaand 现在导航到 https://example.com 可以正常工作,我从应用程序返回“Hello world”!

现在我想我的问题也需要更新:在这种情况下使用SSLProxyCheckPeerName offSSLProxyCheckPeerCN off 是不好的做法、错误或不安全吗? 或者有更好的方法吗? '认为没有办法在 localhost 上订购官方 SSL 证书?

【问题讨论】:

    标签: apache flask ssl gunicorn mod-proxy


    【解决方案1】:

    你正在使用

    ProxyPass / http://localhost:8080/
    

    ProxyPass / https://localhost:8080/
    

    (注意 1 个字母的区别)。

    您的localhost:8080 将提供任一 http https。根据您的描述(和共同期望),它提供 http.如果您将 :443 虚拟主机代理到 http,它会更好地工作

    您可能会遇到更多问题,因为代理应用程序并不真正知道它实际上是通过 https 提供的,但这与这个问题不同。

    【讨论】:

    • 嗯,有道理,是的,我只想通过 https 为客户端提供服务 -> Apache 而不是通过内部 Apache 处理它 -> Gunicorn/Flask。不要认为应用程序关心它是否通过 http/https 提供服务。谢谢!
    • 好吧 - 一些应用程序确实关心 - 只要能够生成使用相同协议的链接。或者拒绝接受任何未加密的凭据。如果你没有遇到这个,幸运(在某种程度上)。另一方面,这会捕获一整类错误。
    • 如果我遇到任何问题,我会记住这一点!您是否碰巧知道更彻底地解释了该问题的任何链接/资源,我有兴趣了解更多关于它以及解决它的可能方法。
    猜你喜欢
    • 2020-06-09
    • 2022-01-15
    • 1970-01-01
    • 2018-12-19
    • 2018-01-29
    • 1970-01-01
    • 2016-07-20
    • 2012-02-15
    • 1970-01-01
    相关资源
    最近更新 更多