Docker+Synapse+Traefik v2 stops working when I make a separate backend network

I'm trying to set up a Matrix Synapse server using Docker and a Traefik v2 reverse proxy.

My setup works if I define a single network in my docker-compose file and have Traefik, Synapse and postgres all use that network.

However, based on what I've learnt about Docker so far, I should put postgres on a separate network (backed) than Traefik (web). Synapse will then be on both networks. However, when I do so, I'm no longer able to connect to Synapse. It times out eventually saying Gateway Timeout.

It's as if Synapse is only listening on the backend network.

version: '3.2'
services:
  synapse:
    container_name: synapse
    hostname: ${MATRIX_HOSTNAME}
    image: docker.io/matrixdotorg/synapse:latest
    restart: unless-stopped
    environment:
      - SYNAPSE_SERVER_NAME=${MATRIX_HOSTNAME}
      - SYNAPSE_REPORT_STATS=yes
      - SYNAPSE_NO_TLS=1
      - SYNAPSE_ENABLE_REGISTRATION=no
      - SYNAPSE_LOG_LEVEL=DEBUG
      - SYNAPSE_REGISTRATION_SHARED_SECRET=${REG_SHARED_SECRET}
      - POSTGRES_DB=synapse
      - POSTGRES_HOST=db
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    # expose: 
    #   - "8008"
    volumes:
      - type: bind
        source: /opt/services/synapse
        target: /data
    depends_on:
      - db
    networks:
      - web
      - backend
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.synapse.rule=Host(`${MATRIX_HOSTNAME}`)"
      - "traefik.http.services.synapse.loadbalancer.server.port=8008"
      - "traefik.http.routers.synapse.entrypoints=websecure"
      - "traefik.http.routers.synapse.tls.certresolver=myresolver"
      - "traefik.docker.network=web"

  db:
    image: docker.io/postgres:10-alpine
    container_name: "synapse_db"
    restart: unless-stopped
    environment:
      - POSTGRES_DB=synapse
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - /opt/services/synapse_db:/var/lib/postgresql/data
    networks:
      - backend
    labels:
      - "traefik.enable=false"
  
  traefik:
    image: traefik:v2.5
    container_name: "traefik"
    command: 
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.network=web"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=${CERTBOT_EMAIL}"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
    ports:
      # Router forwards 443 on WAN to 8443 on host so we don't need root permissions
      - "8443:443"
      - "8080:8080"
    networks:
      - web
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"
    restart:
      unless-stopped

networks:
  web:
  backend:

And within Synapse's homeserver.yaml file, there is a section that could let me bind to a specific interface, but I have not made any changes so it should listen on all interfaces by default:

listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true

    resources:
      # - names: [client, federation]
      - names: [client]
        compress: false

If I go down to a single network setup it works. What am I doing wrong with the two network setup?


Solution 1:

Traefik doesn't know which IP of the container it should try to connect. You're close with traefik.docker.network=web but that's not really the name of the network. The network will get a prefix for the project or stack name.

To hard code the network name, you can use the name field in the final network section (this is specific to version 3.5 or newer):

version '3.5'
services:
  ...
networks:
  web:
    name: web
  backend:

Otherwise, set the project in your label (this is usually the current directory name when using docker-compose):

 labels:
 ...
  - "traefik.docker.network=your_project_name_here_web"