# How to get Let's Encrypt SAN certificate for domain and subdomains in one place?

**URL:** <https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272>\
**Category:** Traefik v2\
**Tags:** docker-swarm\
**Created:** [October 26, 2023, 2:13pm UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272 "2023-10-26T14:13:24Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![tamtakoe](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/tamtakoe/32/7757_2.png) [@tamtakoe](https://community.traefik.io/u/tamtakoe)\
**Post date:** [October 26, 2023, 2:13pm UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/1 "2023-10-26T14:13:24Z")

</div>

So I have `traefik` on `traefik.example.com` and `my-service` on `example.com` in docker-swarm mode and I want to get and define Let's Encrypt certificate for `example.com` and SAN for `*.example.com` (tls/http challenge only). Other words any other services on `www.example.com`, `smth.example.com` etc. should work by https with this settings. What should I write in config?

Current configuration (doesn't work correct):

```yaml
# docker-compose.traefik.yaml
version: '3.9'

services:
  traefik:
    image: traefik:v2.10
    
    ports:
      - 80:80
      - 443:443
      
    deploy:
      restart_policy:
        condition: on-failure
      placement:
        constraints:
          - node.labels.certificate-storage == true
          - node.role == manager
      labels:
        - traefik.enable=true

        - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
        - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true

        - traefik.http.routers.traefik-public-http.rule=Host(`traefik.example.com`)
        - traefik.http.routers.traefik-public-http.entrypoints=http
        - traefik.http.routers.traefik-public-http.middlewares=https-redirect

        - traefik.http.routers.traefik-public-https.rule=Host(`traefik.example.com`)
        - traefik.http.routers.traefik-public-https.entrypoints=https
        - traefik.http.routers.traefik-public-https.tls=true
        - traefik.http.routers.traefik-public-https.tls.certresolver=le
        - traefik.http.routers.traefik-public-https.tls.domains[0].main=example.com
        - traefik.http.routers.traefik-public-https.tls.domains[0].sans=*.example.com
        - traefik.http.routers.traefik-public-https.service=api@internal
        
        - traefik.http.services.traefik.loadbalancer.server.port=8080

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik-public-certificates:/certificates

    command:
      - --providers.docker
      - --providers.docker.exposedbydefault=false
      - --providers.docker.swarmmode
      
      - --entrypoints.http.address=:80
      - --entrypoints.https.address=:443
      
      - --certificatesresolvers.le.acme.email=test@gmail.com
      - --certificatesresolvers.le.acme.storage=/certificates/acme.json
      - --certificatesresolvers.le.acme.tlschallenge=true

    networks:
      - traefik-public

volumes:
  traefik-public-certificates:

networks:
  traefik-public:
    driver: overlay
    attachable: true

```

```yaml
# docker-compose.yaml
version: "3.9"

services:
  my-service:
    image: my-service:latest
    
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
      labels:
        - traefik.enable=true
        
        - traefik.http.services.my-service.loadbalancer.server.port=8080

        - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
        - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true

        - traefik.http.routers.my-service-http.rule=Host(`example.com`)
        - traefik.http.routers.my-service-http.entrypoints=http
        - traefik.http.routers.my-service-http.middlewares=https-redirect
        
        - traefik.http.routers.my-service-https.rule=Host(`example.com`)
        - traefik.http.routers.my-service-https.entrypoints=https
        - traefik.http.routers.my-service-https.tls=true
        - traefik.http.routers.my-service-https.tls.certresolver=le

    networks:
      - traefik-public

networks:
  traefik-public:

```

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [October 26, 2023, 5:21pm UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/2 "2023-10-26T17:21:10Z")

</div>

How many Docker Swarm managers do you have?

In general Traefik open source and LetsEncrypt only works with a single instance.

---

<div class="post-metadata">

**Author:** ![tamtakoe](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/tamtakoe/32/7757_2.png) [@tamtakoe](https://community.traefik.io/u/tamtakoe)\
**Post date:** [October 26, 2023, 5:58pm UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/3 "2023-10-26T17:58:46Z")

</div>

One manager. And all services in one node for now

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [October 27, 2023, 7:19am UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/4 "2023-10-27T07:19:44Z")

</div>

For wildcards you need to use dnsChallenge, define via main/sans, see [Traefik LE doc](https://doc.traefik.io/traefik/https/acme/).

For a couple of sub-domains you can just get separate certs, AFAIK current LE limit is 50 different per week.

---

<div class="post-metadata">

**Author:** ![tamtakoe](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/tamtakoe/32/7757_2.png) [@tamtakoe](https://community.traefik.io/u/tamtakoe)\
**Post date:** [October 27, 2023, 3:37pm UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/5 "2023-10-27T15:37:11Z")

</div>

Yeah, separate certificates is my way for now. Anyway it's strange that Let's Encrypt provides wildcard SAN certificates, Traefik seems to provide them (by tls/http challenge) but I can't configure them

---

<div class="post-metadata">

**Author:** ![tamtakoe](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/tamtakoe/32/7757_2.png) [@tamtakoe](https://community.traefik.io/u/tamtakoe)\
**Post date:** [October 27, 2023, 4:01pm UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/6 "2023-10-27T16:01:54Z")

</div>

And one more question.

I don't understand why we describe SAN certificates for particular route?

```auto
- "traefik.http.routers.traefik-public-https.tls.domains[0].main=example.com"
- "traefik.http.routers.traefik-public-https.tls.domains[0].sans=traefik.example.com, www.example.com"

```

Looks like it should be in a global config because of we use certificate for domain, not for route (generally).

I also found config for SAN certificates looks like more correct

```auto
# traefik.yaml
certificatesResolvers:
  le:
    acme:
      email: $EMAIL
      storage: /acme.json
      httpChallenge:
        entryPoint: http
      tlsChallenge:
        keyType: "EC256"
      domains:
        - main: "example.com"
          sans:
            - "traefik.example.com"
            - "www.example.com"

```

But why I can't describe this resolver inside command section of docker compose? Why I can set both httpChallenge and tlsChallenge? Is this gonna work? Why I have to set `keyType` value instead of `true` if we have default value (according doc)? Why this way of using SAN certificates doesn't work for me? Bad config or this is beta-feature?

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [October 27, 2023, 6:09pm UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/7 "2023-10-27T18:09:08Z")

</div>

You can declare `certResolver` via `command`, see [doc](https://doc.traefik.io/traefik/reference/static-configuration/cli/).

AFAIK you can only use one type of challenge.

---

<div class="post-metadata">

**Author:** ![tamtakoe](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/tamtakoe/32/7757_2.png) [@tamtakoe](https://community.traefik.io/u/tamtakoe)\
**Post date:** [October 27, 2023, 6:20pm UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/8 "2023-10-27T18:20:20Z")

</div>

But I can't declare main/sans via CLI certResolver

---

<div class="post-metadata">

**Author:** ![tamtakoe](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/tamtakoe/32/7757_2.png) [@tamtakoe](https://community.traefik.io/u/tamtakoe)\
**Post date:** [October 27, 2023, 8:56pm UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/9 "2023-10-27T20:56:46Z")

</div>

Can I use `defaultGeneratedCert ` settings for my case?

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [October 28, 2023, 6:31am UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/10 "2023-10-28T06:31:12Z")

</div>

Yes, you can:

> --entrypoints..http.tls.domains[n].main:  
> Default subject name.

> --entrypoints..http.tls.domains[n].sans:  
> Subject alternative names.

---

<div class="post-metadata">

**Author:** ![tamtakoe](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/tamtakoe/32/7757_2.png) [@tamtakoe](https://community.traefik.io/u/tamtakoe)\
**Post date:** [October 29, 2023, 6:03am UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/11 "2023-10-29T06:03:25Z")

</div>

> [@bluepuma77](#):
>
> --entrypoints..http.tls.domains[n].sans:

command traefik error: failed to decode configuration from flags: field not found, node: tls

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [October 29, 2023, 6:12am UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/12 "2023-10-29T06:12:31Z")

</div>

How about you search this forum, as this has been discussed and solved here many times before.

Note the [n] is an index, should be:

```auto
[0].main=example.com
[0].sans=*.example.com

```

---

<div class="post-metadata">

**Author:** ![tamtakoe](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/tamtakoe/32/7757_2.png) [@tamtakoe](https://community.traefik.io/u/tamtakoe)\
**Post date:** [October 29, 2023, 6:20am UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/13 "2023-10-29T06:20:58Z")

</div>

My experiments show that this is the only way to get a SAN certificate:

```yaml
#docker-compose.traefik (services.traefik.deploy.labels)
- traefik.http.routers.traefik.tls.domains[0].main=example.com
- traefik.http.routers.traefik.tls.domains[0].sans=sub1.example.com, sub2.example.com, etc.example.com

```

Asterisk template unfortunatelly doesn't work

```yaml
- traefik.http.routers.traefik.tls.domains[0].sans=*.example.com

```

Unable to obtain ACME certificate for domains "example.com,_.example.com"" rule="Host(`traefik.example.com`)" error="unable to generate a certificate for the domains [[example.com](http://example.com) .example.com]: error: one or more domains had a problem:\n[.example.com] [_.example.com] acme: could not determine solvers\n" routerName=traefik@docker providerName=le.acme ACME CA="[https://acme-v02.api.letsencrypt.org/directory](https://acme-v02.api.letsencrypt.org/directory)"

---

<div class="post-metadata">

**Author:** ![bluepuma77](https://avatars.discourse-cdn.com/v4/letter/b/a9adbd/32.png) [@bluepuma77](https://community.traefik.io/u/bluepuma77)\
**Post date:** [October 29, 2023, 6:52pm UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/14 "2023-10-29T18:52:16Z")

</div>

Did you try with quotes?

```auto
- "--entrypoints.websecure.http.tls.domains[0].main=${DOMAIN}"
- "--entrypoints.websecure.http.tls.domains[0].sans=*.${DOMAIN}"

```

---

<div class="post-metadata">

**Author:** ![alexander-sneg](https://sea2.discourse-cdn.com/flex020/user_avatar/community.traefik.io/alexander-sneg/32/9692_2.png) [@alexander-sneg](https://community.traefik.io/u/alexander-sneg)\
**Post date:** [December 14, 2024, 10:41am UTC](https://community.traefik.io/t/how-to-get-lets-encrypt-san-certificate-for-domain-and-subdomains-in-one-place/20272/15 "2024-12-14T10:41:40Z")

</div>

Hello!

This is an old topic, but it is very relevant to me right now.

Why can’t I use global settings in traefik.yml?  
It simply doesn’t work.  
For example:

```auto
  websecure:
    address: ":443"
    http:
      tls:
        certResolver: letencrypt
        domains:
          - main: example.com
            sans:
              - "*.example.com"

```

```auto
certificatesResolvers:
  letencrypt:
    acme:
      email: e-mail@gmail.com
      storage: /certs/acme.json
# caServer: https://acme-v02.api.letsencrypt.org/directory # production (default)
      caServer: https://acme-staging-v02.api.letsencrypt.org/directory # staging
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - 1.1.1.1:53
          - 1.0.0.1:53

```

If I add labels, for example, to the Traefik service, then everything works perfectly:

```auto
- "traefik.http.routers.wildcard_cert.tls.certresolver=letencrypt"
- "traefik.http.routers.wildcard_cert.tls.domains[0].main=example.com"
- "traefik.http.routers.wildcard_cert.tls.domains[0].sans=*.example.com"

```

Here is the full configuration, but unfortunately, the wildcard certificate is not being issued.(

**traefik.yml**

```auto
global:
  checkNewVersion: false
  sendAnonymousUsage: false

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entrypoint:
          to: websecure
          scheme: https

  websecure:
    address: ":443"
    http:
      tls:
        certResolver: letencrypt
        domains:
          - main: example.com
            sans:
              - "*.example.com"

log:
  level: DEBUG

api:
  insecure: true
  dashboard: true

providers:
  docker:
    exposedByDefault: false

certificatesResolvers:
  letencrypt:
    acme:
      email: e-mail@gmail.com
      storage: /certs/acme.json
# caServer: https://acme-v02.api.letsencrypt.org/directory # production (default)
      caServer: https://acme-staging-v02.api.letsencrypt.org/directory # staging
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - 1.1.1.1:53
          - 1.0.0.1:53
        delayBeforeCheck: 20

```

I’m also interested in the answer to this question:

> [@tamtakoe](#):
>
> I don't understand why we describe SAN certificates for particular route?

> [@tamtakoe](#):
>
> Looks like it should be in a global config because of we use certificate for domain, not for route (generally).

(Please don’t judge me for any mistakes; English is not my native language, and I’m using a translator.)

Best regards,  
Alexander
