与 Traefik 2.0 的讨论

大家好,

我正在迁移到新服务器,并希望使用 Traefik 2.0 作为反向代理。目前我在新的配置上遇到了困难。我在 app.yml 文件底部添加了一个部分。(来源:https://meta.discourse.org/t/discourse-behind-traefik/84874)

...

expose:
  - "8060:80"   # http
  - "8070:443" # https

...

docker_args:
  - "--network=web"
  - "--expose=8060"
  - "-l traefik.enable=true"
  - "-l traefik.http.routers.forum.rule=Host(`forum.example.com`)"
  - "-l traefik.http.routers.forum.entrypoints=websecure"
  - "-l traefik.http.routers.forum.tls=true"
  - "-l traefik.http.routers.forum.tls.certresolver=mytlschallenge"
  - "-l traefik.http.services.forum.loadbalancer.server.port=8060"
  - "-l traefik.docker.network=web"

这似乎不起作用。当我访问该路由时,会收到 Bad Gateway 错误。但如果直接访问 ip_adress:8060,Discourse 可以正常打开。

有人有使用 Traefik 2.0 的经验吗?

谢谢!

经过一番尝试,我已经自行解决了问题。

供后续参考,附上我的 app.yml:

...

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## 如果希望添加 Let's Encrypt (https),请取消以下两行的注释
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"
  #- "templates/web.socketed.template.yml" 

## 此容器应暴露哪些 TCP/IP 端口?
## 如果您希望 Discourse 与 Apache 或 nginx 等其他 Web 服务器共享端口,
## 请参阅 https://meta.discourse.org/t/17247 了解详情
#expose:
#  - "8060:80"   # http
#  - "8070:443" # https

...

docker_args:
  - "--network=web"
  #- "--expose=8060"
  - "-l traefik.enable=true"
  - "-l traefik.http.routers.forum.rule=Host(`forum.example.com`)"
  - "-l traefik.http.routers.forum.entrypoints=websecure"
  - "-l traefik.http.routers.forum.tls=true"
  - "-l traefik.http.routers.forum.tls.certresolver=mytlschallenge"
  - "-l traefik.http.services.forum.loadbalancer.server.port=80"
  - "-l traefik.docker.network=web"

为什么有必要使用 docker_args?根据 GitHub - discourse/discourse_docker: A Docker image for Discourse · GitHub 的说明,应该这样写:

labels:
  monitor: 'true'
  app_name: {{config}}_discourse

为当前容器添加标签。上述配置将在运行容器时向选项添加 --l monitor=true -l app_name=dev_discourse。

此外,docker_args 在哪里有说明?

@Cameron_D
你是怎么发现应该使用 docker_args 的?

我无法让标签部分按预期工作。我不确定具体是为什么它不再起作用,也不确定之后是否已修复,因为我的配置保持不变,目前它能正常工作。

你好,
你能分享一下你的 Traefik 配置吗?

我遇到了 302 重定向,它会自动跳转到 https,然后就没有下文了……
Traefik 仪表板显示一切正常。

我的 docker-compose.yml 在这里
version: "3.7"
    services:
      traefik-reverse-proxy:   
        # 官方 v2.0 Traefik Docker 镜像
        image: traefik:latest #traefik:v2.0
        container_name: "traefik"       
        command:
          # 告诉 Traefik 监听 Docker
          - --providers.docker          # (默认: true)
          # 启用 API/仪表板 / (设置 Docker 端点以与 Docker API 通信)
          - --api=true                    # (默认: false)
          # 激活仪表板。
          - --api.dashboard               # (默认: true)
          # 启用 Web UI / Traefik 默认在端口 8080 监听 API 请求。/ 直接在名为 traefik 的入口点激活 API。(默认: false) --> 端口 '8080'v= 入口点 'traefik',覆盖 --api
          - --api.insecure=true         # (默认: false) 
          # 启用用于调试和分析的附加端点。
          - --api.debug=true            # (默认: false)
          # 设置日志的调试级别
          - --log.level=DEBUG    
          # 写入访问日志
          - --accesslog=true    
          # 定义容器内的存储位置,日志文件写入容器内部。为了在主机上可用,已挂载,请参见 volumes 部分
          - --log.filePath=/var/traefik-container/logs/traefik-log.log
          - --accesslog.filepath=/var/traefik-container/logs/traefik-access.log
          # 覆盖默认端口 80 的入口点名称为 "web"
          - --entrypoints.web.address=:80
          # 声明端口 443 的入口点名称
          - --entrypoints.websecure.address=:443
          #--providers.docker.endpoint=unix:///var/run/docker.sock    
          # Let's Encrypt
          - --certificatesresolvers.mytlschallenge.acme.tlschallenge=true
          - --certificatesresolvers.mytlschallenge.acme.email=my@email.com
          - --certificatesresolvers.mytlschallenge.acme.storage=/var/traefik-container/letsencrypt/acme.json
        ports:
          # HTTP 端口
          - "80:80"
          # HTTPS 端口
          - "443:443"
          # Web UI (通过 --api.insecure=true 启用)
          - "8080:8080"
        volumes:        # 语法 --> 主机位置:容器内路径
          # 以便 Traefik 可以监听 Docker 事件
          - /var/run/docker.sock:/var/run/docker.sock
          - /var/traefik/log:/var/traefik-container/logs
          - /var/traefik/letsencrypt:/var/traefik-container/letsencrypt
        labels:
          - "traefik.enable=true"
          - "traefik.docker.network=bridge_proxy_traefikv2"
          - "traefik.http.routers.traefikv2.rule=Host(`traefik.mydomain.community`)"
          - "traefik.http.routers.traefikv2.entrypoints=web"
          - "traefik.http.services.traefikv2.loadBalancer.server.port=80"

        networks:
          - traefik
          #- default
          
       # 一个小型 Go Web 服务器,将操作系统信息和 HTTP 请求打印到输出
    #  whoami:
    #    image: "containous/whoami"
    #    container_name: "whoami"
    #    labels:
    #      - "traefik.enable=true"
    #      - "traefik.docker.network=bridge_proxy_traefikv2"
    #      - "traefik.http.routers.whoami.rule=Host(`mydomain.community`)"
    #      - "traefik.http.routers.whoami.entrypoints=web"
    #      - "traefik.http.services.whoami.loadBalancer.server.port=80"
    #    networks:
    #      - traefik
    #      #- default
          
      whoami_sub:
        image: "containous/whoami"
        container_name: "whoami_sub"
        labels:
          - "traefik.enable=true"
          - "traefik.name=whoami_sub"
          - "traefik.docker.network=bridge_proxy_traefikv2"
          - "traefik.http.routers.whoami_sub.rule=Host(`whoami.mydomain.community`)"
          - "traefik.http.routers.whoami_sub.entrypoints=web"
          #- "traefik.http.services.whoami_sub.loadBalancer.server.port=80"
        networks:
          - traefik
          - default

    networks:
      traefik:
        external:
          name: bridge_proxy_traefikv2
我的 Discourse app.yml 在这里
## 这是 Discourse 的一体化独立 Docker 容器模板
##
## 修改此文件后,您必须重新构建
## /var/discourse/launcher rebuild app
##
## 编辑时请 *非常* 小心!
## YAML 文件对空白或对齐错误超级敏感!
## 如有需要,请访问 http://www.yamllint.com/ 验证此文件

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## 如果您想添加 Let's Encrypt (https),请取消注释这两行
  - "templates/web.ssl.template.yml"
  - "templates/web.letsencrypt.ssl.template.yml"

## 此容器应暴露哪些 TCP/IP 端口?
## 如果您希望 Discourse 与另一个 Web 服务器(如 Apache 或 nginx)共享端口,
## 请参阅 https://meta.discourse.org/t/17247 了解详情
expose:
#  - "80:80"   # http
#  - "443:443" # https

params:
  db_default_text_search_config: "pg_catalog.english"

  ## 将 db_shared_buffers 设置为总内存的最大 25%。
  ## 将根据检测到的 RAM 自动设置,或者您可以覆盖
  db_shared_buffers: "128MB"

  ## 可以提高排序性能,但会增加每个连接的内存使用量
  #db_work_mem: "40MB"

  ## 此容器应使用哪个 Git 修订版本?(默认: tests-passed)
  #version: tests-passed

labels:
  app_name:                                                 discourse  
  traefik.enable:                                           true
  traefik.docker.network:                                   bridge_proxy_traefikv2  
  traefik.http.services.forum.loadbalancer.server.port:     80
  traefik.http.routers.forum.rule:                          Host(`forum.mydomain.community`)
  traefik.http.routers.forum.entrypoints:                   websecure
  traefik.http.routers.forum.tls:                           true
  traefik.http.routers.forum.tls.certresolver:              mytlschallenge
     
docker_args:
  - "--network=bridge_proxy_traefikv2"
 # - "-l traefik.enable=true"
 # - "-l traefik.http.routers.forum.rule=Host(`fairbnb.community`)"
 # - "-l traefik.http.routers.forum.entrypoints=websecure"
 # - "-l traefik.http.routers.forum.tls=true"
 # - "-l traefik.http.routers.forum.tls.certresolver=mytlschallenge"
 # - "-l traefik.http.services.forum.loadbalancer.server.port=80"
 # - "-l traefik.docker.network=web"
  
env:
  LANG: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  ## 支持多少个并发 Web 请求?取决于内存和 CPU 核心数。
  ## 将根据检测到的 CPU 自动设置,或者您可以覆盖
  UNICORN_WORKERS: 2

  ## TODO: 此 Discourse 实例将响应的域名
  ## 必需。Discourse 无法在纯 IP 地址上运行。
  DISCOURSE_HOSTNAME: forum.fairbnb.community

  ## 如果您希望容器使用与上面指定的相同的主机名 (-h 选项) 启动,请取消注释
  ## (默认 "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: 初始注册时将被设为管理员和开发者的逗号分隔电子邮件列表
  ## 示例 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'discourse@myemail.com'

  ## TODO: 用于验证新账户和发送通知的 SMTP 邮件服务器
  # SMTP 地址、用户名和密码是必需的
  # 警告:SMTP 密码中的字符 '#' 可能会导致问题!
  DISCOURSE_SMTP_ADDRESS: smtp.zoho.eu
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: discourse@myemail.com
  DISCOURSE_SMTP_PASSWORD: "tempPassword"
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (可选,默认 true)

  ## 如果您添加了 Let's Encrypt 模板,请取消注释以下行以获取免费 SSL 证书
  LETSENCRYPT_ACCOUNT_EMAIL: me@example.com

  ## 此 Discourse 实例的 http 或 https CDN 地址(配置为拉取)
  ## 请参阅 https://meta.discourse.org/t/14857 了解详情
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com
  
## Docker 容器是无状态的;所有数据都存储在 /shared 中
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## 插件放在这里
## 请参阅 https://meta.discourse.org/t/19157 了解详情
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

## 构建后运行的任何自定义命令
run:
  - exec: echo "开始自定义命令"
  ## 如果您想设置首次注册的 'From' 电子邮件地址,请取消注释并更改:
  ## 收到首次注册邮件后,请重新注释该行。它只需运行一次。
  - exec: rails r "SiteSetting.notification_email='discourse@zoho.fairbnb.community'"
  - exec: echo "结束自定义命令"

在通过子域名使 Traefik 仪表板可用方面存在问题,但 Discourse 仍然无法访问,详见 Discourse with Traefik 2.0 - Traefik v2 - Traefik Labs Community Forum
以下是我的可用配置。

  1. 带我的注释

    docker-compose: traefikV2_docker-compose.yaml
    # https://stackoverflow.com/questions/49718431/docker-compose-yml-file-naming-convention
    version: "3.7"
    
    services:
      traefik-reverse-proxy:   
        # Traefik 官方 v2.0 Docker 镜像
        #image: traefik:latest 
        #image: traefik:v2.0
        image: traefik:v2.1.1
        container_name: traefik
        #command: 
        ## 若要使用自定义的 Traefik 配置文件,必须声明本地路径并将该位置挂载到主机,请参阅 volumes 部分
        #- --configFile=/etc/traefik/traefik-config.yaml
        
        ports:
          # HTTP 端口
          - 80:80
          # HTTPS 端口
          - 443:443
          # Web UI(通过 --api.insecure=true 启用)
          #- "8080:8080"
        
        volumes:         
        # 语法 --> 主机位置:容器内路径,参见 https://docs.docker.com/compose/compose-file/#volumes
          # 以便 Traefik 可以监听 Docker 事件
          - /var/run/docker.sock:/var/run/docker.sock
          # 将日志文件位置挂载到主机,以便我可以在主机上读取它们
            # 基于 https://unix.stackexchange.com/questions/104936/where-are-all-the-posibilities-of-storing-a-log-file
          - /var/log/traefik:/var/log
          # 将证书位置挂载到主机,以便我可以在主机上读取它们
            # 基于 https://www.getpagespeed.com/server-setup/ssl-directory 和 https://serverfault.com/questions/62496/ssl-certificate-location-on-unix-linux
          - /etc/ssl/certs/traefik/letsencrypt:/etc/ssl/certs/letsencrypt
          # 我使用自定义的 "traefik.toml",因此必须将其挂载到 Traefik 容器中(或存储在那里),结合
            # https://stackoverflow.com/questions/47382756/why-is-my-traefik-toml-file-not-be-read-by-docker-compose-configuration
            # https://stackoverflow.com/questions/57200728/can-the-default-location-of-the-traefik-configuration-file-be-changed-in-the-off
            # https://stackoverflow.com/questions/45902133/how-to-use-custom-traefik-toml-file
            # https://docs.traefik.io/getting-started/configuration-overview/
          - /opt/traefik/traefik-config.yaml:/etc/traefik/traefik.yaml
        
        labels:
          - traefik.enable=true
          #- "traefik.docker.network=bridge_proxy_traefikv2"
          - traefik.http.routers.traefik_dashboard-router.rule=Host(`traefik.fairbnb.community`)
          - traefik.http.routers.traefik_dashboard-router.entrypoints=web
          #- "traefik.http.services.traefik_dashboard-service.loadBalancer.server.port=8080"
          - traefik.http.routers.traefik_dashboard-router.service=api@internal
    
        networks:
          - traefik
          #- default
          
       # 一个打印操作系统信息和 HTTP 请求到输出的微型 Go Web 服务器
       #  whoami:
       #    image: "containous/whoami"
       #    container_name: "whoami"
       #    labels:
       #      - "traefik.enable=true"
       #      - "traefik.docker.network=bridge_proxy_traefikv2"
       #      - "traefik.http.routers.whoami-router.rule=Host(`fairbnb.community`)"
       #      - "traefik.http.routers.whoami-router.entrypoints=web"
       #      - "traefik.http.services.whoami-service.loadBalancer.server.port=80"
       #    networks:
       #      - traefik
       #      #- default
          
      whoami_viaSubdomain:
        image: "containous/whoami"
        container_name: "whoami_viaSubdomain"
        labels:
          - traefik.enable=true
          - traefik.docker.network=bridge_proxy_traefikv2
          - traefik.http.routers.whoami_viaSubdomain-router.rule=Host(`whoami.fairbnb.community`)
          - traefik.http.routers.whoami_viaSubdomain-router.entrypoints=web
          #- "traefik.http.services.whoami_viaSubdomain-service.loadBalancer.server.port=80"
        networks:
          - traefik
          #- default
    
    networks:
      traefik:
        external:
          name: bridge_proxy_traefikv2
           
           
    
    
    
    Traefik 配置:traefik-config.yaml
    global:
      checkNewVersion: true
    #  sendAnonymousUsage: true
    #serversTransport:
    #  insecureSkipVerify: true
    #  rootCAs:
    #  - foobar
    #  maxIdleConnsPerHost: 42
    #  forwardingTimeouts:
    #    dialTimeout: 42
    #    responseHeaderTimeout: 42
    #    idleConnTimeout: 42
    
    entryPoints:
      web:
        address: :80
        #transport:
        #  lifeCycle:
        #    requestAcceptGraceTimeout: 42
        #    graceTimeOut: 42
        #  respondingTimeouts:
        #    readTimeout: 42
        #    writeTimeout: 42
        #    idleTimeout: 42
        #proxyProtocol:
        #  insecure: true
        #  trustedIPs:
        #  - foobar
        #  - foobar
        #forwardedHeaders:
        #  insecure: true
        #  trustedIPs:
        #  - foobar
        #  - foobar
      websecure:
        address: :443
      #traefik_dashboard:
         #address: ":8080"     
    
    api: 
    #api: {}   
    # 激活仪表板。 
      ## 启用 Web UI @ 端口 8080 / Traefik 默认将在端口 8080 上监听 API 请求。/ 直接在名为 traefik 的 entryPoint 上激活 API。(默认:false)--> 端口 '8080'v= entryPoint 'traefik',覆盖 --api  
      #insecure: true
      ## 激活仪表板。(默认:true)
      # dashboard: true
      # 启用用于调试和分析的附加端点。 
       debug: true    
      
    providers:
    # providersThrottleDuration: 42
      docker:
        #constraints: foobar
        ## 监视提供者。(默认:true)
        #watch: true
        ## Docker 服务器端点。可以是 TCP 或 Unix socket 端点。(默认:unix:///var/run/docker.sock)
        #endpoint: unix:///var/run/docker.sock
        #defaultRule: foobar
        #tls:
          #ca: foobar
          #caOptional: true
          #cert: foobar
          #key: foobar
          #insecureSkipVerify: true
        # 默认暴露容器。(默认:true)/ 默认情况下,会为所有检测到的容器创建路由。若要限制 Traefik 服务发现的范围,即禁止为某些容器创建路由,可以通过两种方式实现:通用的 exposedByDefault(被 traefik.enable 覆盖),或基于约束的更细粒度机制。
        exposedByDefault: false
        #useBindPortIP: true
        #swarmMode: true
        # 默认 Docker 网络。
        network: bridge_proxy_traefikv2
        # swarmModeRefreshSeconds: 42  
    
    not used currently-metrics:    # 这仅用于在 Notepad++ 中折叠/展开注释区域
    #metrics:
    #  prometheus:
    #    buckets:
    #    - 42
    #    - 42
    #    addEntryPointsLabels: true
    #    addServicesLabels: true
    #    entryPoint: foobar
    #    manualRouting: true
    #  datadog:
    #    address: foobar
    #    pushInterval: 42
    #    addEntryPointsLabels: true
    #    addServicesLabels: true
    #  statsD:
    #    address: foobar
    #    pushInterval: 42
    #    addEntryPointsLabels: true
    #    addServicesLabels: true
    #    prefix: traefik
    #  influxDB:
    #    address: foobar
    #    protocol: foobar
    #    pushInterval: 42
    #    database: foobar
    #    retentionPolicy: foobar
    #    username: foobar
    #    password: foobar
    #    addEntryPointsLabels: true
    #    addServicesLabels: true
    #ping:
    #  entryPoint: foobar
    #  manualRouting: true
       #
    log:
    #Traefik 的日志文件 
      # 设置日志的调试级别
      level: DEBUG
      # 定义容器内的存储位置,日志文件在容器内写入。若要使其在主机上可用,需进行挂载,请参阅 docker-compose 文件中的 volumes 部分
        # 基于 https://unix.stackexchange.com/questions/104936/where-are-all-the-posibilities-of-storing-a-log-file
      filePath: /var/log/traefik-log.log
      # Traefik 日志格式:json | common(默认:common)
      #format: common
    
    accessLog:      
    # 记录访问尝试   
      # 定义容器内的存储位置,日志文件在容器内写入。若要使其在主机上可用,需进行挂载,请参阅 docker-compose 文件中的 volumes 部分
        # 基于 https://unix.stackexchange.com/questions/104936/where-are-all-the-posibilities-of-storing-a-log-file  
      filePath: /var/log/traefik-access.log
      # 访问日志格式:json | common(默认:common)
      #format: common
    #  filters:
    #    statusCodes:
    #    - foobar
    #    - foobar
    #    retryAttempts: true
    #    minDuration: 42
    #  fields:
    #    defaultMode: foobar
    #    names:
    #      name0: foobar
    #      name1: foobar
    #    headers:
    #      defaultMode: foobar
    #      names:
    #        name0: foobar
    #        name1: foobar
    #  bufferingSize: 42
       #
       
    not used currently-tracing:    # 这仅用于在 Notepad++ 中折叠/展开注释区域
    #tracing:   
    #  serviceName: foobar
    #  spanNameLimit: 42
    #  jaeger:
    #    samplingServerURL: foobar
    #    samplingType: foobar
    #    samplingParam: 42
    #    localAgentHostPort: foobar
    #    gen128Bit: true
    #    propagation: foobar
    #    traceContextHeaderName: foobar
    #    collector:
    #      endpoint: foobar
    #      user: foobar
    #      password: foobar
    #  zipkin:
    #    httpEndpoint: foobar
    #    sameSpan: true
    #    id128Bit: true
    #    sampleRate: 42
    #  datadog:
    #    localAgentHostPort: foobar
    #    globalTag: foobar
    #    debug: true
    #    prioritySampling: true
    #    traceIDHeaderName: foobar
    #    parentIDHeaderName: foobar
    #    samplingPriorityHeaderName: foobar
    #    bagagePrefixHeaderName: foobar
    #  instana:
    #    localAgentHost: foobar
    #    localAgentPort: 42
    #    logLevel: foobar
    #  haystack:
    #    localAgentHost: foobar
    #    localAgentPort: 42
    #    globalTag: foobar
    #    traceIDHeaderName: foobar
    #    parentIDHeaderName: foobar
    #    spanIDHeaderName: foobar
    #    baggagePrefixHeaderName: foobar
       #
    not used currently-hostResolver:     # 这仅用于在 Notepad++ 中折叠/展开注释区域
    #hostResolver:
    #  cnameFlattening: true
    #  resolvConfig: foobar
    #  resolvDepth: 42
      #
    certificatesResolvers:
      tlsChallenge_letsencrypt:
        acme:
          email: my.secret@gmail.com
          # 要使用的 CA 服务器。(默认:https://acme-v02.api.letsencrypt.org/directory)
          #caServer:        
          # 位置基于 https://www.getpagespeed.com/server-setup/ssl-directory 和 https://serverfault.com/questions/62496/ssl-certificate-location-on-unix-linux
          storage: /etc/ssl/certs/letsencrypt/acme.json
          # 用于生成证书私钥的 KeyType。允许的值 'EC256', 'EC384', 'RSA2048', 'RSA4096', 'RSA8192'。(默认:RSA4096)
          #keyType: {}         
          #dnsChallenge:
            # provider: foobar
            # delayBeforeCheck: 42
            # resolvers:
            # - foobar
            # - foobar
            # disablePropagationCheck: true
          #httpChallenge:
            # entryPoint: foobar
          tlsChallenge: {}
      #CertificateResolver1:
      #  acme:
      #    email: my.secret@gmail.com
      #    caServer: foobar
      #    storage: foobar
      #    keyType: foobar
      #    dnsChallenge:
      #      provider: foobar
      #      delayBeforeCheck: 42
      #      resolvers:
      #      - foobar
      #      - foobar
      #      disablePropagationCheck: true
      #    httpChallenge:
      #      entryPoint: foobar
      #    tlsChallenge: {}
    
  2. 不带我的注释

    docker-compose: traefikV2_docker-compose.yaml
    root@Ubuntu18:/opt/10_docker-compose.yml-files# cat traefikV2_docker-compose.yaml | grep -v "#"
    version: "3.7"
    
    services:
      traefik-reverse-proxy:
        image: traefik:v2.1.1
        container_name: traefik
    
        ports:
          - 80:80
          - 443:443
    
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - /var/log/traefik:/var/log
          - /etc/ssl/certs/traefik/letsencrypt:/etc/ssl/certs/letsencrypt
          - /opt/traefik/traefik-config.yaml:/etc/traefik/traefik.yaml
    
        labels:
          - traefik.enable=true
          - traefik.http.routers.traefik_dashboard-router.rule=Host(`traefik.fairbnb.community`)
          - traefik.http.routers.traefik_dashboard-router.entrypoints=web
          - traefik.http.routers.traefik_dashboard-router.service=api@internal
    
        networks:
          - traefik
    
    
      whoami_viaSubdomain:
        image: "containous/whoami"
        container_name: "whoami_viaSubdomain"
        labels:
          - traefik.enable=true
          - traefik.docker.network=bridge_proxy_traefikv2
          - traefik.http.routers.whoami_viaSubdomain-router.rule=Host(`whoami.fairbnb.community`)
          - traefik.http.routers.whoami_viaSubdomain-router.entrypoints=web
        networks:
          - traefik
    
    networks:
      traefik:
        external:
          name: bridge_proxy_traefikv2
    
    
    Traefik 配置:traefik-config.yaml
    root@Ubuntu18:/opt/traefik# cat traefik-config.yaml | grep -v "#"
    global:
      checkNewVersion: true
    
    entryPoints:
      web:
        address: :80
      websecure:
        address: :443
    
    api:
       debug: true
    
    providers:
      docker:
        exposedByDefault: false
        network: bridge_proxy_traefikv2
    
    log:
      level: DEBUG
      filePath: /var/log/traefik-log.log
    
    accessLog:
      filePath: /var/log/traefik-access.log
    
    certificatesResolvers:
      tlsChallenge_letsencrypt:
        acme:
          email: my.secret@gmail.com
          storage: /etc/ssl/certs/letsencrypt/acme.json
          tlsChallenge: {}
    
    

@Cameron_D
@SvenC56
@Cerix
@huberfe
抱歉直接@了各位,但看起来你们是仅有的公开记录中在 Traefik 后端运行 Discourse 的用户。
尽管 Traefik 承诺能处理所有相关配置,但实际设置似乎并不简单。
到目前为止,我尚未成功:

正常工作的 URL:
无法访问的 URL:

如果您能分享 Discourse 和 Traefik 的完整配置,将不胜感激,这将有助于我更好地排查问题。

我在本文末尾发布的 Traefik 配置:Endless 502 / forwarding when calling dashboard via subdomain #6123 - #9 by PackElend - Traefik v2 - Traefik Labs Community Forum

由于我目前仅使用手机,请在此查看我的配置:traefik - SeAT Discourse Documentation
请注意:我的配置仅在 Traefik v1.6 和 v1.7 版本下运行过,不确定是否适用于 v2 版本。

在此配置下,多名用户能够使用我的插件、Discourse 以及 Traefik。

备注:我尚未阅读本线程中的任何帖子,只是针对提醒进行回复。

非常感谢 :slight_smile: :partying_face:

我会尝试将其从 v1 迁移到 v2。

我已经有一些思路了,还需要几个小时来仔细推敲。

我猜 SSL 和 Let’s Encrypt 的模板是被注释掉的,所以模板部分看起来应该是这样的:

    templates:
          - "templates/postgres.template.yml"
          - "templates/redis.template.yml"
          - "templates/web.template.yml"
          - "templates/web.ratelimited.template.yml"
        ## 如果你希望添加 Let's Encrypt (https),请取消注释以下两行
          #- "templates/web.ssl.template.yml"
          #- "templates/web.letsencrypt.ssl.template.yml"

是的,既然你打算在前面启用代理,为什么还要让 Discourse 容器来管理你的 SSL 证书呢?

完成后请发布你的解决方案。

在 Run other websites on the same machine as Discourse - #301 中可以看到:

我建议也在文档中添加模板部分。我注意到在我的安装中它没有被注释掉,因为我是先进行独立安装以获取 app.yml。在最开始的时候,我忘了注释它们。这样可以避免其他人遇到同样的问题。

没问题

它没有显示 Traefik 的静态配置,对吧?

好消息,各位! http://forum.fairbnb.community/ 已可访问。

这是在 app.yml 中改动最小的配置,可通过 http 提供服务。我将在周末深入研究 https。

templates:
    - "templates/postgres.template.yml"
    - "templates/redis.template.yml"
    - "templates/web.template.yml"
    - "templates/web.ratelimited.template.yml"
    ## 如果希望添加 Lets Encrypt (https),请取消注释以下两行
    #- "templates/web.ssl.template.yml"
    #- "templates/web.letsencrypt.ssl.template.yml"  

expose:
      #- "80:80"   # http
      #- "443:443" # https

labels:
    traefik.enable:                                               true
    traefik.http.services.discourse.loadbalancer.server.port:     80
    traefik.http.routers.discourse.rule:                          Host(`forum.fairbnb.community`)
    traefik.http.routers.discourse.entrypoints:                   web

对于 SSL,只需配置 Traefik + Let’s Encrypt,无需使用 Discourse SSL。

Traefik 将管理您所有容器的加密。

目前我正在使用 Traefik 1.6,因此尚未了解如何在 Traefik v2 上启用它。

是的,参见 Run other websites on the same machine as Discourse,但看起来当客户端通过 https 与代理通信时,discourse 期望某些标头信息。

我简要阅读了相关内容。我会尝试将其翻译成普通上班族也能理解的文字。

是的,另见 Redirecting...。起初我直接启用了 https,证书创建也成功了,但仅此而已。现在我需要将其与我此后获得的知识进行对齐。

所以你是通过 https 访问你的论坛,对吧?
你能分享一下 Traefik 和 Discourse 的配置吗?分享得越多,我周末处理起来就越容易。
v1 到 v2 的迁移指南见 Redirecting...,但我会在本周末尝试在这里进行解释。

好的,这是您的 traefik.toml 文件,但不适用于新版本 v2

defaultEntryPoints = ["http", "https"]

[web]
address = ":8080"
  [web.auth.basic]
  users = ["yourusername:yourpassword"]

[entryPoints]
  [entryPoints.http]
  address = ":80"
    [entryPoints.http.redirect]
      entryPoint = "https"
  [entryPoints.https]
  address = ":443"
    [entryPoints.https.tls]

[acme]
email = "XXXXXXXX"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
onDemand = false
[acme.httpChallenge]
entryPoint = "http"
minVersion = "VersionTLS12"

Discourse 配置的一部分

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"

expose:
  - "80"   # http ------ 仅暴露容器端口
  - "443" # https ------ 无需暴露外部主机端口

labels:
  traefik.port: '80'
  traefik.backend: 'mycontainername'
  traefik.frontend.rule: 'Host:www.myhost.com'
  traefik.docker.network: 'mynetworkname'
docker_args:
  - "--network=mynetworkname"

使用此配置,Traefik 会将所有来自端口 80(HTTP)的请求重定向到端口 443(HTTPS),
并在 Discourse 管理面板中启用强制 HTTPS 以避免错误。

@pfaffman,我不确定如果在另一个话题中引用您的回复,通知是否仍然有效,因此我特意标记了您。

所以您的配置看起来与上面类似,但是

并且使用 环境变量(此方法在 https://stackoverflow.com/questions/52804610/how-do-you-set-environmental-variables-for-traefik 和 https://blog.raveland.org/post/traefik_compose 中有所提及)。

太好了,HTTPS 生效了!:tada::tada::tada::tada::tada:
而且我想我已经理解了其中的工作原理🙂。我会在接下来的几天里把它整理记录下来。

我的配置

Discourse app.yml 摘录

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## 如果你希望添加 Let's Encrypt (HTTPS),请取消注释这两行
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

## 此容器应暴露哪些 TCP/IP 端口?
## 如果你希望 Discourse 与 Apache 或 nginx 等其他 Web 服务器共享端口,
## 详见 https://meta.discourse.org/t/17247
expose:
  #- "80:80"   # http
  #- "443:443" # https
  #- "80"      # http
  #- "443"     # https
  #- "40080:80"
  #- "40443:443"

labels:
  app_name:                                                                     discourse

  #----Traefik 标签------------------------
  traefik.enable:                                                               true
  traefik.docker.network:                                                       bridge_proxy_traefikv2

   #---HTTP 路由部分-------------------
  traefik.http.routers.discourse.rule:                                          Host(`forum.fairbnb.community`)
    #--HTTP 部分--------------------------
  traefik.http.routers.discourse.entrypoints:                                   web
  traefik.http.routers.discourse.middlewares:                                   discourse_redirect2https         
  #traefik.http.services.discourse.loadbalancer.server.port:                     80  

   #---HTTPS 路由部分
  traefik.http.routers.discourse_secure.rule:                                   Host(`forum.fairbnb.community`)
    #--HTTPS 部分
  traefik.http.routers.discourse_secure.entrypoints:                            websecure
  traefik.http.services.discourse_secure.loadbalancer.server.port:              80
    #--TLS 部分
  traefik.http.routers.discourse_secure.tls.certresolver:                       tlsChallenge_letsencrypt

   #---中间件部分:将 HTTP 重定向到 HTTPS
  traefik.http.middlewares.discourse_redirect2https.redirectscheme.scheme:      https

docker_args:
  - "--network=bridge_proxy_traefikv2"
  
params:

Traefik 静态配置

global:
  checkNewVersion: true
entryPoints:
  web:
    address: :80
  websecure:
    address: :443

api:
   debug: true

providers:
  docker:
    exposedByDefault: false
    network: bridge_proxy_traefikv2

log:
  level: DEBUG
  filePath: /var/log/traefik-log.log

accessLog:
  filePath: /var/log/traefik-access.log

certificatesResolvers:
  tlsChallenge_letsencrypt:
    acme:
      email: my.secret@gmail.com
      storage: /etc/ssl/certs/letsencrypt/acme.json
      tlsChallenge: {}

你好,

我参考这篇帖子设置了 Discourse 与 Traefik 的集成。目前 Traefik 已经与另一个 Web 应用正常工作。

当我访问 forum.private.com 时,会收到“404 页面未找到”的错误。

看起来某些部分正在运行,因为在 Traefik 仪表板的“服务”选项卡中,我看到了 discourse@docker 和 discourse_secure@docker。

然而,在“路由器”选项卡中并没有关于 Discourse 的任何条目。

我对 app.yml 所做的修改如下,主要基于上述链接的帖子。我在底部的 Docker 参数中添加了一个暴露端口,这似乎使上述服务得以开启。非常感谢您的帮助!

Traefik docker-compose
version: "3.3"

services:
  ################################################
  ####        Traefik Proxy Setup           #####
  ###############################################
  traefik:
    image: traefik:v2.0
    restart: always
    container_name: traefik
    ports:
      - "80:80" # <== http
      - "8080:8080" # <== :8080 是仪表板运行的端口
      - "443:443" # <== https
    command:
    #### 这些是配置 Traefik 并告知其如何工作的 CLI 命令 ####

      - --api.insecure=true # <== 启用不安全的 API,不建议在生产环境中使用
      - --api.dashboard=true # <== 启用仪表板以查看服务、中间件、路由器等...
      - --api.debug=true # <== 启用额外的端点用于调试和性能分析
      ## 日志设置(选项:ERROR, DEBUG, PANIC, FATAL, WARN, INFO)- https://docs.traefik.io/observability/logs/ ##
      - --log.level=DEBUG # <== 设置 Traefik 的日志级别
      ## 提供者设置 - https://docs.traefik.io/providers/docker/#provider-configuration ##
      - --providers.docker=true # <== 启用 Docker 作为 Traefik 的提供者
      - --providers.docker.exposedbydefault=false # <== 不要将所有容器暴露给 Traefik,仅暴露已启用的容器
      - --providers.file.filename=/dynamic.yaml # <== 引用动态配置文件
      - --providers.docker.network=web # <== 在名为 web 的 Docker 网络上操作
      ## 入口点设置 - https://docs.traefik.io/routing/entrypoints/#configuration ##
      - --entrypoints.web.address=:80 # <== 定义名为 web 的端口 :80 的入口点
      - --entrypoints.web-secured.address=:443 # <== 定义名为 web-secured 的端口 :443 的 HTTPS 入口点
      ## 证书设置 (Let's Encrypt) -  https://docs.traefik.io/https/acme/#configuration-examples ##
      - --certificatesresolvers.mytlschallenge.acme.tlschallenge=true # <== 启用 TLS-ALPN-01 以生成和续订 ACME 证书
      - --certificatesresolvers.mytlschallenge.acme.email=private@private.com # <== 设置证书邮箱
      - --certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json # <== 定义用于存储证书信息的 ACME 文件
    volumes:
      - ./letsencrypt:/letsencrypt # <== 证书(TLS)卷
      - /var/run/docker.sock:/var/run/docker.sock # <== Docker 管理卷
      - ./dynamic.yaml:/dynamic.yaml # <== 动态配置文件卷,**参考:第 27 行
    networks:
      - web # <== 将 Traefik 放置在名为 web 的网络上,以访问该网络上的容器
    labels:
    #### 标签定义此容器的 Traefik 代理的行为和规则 ####
      - "traefik.enable=true" # <== 在自身上启用 Traefik 以查看仪表板并分配子域名进行访问
      - "traefik.http.routers.api.rule=Host(`monitor.private.com`)" # <== 设置仪表板的域名
      - "traefik.http.routers.api.service=api@internal" # <== 启用 API 作为可访问的服务


networks:
  web:
    external: true
  backend:
    external: false

volumes:
  db_data: {}
  wordpress:
    external: true
  db:
    external: true

Discourse app.yml
## 这是 Discourse 的一体化独立 Docker 容器模板
##
## 修改此文件后,您必须重新构建
## /var/discourse/launcher rebuild app
##
## 编辑时请*非常*小心!
## YAML 文件对空白或缩进错误极其敏感!
## 如需验证此文件,请访问 http://www.yamllint.com/

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## 如果您想添加 Let's Encrypt (https),请取消注释这两行
  #- "templates/web.ssl.template.yml"
  # "templates/web.letsencrypt.ssl.template.yml"

## 此容器应暴露哪些 TCP/IP 端口?
## 如果您希望 Discourse 与另一个 Web 服务器(如 Apache 或 nginx)共享端口,
## 请参阅 https://meta.discourse.org/t/17247 获取详细信息
expose:
  #- "80:80"   # http
  #- "443:443" # https

params:
  db_default_text_search_config: "pg_catalog.english"

  ## 将 db_shared_buffers 设置为总内存的最大 25%。
  ## 将根据检测到的 RAM 自动由引导程序设置,您也可以覆盖
  db_shared_buffers: "128MB"

  ## 可以提高排序性能,但会增加每个连接的内存使用量
  #db_work_mem: "40MB"

  ## 此容器应使用哪个 Git 修订版本?(默认:tests-passed)
  #version: tests-passed

env:
  LANG: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  ## 支持多少并发 Web 请求?取决于内存和 CPU 核心数。
  ## 将根据检测到的 CPU 自动由引导程序设置,您也可以覆盖
  UNICORN_WORKERS: 2

  ## TODO: 此 Discourse 实例将响应的域名
  ## 必需。Discourse 无法仅使用 IP 地址运行。
  DISCOURSE_HOSTNAME: forum.private.com

  ## 如果您希望容器使用与上述相同的
  ## 主机名(-h 选项)启动,请取消注释(默认值为 "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: 初始注册时将设为管理员和开发人员的逗号分隔邮箱列表
  ## 示例 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'private@private.com'

  ## TODO: 用于验证新账户和发送通知的 SMTP 邮件服务器
  # SMTP 地址、用户名和密码为必填项
  # 警告:SMTP 密码中的字符 '#' 可能导致问题!
  DISCOURSE_SMTP_ADDRESS: in-v3.mailjet.com
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: redacted
  DISCOURSE_SMTP_PASSWORD: "redacted"
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (可选,默认为 true)

  ## 如果您添加了 Let's Encrypt 模板,请取消注释以下行以获取免费 SSL 证书
  LETSENCRYPT_ACCOUNT_EMAIL: private@private.com

  ## 此 Discourse 实例的 http 或 https CDN 地址(配置为拉取)
  ## 详见 https://meta.discourse.org/t/14857
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com

## Docker 容器是无状态的;所有数据都存储在 /shared 中
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## 插件放在这里
## 详见 https://meta.discourse.org/t/19157
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

## 构建后运行的任何自定义命令
run:
  - exec: echo "开始自定义命令"
  ## 如果您想设置首次注册的“发件人”邮箱地址,请取消注释并修改:
  ## 收到首次注册邮件后,请重新注释该行。它只需运行一次。
  #- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
  - exec: echo "结束自定义命令"

labels:
  app_name:                                                                     discourse

  #----Traefik 标签------------------------
  traefik.enable:                                                               true
  traefik.docker.network:                                                       web

   #---HTTP 路由器部分-------------------
  traefik.http.routers.discourse.rule:                                          Host(`forum.private.com`)
    #--HTTP 部分--------------------------
  traefik.http.routers.discourse.entrypoints:                                   web
  traefik.http.routers.discourse.middlewares:                                   discourse_redirect2https         
  traefik.http.services.discourse.loadbalancer.server.port:                     80  

   #---HTTPS 路由器部分
  traefik.http.routers.discourse_secure.rule:                                   Host(`forum.private.com`)
    #--HTTPS 部分
  traefik.http.routers.discourse_secure.entrypoints:                            web-secured
  traefik.http.services.discourse_secure.loadbalancer.server.port:              80
    #--TLS 部分
  traefik.http.routers.discourse_secure.tls.certresolver:                       tlsChallenge_letsencrypt

   #---中间件部分:将 HTTP 重定向到 HTTPS
  traefik.http.middlewares.discourse_redirect2https.redirectscheme.scheme:      https

docker_args:
  - "--network=web"
  - "--expose=80"

谢谢