与 Traefik 2.0 的讨论

Hi all,

I’m migrating to a new server and I want to use Traefik 2.0 as a reverse proxy. I’m currently struggling with the new configuration. I added a section at the bottom of the app.yml file. (Source: Discourse behind Traefik 🐭)

...

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"

This does not seem to work. When I open the route I get a Bad Gateway error. When I go directly to the ip_adress:8060 it opens discourse.

Does anyone have experience with Traefik 2.0?

Thank you!

1 个赞

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

供后续参考,附上我的 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"
8 个赞

why it is neccessary to sue docker_args? According to https://github.com/discourse/discourse_docker#labels it shall work like:

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

Add labels to the current container. The above will add --l monitor=true -l app_name=dev_discourse to the options when running the container.

Moreover, where is docker_args explained?

@Cameron_D
how did you find out that docker_args is the way to go?

I just couldn’t get the labels section working as expected. I’m not sure exactly why it wasn’t working anymore, or whether or not its been fixed since because I’ve just left my configuration as-is because its working.

你好,
你能分享一下你的 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: {}
    
    
1 个赞

@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。

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

3 个赞

非常感谢 :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 以避免错误。

1 个赞

@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: {}
4 个赞

你好,

我参考这篇帖子设置了 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"

谢谢