Discusión con Traefik 2.0

¿Podrías compartir capturas de pantalla?

Adjunto hay dos capturas de pantalla del panel de control de Traefik. Muestran que Discourse aparece (dos veces) en los servicios, pero nada en los enrutadores. No sé necesariamente lo que significa, a decir verdad, pero lo noté.

Edición: Soy un usuario nuevo de Discourse, por lo que no tengo la confianza suficiente para publicar dos imágenes en un solo mensaje, así que responderé con otra.

Necesito levantar mis dockers esta noche para comparar. Te lo haré saber entonces, o quizás algunos otros aquí puedan compartir su panel de control y comparar.

No necesitas eso; es mejor cambiar a la API y usar Traefik v2.1, así:
- "traefik.http.routers.traefik_dashboard-router.service=api@internal"
Consulta Endless 502 / forwarding when calling dashboard via subdomain #6123 - #5 by ldez - Traefik v2 - Traefik Labs Community Forum

¿Podrías eliminar tus comentarios?

Esto nos facilita la lectura.
No te preocupes, me dijeron lo mismo una vez :).
Escribo mis comentarios en una línea aparte, así puedo generar fácilmente una versión limpia usando cat traefikV2.yaml | grep -v "#"

Aquí está mi panel de control

  1. Panel de control
  2. Enrutadores HTTP
  3. Servicios HTTP
  4. Middleware HTTP

Vale, me llevó unos días llegar a esto. He vuelto a configurar mi Traefik para usar un archivo YAML en lugar de poner todo en docker-compose. Sin embargo, después de volver a conectar todo, parece que obtengo el mismo comportamiento o uno similar: recibo un error 404 en mi dominio y, en el panel de control de Traefik, veo entradas bajo Servicios y routers para Discourse, pero nada bajo routers.

docker-compose de Traefik
version: '3'

services:
  traefik:
    image: traefik:v2.0
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - 80:80
      - 443:443
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/traefik.yml:/traefik.yml:ro
      - ./data/acme.json:/acme.json
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`monitor.example.com`)"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=user:redacted"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`monitor.example.com`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=http"
      - "traefik.http.routers.traefik-secure.service=api@internal"

networks:
  proxy:
    external: true
data/traefik.yml de Traefik
api:
  dashboard: true

entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

certificatesResolvers:
  http:
    acme:
      email: nick@innomadic.com
      storage: acme.json
      httpChallenge:
        entryPoint: http
containers/app.yml
templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"

expose:

params:
  db_default_text_search_config: "pg_catalog.english"

  db_shared_buffers: "128MB"



env:
  LANG: en_US.UTF-8

  UNICORN_WORKERS: 2

  DISCOURSE_HOSTNAME: forum.example.com


  DISCOURSE_DEVELOPER_EMAILS: 'info@example.com'

  DISCOURSE_SMTP_ADDRESS: redacted.com
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: redacted
  DISCOURSE_SMTP_PASSWORD: "redacted"

  LETSENCRYPT_ACCOUNT_EMAIL: info@example.com


volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

run:
  - exec: echo "Beginning of custom commands"
  - exec: echo "End of custom commands"

labels:
  app_name:                                                                     discourse

  traefik.enable:                                                               true
  traefik.docker.network:                                                       proxy
  traefik.http.routers.discourse.rule:                                          Host(`forum.example.com`)
  traefik.http.routers.discourse.entrypoints:                                   http
  traefik.http.routers.discourse.middlewares:                                   discourse_redirect2https
  traefik.http.services.discourse.loadbalancer.server.port:                     80

  traefik.http.routers.discourse_secure.rule:                                   Host(`forum.example.com`)
  traefik.http.routers.discourse_secure.entrypoints:                            https

  traefik.http.services.discourse_secure.loadbalancer.server.port:              80
  traefik.http.routers.discourse_secure.tls.certresolver:                       tlsChallenge_letsencrypt

  traefik.http.middlewares.discourse_redirect2https.redirectscheme.scheme:      https

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

Creo que también ejecuté el comando docker network connect proxy para conectar esto a la red de Traefik.

