Help with pgbouncer

Hi,

I have a docker file, with the following configuration (only relevant parts reported)

For traefik:

version: '3.5'
services:
  shared-traefik:
    image: traefik:v2.6.3
    container_name: shared-traefik
    ports:
      - "80:80"
      - "443:443"
      - "6432:6432"
    command:
      ...
      - --entrypoints.pgbouncer.address=:6432
      #- --entrypoints.pgbouncer.http.tls=true
      #- --entrypoints.pgbouncer.http.tls.certresolver=myresolver
    networks:
      .aaa_shared_network:

For pgbouncer:

  pgbouncer:
    image: bitnami/pgbouncer:1.16.1-debian-10-r117
    container_name: shared-pgbouncer
    ...
    networks:
      .aaa_shared_network:
    labels:
      - "traefik.enable=true"
      - "traefik.tcp.services.shared-pgbouncer.loadbalancer.server.port=6432"
      - "traefik.tcp.routers.shared-pgbouncer.entrypoints=pgbouncer"
      - "traefik.tcp.routers.shared-pgbouncer.service=shared-pgbouncer"
      - "traefik.tcp.routers.shared-pgbouncer.tls=false"
      - "traefik.tcp.routers.shared-pgbouncer.tls.certresolver=myresolver"
      - "traefik.tcp.routers.shared-pgbouncer.tls.domains[0].main=my.domain.com"
      - "traefik.tcp.routers.shared-pgbouncer.rule=HostSNI(`*`)"

This works fine: no tls, I can connect a client (e.g. pgadmin) to pgbouncer.
The issue is that I am unable to switch to TLS, for example, if I change the line:

- "traefik.tcp.routers.shared-pgbouncer.tls=false"

With:

- "traefik.tcp.routers.shared-pgbouncer.tls=true"

I am no more able to connect: I always go in "timeout".
I also tried to change:

- "traefik.tcp.routers.shared-pgbouncer.rule=HostSNI(`*`)"

With:

- "traefik.tcp.routers.shared-pgbouncer.rule=HostSNI(`my.domain.com`)"

But with no luck.
Can someone help please?

Regards.

I had the same troubles and this is how I solved it :slight_smile:

  • create only 1 resolver at the central traefik level
  • use it to generate domain.tld + *.domain.tld certs
  • have your services use this endpoint
  traefik:
    image: traefik:latest
    container_name: "traefik"
    command:
      - --log.level=DEBUG
      - --api.dashboard=true
      - --api.insecure=true
       # Do not expose all Docker services by default
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - -- "--providers.docker.endpoint=unix:///var/run/docker.sock"
      #- --providers.docker.endpoint=tcp://proxy:2375
      - --providers.docker.network=traefik-proxy
      
        # DNS Challenge (domain.tld and *.domain.tld DNS zones are defined there) : hetzner 
      #- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      - --certificatesresolvers.myresolver.acme.email=postmaster@${SERVER_HOSTNAME}
      - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.myresolver.acme.dnschallenge=true
      - --certificatesresolvers.myresolver.acme.dnschallenge.delaybeforecheck=0
      - --certificatesresolvers.myresolver.acme.dnschallenge.provider=hetzner
      - --certificatesresolvers.myresolver.acme.dnschallenge.resolvers=helium.ns.hetzner.de,hydrogen.ns.hetzner.com,oxygen.ns.hetzner.com 
        
        # HTTPS : port 443, with letsencrypt certificates provided by myresolver
      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls=true
      - --entrypoints.websecure.http.tls.certResolver=myresolver
      - --entrypoints.websecure.http.tls.domains[0].main=${CERT_DOMAIN}
      - --entrypoints.websecure.http.tls.domains[0].sans=*.${CERT_DOMAIN}

        # Redirect HTTP (web) to HTTPS (websecure)
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entryPoint.scheme=https
      - --entrypoints.web.http.redirections.entrypoint.permanent=true

and for a random service in another docker-compose.yml file

version: "3.6"

