Docker环境下Traefik对接Varnish时如何实现SSL终止
解决Traefik+Varnish架构中HTTPS请求缓存未命中的问题
首先咱们理清问题核心:你已经通过Traefik完成了SSL终止(配置了web-secured入口点和TLS证书解析器),HTTPS请求到Traefik后会被转换成HTTP请求转发给Varnish,但所有HTTPS请求都显示MISS,根本原因出在Varnish的缓存键规则上。
问题根源
Varnish默认的缓存哈希键会包含请求头中的部分字段,其中Traefik自动添加的X-Forwarded-Proto头是关键——HTTPS请求的这个头值为https,HTTP请求的则是http。这就导致同一个URL的HTTPS和HTTP请求被Varnish判定为不同请求,生成不同的缓存键,自然无法命中缓存。
解决方案
我们需要调整Varnish的VCL配置,统一缓存规则,同时优化Traefik的转发逻辑。
1. 修改Varnish的default.vcl配置
调整缓存键生成规则,忽略协议差异带来的影响,同时保留必要的客户端信息:
vcl 4.0; backend default { .host = "dev-ui-service"; .port = "4200"; } sub vcl_recv { # 信任Traefik传递的X-Forwarded-Proto头(Traefik作为SSL终止点,这个头是可信的) set req.http.X-Forwarded-Proto = req.http.X-Forwarded-Proto || "http"; # 移除X-Forwarded-Proto头,让Varnish生成缓存键时忽略协议差异 # 这样HTTP和HTTPS请求会共享同一缓存(如果业务内容一致) unset req.http.X-Forwarded-Proto; # 跳过非GET/HEAD请求的缓存(POST/PUT等动态请求通常不需要缓存) if (req.method != "GET" && req.method != "HEAD") { return (pass); } } sub vcl_deliver { # 显示缓存命中/未命中状态 if (obj.hits > 0) { set resp.http.V-Cache = "HIT"; } else { set resp.http.V-Cache = "MISS"; } # 回写正确的协议头给客户端,确保客户端感知到HTTPS连接 set resp.http.X-Forwarded-Proto = "https"; # 保留你原来的CORS配置 set resp.http.Access-Control-Allow-Origin = "*"; set resp.http.Access-Control-Allow-Headers = "Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Mx-ReqToken,X-Requested-With"; set resp.http.Allow = "GET, POST"; set resp.http.Access-Control-Allow-Credentials = "true"; set resp.http.Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, OPTIONS, PATCH"; set resp.http.Access-Control-Expose-Headers = "X-Pagination-Total, X-Pagination-Page, X-Pagination-Limit"; } sub vcl_backend_response { if (beresp.status == 200) { unset beresp.http.Cache-Control; set beresp.http.Cache-Control = "public; max-age=200"; set beresp.ttl = 200s; } set beresp.http.Served-By = beresp.backend.name; set beresp.http.V-Cache-TTL = beresp.ttl; set beresp.http.V-Cache-Grace = beresp.grace; }
2. (可选)在Traefik层面强制HTTP转HTTPS
如果你的业务只允许HTTPS访问,可以修改Varnish的Traefik标签,添加重定向中间件,彻底避免HTTP请求的干扰:
deploy: labels: - "traefik.enable=true" # HTTP路由器:将所有HTTP请求重定向到HTTPS - "traefik.http.routers.ui.rule=Host(`mydomain.com`)" - "traefik.http.routers.ui.entrypoints=web" - "traefik.http.routers.ui.middlewares=redirect-to-https" # HTTPS路由器:处理加密请求 - "traefik.http.routers.ui-secured.rule=Host(`mydomain.com`)" - "traefik.http.routers.ui-secured.entrypoints=web-secured" - "traefik.http.routers.ui-secured.tls.certresolver=mytlschallenge" - "traefik.http.services.ui.loadbalancer.server.port=80" - "traefik.docker.network=traefik-proxy" # 定义重定向中间件 - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
3. 验证配置
修改完成后,重启Varnish服务:
docker-compose up -d --force-recreate varnish
多次访问https://mydomain.com,用curl -I https://mydomain.com查看响应头,第一次会显示V-Cache: MISS,后续刷新应该会变成V-Cache: HIT,说明缓存已经正常生效。
内容的提问来源于stack exchange,提问作者Mostafa Azarirad
相关产品推荐
相关产品推荐

