SSLmentor

Quality TLS/SSL certificates for websites and internet projects.

Lego & ACME WildCard

Lego & ACME WildCard

ACME client Lego - WildCard SSL

A detailed guide for deploying a star WildCard SSL certificate via the ACME client Lego and API DNS validation with the VEDOS web hosting. The procedure is intended for certificates of the type example.com and *.example.com, where renewal should be automatic without manually entering TXT records. The guide uses an ACME certificate from the Certum certificate authority. The certificate used serves only as an example – the operating principle and the ACME deployment procedure are the same for all certificate authorities.

The guide uses syntax verified on Lego 5.2.2. Lego v5 changed some parameters compared to older versions, so in case of an error such as flag provided but not defined verify the correct syntax using lego accounts register --help, lego run --help or lego --help.

Basic concepts

  • ACME – protocol for automated issuance and renewal of SSL/TLS certificates.
  • Lego – an ACME client written in Go. It can perform DNS validation through many DNS providers (list of supported DNS providers).
  • DNS-01 – validation via the DNS TXT record _acme-challenge. It is required for WildCard certificates.
  • EAB kid + hmac – External Account Binding (EAB) details from the certificate authority. They link ACME client to an account or product.
  • VEDOS WAPI – the VEDOS API interface through which Lego creates and deletes DNS TXT records.
  • Systemd service - a configuration file that tells the Linux system how to start an application and keep it running even after a server restart.

In all the examples shown, replace the domain example.com with your own domain.

Lego installation

apt update
apt install -y curl tar

