How to Re-issue let's encrypt when new subdomains/mutiple domains added for Trafik on docker and also config refactoring to own toml for each service

Hi :slight_smile:

  1. My previous effort to add additional domain was just to do
  • docker-compose down
  • remove the acme.json file
  • add another section in traefik.toml for the new domain
  • docker-compose up -d
  • new acme.json was generated

Now the problem is I tried the same procedure and it failed,
the acme.json file, if I delete the file and do docker-compose down && docker-compose up -d it is created as a directory

Also, I want to add new subdomains, for some reason only www is being available in the certificate. Can someone check my configs and see where I made mistake?

What is a good approach to drop current certificates for our domain and re-issue new certificate having additional subdomains?

  1. And while here, how to refactor the traefik.frontend.rule=PathPrefix labels in own config file, cause they are hard to maintain?

In the docker composer base directory I got a directory called traefik/ for the same service having a Trafik docker image.

traefik.toml

    debug = false

    logLevel = "ERROR"
    defaultEntryPoints = ["https","http"]
    
    [entryPoints]
      [entryPoints.http]
      address = ":80"
        [entryPoints.http.redirect]
        entryPoint = "https"
      [entryPoints.https]
      address = ":443"
      [entryPoints.https.tls]
    
    [docker]
    domain = 'mydomain.mk'
    exposedByDefault = false
    
    [acme]
    email = "info@mydomain.mk"
    storage = "acme.json"
    entryPoint = "https"
    onHostRule = true
    
    [acme.httpChallenge]
    entryPoint = "http"
    
    [[acme.domains]]
    main = "*.mydomain.mk"
    sans = ["mydomain.mk", "www.mydomain.mk", "api.mydomain.mk", "beta.mydomain.mk"]
    
    
    [[acme.domains]]
    main = "*.mydomain.de"
    sans = ["mydomain.de", "www.mydomain.de", "api.mydomain.de", "beta.mydomain.de"]

acme.json

    {
      "Account": {
        "Email": "info@mydomain.mk",
        "Registration": {
          "body": {
            "status": "valid",
            "contact": [
              "mailto:info@mydomain.mk"
            ]
          },
          "uri": "https://acme-v02.api.letsencrypt.org/acme/acct/50006191"
        },
        "PrivateKey": "base64 excerpt...",
        "KeyType": "4096"
      },
      "Certificates": [
        {
          "Domain": {
            "Main": "mydomain.mk",
            "SANs": [
              "www.mydomain.mk"
            ]
          },
          "Certificate": "base64 excerpt...",
          "Key": "base64 excerpt...
        },
        {
          "Domain": {
            "Main": "mydomain.de",
            "SANs": [
              "www.mydomain.de"
            ]
          },
          "Certificate": "base64 excerpt...",
          "Key": "base64 excerpt..."
        }
      ],
      "HTTPChallenges": {},
      "TLSChallenges": null
    }

docker-compose.yml

version: '3.1'
services:
  traefik:
    image: traefik
    command:
        --accessLog.filePath="/logs/access.log" \
        --acme.storage=/acme.json --logLevel=debug \
        ${TRAEFIK_ENTRYPOINT_HTTP} ${TRAEFIK_ENTRYPOINT_HTTPS} \
        --defaultentrypoints=${TRAEFIK_DEFAULT_ENTRYPOINTS} \
        --acme=${ACME_ENABLE} --acme.entrypoint=https --acme.httpchallenge --acme.httpchallenge.entrypoint=http \
        --acme.domains="${ACME_DOMAINS}" --acme.email="${ACME_EMAIL}" \
        --docker --docker.domain="${DOCKER_DOMAIN}" --docker.endpoint="unix:///var/run/docker.sock" \
        --docker.watch=true --docker.exposedbydefault="true"
    ports:
      - "${EDGE_PORT:-80:80}"           # The HTTP port
      - "${EDGES_PORT:-443:443}"        # The HTTPS port
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock  # So that Traefik can listen to the Docker events
      - ./traefik/traefik.toml:/traefik.toml
      - ./traefik/acme.json:/acme.json
      - router-logs:/logs
    labels:
      - "traefik.frontend.headers.allowedHosts=www.mydomain.mk,mydomain.mk,www.mydomain.de,mydomain.de,${ADDITIONAL_HOSTS}"
      - "traefik.frontend.headers.browserXSSFilter=true"

    restart: on-failure
  service1:
      image: '${DOCKER_REGISTRY:-mydomain.mk:5000/}${SERVICE1_IMG:-service1:latest}'
      labels:
          - "traefik.port=80"
          - "traefik.frontend.entryPoints=https,http"
          - "traefik.frontend.rule=PathPrefix:/v/,/v/dashboard,/v/dashboard/"
          - "traefik.frontend.rule=PathPrefixStrip:/v/,/v/dashboard,/v/dashboard/"
          - "traefik.frontend.headers.allowedHosts=www.mydomain.mk,mydomain.mk,www.mydomain.de,mydomain.de,${ADDITIONAL_HOSTS}"
          - "traefik.frontend.headers.browserXSSFilter=true"