Agradezco cualquier ayuda para ver qué me estoy perdiendo, y también me encantaría saber si tengo mis medidas de seguridad bien organizadas.

No sé qué te falta. Esto es lo que hago en Ansible para poner en marcha sitios con Traefik:

        --docker-args "-l traefik.frontend.rule=Host:{{discourse_hostname}} \
        -l traefik.frontend.entryPoints=https \
        -l traefik.backend={{discourse_shortname}} \
        -l traefik.port=80"

Y luego ejecuta:

       ./launcher start {{ discourse_yml }} {{ docker_args }}

Agregar las reglas de Traefik en docker_args en lugar de en el archivo yml tiene el beneficio adicional de que Traefik no preste atención al contenedor que se está inicializando.

Creo que eso es Traefik v1, ¿verdad?

Oh. Lo siento. Sí, estoy bastante seguro de que se trata de Traefik 1, así que no podré ayudarte con los detalles específicos.

Parece que no estás estableciendo ningún valor en esas etiquetas en app.yml. Creo que necesitas definir una regla y, quizás, un middleware.

Si no quieres tiempo de inactividad durante el arranque, deberás configurarlo con ./launcher start, como en mi ejemplo.

¿Quizás “middleware” es lo que antes se llamaba “backend”? Necesitarás hacer algo para establecer que el contenedor de Discourse es el servidor que deseas y… algo más… para conectar algún front-end/URL con el backend/servidor correspondiente.

Se están configurando, pero tienes que desplazarte un poco hacia la derecha para verlos. Es solo un tema de formato.

Gracias

Jaja. Lo siento por eso.

Bueno, no tengo ni idea de lo que estoy hablando, pero no me tiene sentido que configures tu discourse@docker como un equilibrador de carga.

Hola, creo que lo he solucionado.

Eliminé la línea:
# traefik.http.services.discourse_secure.loadbalancer.server.port: 80

pero dejé esta:

traefik.http.services.discourse.loadbalancer.server.port: 80

labels:
  app_name:                                                                     discourse

  #----Etiquetas de Traefik------------------------
  traefik.enable:                                                               true
  traefik.docker.network:                                                       proxy
   #---SECCIÓN DE ROUTER HTTP-------------------
  traefik.http.routers.discourse.rule:                                          Host(`forum.example.com`)
    #--SECCIÓN HTTP--------------------------
  traefik.http.routers.discourse.entrypoints:                                   http
  traefik.http.routers.discourse.middlewares:                                   discourse_redirect2https
  traefik.http.services.discourse.loadbalancer.server.port:                     80

   #---SECCIÓN DE ROUTER HTTPS
  traefik.http.routers.discourse_secure.rule:                                   Host(`forum.example.com`)
    #--SECCIÓN HTTPS
  traefik.http.routers.discourse_secure.entrypoints:                            https

 # traefik.http.services.discourse_secure.loadbalancer.server.port:              80
    #--SECCIÓN TLS
  traefik.http.routers.discourse_secure.tls.certresolver:                       tlsChallenge_letsencrypt

   #---SECCIÓN DE MIDDLEWARE redirigir HTTP a HTTPS
  traefik.http.middlewares.discourse_redirect2https.redirectscheme.scheme:      https

No estoy seguro de cómo llegó ahí ni por qué está así, pero funciona. Así que, usando toda la configuración que publiqué arriba en el hilo, pero haciendo este único cambio, ahora me está funcionando.

¡Gracias a todos!

Eso es correcto.
Yo puse eso en mi configuración:

#—SECCIÓN DE SERVICIO: le dice a Traefik a dónde enviar la solicitud
traefik.http.services.discourse.loadbalancer.server.port: 80

¿Te suena?
Lo que estás haciendo aquí es indicar a quién (servicio) se envía la solicitud y en qué puerto.
También podrías solucionarlo usando expose, pero desde una perspectiva de seguridad, quieres exponer lo menos posible de tus contenedores. Además, Traefik selecciona el primer puerto si expones múltiples puertos, por lo que usar loadbalancer es más limpio.


Traefik data/traefik.yml

