Docker Registry Behind Traefik: Bad Certificate

I am trying to deploy a private docker registry on my server. The Docker registry works if I expose port 5000 via Docker. My goal, however, is to hide it behind traefik. I am using Let's Encrypt certificates.

When I try to access the registry via its traefik subdomain, I get the following error from the registry: remote error: tls: bad certificate

docker_registry  | 2022/03/09 15:03:33 http: TLS handshake error from xxx.xxx.xxx.xxx:48544: remote error: tls: bad certificate

After some Googling I think the reason might be that traefik terminates TLS, but that the registry expects TLS to be present. I am unsure though. Do you know why this might be happening and how I can make it work?

Works:

docker login registry.domain.com:5000

Does not work: (but should ideally work)

docker login registry.domain.com

My traefik and registry setup is following here:

Summary

Traefik Setup:

docker-compose.yml
.env only contains the DASHBOARD_PASSWORD used in dyanmic_conf.yml.

version: '2'
services:
  traefik:
    image: traefik:2.6
    container_name: traefik
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik.yml:/traefik.yml
      - ./dynamic_conf.yml:/dynamic_conf.yml
      - ./acme.json:/acme.json
    networks:
      - traefik
    env_file: .env

networks:
  traefik:
    external: true

traefik.yml

entryPoints:
  dashboard:
    address: :8080
  http:
    address: :80
  https:
    address: :443
    
api:
  dashboard: true

certificatesResolvers:
  myhttpchallenge:
    acme:
      httpChallenge:
        entryPoint: http
      email: my@mail.com
      storage: acme.json

providers:
  docker:
    exposedByDefault: false
    network: traefik
  file:
    filename: dynamic_conf.yml
    watch: true

log:
  level: INFO
  filePath: "./logs.log"
accessLog: {}

dyanmic_conf.yml

http:
  middlewares:
    dashboard-auth:
      basicAuth:
        users:
          - "admin:{{ env "DASHBOARD_PASSWORD"  }}"

    redirect-to-https:
      redirectScheme:
        scheme: https
        permanent: true

  routers:
    dashboard-api:
      entryPoints:
        - dashboard
      rule: "Host(`dashboard.domain.com`)"
      service: api@internal
      middlewares:
        - dashboard-auth

    secure-dashboard-api:
      entryPoints:
        - https
      rule: "Host(`dashboard.domain.com`)"
      service: api@internal
      middlewares:
        - dashboard-auth
      tls:
        certResolver: myhttpchallenge

    https-redirect:
      entryPoints:
        - http
      rule: "HostRegexp(`{host:.+}`)"
      service: dummy
      middlewares:
        - redirect-to-https

  services:
    dummy:
      loadBalancer:
        servers:
          - url: localhost

Registry setup

docker-compose.yml:

The certificate.crt and privatekey.key have been issued by Let's Encrypt and extracted from acme.json.

version: "3.9"
services:
  registry:
    image: registry:2.8.0
    container_name: docker_registry
    restart: always
    ports:
      - "5000:5000"
    volumes:
      - ./cert:/cert
      - ./data:/data
      - ./htpasswd:/auth/htpasswd
    environments:
      - REGISTRY_AUTH=htpasswd
      - REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
      - REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
      - REGISTRY_HTTP_TLS_CERTIFICATE=/cert/certificate.crt 
      - REGISTRY_HTTP_TLS_KEY=/cert/privatekey.key
      - REGISTRY_LOG_LEVEL=debug
      - REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.services.registry.loadbalancer.server.port=5000"
      - "traefik.http.services.registry.loadbalancer.server.scheme=https"
      - "traefik.http.routers.registry.entrypoints=https"
      - "traefik.http.routers.registry.tls.certresolver=myhttpchallenge"
      - "traefik.http.routers.registry.tls=true"
      - "traefik.http.routers.registry.rule=Host(`registry.domain.com`)"
    networks:
      - traefik

Hello @ocrmtinamu

One of Traefik's features is TLS termination so there is no need for extracting issued certificates from acme.json. Traefik will present a certificate that has been issued from Let's Encrypt for you configured domain in the rule section. The registry should be presented via HTTP and TLS termination is happening between client and Traefik.

Client -- HTTPS--> Traefik -- HTTP--> registry

Seems you just need to remove those environment variables:

  - REGISTRY_HTTP_TLS_CERTIFICATE=/cert/certificate.crt 
  - REGISTRY_HTTP_TLS_KEY=/cert/privatekey.key

and let Traefik do the rest of the job in regards to TLS.

What do you think?

1 Like

Yes, you were absolutely right. I removed both environment variables as well as the following line and it works.

Thank you very much for your input!

      - "traefik.http.services.registry.loadbalancer.server.scheme=https"

Perfect! Glad to hear that! :slight_smile:

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