使用 Caddy 为 Flask 应用轻松添加 HTTPS
在 Web 开发中,将我们的应用从本地开发环境部署到服务器只是第一步。默认情况下,我们的 Flask 应用可能通过 HTTP 和服务器 IP 地址直接访问,例如 http://your_server_ip:5001。
对于生产环境或任何需要保护用户数据传输的场景来说,启用 HTTPS 是必不可少的。借助 Caddy Web 服务器,为现有应用添加 HTTPS 并使用自定义域名变得异常简单。Caddy 以其开箱即用的自动 HTTPS 功能而闻名。
本文将记录如何为一个已部署的 Flask 应用(监听在 5001 端口)配置 Caddy,以实现通过自定义域名 xxx.xxx.com 进行 HTTPS 访问。
前提条件:
- 一台可以通过 SSH 访问的 Linux 服务器。
- 一个已部署并正在运行的 Flask 应用(本文假设它监听在
localhost:5001或0.0.0.0:5001)。 - 一个域名(例如
xxx.xxx.com),并且其 DNS A 记录已指向你的服务器 IP 地址。 - Caddy 已在服务器上安装。如果未安装,可以参考 Caddy 官方文档进行安装。
步骤 1:检查并确保 Caddy 正在运行
首先,我们需要确认 Caddy 是否已安装并检查其运行状态。
# 检查 Caddy 是否安装
command -v caddy
# 检查 Caddy 服务状态 (通常使用 systemd)
systemctl status caddy
在我们的案例中,初次检查发现 Caddy 服务处于 failed 状态。日志显示错误信息 listen tcp :80: bind: address already in use。这意味着服务器上的 80 端口已被其他程序占用。
我们需要找出哪个进程占用了 80 端口:
sudo lsof -i :80
输出显示 docker-proxy 占用了该端口。进一步检查运行中的 Docker 容器:
sudo docker ps
发现是一个名为 dnginx 的 Nginx 容器占用了 80 和 443 端口。由于我们决定使用 Caddy 来处理 HTTPS,我们需要停止这个冲突的 Nginx 容器:
sudo docker stop dnginx
停止冲突容器后,我们再次尝试启动 Caddy 服务并检查其状态:
sudo systemctl start caddy
systemctl status caddy
这次,状态显示 Active: active (running),表明 Caddy 已成功启动。
步骤 2:确认 Flask 应用监听端口
Caddy 需要知道将请求代理到哪里。我们需要确认 Flask 应用实际监听的端口。虽然我们的部署脚本和代码显示它应该在 5001 端口,但最好在服务器上确认一下:
# 查找监听 TCP 端口的 Python 进程
sudo ss -tlpn | grep python
输出确认了有 Python 进程监听在 0.0.0.0:5001。
步骤 3:配置 Caddyfile 实现反向代理
Caddy 的主要配置文件是 Caddyfile,通常位于 /etc/caddy/Caddyfile。我们需要修改这个文件,告诉 Caddy 监听我们的域名,并自动处理 HTTPS,然后将流量转发给 Flask 应用。
我们将 /etc/caddy/Caddyfile 的内容修改为:
xxx.xxx.com {
reverse_proxy localhost:5001
}
这个简单的配置块做了几件事:
- 定义了一个站点块,监听发往
xxx.xxx.com的请求。 - Caddy 会自动为这个域名申请并续订 Let's Encrypt (或其他配置的 ACME CA) 的 TLS 证书,启用 HTTPS。所有 HTTP 请求也会自动重定向到 HTTPS。
reverse_proxy localhost:5001指令将所有接收到的请求转发给运行在同一台机器上、监听在 5001 端口的 Flask 应用。
我们可以通过 SSH 更新服务器上的文件:
# 注意:根据你的 shell 环境,可能需要调整引号和转义
echo -e 'weibo.haoxueren.com {\n reverse_proxy localhost:5001\n}' | sudo tee /etc/caddy/Caddyfile
步骤 4:重新加载 Caddy 配置并测试
修改配置文件后,我们需要让 Caddy 重新加载配置以使更改生效:
sudo systemctl reload caddy
Caddy 会平滑地应用新配置。此时,Caddy 会在后台开始为 xxx.xxx.com 获取证书(如果是第一次配置)。这可能需要几秒到一分钟。
稍等片刻后,打开浏览器访问 https://xxx.xxx.com。如果一切顺利,你应该能看到你的 Flask 应用通过安全的 HTTPS 连接加载了!
步骤 5:增强安全性 - 限制 Flask 应用直接访问(推荐)
现在,虽然我们可以通过 https://xxx.xxx.com 访问应用,但原来的 http://your_server_ip:5001 可能仍然可以直接访问 Flask 应用,绕过了 Caddy。为了提高安全性,最佳实践是让后端应用(Flask)只监听本地回环地址 (127.0.0.1),这样只有本机上的进程(如 Caddy)可以连接到它。
我们需要修改 Flask 应用的启动方式。在我们的 app.py 文件中,找到 app.run() 的调用:
# app.py (文件末尾)
if __name__ == '__main__':
# 将 host 从 '0.0.0.0' 修改为 '127.0.0.1'
app.run(debug=True, host='127.0.0.1', port=5001)
修改完成后,需要将更新后的 app.py 重新部署到服务器(例如,通过运行你的 deploy.sh 脚本),并确保 Flask 应用被重启以应用新的监听地址。
完成此步骤后,你的 Flask 应用将不再能通过服务器的公共 IP 地址直接访问,所有流量都必须经过 Caddy 代理,确保了 HTTPS 的强制使用和统一的访问入口。
总结
通过 Caddy,我们仅用一个非常简洁的配置文件就为 Flask 应用启用了 HTTPS,并配置了基于域名的访问。Caddy 自动处理了 TLS 证书的获取和续订,大大简化了 HTTPS 的部署和维护工作。同时,通过限制后端应用的监听地址,我们进一步增强了应用部署的安全性。Caddy 无疑是现代 Web 服务部署中一个强大而易用的工具。