From the makers of DNScale: PostScale -- reliable email delivery for developers. PostScale

    Fundamentals

    lego DNS-01 with the DNScale DNS Provider

    Use lego v5+ with DNScale to automate Let's Encrypt DNS-01 certificates, including wildcard certificates, Docker runs, systemd renewals, and external certificate use with Caddy or Traefik.

    Updated

    TL;DR

    DNScale is built into lego v5+ as DNS provider `dnscale`. Set `DNSCALE_API_TOKEN`, run lego with `--dns dnscale`, test first against Let's Encrypt staging, then schedule `lego renew` with a deploy hook that reloads your web server or proxy. Traefik and other Go products only support DNScale after they embed lego v5+; Caddy needs a native DNS module for in-process DNS-01, so use lego as an external certificate runner until then.

    What you'll learn

    • Install or run a lego v5+ binary that includes the DNScale DNS provider
    • Issue a Let's Encrypt wildcard certificate through DNScale DNS-01
    • Store the DNScale token safely with environment variables or `_FILE` secrets
    • Renew certificates unattended and hand them to nginx, Caddy, Traefik, or another TLS terminator

    The lego ACME client can now solve DNS-01 challenges through DNScale. That means a single Go binary can create the temporary _acme-challenge TXT record, wait for propagation, complete the ACME validation, and clean the record up after issuance.

    Use this guide when you want a lightweight certificate runner for:

    • Wildcard certificates such as *.example.com
    • Origins behind edge proxies or load balancers
    • Hosts without a public HTTP listener on port 80
    • Internal services that still need publicly trusted TLS certificates
    • External certificate management for proxies such as nginx, Caddy, HAProxy, or Traefik

    For the broader ACME comparison across certbot, acme.sh, cert-manager, and lego, see Let's Encrypt DNS-01 Challenges with DNScale.

    How the integration works

    lego loads DNS providers at build time. In lego v5+, the DNScale provider is compiled into the official binary under provider code dnscale.

    At issuance time, lego:

    1. Reads DNSCALE_API_TOKEN or DNSCALE_API_TOKEN_FILE.
    2. Finds the matching DNScale zone for the requested name.
    3. Creates a TXT record at _acme-challenge.<name>.
    4. Polls DNS until the TXT value is visible.
    5. Asks the ACME CA to validate the challenge.
    6. Deletes the TXT record.
    7. Writes the certificate and private key under the lego storage path.

    This is why the token should be scoped tightly. The ACME runner needs read access to zones and create/delete access for challenge TXT records; it does not need billing, user-management, or unrelated zone access.

    Prerequisites

    Before starting, prepare:

    • A DNScale-hosted zone, for example example.com
    • A DNScale API token scoped to that zone
    • lego v5 or newer
    • A contact email address for the ACME account
    • CAA records that allow your CA, if you publish CAA

    Check your lego version:

    lego --version

    If you install from Go source, use the v5 module path:

    go install github.com/go-acme/lego/v5/cmd/lego@v5.2.0

    You can also use the official container image in the Docker example below.

    First staging issuance

    Always test a new ACME setup against Let's Encrypt staging before production. Staging certificates are not trusted by browsers, but they prove that token permissions, zone discovery, propagation, and cleanup all work without spending production rate limits.

    export DNSCALE_API_TOKEN="<your-token>"
     
    lego \
      --server https://acme-staging-v02.api.letsencrypt.org/directory \
      --accept-tos \
      --email admin@example.com \
      --dns dnscale \
      --path /var/lib/lego \
      --domains example.com \
      --domains "*.example.com" \
      run

    After the run succeeds, inspect the output directory:

    sudo ls -l /var/lib/lego/certificates/

    For a request whose first domain is example.com, lego writes files similar to:

    example.com.crt
    example.com.issuer.crt
    example.com.json
    example.com.key

    Production issuance

    Run the same command without the staging server:

    DNSCALE_API_TOKEN="<your-token>" lego \
      --accept-tos \
      --email admin@example.com \
      --dns dnscale \
      --path /var/lib/lego \
      --domains example.com \
      --domains "*.example.com" \
      run

    If your environment has slower DNS visibility, tune the DNScale propagation settings:

    DNSCALE_API_TOKEN="<your-token>" \
    DNSCALE_PROPAGATION_TIMEOUT=120 \
    DNSCALE_POLLING_INTERVAL=5 \
    DNSCALE_TTL=120 \
    lego \
      --accept-tos \
      --email admin@example.com \
      --dns dnscale \
      --path /var/lib/lego \
      --domains example.com \
      --domains "*.example.com" \
      run

    Store the token as a file

    For servers and containers, prefer a secret file over a literal environment variable in shell history:

    sudo install -d -m 700 /etc/lego
    printf '%s' '<your-token>' | sudo tee /etc/lego/dnscale-token >/dev/null
    sudo chmod 600 /etc/lego/dnscale-token

    Then run lego with _FILE:

    DNSCALE_API_TOKEN_FILE=/etc/lego/dnscale-token lego \
      --accept-tos \
      --email admin@example.com \
      --dns dnscale \
      --path /var/lib/lego \
      --domains example.com \
      --domains "*.example.com" \
      run

    Docker example

    This command keeps lego state in a local .lego directory and passes the DNScale token through the container environment:

    mkdir -p .lego
     
    docker run --rm \
      -e DNSCALE_API_TOKEN="<your-token>" \
      -v "$PWD/.lego:/root/.lego" \
      goacme/lego:v5.2.0 \
      --accept-tos \
      --email admin@example.com \
      --dns dnscale \
      --domains example.com \
      --domains "*.example.com" \
      run

    For production containers, mount the token from your secret manager and use DNSCALE_API_TOKEN_FILE:

    docker run --rm \
      -e DNSCALE_API_TOKEN_FILE=/run/secrets/dnscale_api_token \
      -v "$PWD/.lego:/root/.lego" \
      -v /run/secrets/dnscale_api_token:/run/secrets/dnscale_api_token:ro \
      goacme/lego:v5.2.0 \
      --accept-tos \
      --email admin@example.com \
      --dns dnscale \
      --domains example.com \
      --domains "*.example.com" \
      run

    Automatic renewals with systemd

    Create a renewal script:

    sudo tee /usr/local/sbin/renew-example-com >/dev/null <<'EOF'
    #!/bin/sh
    set -eu
     
    export DNSCALE_API_TOKEN_FILE=/etc/lego/dnscale-token
     
    lego \
      --accept-tos \
      --email admin@example.com \
      --dns dnscale \
      --path /var/lib/lego \
      --domains example.com \
      --domains "*.example.com" \
      --renew-days 30 \
      --deploy-hook "systemctl reload nginx" \
      renew
    EOF
     
    sudo chmod 750 /usr/local/sbin/renew-example-com

    Then add a service and timer:

    # /etc/systemd/system/lego-example-com.service
    [Unit]
    Description=Renew example.com certificate with lego and DNScale
     
    [Service]
    Type=oneshot
    ExecStart=/usr/local/sbin/renew-example-com
    # /etc/systemd/system/lego-example-com.timer
    [Unit]
    Description=Daily lego renewal check for example.com
     
    [Timer]
    OnCalendar=daily
    RandomizedDelaySec=1h
    Persistent=true
     
    [Install]
    WantedBy=timers.target

    Enable the timer:

    sudo systemctl daemon-reload
    sudo systemctl enable --now lego-example-com.timer
    sudo systemctl start lego-example-com.service

    lego renews only when the certificate is inside the renewal window. Running the timer daily is normal.

    Use with Caddy or Traefik as external certs

    lego can manage the certificate while another Go-based product serves it. This is the safe compatibility path when the proxy does not yet expose DNScale as an in-process DNS provider.

    Caddy with certificate files

    Point Caddy at the files created by lego:

    example.com, *.example.com {
      tls /var/lib/lego/certificates/example.com.crt /var/lib/lego/certificates/example.com.key
      reverse_proxy 127.0.0.1:8080
    }

    Reload Caddy from the lego deploy hook:

    --deploy-hook "systemctl reload caddy"

    Do not use tls { dns dnscale ... } unless your Caddy build includes a native DNScale DNS module. Caddy DNS modules are separate from lego DNS providers.

    Traefik with certificate files

    With Traefik's file provider, publish the lego-managed files in dynamic configuration:

    tls:
      certificates:
        - certFile: /certs/example.com.crt
          keyFile: /certs/example.com.key

    Mount /var/lib/lego/certificates into the Traefik container or host path that backs /certs, then reload Traefik after successful renewal if your deployment does not watch the file provider automatically.

    Traefik's native ACME dnsChallenge.provider: dnscale will work only in Traefik versions that embed lego v5 or newer. Older Traefik builds embed lego v4 and will reject dnscale as an unknown DNS provider.

    Environment variable reference

    VariableRequiredPurpose
    DNSCALE_API_TOKENYes, unless _FILE is usedDNScale API token.
    DNSCALE_API_TOKEN_FILEAlternativePath to a file containing the DNScale token.
    DNSCALE_TTLNoTTL for challenge TXT records, in seconds.
    DNSCALE_PROPAGATION_TIMEOUTNoMaximum time lego waits for TXT propagation, in seconds.
    DNSCALE_POLLING_INTERVALNoTime between propagation checks, in seconds.
    DNSCALE_HTTP_TIMEOUTNoTimeout for DNScale API requests, in seconds.

    Troubleshooting

    unrecognized DNS provider: dnscale

    The binary is not lego v5+. Upgrade the standalone lego CLI, use the official v5 container image, or wait for the embedding product to ship a lego v5+ dependency.

    some credentials information are missing: DNSCALE_API_TOKEN

    Set DNSCALE_API_TOKEN, or set DNSCALE_API_TOKEN_FILE to a readable file. The file must contain the raw token, not DNSCALE_API_TOKEN=<token>.

    zone not found

    Check that the requested domain is hosted in DNScale and that the token can read that zone. For www.example.com, lego searches upward for example.com; if that zone is not visible to the token, challenge setup fails.

    Validation times out

    Increase DNSCALE_PROPAGATION_TIMEOUT to 120 or 180 seconds and keep DNSCALE_TTL low, usually 120 seconds. Also check for stale negative DNS cache from a previous failed attempt.

    CAA blocks issuance

    If you publish CAA records, allow your ACME CA:

    example.com.  3600  CAA  0 issue "letsencrypt.org"
    example.com.  3600  CAA  0 issuewild "letsencrypt.org"

    Confirm with:

    dig CAA example.com +short

    Frequently asked questions

    Which lego version do I need for DNScale?
    DNScale support starts with lego v5.0.0. Use lego v5 or newer and verify with `lego --version`. If a product embeds lego internally, that product must also ship a lego v5+ dependency before provider `dnscale` is available there.
    What environment variable does lego use for DNScale?
    Set `DNSCALE_API_TOKEN` to a DNScale API token, or set `DNSCALE_API_TOKEN_FILE` to a path containing only the token value. Optional tuning variables are `DNSCALE_TTL`, `DNSCALE_PROPAGATION_TIMEOUT`, `DNSCALE_POLLING_INTERVAL`, and `DNSCALE_HTTP_TIMEOUT`.
    Can I use this for wildcard certificates?
    Yes. DNS-01 is the ACME challenge type required for wildcard certificates. Request both the apex and wildcard names, for example `--domains example.com --domains "*.example.com"`, so one certificate covers both.
    Can I use DNScale directly in Traefik today?
    Only if your Traefik build embeds lego v5 or newer. Builds that still vendor lego v4 do not know provider `dnscale`. Until your Traefik version includes lego v5+, run lego externally and point Traefik at the resulting certificate files.
    Can I configure `dns dnscale` in Caddy?
    Not as a plain lego provider. Caddy uses CertMagic and Caddy DNS modules, not lego's provider list. Use lego externally and configure Caddy with certificate files until a native DNScale Caddy DNS module exists.

    Ready to manage your DNS with confidence?

    DNScale provides anycast DNS hosting with a global network, real-time analytics, and an easy-to-use API.

    Start free