networks:
  database: {}
  node: {}
  frontend:
    external:
      name: traefik-proxy

services:
  whoami:
    image: "traefik/whoami"
    container_name: "whoami"
    networks:
      - frontend 
      - node
      - database
    ports:
      - 90:80
    labels:
      - traefik.enable=true
      - traefik.docker.network=traefik-proxy
      - traefik.http.routers.whoami.rule=Host(`whoami.${CERT_DOMAIN}`)
      - traefik.http.routers.whoami.entrypoints=websecure
      - traefik.http.services.whoami.loadbalancer.server.port=80

Note that I am using hetzner DNS challenge, but it should work with any other provider !

hope it helps !

Hi,

thank you for the help.
Actually, my issue is somehow different (and sorry, I did not state it clearly).
Exposing HTTP/HTTPS endpoints works fine for me, also over non default ports (i.e. no 80/443).

My issue is in exposing TCP/TCP+TLS endpoints.
The strange thing is that if I use Mosquitto, I am able to proxy 1883 (TCP/MQTT) and 8883 (TCP+TLS/MQTTS). Traefik:

services:
  shared-traefik:
    ...
    ports:
      - "80:80"
      - "443:443"
      - "1883:1883"
      - "8883:8883"
    command:
      - --log.level=INFO
      - --api=true
      - --api.insecure=true
      - --api.dashboard=true
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entryPoint.scheme=https
      - --entrypoints.web.http.redirections.entryPoint.priority=1
      - --entrypoints.web.http.redirections.entryPoint.permanent=true
      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls=true
      - --entrypoints.websecure.http.tls.certresolver=myresolver
      - --entrypoints.mqtt.address=:1883
      - --entrypoints.mqtt.http.tls=false
      - --entrypoints.mqtts.address=:8883
      - --entrypoints.mqtts.http.tls=true
      - --entrypoints.mqtts.http.tls.certresolver=myresolver
      - --certificatesresolvers.myresolver.acme.httpchallenge=true
      - --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
      #- --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
      - --certificatesresolvers.myresolver.acme.email=my@email.it
      - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
      - --providers.file.directory=/traefik-config
      - --providers.file.watch=true
      - --serverstransport.insecureskipverify=true
    networks:
      .aaa_shared_network:
   ...

And mosquitto:

shared-mosquitto:
      ...
      networks:
        .aaa_shared_network:
      labels:
        - "traefik.enable=true"
        - "traefik.tcp.services.shared-mosquitto.loadbalancer.server.port=1883"
        - "traefik.tcp.routers.shared-mosquitto.entrypoints=mqtts"
        - "traefik.tcp.routers.shared-mosquitto.tls=true"
        - "traefik.tcp.routers.shared-mosquitto.tls.certresolver=myresolver"
        - "traefik.tcp.routers.shared-mosquitto.rule=HostSNI(`my.domain.it`)"
        - "traefik.tcp.routers.shared-mosquitto-mqtt.entrypoints=mqtt"
        - "traefik.tcp.routers.shared-mosquitto-mqtt.rule=HostSNI(`*`)"
        - "traefik.tcp.routers.shared-mosquitto-mqtt.tls=false"

So I was expecting to be able to proxy pgbouncer with a similar config.
And actually, for the plain TCP case pgbouncer works fine.
So I am unable to understand why with TCP+TLS it does not works...
Every connection I try goes in timeout. So I tried a lot of tweaks in the hope to make it work, but with no luck. Maybe is it an incompatibility with pgbouncer? Or someting I do wrong in the connection? Or something else?

Regards

Hi,

after more research, I ended up with this answer in a similar post:

So I suppose it is not possible. It would have been nice, since traefik exposes valid certificates...

Regards.

The problem is the way that postgres does tls.

Postgres starts tls after connecting, it is done within postgres frontend/backend protocol. PostgreSQL: Documentation: 14: 53.2. Message Flow

Traefik is expecting a TLS handshake at the start and uses the servername from the SNI extensions to match a router.