Traefik in docker compose with a proxy service to forward to host service

Running on Ubuntu 22.04, I have a docker compose which includes some backend and frontend services which are using Traefik with labels without problem, but I would like to specify a proxy for some service running on host (created by supabase CLI)

Here is the interesting extract of docker-compose:

version: "3.8"

services:
  traefik:
    image: traefik:v2.7
    container_name: traefik
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=${EMAIL}"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
      - "--log.level=DEBUG"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"
    restart: always
    env_file:
      - .env
...
working backend and frontend part
...
  # Supabase API Proxy Service
  supabase-api-proxy:
    image: alpine
    container_name: supabase-api-proxy
    command: /bin/sh -c "sleep infinity"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.supabase-api.rule=Host(`${SUPABASE_API_DOMAIN_NAME}`)"
      - "traefik.http.routers.supabase-api.entrypoints=websecure"
      - "traefik.http.routers.supabase-api.tls.certresolver=myresolver"
      - "traefik.http.services.supabase-api.loadalancer.server.port=54321"
      - "traefik.http.services.supabase-api.loadbalancer.server.scheme=http"
      - "traefik.http.services.supabase-api.loadbalancer.passhostheader=true"
    networks:
      - default
    extra_hosts:
      - "host.docker.internal:${HOST_IP}"

  # Supabase Studio Proxy Service
  supabase-studio-proxy:
    image: alpine
    container_name: supabase-studio-proxy
    command: /bin/sh -c "sleep infinity"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.supabase-studio.rule=Host(`${SUPABASE_STUDIO_DOMAIN_NAME}`)"
      - "traefik.http.routers.supabase-studio.entrypoints=websecure"
      - "traefik.http.routers.supabase-studio.tls.certresolver=myresolver"
      - "traefik.http.services.supabase-studio.loadbalancer.server.port=54323"
      - "traefik.http.services.supabase-studio.loadbalancer.server.scheme=http"
      - "traefik.http.services.supabase-studio.loadbalancer.passhostheader=true"
    networks:
      - default
    extra_hosts:
      - "host.docker.internal:${HOST_IP}"

To add more context, supabase CLI is behind the scene launch its own docker compose with several services like follow:

28680490c70e   public.ecr.aws/supabase/studio:20240301-0942bfe   "docker-entrypoint.s…"   2 days ago      Up 2 days (healthy)          0.0.0.0:54323->3000/tcp, :::54323->3000/tcp                            supabase_studio_secondbrain
7bc28a457495   public.ecr.aws/supabase/postgres-meta:v0.79.0     "docker-entrypoint.s…"   2 days ago      Up 2 days (healthy)          8080/tcp                                                               supabase_pg_meta_secondbrain
145d3e2754ff   public.ecr.aws/supabase/edge-runtime:v1.38.0      "sh -c 'mkdir -p /ho…"   2 days ago      Up 2 days                    8081/tcp                                                               supabase_edge_runtime_secondbrain
21935e272123   public.ecr.aws/supabase/imgproxy:v3.8.0           "imgproxy"               2 days ago      Up 2 days (healthy)          8080/tcp                                                               storage_imgproxy_secondbrain
d8f41fa6e77e   public.ecr.aws/supabase/storage-api:v0.46.4       "docker-entrypoint.s…"   2 days ago      Up 2 days (healthy)          5000/tcp                                                               supabase_storage_secondbrain
49fdf5a610d2   public.ecr.aws/supabase/postgrest:v12.0.1         "/bin/postgrest"         2 days ago      Up 2 days                    3000/tcp                                                               supabase_rest_secondbrain
b912200fe3ae   public.ecr.aws/supabase/realtime:v2.25.66         "/usr/bin/tini -s -g…"   2 days ago      Up 2 days (healthy)          4000/tcp                                                               realtime-dev.supabase_realtime_secondbrain
0318c317aebd   public.ecr.aws/supabase/inbucket:3.0.3            "/start-inbucket.sh …"   2 days ago      Up 2 days (healthy)          1100/tcp, 2500/tcp, 0.0.0.0:54324->9000/tcp, :::54324->9000/tcp        supabase_inbucket_secondbrain
3693ec574d85   public.ecr.aws/supabase/gotrue:v2.143.0           "auth"                   2 days ago      Up 2 days (healthy)          9999/tcp                                                               supabase_auth_secondbrain
f4ade71d687b   public.ecr.aws/supabase/kong:2.8.1                "sh -c 'cat <<'EOF' …"   2 days ago      Up 2 days (healthy)          8001/tcp, 8443-8444/tcp, 0.0.0.0:54321->8000/tcp, :::54321->8000/tcp   supabase_kong_secondbrain
6f9e292eaffa   public.ecr.aws/supabase/postgres:15.1.0.147       "sh -c 'cat <<'EOF' …"   2 days ago      Up 2 days (healthy)          0.0.0.0:54322->5432/tcp, :::54322->5432/tcp                            supabase_db_secondbrain

