Sanic 与 Caddy 反向代理部署实战:TLS、HTTP/3 与静态资源卸载
2026/9/21 15:18:16 网站建设 项目流程

Sanic 与 Caddy 反向代理部署实战:TLS、HTTP/3 与静态资源卸载

【免费下载链接】sanicAccelerate your web app development | Build fast. Run fast.项目地址: https://gitcode.com/gh_mirrors/sa/sanic

导读

本文基于 Sanic 官方部署指南(guide/content/en/guide/deployment/caddy.md),完整讲解如何让 Sanic 应用在本地端口监听,由 Caddy 作为面向公网的入口服务器:自动签发 Let's Encrypt TLS 证书、支持 HTTP/1.1/2/3、处理反向代理头,并进一步将静态文件托管、Brotli 预压缩与 Unix Socket 通信等高级玩法落到可复制的配置。读完你将掌握一套从单行命令起步、到 Caddyfile 与 Sanic 代理头配置的完整部署方案。

部署架构一览

Caddy 是一款现代 Web 服务器与反向代理,支持最高 HTTP/3 协议。它的简洁性体现在极简配置和内置能力上:自动为你的域名从 Let's Encrypt 申请 TLS 证书,无需手动管理证书续期。

在本部署方案中,分工如下:

组件角色监听位置
Sanic 应用业务后端,仅监听本地127.0.0.1:8001
Caddy面向公网的入口代理example.com:443(TCP/UDP)

Caddy 承担 TLS 终止、HTTP 到 HTTPS 跳转、反向代理头注入、流式传输与 WebSocket 转发,Sanic 只关心业务逻辑。Caddy 可通过各平台(Windows、Linux、Mac)的软件包管理器安装,软件包名为caddy

第一步:准备一个"可被代理"的 Sanic 应用

以官方指南中的proxied_example.py为例:

from sanic import Sanic from sanic.response import text app = Sanic("proxied_example") @app.get("/") def index(request): # This should display external (public) addresses: return text( f"{request.remote_addr} connected to {request.url_for('index')}\n" f"Forwarded: {request.forwarded}\n" )

保存为proxied_example.py,通过 Sanic 命令行接口启动:

SANIC_PROXIES_COUNT=1 sanic proxied_example --port 8001

设置SANIC_PROXIES_COUNT环境变量的作用是告诉 Sanic 信任 Caddy 发送的 X-Forwarded-* 请求头,从而正确识别真实客户端的 IP 地址等信息。注意此时--port 8001仅绑定本地回环地址127.0.0.1,外部流量必须经由 Caddy 进入。

代理头在源码层面是如何生效的

SANIC_PROXIES_COUNT对应应用配置中的PROXIES_COUNT,默认值为None(见 sanic/config.py),即默认不信任任何代理头——这本身就是一道安全防线:恶意客户端无法通过伪造X-Forwarded-For来伪装自己的 IP。

当配置了PROXIES_COUNT后,sanic/headers.py 中的parse_xforwarded会:

  1. 读取REAL_IP_HEADER指定头部(如CF-Connecting-IP)作为直接来源;
  2. 否则拼接、拆分并过滤X-Forwarded-For链中的所有 IP(FORWARDED_FOR_HEADER默认即X-Forwarded-For);
  3. 取链中倒数第PROXIES_COUNT个 IP 作为真实客户端地址:addr = proxies[-proxies_count],即"前面每一跳都是代理,只有倒数第 N 个才是用户"。

随后请求对象的request.forwarded属性会综合 RFC 7239Forwarded头与传统 X-头(x-forwarded-protox-forwarded-hostx-forwarded-portx-forwarded-pathx-scheme),归一化出forprotohostportpath字段(实现见 sanic/request/types.py)。request.remote_addr即取forwarded["for"]的值;若要"有代理读代理、无代理读直连",可优先使用request.client_ipself.remote_addr or self.ip,见 sanic/request/types.py)。

相关配置项在 sanic/config.py 中的默认值如下:

配置项默认值说明
PROXIES_COUNTNone信任的代理层数,须为正整数
REAL_IP_HEADERNone直接携带真实 IP 的头部名
FORWARDED_FOR_HEADERX-Forwarded-For传统代理链头部
FORWARDED_SECRETNoneRFC 7239Forwarded头的校验密钥

