与 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 "结束自定义命令"

There were problems make Traefik’s dashboard available via a subdomain but discourse is still not reachable, see https://community.containo.us/t/discourse-instance-is-handled-by-api-internal-is-that-normal/3690/1
Here are my working configs.

  1. With my comments

    docker-compose: traefikV2_docker-compose.yaml
    # https://stackoverflow.com/questions/49718431/docker-compose-yml-file-naming-convention
    version: "3.7"
    
    services:
      traefik-reverse-proxy:   
        # The official v2.0 Traefik docker image
        #image: traefik:latest 
        #image: traefik:v2.0
        image: traefik:v2.1.1
        container_name: traefik
        #command: 
        ## to work with custom traefik configuration file you have to declare the local path and mount the location on the host, see volume section
        #- --configFile=/etc/traefik/traefik-config.yaml
        
        ports:
          # The HTTP port
          - 80:80
          # The HTTPS port
          - 443:443
          # The Web UI (enabled by --api.insecure=true)
          #- "8080:8080"
        
        volumes:         
        # syntax --> host-location:path-in-container, see https://docs.docker.com/compose/compose-file/#volumes
          # So that Traefik can listen to the Docker events
          - /var/run/docker.sock:/var/run/docker.sock
          # mount the location for the log files to the host, so that I can read them on the host
            # chosen based on https://unix.stackexchange.com/questions/104936/where-are-all-the-posibilities-of-storing-a-log-file
          - /var/log/traefik:/var/log
          # mount the location for the certifcates to the host, so that I can read them on the host
            #based on https://www.getpagespeed.com/server-setup/ssl-directory and https://serverfault.com/questions/62496/ssl-certificate-location-on-unix-linux
          - /etc/ssl/certs/traefik/letsencrypt:/etc/ssl/certs/letsencrypt
          # I use a customized "traefik.toml", so it has to be mounted into the traefik container (or stored there), combine 
            # 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
          
       #Tiny Go webserver that prints os information and HTTP request to output
       #  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 configuration: 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: {}   
    # Activate dashboard. 
      ## Enables the web UI @ port 8080/ Traefik will listen on port 8080 by default for API request. / Activate API directly on the entryPoint named traefik. (Default: false) --> port '8080'v= entryPoint 'traefik', overrides --api  
      #insecure: true
      ## Activate dashboard. (Default: true)
      # dashboard: true
      # Enable additional endpoints for debugging and profiling. 
       debug: true    
      
    providers:
    # providersThrottleDuration: 42
      docker:
        #constraints: foobar
        ## Watch provider. (Default: true)
        #watch: true
        ## Docker server endpoint. Can be a tcp or a unix socket endpoint. (Default: unix:///var/run/docker.sock)
        #endpoint: unix:///var/run/docker.sock
        #defaultRule: foobar
        #tls:
          #ca: foobar
          #caOptional: true
          #cert: foobar
          #key: foobar
          #insecureSkipVerify: true
        # Expose containers by default. (Default: true) / By default, routes for all detected containers are creates. ITo limit the scope of Traefik's service discovery, i.e. disallow route creation for some containers, you can do so in two different ways: gerneric exposedByDefault (overriden by traefik.enable), or with a finer granularity mechanism based on constraints.
        exposedByDefault: false
        #useBindPortIP: true
        #swarmMode: true
        # Default Docker network used.
        network: bridge_proxy_traefikv2
        # swarmModeRefreshSeconds: 42  
    
    not used currently-metrics:    # this is only hear to fold/unfold the commented region in  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's log file 
      # set debug level of the log
      level: DEBUG
      # defining the storage location inside the container, log file is written inside the container. To make it avaiable on the host it is mounted, see volumes section in docker-compose file
        # chosen based on https://unix.stackexchange.com/questions/104936/where-are-all-the-posibilities-of-storing-a-log-file
      filePath: /var/log/traefik-log.log
      # Traefik log format: json | common (Default: common)
      #format: common
    
    accessLog:      
    # Logging access attempts   
      # defining the storage location inside the container, log file is written inside the container. To make it avaiable on the host it is mounted, see volumes section in docker-compose file
        # chosen based on https://unix.stackexchange.com/questions/104936/where-are-all-the-posibilities-of-storing-a-log-file  
      filePath: /var/log/traefik-access.log
      # Access log format: json | common (Default: 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:    # this is only hear to fold/unfold the commented region in  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:     # this is only hear to fold/unfold the commented region in  Notepad++
    #hostResolver:
    #  cnameFlattening: true
    #  resolvConfig: foobar
    #  resolvDepth: 42
      #
    certificatesResolvers:
      tlsChallenge_letsencrypt:
        acme:
          email: my.secret@gmail.com
          # CA server to use. (Default: https://acme-v02.api.letsencrypt.org/directory)
          #caServer:        
          # location chosen based on  on https://www.getpagespeed.com/server-setup/ssl-directory and https://serverfault.com/questions/62496/ssl-certificate-location-on-unix-linux
          storage: /etc/ssl/certs/letsencrypt/acme.json
          # KeyType used for generating certificate private key. Allow value 'EC256', 'EC384', 'RSA2048', 'RSA4096', 'RSA8192'. (Default: 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. Without my comments

    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 configuration: 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 上启用它。

是的,参见 https://meta.discourse.org/t/running-other-websites-on-the-same-machine-as-discourse/17247,但看起来当客户端通过 https 与代理通信时,discourse 期望某些标头信息。

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

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

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

好的,这是您的 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-traefikhttps://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@dockerdiscourse_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"

谢谢