> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pangolin.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Wildcard Domains

> Configure wildcard TLS certificates with Traefik DNS-01 challenges

<div id="pangolin-toc-cta" className="pangolin-toc-cta-source">
  <Card title="Try free on Pangolin Cloud" icon="cloud" href="https://app.pangolin.net/auth/signup" arrow="true" cta="Sign up free">
    Fastest way to get started with Pangolin using the hosted control plane. No credit card required.
  </Card>
</div>

Wildcard certificates let one certificate cover every first-level subdomain of a domain, such as `*.example.com`. They are useful when you create many resources under the same base domain because Traefik does not need to request a new certificate for every resource hostname.

Traefik is the reverse proxy in the self-hosted Pangolin stack. It receives HTTPS traffic, requests certificates from Let's Encrypt, and routes requests to Pangolin resources. A Traefik certificate resolver is the named block of Traefik configuration that tells Traefik how to request certificates.

<Warning>
  Wildcard certificates require a DNS-01 challenge. You must control the domain's DNS records and have API credentials for a DNS provider supported by Traefik.
</Warning>

<Note>
  Let's Encrypt only issues wildcard certificates through DNS-01 challenges. See the [Traefik ACME documentation](https://doc.traefik.io/traefik/https/acme/) and [Lego DNS provider list](https://go-acme.github.io/lego/dns/) for provider-specific options.
</Note>

## How Wildcards Work

* `*.example.com` covers `app.example.com`, `api.example.com`, and `blog.example.com`.
* `*.example.com` does not cover `app.internal.example.com`; that needs `*.internal.example.com`.
* A wildcard certificate can reduce Let's Encrypt rate limit pressure because many resource hostnames can reuse the same certificate.

Pangolin can prefer wildcard certificates when it generates Traefik router configuration. For example, if you have resources at `blog.example.com` and `api.example.com`, Pangolin can ask Traefik to request `*.example.com` instead of separate certificates for each hostname.

## Benefits

<CardGroup cols={3}>
  <Card title="Single Certificate" icon="certificate">
    Secure many subdomains under the same base domain with one certificate.
  </Card>

  <Card title="Instant Subdomains" icon="bolt">
    New resource subdomains can use the existing wildcard certificate instead of waiting for a new certificate request.
  </Card>

  <Card title="Rate Limit Friendly" icon="shield">
    Fewer certificate requests can help reduce the chance of hitting Let's Encrypt rate limits.
  </Card>
</CardGroup>

## Choose a Resolver Strategy

Most installs start with one Traefik certificate resolver named `letsencrypt` that uses HTTP-01:

```yaml title="traefik_config.yml" theme={"theme":"gruvbox-light-hard"}
certificatesResolvers:
  letsencrypt:
    acme:
      httpChallenge:
        entryPoint: web
      email: "admin@example.com"
      storage: "/letsencrypt/acme.json"
      caServer: "https://acme-v02.api.letsencrypt.org/directory"
```

HTTP-01 proves domain ownership by serving a challenge over port `80`. DNS-01 proves domain ownership by creating a temporary DNS record through your DNS provider. Wildcard certificates require DNS-01.

For wildcard certificates, you have two good options. Most users should replace the existing `letsencrypt` resolver with DNS-01; add a second resolver only if you know you need both HTTP-01 and DNS-01.

| Strategy                          | When to use it                                                                                  |
| --------------------------------- | ----------------------------------------------------------------------------------------------- |
| Replace `letsencrypt` with DNS-01 | Simplest option. Use this if all certificates can be issued through your DNS provider.          |
| Add a second resolver             | Use this if you want to keep HTTP-01 for some routers and use DNS-01 only for wildcard domains. |

Traefik does not automatically apply a resolver just because it exists. Each router must reference the resolver with `tls.certResolver`, and Pangolin's `cert_resolver` setting must match the Traefik resolver name.

<Note>
  In the Pangolin dashboard, `default` uses Pangolin's configured `traefik.cert_resolver` value. In a standard install, that default value is `letsencrypt`.