When trying to access one the service (Studio for example), I got:

traefik | time="2024-03-12T16:38:57Z" level=debug msg="'502 Bad Gateway' caused by: dial tcp 172.27.0.3:54323: connect: connection refused"

Any hint would of course be greatly appreciated!

Thanks in advance,
Pascal

"Bad Gateway" usually happens when using Traefik Docker Configuration Discovery and multiple Docker networks.

The logic is a bit dump, as Traefik will identify all IPs of the target services/containers and send to them round robin, without checking if Traefik is actually part of the network itself.

Use docker.network to specify the network to use, on provider or labels.

Thanks for the answer @bluepuma77 !

I updated as follow:

  supabase-studio-proxy:
    image: alpine
    container_name: supabase-studio-proxy
    command: /bin/sh -c "sleep infinity"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.supabase-studio.rule=Host(`${SUPABASE_STUDIO_DOMAIN_NAME}`)"
      - "traefik.http.routers.supabase-studio.entrypoints=websecure"
      - "traefik.http.routers.supabase-studio.tls.certresolver=myresolver"
      - "traefik.http.services.supabase-studio.loadbalancer.server.port=54323"
      - "traefik.http.services.supabase-studio.loadbalancer.server.scheme=http"
      - "traefik.http.services.supabase-studio.loadbalancer.passhostheader=true"
      - "traefik.docker.network=supabase_network_secondbrain"
    # extra_hosts:
    #   - "host.docker.internal:${HOST_IP}"

where supabase_network_secondbrain is the netwrok name where the supabase services are running but similar log...

I decided to give a try at mixing both docker and file providers and it worked out!

version: "3.8"

services:
  traefik:
    image: traefik:v2.7
    container_name: traefik
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.file.directory=/traefik"
      - "--providers.file.watch=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=${EMAIL}"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
      - "--log.level=DEBUG"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"
      - "./traefik:/traefik"
    restart: always
    env_file:
      - .env

and

http:
  routers:
    supabase-api:
      rule: "Host(`{{env "SUPABASE_API_DOMAIN_NAME"}}`)"
      service: "supabase-api"
      entryPoints: ["websecure"]
      tls:
        certResolver: myresolver
    supabase-studio:
      rule: "Host(`{{env "SUPABASE_STUDIO_DOMAIN_NAME"}}`)"
      service: "supabase-studio"
      entryPoints: ["websecure"]
      tls:
        certResolver: myresolver

  services:
    supabase-api:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://{{env "HOST_IP"}}:54321"
    supabase-studio:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://{{env "HOST_IP"}}:54323"
1 Like

You can simplify by placing certresolver only one time on entrypoint.

Note there is official Docker self-hosting (link) and a referenced Docker with Traefik self-hosting (link).

1 Like

Yes, I know about the self-hosting but I depend on an OS project where I currently can't do it...

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.