You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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/仍无法正常工作,现寻求完整解决方案。

完整解决方案

核心问题分析

  1. 初始错误源于Docker Compose会解析${1}作为环境变量插值,需转义为$$${1};
  2. PHP服务证书问题是未指定证书解析器,导致无法自动申请覆盖主域名和子域名的证书;
  3. 仪表盘非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}改为$$${1},避免Docker Compose误解析为环境变量;
  2. 全局中间件:将非www转www的中间件设置为WebSecure入口的默认中间件,所有HTTPS请求自动应用重定向;
  3. 证书问题解决:给PHP服务路由指定证书解析器,让Traefik自动申请包含主域名和www子域名的有效证书;
  4. 仪表盘路由覆盖:修改仪表盘路由规则,同时匹配www和非www域名,结合全局重定向中间件实现自动跳转;
  5. 增强HTTP跳转:设置HTTP到HTTPS的跳转为永久重定向,提升搜索引擎优化效果。

验证步骤

  1. 删除旧的acme.json文件(若存在),避免证书缓存干扰;
  2. 执行docker-compose up -d启动服务;
  3. 访问http://domain-name.ga、https://domain-name.ga,验证是否自动跳转至https://www.domain-name.ga且证书有效;
  4. 访问http://traefik.domain-name.ga、https://traefik.domain-name.ga,验证是否自动跳转至https://www.traefik.domain-name.ga且证书有效;
  5. 查看Traefik日志,确认无证书相关错误信息。

内容的提问来源于stack exchange,提问作者Federico Galimberti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 23:19:01