尝试在 Traefik 上配置 HTTPS 时获取 502 Bad Gateway

Getting 502 Bad Gateway when trying to configure HTTPS on Traefik

我有一个适用于 HTTP 的基本 Traefik 2 设置 ...

现在我正在尝试让 HTTPS 工作,并使用 TLS 和重定向对仪表板进行基本身份验证...

docker_compose.yml:

version: '3.8'
networks:
  myweb:
    external: true

services:
  proxy:
    image: traefik:v2.3.0-rc4-windowsservercore-1809
    container_name: traefik
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      # Mount the certs drive
      - ./traefik-ssl-certs/:c:/certs/
      # Mount the config folder
      - ./traefik-config/:c:/config/
      # Mount the host docker engine pipe ("docker volume ls")
      - source: '\.\pipe\docker_engine'
        target: '\.\pipe\docker_engine'
        type: npipe
    command:
      - "--api.insecure=true"

      # Register the traefik config directory as per: https://docs.traefik.io/providers/file/#directory
      - --providers.file.directory=c:/config/
      - --providers.file.watch=true

      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443

      # Redirect http to https
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entryPoint.scheme=https
      - --entrypoints.web.http.redirections.entrypoint.permanent=true

      # Configure Docker provider
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.endpoint=npipe:////./pipe/docker_engine"
      - "--providers.docker.network=myweb"
      - "--providers.docker.watch=true"
    networks:
      - myweb
    labels:
      - traefik.http.routers.api.service=api@internal
      - traefik.enable=true
      - traefik.docker.network=myweb

      
  remoteling:
    image: remoteling:latest
    container_name: remoteling
    networks:
      - myweb
    labels:
      - traefik.enable=true
      - traefik.docker.network=myweb

      - traefik.http.middlewares.http2https.redirectscheme.scheme=https
      - traefik.http.routers.remoteling-http.middlewares=http2https
      - traefik.http.routers.remoteling-http.rule=Host(`example.com`) || Host(`example.example.com`)
      - traefik.http.routers.remoteling-http.entrypoints=web
      
      - traefik.http.services.remoteling.loadbalancer.server.port=443
      - traefik.http.routers.remoteling-https.rule=Host(`example.com`) || Host(`example.example.com`)
      - traefik.http.routers.remoteling-https.entrypoints=websecure
      - traefik.http.routers.remoteling-https.tls=true
    depends_on:
      - proxy

来自 powershell 我是 运行:

docker network create -d nat myweb
docker-compose -p myweb up 

在我的工作目录中,我有以下文件结构:

traefik.yml 文件如下所示:

tls:
  certificates:
    - certFile: c:/certs/example.example.com.crt
      keyFile: c:/certs/example.example.com.key
    - certFile: c:/certs/example.com.crt
      keyFile: c:/certs/example.com.key

traefik 仪表板显示我的服务定义为负载均衡器,这很好(除了负载均衡器之外还有其他类型的服务吗?我不确定除了通过负载均衡器之外还有什么其他方式定义端口)。单击该服务会为我提供本地网络 IP - 当我访问该 IP 时,我的网站加载正常(尽管有 SSL 证书不匹配警告 - 预期)。

然而,当我尝试访问 https://example.com or https://example.example.com - 时,我收到了 502 Bad Gateway。知道为什么我会得到这个吗?

浏览器显示 SSL 证书有效,没有警告,所以我认为我的证书配置没问题。

如果我访问 http://example.com it forwards me to https://example.com

,http 到 https 重定向似乎有效

我的路由配置有什么问题导致这些错误的网关?

我的问题解决了!有几个问题:

  1. 我在我的 Docker 文件中配置了一个 TLS 证书,从我 运行 将图像作为我的服务器上的单个服务开始。所以我的图像已经绑定了 TLS 证书的端口 443。我认为当 Traefik 路由器尝试为服务配置 TLS 时,这会导致问题。所以我不得不重建我的形象,删除 TLS。我也删除了需要 HTTPS 属性的代码,现在由 traefik 负责。

Image只需要暴露1个端口:我现在的理解是我的web应用应该 运行通过端口80(例如,甚至不需要在图像的防火墙中暴露端口 443)并且 Traefik 路由器通过端口 80 配置和处理 TLS/443 等。

  1. 我实际上并没有正确定义我的 HTTP 和 HTTPS 服务。我在下面分享了我的 docker-compose.yml 文件——注意 traefik 和我的其他服务,我将标签分成几个部分:定义服务、HTTP 路由、HTTPS 路由、重定向中间件和基本身份验证traefik 仪表板。我找不到任何好的文档或教程来真正分解 traefik 2.0 的必要方面并将它们清楚地分类。

服务定义标签/负载均衡器端口应指向托管图像服务的任何端口,例如在大多数情况下端口 80,或者在 traefik 服务 8080 的情况下。但关键是它不需要 also 指向 443 以获得 https。