更完整的代理头语义(含FORWARDED_SECRET用法与 curl 验证示例)可参见 guide/content/en/guide/advanced/proxy-headers.md。另外注意:PROXIES_COUNT为负数会触发断言错误,对应测试见 tests/test_config.py。

第二步:一行命令完成公网部署

如果你机器上没有运行其他 Web 服务器,可以直接用 Caddy 命令行(Linux 下需要sudo):

caddy reverse-proxy --from example.com --to :8001

这条命令背后是一个完整的生产级服务器:为你的域名申请并管理证书、HTTP 自动跳转 HTTPS、注入反向代理头、支持流式传输和 WebSocket。执行后,你的 Sanic 应用即可通过 HTTP/1.1、HTTP/2 与 HTTP/3 三种版本对外提供服务。

提醒:要在公网启用 HTTP/3(基于 QUIC),请记得在防火墙中开放UDP/443端口;仅开放 TCP/443 无法建立 H3 连接。

第三步:从命令行到 Caddyfile

单行命令适合起步,但很快你会需要托管多个站点、或对细节有更多控制——此时应当使用配置文件。上面的命令等价于以下Caddyfile,它也是你部署的起点:

example.com { reverse_proxy localhost:8001 }

Caddy 配置的加载方式

部分 Linux 发行版安装 Caddy 后,会自动从/etc/caddy/Caddyfile读取配置,并对每个站点执行import /etc/caddy/conf.d/*。如果你的发行版没有这样的机制,则需要手动将caddy run作为系统服务运行,并指向正确的配置文件:

caddy run --config /path/to/Caddyfile

另一种方式是使用 Caddy 的 API 模式持久化修改配置:

caddy run --resume

需要特别留意:任何一次 Caddyfile 的加载都会替换掉此前全部配置,因此传统方式下,caddy-api管理接口所保存的配置并不与 Caddyfile 混用。

第四步(进阶):静态资源卸载与 Unix Socket

有时你希望站点根路径同时服务静态文件与业务处理器,获得更干净的 URL。在 Sanic 中可以这样实现:

app.static("/", "static", index="index.html")

app.static的完整签名见 sanic/mixins/static.py,除index外还支持stream_large_files(大文件流式传输)、use_content_range(范围请求)、directory_view(目录浏览)等参数。

不过,为了更好的性能,可以把静态文件服务卸载给 Caddy,让 Sanic 专注于动态请求:

app.example.com { # Look for static files first, proxy to Sanic if not found route { file_server { root /srv/sanicexample/static precompress br # brotli your large scripts and styles pass_thru } reverse_proxy unix//tmp/sanic.socket # sanic --unix /tmp/sanic.socket } }

这段配置的三个要点:

  • file_server:指定静态文件根目录/srv/sanicexample/staticprecompress br预先用 Brotli 压缩体积较大的脚本和样式文件并直接下发;pass_thru表示未命中静态文件时继续走后续处理流程,即把请求转交给反向代理;
  • reverse_proxy unix//tmp/sanic.socket:通过 Unix Domain Socket 转发动态请求,省去 TCP 回环开销;
  • Sanic 侧对应启动方式sanic --unix /tmp/sanic.socket,即让应用监听 Unix Socket 而非 TCP 端口。代码中亦可等价地通过app.run(unix="./uds_socket")指定(见 examples/unix_socket.py),Nginx 部署指南中同样给出了 Unix Socket 的上游写法可作参照(见 guide/content/en/guide/deployment/nginx.md)。

验证与排查建议

完成部署后,可以在浏览器或 curl 中检查:

  • https://example.com/应展示request.remote_addr为真实公网 IP,request.forwarded中包含for/proto等字段,证明代理头配置生效;
  • remote_addr显示为127.0.0.1之类的代理地址,优先检查SANIC_PROXIES_COUNT是否设置、Caddy 是否正常注入代理头;
  • 若 HTTP/3 不可用,确认防火墙已开放 UDP/443,并可用支持 QUIC 的浏览器访问验证。

更多 Caddy 指令与高级选项(如负载均衡、访问日志、重写规则),可查阅 Caddy 官方文档;Sanic 侧的代理头语义与FORWARDED_SECRET的强校验用法,则可继续阅读仓库中的 代理配置指南。

【免费下载链接】sanicAccelerate your web app development | Build fast. Run fast.项目地址: https://gitcode.com/gh_mirrors/sa/sanic

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询