Acme: error: 403 :: urn:ietf:params:acme:error:unauthorized

Hi, I am new to traefik, and struggling with some problems. I am using traefik with docker and getting error cme: error: 403 :: urn:ietf:params:acme:error:unauthorized while trying to get certificate.
Full trace

time="2023-01-13T05:31:04Z" level=error msg="Unable to obtain ACME certificate for domains \"cp.dev.platina.uz\": unable to generate a certificate for the domains [cp.dev.platina.uz]: error: one or more domains had a problem:\n[cp.dev.platina.uz] acme: error: 403 :: urn:ietf:params:acme:error:unauthorized :: 109.205.182.6: Invalid response from https://t.me/Azamat_yamin: \"<!DOCTYPE html>\\n<html>\\n  <head>\\n    <meta charset=\\\"utf-8\\\">\\n    <title>Telegram: Contact @Azamat_yamin</title>\\n    <meta name=\\\"vi\", url: \n" routerName=web-secure-router@file rule="Host(`cp.dev.platina.uz`)" providerName=letsencrypt.acme

traefik.yml

log:
  level: INFO

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: web-secure

  web-secure:
    address: ":443"

certificatesResolvers:
  letsencrypt:
    acme:
      email: "email@gmail.com"
      storage: /etc/traefik/acme/acme.json
      httpChallenge:
        entryPoint: web

http:
  routers:
    web-secure-router:
      rule: "Host(`cp.dev.platina.uz`)"
      entryPoints:
        - web-secure
      middlewares:
        - csrf
      service: django
      tls:
        certResolver: letsencrypt

  middlewares:
    csrf:
      headers:
        hostsProxyHeaders: ["X-CSRFToken"]

  services:
    django:
      loadBalancer:
        servers:
          - url: http://django:5000

providers:
  file:
    filename: /etc/traefik/traefik.yml
    watch: true

Dockerfile

FROM traefik:v2.2.11
RUN mkdir -p /etc/traefik/acme \
  && touch /etc/traefik/acme/acme.json \
  && chmod 600 /etc/traefik/acme/acme.json
COPY ./compose/prod/traefik/traefik.yml /etc/traefik

prod.yml

  traefik:
    build:
      context: .
      dockerfile: ./compose/prod/traefik/Dockerfile
    image: platinauz_prod_traefik
    depends_on:
      - django
    volumes:
      - prod_traefik:/etc/traefik/acme
    ports:
      - "0.0.0.0:8080:80"
      - "0.0.0.0:4443:443"

Traefik splits its configuration into static (entrypoints, certresolver) and dynamic (router, service) configuration.

Static goes into traefik.yml in a default path or using --configFile=/traefik.yml (in command in docker-compose.yml). Alternatively place config as separate parameters under command.

Dynamic config can be loaded by a provider, either from file or from docker via labels.

You have your router in the static config, that does not work.

# static configuration traefik.yml
providers:
  file:
    filename: /etc/traefik/traefik-dynamic.yml
    watch: true
# dynamic config traefik-dynamic.yml
http:
  routers:
    web-secure-router:
      rule: "Host(`cp.dev.platina.uz`)"
      entryPoints:
        - web-secure
      middlewares:
        - csrf
      service: django
      tls:
        certResolver: letsencrypt
      middlewares:
        csrf

  middlewares:
    csrf:
      headers:
        hostsProxyHeaders: ["X-CSRFToken"]

  services:
    django:
      loadBalancer:
        servers:
          - url: http://django:5000

When you use a docker-compose.yml file, then you can do a setup without more files:

version: '3.9'

services:
  traefik:
    image: traefik:v2.96
    ports:
      - published: 80
        target: 80
        protocol: tcp
        mode: host
      - published: 443
        target: 443
        protocol: tcp
        mode: host
    networks:
      - proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /root/traefik-certificates:/traefik-certificates
    command:
      --providers.docker=true
      --providers.docker.network=proxy
      --providers.docker.exposedByDefault=false
      --entryPoints.web.address=:80
      --entryPoints.web.http.redirections.entryPoint.to=websecure
      --entryPoints.web.http.redirections.entryPoint.scheme=https
      --entryPoints.websecure.address=:443
      --entryPoints.websecure.http.tls=true
      --api.debug=true
      --api.dashboard=true
      --log.level=DEBUG
      --accesslog=true
      --certificatesResolvers.myresolver.acme.email=mail@example.com
      --certificatesResolvers.myresolver.acme.tlschallenge=true
      --certificatesResolvers.myresolver.acme.storage=/traefik-certificates/acme.json
    labels:
      - traefik.enable=true
      - traefik.http.routers.mydashboard.entrypoints=websecure
      - traefik.http.routers.mydashboard.rule=Host(`traefik.example.com`)
      - traefik.http.routers.mydashboard.tls.certresolver=myresolver
      - traefik.http.routers.mydashboard.service=api@internal
      - traefik.http.routers.mydashboard.middlewares=myauth
      - traefik.http.middlewares.myauth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/

  whoami:
    image: traefik/whoami:v1.8
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.mywhoami.entrypoints=websecure
      - traefik.http.routers.mywhoami.rule=Host(`example.com`) || Host(`www.example.com`)
      - traefik.http.routers.mywhoami.tls.certresolver=myresolver
      - traefik.http.services.mywhoami.loadbalancer.server.port=80

Note that you do not need to expose you application ports externally, Traefik and your application should just be in the same Docker network. acme.json should be placed in a volume or mounted folder to survive container re-builds, LetsEncrypt has some usage limits you might hit otherwise.

Thanks for anwer and attention.
What should I change in my case ? I am bit confused cause it is first time I use traefik. I do not understand why I am getting 403 error. I followed this tutorial which is the same settings used and worked with no problem.

There is a bunch of stuff not “best practice” looking at your configuration. And I don’t have time to watch the tutorial.

Basic LetsEncrypt needs port 80 or 443 to validate a certificate. You can’t use only 8080 and 4443.

You build your own Traefik container with Dockerfile. Why would you do that? Parallel you also have an image set. If you need a configuration file, you can mount it as folder from host or as volume. Makes it much easier to always use the latest version.

My recommendation: use my last docker-compose.yml and plug in your Django service where whoami is currently, replace label Host with your domain.

# create overlay network
docker network create -d overlay --attachable proxy

# start containers
docker compose up -d

I tried to use your docker-compose.yml , but got error service "treafik" refers to undefined network proxy: invalid compose project and created network docker network create -d overlay --attachable proxy, and now getting service "whoami" refers to undefined network proxy: invalid compose project , I have no idea what to do.

It probably depends on the compose file version you use.

Try adding the network definition:

networks:
  proxy:
    name: proxy
    external: true