</Note>

## Configure DNS-01 Wildcards

<Steps>
  <Step title="Stop the stack">
    Stop Pangolin before editing Traefik and Pangolin configuration.

    ```bash theme={"theme":"gruvbox-light-hard"}
    sudo docker compose down
    ```
  </Step>

  <Step title="Update the Traefik resolver">
    Replace the default HTTP-01 resolver with a DNS-01 resolver. This example uses Cloudflare.

    ```yaml title="config/traefik/traefik_config.yml" highlight={4-6} theme={"theme":"gruvbox-light-hard"}
    certificatesResolvers:
      letsencrypt:
        acme:
          dnsChallenge:
            provider: "cloudflare"
            # See https://doc.traefik.io/traefik/https/acme/#providers
          email: "admin@example.com"
          storage: "/letsencrypt/acme.json"
          caServer: "https://acme-v02.api.letsencrypt.org/directory"
    ```

    <Note>
      The resolver name is the key under `certificatesResolvers`. In this example it is `letsencrypt`, so Pangolin's `cert_resolver` and any Traefik `tls.certResolver` values must also use `letsencrypt`.
    </Note>
  </Step>

  <Step title="Add DNS provider credentials">
    Add the environment variables required by your DNS provider to the `traefik` service. Cloudflare requires an API token with `Zone:Read` and `DNS:Edit` permissions for every zone Traefik needs to solve challenges for.

    ```yaml title="docker-compose.yml" highlight={11-12} theme={"theme":"gruvbox-light-hard"}
    traefik:
      image: docker.io/traefik:v3.6
      container_name: traefik
      restart: unless-stopped
      network_mode: service:gerbil
      depends_on:
        pangolin:
          condition: service_healthy
      command:
        - --configFile=/etc/traefik/traefik_config.yml
      environment:
        CLOUDFLARE_DNS_API_TOKEN: "your-cloudflare-api-token" # REPLACE
      volumes:
        - ./config/traefik:/etc/traefik:ro
        - ./config/letsencrypt:/letsencrypt
    ```
  </Step>

  <Step title="Tell Pangolin to prefer wildcard certificates">
    Set `prefer_wildcard_cert: true` for the domain in `config/config.yml`.

    ```yaml title="config/config.yml" highlight={4} theme={"theme":"gruvbox-light-hard"}
    domains:
      domain1:
        base_domain: "example.com"
        prefer_wildcard_cert: true
        cert_resolver: "letsencrypt"
    ```

    If you manage domains through the Pangolin dashboard instead, restart Pangolin and enable wildcard preference on the domain there. The dashboard also lets you set the domain's certificate resolver; it must match the resolver name in Traefik.
  </Step>

  <Step title="Restart the stack">
    Start the stack and watch Traefik logs. You should see Traefik create DNS challenge records through your provider.

    ```bash theme={"theme":"gruvbox-light-hard"}
    sudo docker compose up -d
    sudo docker compose logs -f traefik
    ```
  </Step>
</Steps>

## Multiple Certificate Resolvers

You can define more than one Traefik certificate resolver. This is useful when you want to keep HTTP-01 available as the default resolver, but use a DNS-01 resolver for wildcard domains.

```yaml title="config/traefik/traefik_config.yml" theme={"theme":"gruvbox-light-hard"}
certificatesResolvers:
  letsencrypt:
    acme:
      httpChallenge:
        entryPoint: web
      email: "admin@example.com"
      storage: "/letsencrypt/acme-http.json"
      caServer: "https://acme-v02.api.letsencrypt.org/directory"

  letsencrypt-dns:
    acme:
      dnsChallenge:
        provider: "cloudflare"
      email: "admin@example.com"
      storage: "/letsencrypt/acme-dns.json"
      caServer: "https://acme-v02.api.letsencrypt.org/directory"
```

Then point the wildcard domain at the DNS resolver. You can do this in `config/config.yml` for file-managed domains:

