使用Traefik 2实现非www到www重定向的系列问题排查
需求
实现将非www域名(如https://domainname.com)重定向至带www的域名(https://www.domainname.com)。
初始配置及问题
编写了包含Traefik 2和PHP服务的docker-compose.yml配置:
version: "3.9" services: traefik: build: ./traefik image: image-traefik-eb:v.1.0 container_name: container-traefik-eb command: - --log.level=INFO - --log.filePath=/data-log/traefik.log - --log.format=json - --accesslog=true - --api.insecure - --api.dashboard - --providers.docker - --providers.docker.exposedbydefault=false - --entrypoints.web.address=:80 - --entrypoints.web.http.redirections.entryPoint.to=websecure - --entrypoints.web.http.redirections.entrypoint.scheme=https - --entrypoints.websecure.address=:443 - --entrypoints.websecure.http.tls=true - --entrypoints.websecure.http.tls.certresolver=leresolver - --certificatesresolvers.leresolver.acme.tlsChallenge=true - --certificatesresolvers.leresolver.acme.email=#########@gmail.com - --certificatesresolvers.leresolver.acme.storage=/letsencrypt/acme.json - --entrypoints.websecure.http.middlewares.redirect-non-www-to-www.redirectregex.permanent=true - --entrypoints.websecure.http.middlewares.redirect-non-www-to-www.redirectregex.regex="^https?://(?:www\.)?(.+)" - --entrypoints.websecure.http.middlewares.redirect-non-www-to-www.redirectregex.replacement="https://www.${1}" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./volumes/data-letsencrypt/:/letsencrypt - ./volumes/data-log/:/data-log/ restart: always ports: - 80:80 - 443:443 networks: - eb - traefik-network php: build: ./php-apache image: image-php-apache-eb:v.1.0 labels: traefik.enable: 'true' traefik.http.services.php.loadbalancer.server.port: 80 traefik.http.services.php.loadbalancer.server.scheme: http traefik.http.routers.php.rule: Host(`www.#########.ml`,`#########.ml`) traefik.http.routers.php.middlewares: redirect-non-www-to-www volumes: - ./volumes/data-php:/var/www/html restart: always depends_on: - traefik networks: - eb networks: eb: internal: true traefik-network:
配套Dockerfile:
FROM php:8.1-apache EXPOSE 80
FROM traefik:v2.8.0
执行后触发错误:
ERROR: Invalid interpolation format for "command" option in service "traefik": "--entrypoints.websecure.http.middlewares.redirect-non-www-to-www.redirectregex.replacement="https://www.${1}""
调整配置后的情况
修改配置后内容如下:
version: "3.9" services: traefik: build: ./traefik image: image-traefik-eb:v.1.0 container_name: container-traefik-eb command: - --log.level=INFO - --log.filePath=/data-log/traefik.log - --log.format=json - --accesslog=true - --api.insecure=false - --api.dashboard=true - --providers.docker - --providers.docker.exposedbydefault=false - --entrypoints.web.address=:80 - --entrypoints.web.http.redirections.entryPoint.to=websecure - --entrypoints.web.http.redirections.entrypoint.scheme=https - --entrypoints.websecure.address=:443 - --entrypoints.websecure.http.tls=true - --entrypoints.websecure.http.tls.certresolver=leresolver - --certificatesresolvers.leresolver.acme.tlsChallenge=true - --certificatesresolvers.leresolver.acme.email=domain-name@gmail.com - --certificatesresolvers.leresolver.acme.storage=/letsencrypt/acme.json labels: traefik.enable: true traefik.http.routers.dashboard.rule: Host(`www.traefik.domain-name.ga`) traefik.http.routers.dashboard.service: api@internal traefik.http.routers.dashboard.middlewares: auth traefik.http.middlewares.auth.basicauth.users: user:*********************** traefik.http.routers.unmatchedwww.rule: HostRegexp(`{name:^www\..*}`) traefik.http.routers.unmatchedwww.service: noop@internal traefik.http.routers.unmatchedwww.priority: 2 traefik.http.routers.matchlast.rule: PathPrefix(`/`) traefik.http.routers.matchlast.priority: 1 traefik.http.routers.matchlast.middlewares: addwww traefik.http.middlewares.addwww.redirectregex.regex: ^https://(?:www\.)?(.*) traefik.http.middlewares.addwww.redirectregex.replacement: https://www.$${1} volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./volumes/data-letsencrypt/:/letsencrypt - ./volumes/data-log/:/data-log/ restart: always ports: - 80:80 - 443:443 networks: - eb - traefik-network php: build: ./php-apache image: image-php-apache-eb:v.1.0 labels: traefik.enable: 'true' traefik.http.services.php.loadbalancer.server.port: 80 traefik.http.services.php.loadbalancer.server.scheme: http traefik.http.routers.php.rule: Host(`www.domain-name.ga`) traefik.http.routers.php.tls.domains[0].main: domain-name.ga traefik.http.routers.php.tls.domains[0].sans: www.domain-name.ga volumes: - ./volumes/data-php:/var/www/html restart: always depends_on: - traefik networks: - eb networks: eb: internal: true traefik-network:
配套Dockerfile:
FROM traefik:v2.8.0
FROM php:8.1-apache EXPOSE 80
此时实现了以下功能:
- 可通过有效证书以安全模式访问Traefik仪表盘;
- 正常访问PHP服务;
- 完成HTTP到HTTPS、非www到www的重定向;
但存在两个问题: - PHP服务的index.php没有有效证书(仅仪表盘有证书);
- 域名服务器出现大量错误警告。
进一步调整后的剩余问题
添加以下配置后情况有所改善:
traefik.http.routers.php.tls.certresolver: leresolver Host(`www.traefik.domain-name.ga`,`traefik.domain-name.ga`)
但https://traefik.domain-name.ga/和http://traefik.domain-name.ga/仍无法正常工作,现寻求完整解决方案。
完整解决方案
核心问题分析
- 初始错误源于Docker Compose会解析
${1}作为环境变量插值,需转义为$$${1}; - PHP服务证书问题是未指定证书解析器,导致无法自动申请覆盖主域名和子域名的证书;
- 仪表盘非www域名无法访问是因为路由规则未覆盖该域名,且缺少对应重定向逻辑。
最终配置文件
docker-compose.yml
version: "3.9" services: traefik: build: ./traefik image: image-traefik-eb:v.1.0 container_name: container-traefik-eb command: - --log.level=INFO - --log.filePath=/data-log/traefik.log - --log.format=json - --accesslog=true - --api.insecure=false - --api.dashboard=true - --providers.docker - --providers.docker.exposedbydefault=false - --entrypoints.web.address=:80 # HTTP强制跳转HTTPS(永久重定向) - --entrypoints.web.http.redirections.entryPoint.to=websecure - --entrypoints.web.http.redirections.entryPoint.scheme=https - --entrypoints.web.http.redirections.entryPoint.permanent=true - --entrypoints.websecure.address=:443 - --entrypoints.websecure.http.tls=true - --entrypoints.websecure.http.tls.certresolver=leresolver # ACME证书配置 - --certificatesresolvers.leresolver.acme.tlsChallenge=true - --certificatesresolvers.leresolver.acme.email=your-email@gmail.com - --certificatesresolvers.leresolver.acme.storage=/letsencrypt/acme.json # 全局绑定非www转www中间件 - --entrypoints.websecure.http.middlewares=redirect-non-www-to-www@docker labels: traefik.enable: true # 仪表盘路由:同时匹配www和非www域名 traefik.http.routers.dashboard.rule: Host(`www.traefik.domain-name.ga`, `traefik.domain-name.ga`) traefik.http.routers.dashboard.service: api@internal traefik.http.routers.dashboard.middlewares: auth traefik.http.middlewares.auth.basicauth.users: user:your-encrypted-password # 非www转www全局中间件 traefik.http.middlewares.redirect-non-www-to-www.redirectregex.regex: ^https?://(?:www\.)?(.+) traefik.http.middlewares.redirect-non-www-to-www.redirectregex.replacement: https://www.$$${1} traefik.http.middlewares.redirect-non-www-to-www.redirectregex.permanent: true volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./volumes/data-letsencrypt/:/letsencrypt - ./volumes/data-log/:/data-log/ restart: always ports: - 80:80 - 443:443 networks: - eb - traefik-network php: build: ./php-apache image: image-php-apache-eb:v.1.0 labels: traefik.enable: 'true' traefik.http.services.php.loadbalancer.server.port: 80 traefik.http.services.php.loadbalancer.server.scheme: http # PHP服务路由:同时匹配www和非www域名 traefik.http.routers.php.rule: Host(`www.domain-name.ga`, `domain-name.ga`) # 启用TLS并指定证书解析器 traefik.http.routers.php.tls: true traefik.http.routers.php.tls.certresolver: leresolver # 配置证书涵盖主域名和www子域名 traefik.http.routers.php.tls.domains[0].main: domain-name.ga traefik.http.routers.php.tls.domains[0].sans: www.domain-name.ga volumes: - ./volumes/data-php:/var/www/html restart: always depends_on: - traefik networks: - eb networks: eb: internal: true traefik-network:
Dockerfile(Traefik)
FROM traefik:v2.8.0
Dockerfile(PHP-Apache)
FROM php:8.1-apache EXPOSE 80
配置说明
- 环境变量转义:将正则替换中的
${1}改为$$${1},避免Docker Compose误解析为环境变量; - 全局中间件:将非www转www的中间件设置为WebSecure入口的默认中间件,所有HTTPS请求自动应用重定向;
- 证书问题解决:给PHP服务路由指定证书解析器,让Traefik自动申请包含主域名和www子域名的有效证书;
- 仪表盘路由覆盖:修改仪表盘路由规则,同时匹配www和非www域名,结合全局重定向中间件实现自动跳转;
- 增强HTTP跳转:设置HTTP到HTTPS的跳转为永久重定向,提升搜索引擎优化效果。
验证步骤
- 删除旧的
acme.json文件(若存在),避免证书缓存干扰; - 执行
docker-compose up -d启动服务; - 访问
http://domain-name.ga、https://domain-name.ga,验证是否自动跳转至https://www.domain-name.ga且证书有效; - 访问
http://traefik.domain-name.ga、https://traefik.domain-name.ga,验证是否自动跳转至https://www.traefik.domain-name.ga且证书有效; - 查看Traefik日志,确认无证书相关错误信息。
内容的提问来源于stack exchange,提问作者Federico Galimberti
相关产品推荐
相关产品推荐