Yo no lo hago así, ya que esa ruta es la predeterminada.

Aquí no trabajas con la ruta completa, usando una ruta predeterminada. No me gusta esto porque tienes que tener en mente la ruta. Yo uso storage: /etc/ssl/certs/letsencrypt/acme.json.

Defino la red; no me gustan las configuraciones predeterminadas.

providers:
  docker:
    exposedByDefault: false
    network: bridge_proxy_traefikv2

containers/app.yml

No necesitas hacer esto, ya que loadbalancer lo hace automáticamente.

Traefik docker-compose

Quizás quieras darle un nombre a esta red; en mi caso:

networks:
  traefik:
    external:
      name: bridge_proxy_traefikv2

He estado trabajando con tus sugerencias aquí. Gracias por tu respuesta.

Quisiera señalar que para el endpoint dices que confiemos en los valores predeterminados, mientras que para la ubicación de almacenamiento dices que no te gusta confiar en ellos. :slight_smile:

Intenté hacer el cambio para acme.json que mencionaste:

Sin embargo, mi contenedor de Traefik no encontró el archivo. Apareció como un error en el registro. Así que lo he dejado como acme.json por ahora.

Quisiera preguntarte sobre este punto:

¿No estás simplemente renombrando la red aquí, o dándole un nombre localizado? Creo que yo solo la referenciaba como proxy en la otra configuración y aquí localmente. Todavía tiene un nombre que definí, simplemente no la estoy renombrando. Al menos, así es como lo entiendo.

Tengo una última preocupación notable. Noté después de mi publicación de “¡Éxito!” anterior que, aunque HTTPS está funcionando, estoy recibiendo una advertencia de contenido mixto. Así que no todo está siendo cifrado.

Estoy recibiendo el error de contenido mixto para mi instalación de Discourse, pero no para la instalación de WordPress que tengo en el mismo servidor. Por lo tanto, debe ser algo específico de mis configuraciones de Discourse.

Al revisar la consola de desarrollador, veo:

Cargando contenido de visualización mixto (inseguro) “http://talk.redacted.com/uploads/default/optimized/1X/_129430568242d1b7f853bb13ebea28b3f6af4e7_2_180x180.png” en una página segura FaviconLoader.jsm:174:19

¿Será que mi redirección no está funcionando correctamente de alguna manera?

Adjunto los archivos relevantes a continuación para su revisión.

Traefik.yml

api:
dashboard: true

entryPoints:
http:
address: “:80”
https:
address: “:443”

providers:
docker:
exposedByDefault: false
network: proxy

certificatesResolvers:
http:
acme:
email: info@private.com
storage: acme.json
httpChallenge:
entryPoint: http

Traefik docker-compose

version: ‘3’

services:
traefik:
image: traefik:v2.0
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- proxy
ports:
- 80:80
- 443:443
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme.json:/acme.json
labels:
- “traefik.enable=true”
- “traefik.http.routers.traefik.entrypoints=http”
- “traefik.http.routers.traefik.rule=Host(monitor.private.com)”
- "traefik.http.middlewares.traefik-auth.basicauth.users=private:private”
- “traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https”
- “traefik.http.routers.traefik.middlewares=traefik-https-redirect”
- “traefik.http.routers.traefik-secure.entrypoints=https”
- “traefik.http.routers.traefik-secure.rule=Host(monitor.private.com)”
- “traefik.http.routers.traefik-secure.middlewares=traefik-auth”
- “traefik.http.routers.traefik-secure.tls=true”
- “traefik.http.routers.traefik-secure.tls.certresolver=http”
- “traefik.http.routers.traefik-secure.service=api@internal”

networks:
proxy:
external: true

app.yml

templates:

  • “templates/postgres.template.yml”
  • “templates/redis.template.yml”
  • “templates/web.template.yml”
  • “templates/web.ratelimited.template.yml”

expose:

params:
db_default_text_search_config: “pg_catalog.english”

db_shared_buffers: “128MB”

env:
LANG: en_US.UTF-8

UNICORN_WORKERS: 2

DISCOURSE_HOSTNAME: talk.private.com