```yaml title="config/config.yml" highlight={5-6} theme={"theme":"gruvbox-light-hard"}
domains:
  domain1:
    base_domain: "example.com"
    prefer_wildcard_cert: true
    cert_resolver: "letsencrypt-dns"
```

If you want UI-created domains to use the DNS resolver by default, set the Traefik defaults too:

```yaml title="config/config.yml" theme={"theme":"gruvbox-light-hard"}
traefik:
  cert_resolver: "letsencrypt-dns"
  prefer_wildcard_cert: true
```

For dashboard-managed domains, open the domain settings in Pangolin and set the certificate resolver to the custom Traefik resolver name, such as `letsencrypt-dns`. Enable wildcard preference on the same domain if you want Pangolin to request wildcard certificates for resources under that domain.

<Note>
  If you split ACME storage across multiple files, configure Pangolin's private `acme.acme_json_path` setting as the directory that contains them, for example `config/letsencrypt`. Pangolin will scan the directory for ACME JSON files, including nested files. See [ACME configuration](/self-host/advanced/private-config-file#acme-configuration).
</Note>

## Dashboard Certificate

The `prefer_wildcard_cert` setting affects resource routers generated by Pangolin. If you also want Traefik to request a wildcard certificate for the Pangolin dashboard router, add the wildcard domain to the dashboard router's `tls.domains` list in `config/traefik/dynamic_config.yml`.

```yaml title="config/traefik/dynamic_config.yml" highlight={8-12} theme={"theme":"gruvbox-light-hard"}
next-router:
  rule: "Host(`pangolin.example.com`) && !PathPrefix(`/api/v1`)"
  service: next-service
  entryPoints:
    - websecure
  tls:
    certResolver: letsencrypt
    domains:
      - main: "example.com"
        sans:
          - "*.example.com"
```

If you use a second resolver, set `certResolver` to that resolver name, such as `letsencrypt-dns`.

## Verify It Works

<Tip>
  If Traefik already issued certificates with the old resolver, clear the old certificates before testing so Traefik requests them again. Remove the relevant ACME storage file, or use `pangctl clear-certs` if Pangolin has already synced stale certificates.
</Tip>

<Steps>
  <Step title="Create or open a resource">
    Create a resource on an unused subdomain such as `test.example.com`, or open an existing resource under the same base domain.
  </Step>

  <Step title="Check Traefik logs">
    Traefik should use the DNS-01 resolver and should not need a separate certificate for every resource hostname after the wildcard certificate exists.

    ```bash theme={"theme":"gruvbox-light-hard"}
    sudo docker compose logs traefik
    ```
  </Step>

  <Step title="Inspect ACME storage">
    Check the ACME storage file in `config/letsencrypt`. The certificate domain should include a wildcard SAN such as `*.example.com`.
  </Step>
</Steps>

```json highlight={6} theme={"theme":"gruvbox-light-hard"}
{
  "Certificates": [
    {
      "domain": {
        "main": "example.com",
        "sans": ["*.example.com"]
      },
      "certificate": "...",
      "key": "...",
      "Store": "default"
    }
  ]
}
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Wildcard certificate is not created">
    Confirm the DNS provider is correct, the provider environment variables are present on the `traefik` service, and the API token has permission to edit DNS records for the zone.
  </Accordion>

  <Accordion title="Traefik still uses HTTP-01">
    Check the resolver name. The router's `tls.certResolver` and Pangolin's `cert_resolver` must match the DNS-01 resolver name exactly.
  </Accordion>

  <Accordion title="Old certificates are still served">
    Clear old certificates so Traefik can request them again. You can remove the relevant ACME storage file, or use `pangctl clear-certs` if Pangolin has already synced stale certificates.
  </Accordion>

  <Accordion title="DNS challenge times out">
    Review Traefik debug logs, confirm DNS propagation is working, and check whether your DNS provider requires additional propagation delay or custom resolvers. If your DNS provider has a firewall, make sure it allows DNS traffic, typically UDP on port `53`.
  </Accordion>
</AccordionGroup>
