DEV Community

Cover image for How to Secure Nginx Wildcard SSL Certificates
Raizan
Raizan

Posted on Originally published at chasebot.online

How to Secure Nginx Wildcard SSL Certificates

What You'll Need

Before setting up wildcard certificates on your web server, make sure you have the following resources and access rights ready:

  • A cloud server running Ubuntu 22.04 or Debian 12 hosted on a Hetzner VPS or Contabo VPS
  • A domain registered through Namecheap or another domain registrar
  • DNS management delegated to Cloudflare or another DNS provider with API access
  • An alternative cloud host like DigitalOcean if you prefer Droplets
  • Root or sudo privileges on your Linux machine
  • Nginx installed and running on your system

Table of Contents

Understanding Wildcard Certificates and DNS-01 Validation

Managing TLS certificates for dynamic subdomains can quickly turn into a maintainer's nightmare. Standard TLS certificates issued by Let's Encrypt use HTTP-01 challenges. The Let's Encrypt validation server makes an HTTP request to an explicit URL on your server under .well-known/acme-challenge/ to verify ownership of a single hostname like app.example.com.

When you need to secure *.example.com alongside the root domain example.com, HTTP validation fails because a single HTTP path cannot prove control over every arbitrary subdomain that might exist in the future. Instead, Let's Encrypt requires a DNS-01 challenge for wildcard certificates.

In a DNS-01 challenge, Certbot requests a cryptographic TXT record token from Let's Encrypt, creates a _acme-challenge.example.com record on your authoritative DNS provider, and asks Let's Encrypt to query the global DNS network to verify ownership.

If you are already configuring centralized log aggregation with Grafana Loki across multiple microservices, consolidating your secure endpoints under a single wildcard SSL certificate reduces certificate administration overhead and cuts down on certificate expiration alerts across your infrastructure.

In this guide, I will walk you through setting up fully automated, highly secure wildcard SSL certificates using Certbot, Cloudflare DNS integration, and Nginx on a fresh Linux server.

Step 1: Installing Certbot and the DNS Plugin

To perform automated DNS-01 challenges, Certbot requires a plugin capable of communicating directly with your DNS provider's API. I recommend using Cloudflare for DNS management because propagation takes seconds and Certbot offers a robust, official plugin for it.

First, log into your server. If you need a scalable instance, I usually deploy on a Hetzner VPS or a DigitalOcean instance for consistent network performance.

Update your system packages and install Python 3 along with Certbot and the Cloudflare DNS plugin:

sudo apt update
sudo apt install -y certbot python3-certbot-nginx python3-certbot-dns-cloudflare
Enter fullscreen mode Exit fullscreen mode

Verify that Certbot has correctly recognized the Cloudflare plugin by running:

sudo certbot plugins
Enter fullscreen mode Exit fullscreen mode

You should see dns-cloudflare listed under the available plugins.

Next, you need to generate an API token inside your Cloudflare dashboard:

  1. Log into your Cloudflare account.
  2. Go to My Profile > API Tokens.
  3. Click Create Token.
  4. Select the Edit zone DNS template.
  5. Under Zone Resources, select Include > All zones (or narrow it down to your specific domain).
  6. Click Continue to summary and then Create Token.
  7. Copy the generated API token string.

Now, create a secure directory and configuration file on your server to store this sensitive token:

sudo mkdir -p /etc/letsencrypt
sudo nano /etc/letsencrypt/cloudflare.ini
Enter fullscreen mode Exit fullscreen mode

Paste the following content into /etc/letsencrypt/cloudflare.ini, replacing YOUR_CLOUDFLARE_API_TOKEN with the actual token you generated:

dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
Enter fullscreen mode Exit fullscreen mode

Save the file and exit the editor. Because this file contains credentials that can modify your domain's DNS records, restrict file permissions so only root can read it:

sudo chmod 600 /etc/letsencrypt/cloudflare.ini
Enter fullscreen mode Exit fullscreen mode

💡 Fast-Track Your Project: Don't want to configure this yourself? I build custom n8n pipelines and bots. Message me with code SYS3-DEVTO.

Step 2: Obtaining the Wildcard Certificate via DNS API

With your API credentials secured, you can request the wildcard certificate. The command below requests a certificate covering both the root domain (example.com) and all first-level subdomains (*.example.com).

Replace example.com with your domain registered via Namecheap or your preferred provider, and replace admin@example.com with your actual email address.

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  --dns-cloudflare-propagation-seconds 30 \
  -d example.com \
  -d "*.example.com" \
  --agree-tos \
  -m admin@example.com \
  --no-eff-email
Enter fullscreen mode Exit fullscreen mode

Here is a breakdown of what these arguments do:

  • certonly: Tells Certbot to request the certificate files without automatically altering your web server config files yet.
  • --dns-cloudflare: Specifies that the Cloudflare DNS plugin should handle the DNS-01 validation.
  • --dns-cloudflare-credentials: Points Certbot to the API token file created in Step 1.
  • --dns-cloudflare-propagation-seconds 30: Waits 30 seconds after writing the TXT record to allow DNS changes to replicate globally before asking Let's Encrypt to verify.
  • -d example.com -d "*.example.com": Defines the explicit domains covered by this single certificate.