DISCOURSE_DEVELOPER_EMAILS: ‘info@private.com’

LETSENCRYPT_ACCOUNT_EMAIL: info@private.com

volumes:

  • volume:
    host: /var/discourse/shared/standalone
    guest: /shared
  • volume:
    host: /var/discourse/shared/standalone/log/var-log
    guest: /var/log

hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone GitHub - discourse/docker_manager: Plugin for use with discourse docker image · GitHub

run:

  • exec: echo “Beginning of custom commands”
  • exec: echo “End of custom commands”

labels:
app_name: discourse

traefik.enable: true
traefik.docker.network: proxy
traefik.http.routers.discourse.rule: Host(talk.private.com)
traefik.http.routers.discourse.entrypoints: http
traefik.http.routers.discourse.middlewares: discourse_redirect2https
traefik.http.services.discourse.loadbalancer.server.port: 80

traefik.http.routers.discourse_secure.rule: Host(talk.private.com)
traefik.http.routers.discourse_secure.entrypoints: https
traefik.http.routers.discourse_secure.tls: true
traefik.http.routers.discourse_secure.service: discourse
traefik.http.routers.discourse_secure.tls.certresolver: http

traefik.http.middlewares.discourse_redirect2https.redirectscheme.scheme: https

docker_args:

  • “–network=proxy”

Entonces, ¿tienes alguna idea sobre por qué estoy recibiendo el error de contenido mixto?

Bueno, por un momento pensé que Discourse se había vuelto consciente porque recibí esta notificación en mi vista de administrador:

Sin embargo, hice este cambio y aún así recibí el error de contenido mixto. También cerré sesión, borré la caché y volví a iniciar sesión. Lo mismo.

Parece que mis solicitudes de inicio de sesión aún están cifradas, lo cual es bueno, supongo, pero necesito eliminar este error de contenido mixto. La configuración está arriba en la publicación anterior.

Otra actualización: la advertencia de contenido mixto ya no aparece. No estoy seguro de por qué. Supongo que está relacionado con la configuración force_https, sin embargo, no obtuve una carga limpia de la página durante quizás 30 minutos después de cambiar la configuración, a pesar de que limpié mi caché y cerré y volví a iniciar sesión, como mencioné anteriormente.

La buena noticia es que parece tener una instalación de Discourse funcional detrás de un proxy inverso Traefik.


Son las imágenes, que se cargan mediante conexiones HTTP. Tuve el mismo problema, mira:


¿Has montado el volumen correctamente? Traefik puede ser bastante confuso cuando se trata de las rutas.
Por ejemplo, yo hago lo siguiente:

volumes:       
  - /etc/ssl/certs/traefik/letsencrypt:/etc/ssl/certs/letsencrypt
  - /opt/traefik/traefik-config.yaml:/etc/traefik/traefik.yaml
  - /etc/passwd.traefik.dashboard:/etc/passwd.BasicAuth.dashboard
  - /etc/passwd.traefik.whoami:/etc/passwd.BasicAuth.whoami

No lo recuerdo con exactitud, pero había una razón para ello, quizás para poder verla bien en la CLI al listar las redes.

No, no lo monté de esta manera. Aquí está mi sección de volúmenes en docker-compose para Traefik:

    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data/traefik.yml:/traefik.yml:ro
      - ./data/acme.json:/acme.json

Noto que el mío ni siquiera menciona Let’s Encrypt, mientras que el tuyo sí. Supongo que creaste esa carpeta anidada en tu directorio de docker-compose y colocaste tu acme.json allí.

Lo otro que noto es que tengo esto: docker.sock y localtime. No estoy seguro de qué es el de localtime, y quizás la declaración de docker.sock sea un problema de seguridad. Necesito informarme sobre eso.

La creación del certificado de Let’s Encrypt la realiza Traefik. Montar un volumen me permite almacenarlo en el host en lugar de en Docker.
Recuerdo que configurar todos los montajes fue un verdadero dolor de cabeza; tuve que hacer todas las comprobaciones ejecutando docker exec -it:

  • ls
  • dir
  • vi