总而言之,我的(冗长的)学习笔记毕竟是,你需要:

  • 再次将服务定义为标签:没有服务定义标签对我不起作用。我必须添加一个服务标签,指向定义图像的服务名称。
  • 为 http 和 https 定义路由器:在 traefik.http.routers.YOUR_ROUTER_NAME 之后放置的任何文本都会成为您的路由器。我不清楚我需要用于 http 和 https 的单独路由器。您必须为每项服务(例如 traefik、whoami、remoteling 等)执行此操作
  • 定义路由器的入口点:据我所知,您在 traefik 命令中入口点后面的名称定义了一个可用于其他服务的新入口点。因此,在 traefik 服务定义中,您将拥有 --entrypoints.WEBNAME.address=:80 和 --entrypoints.WEBSECURENAME.address=:443(用您自己的名字替换这些大写字母,以便在 docker-compose.yml 中使用文件。
  • 定义要捕获的路由器域名:就像为每个 http 和 https 定义路由器一样,您必须为这两个路由器定义要捕获的域,即使只是相同 domain/path.
  • 为 https 路由器添加 tls:对于 https 路由器,您需要 tls.true 标签。
  • traefik 和您的每个服务的单独中间件重定向定义:我读过您可以声明一个全局的,但是 AFAIK 每个服务必须 opt-in将中间件分配给 http 路由器。
  • 在 Docker 上为 Windows 提供您自己的 SSL 证书:关于 运行ning Docker 的信息很少对于 Windows 使用您自己的 SSL 证书。我的 'traefik' 工作目录中有一个批处理脚本,其中包含一个包含 SSL 证书(crt 和密钥文件)的子文件夹。我将此作为第一卷安装,- ./traefik-ssl-certs/:c:/certs/。然后,在我的工作目录中,我有另一个名为 traefik-config 的文件夹,其中包含我的 traefik.yml 文件(上述问题中的详细信息)。在 linux 中,每个人似乎都直接挂载配置文件,但在 Windows 中挂载文件不起作用,所以我不得不作为文件夹挂载,然后我使用了命令 providers.file.directory=c:/config/,它告诉 traefik 在那里寻找配置文件。配置文件为 traefik 加载提供了 SSL 证书的位置。如果您为路由器启用 TLS,Traefik 将自动使用与您在该路由器上指定的域匹配的任何证书。
  • Basic Auth: 必须将中间件定义为一个标签,然后将该中间件分配给您的 https 路由器。我想如果您不使用 HTTPS 重定向,那么您可以将它分配给您的 http 路由器,但它显然不安全。

docker-compose.yml:

version: '3.8'
networks:
  myweb:
    external: true

services:
  proxy:
    image: traefik:v2.3.0-rc4-windowsservercore-1809
    container_name: traefik
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      # Mount the certs drive
      - ./traefik-ssl-certs/:c:/certs/
      # Mount the config folder
      - ./traefik-config/:c:/config/
      # Mount the host docker engine pipe ("docker volume ls")
      - source: '\.\pipe\docker_engine'
        target: '\.\pipe\docker_engine'
        type: npipe
    command:
      - --api=true
      - --api.dashboard=true
      - --api.insecure=false

      # Register the traefik config directory as per: https://docs.traefik.io/providers/file/#directory
      - --providers.file.directory=c:/config/
      - --providers.file.watch=true

      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443

      # Configure Docker provider
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --providers.docker.endpoint=npipe:////./pipe/docker_engine
      - --providers.docker.network=myweb
      - --providers.docker.watch=true
    networks:
      - myweb
    labels:
      - traefik.enable=true
      - traefik.docker.network=myweb

      # Define the service
      - traefik.http.services.proxy.loadbalancer.server.port=8080

      # Routing for dashboard HTTP
      - traefik.http.routers.dash-http.service=api@internal
      - traefik.http.routers.dash-http.rule=Host(`example.com`)
      - traefik.http.routers.dash-http.entrypoints=web

      # Routing for dashboard HTTPS
      - traefik.http.routers.dash-https.service=api@internal
      - traefik.http.routers.dash-https.rule=Host(`example.com`)
      - traefik.http.routers.dash-https.entrypoints=websecure
      - traefik.http.routers.dash-https.tls=true

      # Http-to-Https redirect Middleware
      - traefik.http.middlewares.dash-http2https.redirectscheme.scheme=https
      - traefik.http.middlewares.dash-http2https.redirectscheme.permanent=true
      - traefik.http.routers.dash-http.middlewares=dash-http2https

      # BasicAuth for dashboard
      # Windows doesn't have htpasswd command so I generated one here: https://hostingcanada.org/htpasswd-generator/
      # As per Traefik documentation, escaped single $ char with $$ for the yml parser
      # user/pass = admin/testpassword 
      - traefik.http.middlewares.api-auth.basicauth.users=admin:$y$$$mfWQ11K16V6gVK.8Y6q1Eeh765NZscmjCrjJlAtaWubEsjU8HLYOO
      - traefik.http.routers.dash-https.middlewares=api-auth

  remoteling:
    image: remoteling:latest
    container_name: remoteling
    networks:
      - myweb
    labels:
      - traefik.enable=true
      - traefik.docker.network=myweb

      # Define the service
      - traefik.http.services.remoteling.loadbalancer.server.port=80

      # Routing for remoteling HTTP
      - traefik.http.routers.remoteling-http.service=remoteling
      - traefik.http.routers.remoteling-http.entrypoints=web
      - traefik.http.routers.remoteling-http.rule=Host(`services.example.com`) 

      # Routing for remoteling HTTPS
      - traefik.http.routers.remoteling-https.service=remoteling
      - traefik.http.routers.remoteling-https.entrypoints=websecure
      - traefik.http.routers.remoteling-https.rule=Host(`services.example.com`)
      - traefik.http.routers.remoteling-https.tls=true
      
      # Http-to-Https redirect Middleware
      - traefik.http.middlewares.remoteling-http2https.redirectscheme.scheme=https
      - traefik.http.middlewares.remoteling-http2https.redirectscheme.permanent=true
      - traefik.http.routers.remoteling-http.middlewares=remoteling-http2https
    depends_on:
      - proxy

希望其他人觉得有用。