Upon successful completion, Certbot outputs the location of your newly issued certificate chain and private key:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2026-06-15.
Enter fullscreen mode Exit fullscreen mode

If you ever build automation scripts or backend webhooks that handle standard payload responses, like when handling structured output with OpenAI Function Calling, having HTTPS properly configured across all present and future subdomains ensures that all internal and external communication remains encrypted without needing to issue a new SSL certificate for every new endpoint.

Step 3: Configuring Nginx with Hardened TLS Settings

Now that your certificate and key files are located at /etc/letsencrypt/live/example.com/, you need to configure Nginx to use them with strong encryption standards.

First, create a Diffie-Hellman parameter file to strengthen key exchange security:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
Enter fullscreen mode Exit fullscreen mode

Next, create an optimized Nginx SSL configuration snippet that implements modern TLS security policies, HSTS, and secure cipher suites.

sudo nano /etc/nginx/conf.d/ssl-params.conf
Enter fullscreen mode Exit fullscreen mode

Paste the following configuration into /etc/nginx/conf.d/ssl-params.conf:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_dhparam /etc/ssl/certs/dhparam.pem;

ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
Enter fullscreen mode Exit fullscreen mode

Save and close the file. Now, configure your server block to handle both the apex domain and wildcards. Open or create your virtual host configuration file:

sudo nano /etc/nginx/sites-available/example.com.conf
Enter fullscreen mode Exit fullscreen mode

Insert the complete configuration below. Make sure to replace example.com with your actual domain name:

server {
    listen 80;
    listen [::]:80;
    server_name example.com *.example.com;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/nginx/conf.d/ssl-params.conf;

    root /var/www/example.com/html;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name *.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/nginx/conf.d/ssl-params.conf;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
Enter fullscreen mode Exit fullscreen mode

Enable the configuration by creating a symbolic link to the sites-enabled directory:

sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/
Enter fullscreen mode Exit fullscreen mode

Test the Nginx configuration syntax to ensure there are no missing semicolons or formatting errors:

sudo nginx -t
Enter fullscreen mode Exit fullscreen mode

If the syntax test passes, reload Nginx to apply your changes:

sudo systemctl reload nginx
Enter fullscreen mode Exit fullscreen mode

Step 4: Automating Certificate Renewal and Monitoring

Certbot sets up a systemd timer by default to handle background renewals. However, because Nginx caches TLS certificates in memory, Nginx must be reloaded whenever a certificate is renewed.

To ensure Nginx automatically reloads after a successful renewal, edit the Certbot renewal configuration file:

sudo nano /etc/letsencrypt/renewal/example.com.conf
Enter fullscreen mode Exit fullscreen mode

Scroll to the [renewalparams] section and add a deploy hook line at the bottom:

renew_before_expiry = 30 days
version = 2.1.0
archive_dir = /etc/letsencrypt/archive/example.com
cert = /etc/letsencrypt/live/example.com/cert.pem
privkey = /etc/letsencrypt/live/example.com/privkey.pem
chain = /etc/letsencrypt/live/example.com/chain.pem
fullchain = /etc/letsencrypt/live/example.com/fullchain.pem

[renewalparams]
account = 1234567890abcdef1234567890abcdef
authenticator = dns-cloudflare
dns_cloudflare_credentials = /etc/letsencrypt/cloudflare.ini
server = https://acme-v02.api.letsencrypt.org/directory
key_type = ecdsa
renew_hook = systemctl reload nginx
Enter fullscreen mode Exit fullscreen mode

Save and exit. Test the full automated renewal process using Certbot's dry-run feature:

sudo certbot renew --dry-run
Enter fullscreen mode Exit fullscreen mode

If the dry run finishes without errors, your automated certificate renewal pipeline is fully functioning.

To keep track of Nginx renewal processes, traffic spikes, or potential SSL connection drops, check out my guide on how to stream container logs to Loki. Centralizing Nginx access and error logs gives you immediate visibility into any TLS handshake issues or certificate deployment errors.

Getting Started

Securing your infrastructure with wildcard certificates eliminates the operational overhead of generating separate certificates for every new service or subdomain. By pairing Certbot with DNS-01 API validation and Nginx, you get seamless, automated HTTPS coverage across your entire domain space.

To implement this architecture on your own systems:

  • Deploy a high-performance cloud instance using a Hetzner VPS or Contabo VPS.
  • Register your base domains through Namecheap and point your nameservers to Cloudflare.
  • Spin up alternative testing droplets on DigitalOcean to test your automated deployment scripts before running them in production.

Outsource Your Automation

Don't have time? I build production n8n workflows, WhatsApp bots, and fully automated YouTube Shorts pipelines. Hire me on Fiverr, mention SYS3-DEVTO for priority. Or DM at chasebot.online.


Originally published on Automation Insider.

Top comments (0)