.env file content

EDGE_PORT=80:80
EDGES_PORT=443:443

# This will allow local development or new domains
# ADDITIONAL_HOSTS=

# ACME
ACME_ENABLE=true
ACME_EMAIL=info@mydomain.mk
ACME_DOMAINS=mydomain.mk,www.mydomain.mk,mydomain.de,www.mydomain.de

DOCKER_DOMAIN=mydomain.mk

TRAEFIK_DEFAULT_ENTRYPOINTS=http
TRAEFIK_ENTRYPOINT_HTTP=--entryPoints="Name:http Address::80"
TRAEFIK_ENTRYPOINT_HTTPS=--entryPoints="Name:https Address::443 TLS"
TRAEFIK_HOST=mydomain.mk,www.mydomain.mk,mydomain.de,www.mydomain.de

Hello,

It’s not possible to add 2 traefik.frontend.rule on one container.

Hi @damjan, a few feedbacks here:


Cleaning up the docker-compose stack:

Whatever solution you're taking for the acme.json file (see below), you might want to use docker-compose down --volumes (Reference: https://docs.docker.com/compose/reference/down/): this flag also delete all the volumes related to the containers of your docker compose stack, ensuring that no state is kept between your different tries.


Iterating over ACME Traefik Configuration avoiding rate limits:

# traefik.toml
...
[acme]
...
caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
...

You might be interested in setting the acme.caServer option (reference from https://docs.traefik.io/configuration/acme/)
to the Let's Encrypt staging (https://letsencrypt.org/docs/staging-environment/)

so you can easily iterate on your ACME configuration without reaching Let's Encrypt rate limits.

The only "downside" is that the generated certificates from Let's Encrypt will be signed by the authority "Fake LE X1" that you might want to trust.

Once your configuration is OK: cleanup the environement and disable this directive to switch to the "production" Let's Encrypt with rate limit (but full browser support)


ACME json file storage

You might want to specify a folder /acme where to store the JSON file as a docker host-mounted volume, so it will be an empty directory containing the file, instead of the file itself:

# docker-compose.yml
...
    command:
      ...
      - --acme.storage:/acme/acme.json
      ...
    volumes:
      - ./traefik/acme:/acme

An improved way would be to use a Docker Named Volume in your compose file, and mount this volume for the acme.json. This would make the docker-compose.yml more portable (think remote Docker Engines). Any backup of the acme.json file would be done with a docker cp ... :slight_smile:


Simplify Traefik Configuration:

You might want to choose to configure Traefik either with only CLI flags, or with traefik.toml, but you should avoid using a mix of both, as it complexify precedence of arguments.

It sounds like you're using environment variables: maybe a full CLI flags solution, without traefik.toml would be preferable in this context.


Friends don't let friends to use :latest:

You might want to set the tag of the traefik Docker image, to avoid breaking your stack when the v2.0 will be released

@damjan Remove the rule PathPrefix, as PathPrefixStrip is implying PathPrefix , as explained in https://docs.traefik.io/basics/#modifiers .