cd /tmp
LEGO_URL=$(curl -s https://api.github.com/repos/go-acme/lego/releases/latest | sed -n 's/.*"browser_download_url": "\(.*linux_amd64.tar.gz\)".*/\1/p' | head -n1)
echo "$LEGO_URL"
curl -L -o lego.tar.gz "$LEGO_URL"
tar -xzf lego.tar.gz
install -m 0755 lego /usr/local/bin/lego
lego --version

After a successful installation, we recommend removing the temporary files.

rm -f /tmp/lego /tmp/lego.tar.gz /tmp/LICENSE /tmp/CHANGELOG.md
Command / value What it does / what to replace
apt update Updates the package list.
apt install -y curl tar Installs the tools for downloading and extracting Lego.
LEGO_URL=... Finds the URL of the latest Linux amd64 release package.
curl -L -o lego.tar.gz Downloads the Lego archive.
tar -xzf lego.tar.gz Extracts the archive.
install -m 0755 lego /usr/local/bin/lego Installs Lego as an executable system command.
lego --version Verifies the installed version of Lego.

DNS API provider

This guide uses the DNS API from the domain registrar Vedos, which offers an API for managing the DNS of registered domains. For Vedos web hosting, you need to activate WAPI and also fill in the allowed IP addresses and the WAPI password.

The LEGO client supports hundreds of other DNS providers.
You can find their list on the LEGO website - list of supported DNS providers.

IP addresses of the VPS server

curl -4 ifconfig.me
curl -6 ifconfig.me
Command / value What it does / what to replace
curl -4 ifconfig.me Shows the server's public IPv4 address, which needs to be allowed in VEDOS WAPI.
curl -6 ifconfig.me Shows the server's public IPv6 address, if the VPS uses one. It is advisable to allow this address in VEDOS WAPI as well.

In the Allowed IP addresses field, enter all outgoing IP addresses of your server, typically both IPv4 and IPv6. The values are separated by a space. VEDOS allows API requests only from the listed IP addresses.
Important: If you allow only IPv4 and some API request goes out over IPv6, the certificate issuance may succeed, but the cleanup of TXT records will fail with the error Access not allowed from this IP address.

Recommended values for the VEDOS DNS provider

Field Recommended value
Activate WAPI On
Allowed IP addresses The VPS's public IPv4 and possibly IPv6 address
Notification method POLL queue
Preferred protocol JSON
Password The generated WAPI password, not the ordinary administration password

Apache, webroot

The basic Apache setup is a supporting part. DNS validation runs through the DNS API, not over HTTP, but the Apache vhost is needed to serve the website after the certificate is issued.

›› Show/Hide section

Before running, replace the value example.com in the line DOMAIN="example.com" with your own domain without the asterisk. The variable $DOMAIN is then used in the following commands for paths, the Apache vhost and the test page.

cd /var/www
apt update
apt install -y apache2
systemctl enable --now apache2
a2enmod rewrite headers ssl
systemctl reload apache2

DOMAIN="example.com"
mkdir -p /var/www/$DOMAIN/public
chown -R www-data:www-data /var/www/$DOMAIN
chmod -R 755 /var/www/$DOMAIN
echo "OK $DOMAIN" > /var/www/$DOMAIN/public/index.html
Command / value What it does / what to replace
cd /var/www Changes to the directory where web files are usually stored.
apt update Updates the package list.
apt install -y apache2 Installs Apache; -y automatically confirms the installation.
systemctl enable --now apache2 Enables Apache at server startup and starts it at the same time.
a2enmod rewrite headers ssl Enables modules for redirects, headers and HTTPS.
DOMAIN="example.com" Sets the domain variable. Replace example.com with your own domain.
mkdir/chown/chmod/echo Creates the webroot, sets permissions for Apache and saves a simple test page.

HTTP vhost for both the apex and subdomains:


cat > /etc/apache2/sites-available/$DOMAIN.conf <<EOF
<VirtualHost *:80>
    ServerName $DOMAIN
    ServerAlias *.$DOMAIN

    DocumentRoot /var/www/$DOMAIN/public
    <Directory /var/www/$DOMAIN/public>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog \${APACHE_LOG_DIR}/${DOMAIN}_error.log
    CustomLog \${APACHE_LOG_DIR}/${DOMAIN}_access.log combined
</VirtualHost>
EOF

a2ensite $DOMAIN.conf
apache2ctl configtest
systemctl reload apache2
curl -I http://$DOMAIN
Command / value What it does / what to replace
cat > ... <<EOF Writes a new Apache HTTP vhost to a file in sites-available.
ServerName $DOMAIN The main domain of the virtual host.
ServerAlias *.$DOMAIN Allows handling of any first-level subdomain.
DocumentRoot The directory from which Apache serves content.
a2ensite $DOMAIN.conf Enables the vhost.
apache2ctl configtest Verifies the Apache configuration syntax.
curl -I http://$DOMAIN Verifies the domain's HTTP response.

Lego configuration files

The recommended approach for Lego v5 is to store the settings in a configuration file. The systemd service then does not need to contain a long command with domains, the DNS provider and hooks.

Configuration file .env

The .env file is a text configuration file in which environment variables are stored, for example access credentials, API keys or application settings. For clarity, you can name the file provider-domain.env. The vedos-example.com.env file will contain the VEDOS WAPI login credentials, so we store it in /etc/lego and set restricted permissions on it.

DOMAIN="example.com"

mkdir -p /etc/lego/$DOMAIN
nano /etc/lego/vedos-$DOMAIN.env
Command / value What it does / what to replace
DOMAIN="example.com" Sets the domain for the following commands. Replace with your own domain.
mkdir -p /etc/lego/$DOMAIN Creates the directory for the Lego data and configuration of the given domain.
nano /etc/lego/vedos-$DOMAIN.env Opens the file for the VEDOS API variables.

In the configuration below, replace WEDOS_LOGIN with your VEDOS login and WEDOS_WAPI_PASSWORD with the password generated in VEDOS WAPI. You can leave the timeout and interval values as they are.

WEDOS_USERNAME='WEDOS_LOGIN'
WEDOS_WAPI_PASSWORD='WEDOS_WAPI_PASSWORD'
WEDOS_PROPAGATION_TIMEOUT=3600
WEDOS_POLLING_INTERVAL=30
WEDOS_TTL=300
Command / value What it does / what to replace
WEDOS_USERNAME The VEDOS login of the account that manages the DNS zone.
WEDOS_WAPI_PASSWORD The WAPI password generated in the VEDOS administration.
WEDOS_PROPAGATION_TIMEOUT The maximum wait time for DNS propagation in seconds.
WEDOS_POLLING_INTERVAL The interval between DNS propagation checks.
WEDOS_TTL The TTL of the TXT records created for the ACME challenge.
chmod 600 /etc/lego/vedos-$DOMAIN.env

Configuration file lego.yml

The .yml file is a text configuration file in YAML format, used for a clear notation of settings, parameters and structured data. Before saving the YAML configuration, replace example.com with your own domain, *.example.com with the wildcard name, your@email.com with your contact e-mail and the KID / HMAC values with the details from your ACME certificate order. Names such as certum-example or example-com-wildcard are internal labels; you can leave them, but with multiple domains it is advisable to rename them according to the domain.

mkdir /etc/lego/$DOMAIN
nano /etc/lego/$DOMAIN/lego.yml
storage: /etc/lego/example.com

accounts:
  certum-example:
    server: certum
    email: your@email.com
    acceptsTermsOfService: true
    eab:
      kid: KID
      hmacKey: HMAC

servers:
  certum:
    url: https://acme.certum.pl/directory

challenges:
  vedos-dns:
    dns:
      provider: vedos
      envFile: /etc/lego/vedos-example-com.env
      resolvers:
        - 1.1.1.1:53

certificates:
  example-com-wildcard:
    account: certum-example
    challenge: vedos-dns
    domains:
      - example.com
      - "*.example.com"
    renew:
      days: 30

hooks:
  deploy:
    command: systemctl reload apache2
Command / value What it does / what to replace
storage Directory for the Lego account, certificates and metadata.
accounts Definition of the ACME account including the e-mail and EAB details.
servers.certum.url The Certum ACME endpoint.
challenges.vedos-dns DNS-01 validation through the VEDOS provider.
envFile The file with the VEDOS API login credentials.
certificates List of certificates that Lego should manage.
domains The apex domain and the wildcard domain in the certificate.
renew.days How many days before expiration Lego should renew.
hooks.deploy.command Command after a successful issuance or renewal, here reloading Apache.
chmod 600 /etc/lego/$DOMAIN/lego.yml

The lego.yml file contains the EAB HMAC, so it must have restricted permissions. In customer documentation, use only placeholders.

Certificate issuance

Before running, replace example.com in the path with the domain you used when creating the directory. The first run creates the ACME account, sets the DNS TXT records through the DNS API, performs DNS-01 validation and saves the certificate.

lego --config /etc/lego/$DOMAIN/lego.yml

While waiting, Lego may print:

dns01: waiting for record propagation timeout=1h0m0s interval=30s
Command / value What it does / what to replace
lego --config Runs Lego according to the configuration file. On the first run it issues the certificate, on subsequent runs it handles renewal.
dns01: waiting for record propagation Lego has created the TXT record and is waiting until it is visible in DNS.
timeout=1h0m0s Waits at most one hour.
interval=30s Checks DNS every 30 seconds.

This means that Lego checks DNS every 30 seconds and waits at most 1 hour. After success, verify the files:

ls -la /etc/lego/$DOMAIN/certificates/

The certificates/ directory contains the issued .crt, .key, intermediate certificates of the certificate authority and metadata.

Alternative CLI procedure for Lego v5

›› Show/Hide section

If you do not use a configuration file, in Lego v5 the EAB is entered during account registration. Before running, replace example.com with your own domain, your@email.com with your own e-mail and KID / HMAC with the values from your order.

lego accounts register \
  --path /etc/lego/example.com \
  --server https://acme.certum.pl/directory \
  --email your@email.com \
  --accept-tos \
  --eab \
  --eab.kid 'KID' \
  --eab.hmac 'HMAC'
Command / value What it does / what to replace
lego accounts register Registers the ACME account manually via the CLI without lego.yml.
--path Directory for the account and certificates.
--server Certum ACME endpoint.
--email Contact e-mail.
--accept-tos Agreement with the terms of service.
--eab Enables External Account Binding.
--eab.kid / --eab.hmac EAB details from CertManager.

Listing of accounts. In the path, use the same domain as in the previous command again:

lego accounts list --path /etc/lego/example.com

Certificate issuance now without EAB parameters. Replace example.com with your own domain and *.example.com with the wildcard name.

set -a
. /etc/lego/vedos-example.com.env
set +a

lego run \
  --path /etc/lego/example.com \
  --server https://acme.certum.pl/directory \
  --email your@email.com \
  --dns vedos \
  --dns.resolvers 1.1.1.1:53 \
  --domains example.com \
  --domains '*.example.com'
Command / value What it does / what to replace
set -a Automatically exports the variables loaded from the file.
. /etc/lego/vedos-example.com.env Loads the VEDOS API variables into the current shell.
set +a Turns off automatic export of variables.
lego run Issues or renews the certificate without a configuration file.
--dns vedos Uses the DNS API.
--domains The domains that will be in the certificate.

Deploying the certificate to Apache

Before creating the HTTPS vhost, replace example.com with your own domain in the file name, the ServerName and ServerAlias values, the webroot paths and the certificate paths. These paths must match the domain used in the Lego configuration.


cat > /etc/apache2/sites-available/example.com-le-ssl.conf <<'EOF'
<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName example.com
    ServerAlias *.example.com

    DocumentRoot /var/www/example.com/public
    <Directory /var/www/example.com/public>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    SSLEngine on
    SSLCertificateFile /etc/lego/example.com/certificates/example.com.crt
    SSLCertificateKeyFile /etc/lego/example.com/certificates/example.com.key

    ErrorLog ${APACHE_LOG_DIR}/example.com_ssl_error.log
    CustomLog ${APACHE_LOG_DIR}/example.com_ssl_access.log combined
</VirtualHost>
</IfModule>
EOF

a2ensite example.com-le-ssl.conf
apache2ctl configtest
systemctl reload apache2

curl -I https://example.com
curl -I https://test.example.com
Command / value What it does / what to replace
cat > ...-le-ssl.conf Creates the Apache HTTPS vhost.
ServerName / ServerAlias Specifies the apex domain and the wildcard subdomains.
SSLCertificateFile Path to the certificate from Lego.
SSLCertificateKeyFile Path to the private key from Lego.
a2ensite Enables the HTTPS vhost.
systemctl reload apache2 Reloads the new Apache configuration.
curl -I https://... Verifies the HTTPS response.

Automatic renewal

Lego can renew the certificate, but after installation it does not create a systemd timer on its own. Regular execution is set up via a custom service and timer. Before inserting, replace example-com in the service/timer name with your own safe name without dots, for example mojedomena-cz, and replace example.com in the configuration path with your own domain.


cat > /etc/systemd/system/lego-example-com-renew.service <<'EOF'
[Unit]
Description=Renew Certum WildCard SSL for example.com using Lego and VEDOS DNS
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/lego --config /etc/lego/example.com/lego.yml
EOF

cat > /etc/systemd/system/lego-example-com-renew.timer <<'EOF'
[Unit]
Description=Daily Lego renewal check for example.com

[Timer]
OnCalendar=*-*-* 03:20:00
RandomizedDelaySec=1800
Persistent=true

[Install]
WantedBy=timers.target
EOF

systemctl daemon-reload
systemctl enable --now lego-example-com-renew.timer
systemctl list-timers | grep lego
Command / value What it does / what to replace
lego-example-com-renew.service Systemd service for a one-time run of Lego renew/run.
Type=oneshot The service starts, does its work and finishes.
ExecStart Runs Lego according to lego.yml.
lego-example-com-renew.timer Systemd timer that runs the service regularly.
OnCalendar Time of the daily check.
RandomizedDelaySec Random delay so that the requests do not all start at exactly the same time.
Persistent=true Runs a missed execution after the server starts.
systemctl enable --now Enables the timer and activates it immediately.

Safe test of the service:

systemctl start lego-example-com-renew.service
journalctl -u lego-example-com-renew.service -n 100 --no-pager
Command / value What it does / what to replace
systemctl start ...service Manually runs the renewal service for a test.
journalctl -u ... Shows the service's latest logs.

If the certificate is not close to expiration, Lego may report that renewal is not needed. This is correct behavior.

Common errors

Unknown parameter in Lego

In Lego v5 the EAB parameters are --eab.kid and --eab.hmac. The parameters always belong to a specific subcommand.

lego accounts register --help
lego accounts list --help
lego run --help

Cleanup of TXT records fails on a disallowed IP

Cleaning up failed ... Access not allowed from this IP address (2a02:...)

Also add the server's IPv6 address to the allowed IP addresses in VEDOS WAPI. The certificate may be issued correctly, but the TXT records will remain in DNS after validation.

Verification checklist

dig TXT _acme-challenge.example.com +short
lego --config /etc/lego/example.com/lego.yml
systemctl status lego-example-com-renew.timer
apache2ctl configtest
curl -I https://example.com
Command / value What it does / what to replace
dig TXT Verifies the TXT records in DNS.
lego --config Runs the Lego configuration.
systemctl status Shows the timer status.
apache2ctl configtest Verifies the Apache configuration.
curl -I Verifies the HTTPS response.

Back to Help
Found an error or don't understand something? Write us!

CA Sectigo
CA RapidSSL
CA Thawte
CA GeoTrust
CA DigiCert
CA Certum