Sunday, May 24, 2026

NGINX with Automatic HTTPS Using Let’s Encrypt and Active24 DNS Challenge

This blog post is run-book how to deploy NGINX web server with Automatic TLS certificate issuance and renewal leveraging Let’s Encrypt DNS Challenge via Active24 DNS provider.

This article describes how to deploy NGINX on FreeBSD with both HTTP and HTTPS support, where the TLS certificate is automatically issued and renewed using Let’s Encrypt, acme.sh, and the Active24 DNS API.

The solution uses the DNS-01 challenge, so the web server does not need to expose port 80 for certificate validation. This is useful for internal services, servers behind NAT, wildcard certificates, or environments where HTTP validation is not suitable.

Target Architecture

Internet
    |
    v
NGINX on FreeBSD
    |
    +-- HTTP  on TCP/80
    |
    +-- HTTPS on TCP/443
            |
            v
      TLS certificate
            |
            v
      acme.sh renewal
            |
            v
      Active24 DNS API
            |
            v
      DNS-01 challenge

Prerequisites

You need the following:

  • FreeBSD server
  • Domain hosted in Active24 DNS
  • Active24 API Key
  • Active24 API Secret
  • Root access to the FreeBSD server
  • Internet access from the server

In this example I will use:

example.cz

Replace it with your real domain.

Install Required Packages

pkg update

pkg install -y nginx acme.sh

Enable NGINX:

sysrc nginx_enable="YES"

Enable cron, because acme.sh uses cron for automatic renewal:

sysrc cron_enable="YES"
service cron start

Verify cron:

service cron status

Create Web Root Directory

mkdir -p /usr/local/www/blog.uw.cz

Create a simple test page:

cat > /usr/local/www/blog.uw.cz/index.html <<EOF
<html>
<body>
<h1>NGINX on FreeBSD</h1>
</body>
</html>
EOF

Set ownership:

chown -R www:www /usr/local/www/example.cz

Install Active24 hook

mkdir -p /root/.acme.sh/dnsapi

fetch -o /root/.acme.sh/dnsapi/dns_active24.sh \
https://raw.githubusercontent.com/acmesh-official/acme.sh/master/dnsapi/dns_active24.sh

chmod 600 /root/.acme.sh/dnsapi/dns_active24.sh 

Configure Active24 API Credentials

To make Active24 API Credentials persistent for the root user, add them to:

/root/.profile

For example:

vi /root/.profile

Add:

export Active24_ApiKey="YOUR_API_KEY"
export Active24_ApiSecret="YOUR_API_SECRET"

Load the profile:

. /root/.profile

Issue TLS Certificate Using Active24 DNS Challenge

Register account:

acme.sh \
  --register-account \
  -m david.pasek@gmail.com 

Request a certificate using the Active24 DNS hook:

acme.sh \
--issue \
--dns dns_active24 \
-d blog.uw.cz

This command requests a certificate for a single service (blog.uw.cz).

The wildcard certificate for *.uw.cz is useful for services such as:

www.uw.cz
admin.uw.cz
grafana.uw.cz
cloud.uw.cz 

... but not as secure as a single service.

During validation, acme.sh creates a temporary TXT record:

_acme-challenge.example.cz

The record is created through the Active24 API. After successful validation, Let’s Encrypt issues the certificate.

Install Certificate for NGINX

Create a directory for NGINX certificates:

mkdir -p /usr/local/etc/nginx/certs/blog.uw.cz

Install the certificate:

acme.sh \
  --install-cert \
  -d blog.uw.cz \
  --key-file /usr/local/etc/nginx/certs/blog.uw.cz/key.pem \
  --fullchain-file /usr/local/etc/nginx/certs/blog.uw.cz/fullchain.pem \
  --reloadcmd "service nginx reload"

The important part is:

--reloadcmd "service nginx reload"

This means that after every successful certificate renewal, NGINX is reloaded automatically.

Configure NGINX

Edit the NGINX configuration file:

vi /usr/local/etc/nginx/nginx.conf

Example configuration:

worker_processes auto;

events {
    worker_connections 1024;
}

http {
    include mime.types;
    default_type application/octet-stream;

    sendfile on;

    server {
        listen 80;
        server_name blog.uw.cz;

        root /usr/local/www/blog.uw.cz;
        index index.html;

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

    server {
        listen 443 ssl http2;
        server_name blog.uw.cz;

        ssl_certificate /usr/local/etc/nginx/certs/blog.uw.cz/fullchain.pem;
        ssl_certificate_key /usr/local/etc/nginx/certs/blog.uw.cz/key.pem;

        ssl_protocols TLSv1.2 TLSv1.3;

        root /usr/local/www/blog.uw.cz;
        index index.html;

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

Validate the configuration:

nginx -t

Start NGINX:

service nginx start

Verify HTTP and HTTPS

Check that NGINX is listening on ports 80 and 443:

sockstat -4 -l | grep nginx

Test HTTPS certificate:

openssl x509 \
  -in /usr/local/etc/nginx/certs/example.cz/fullchain.pem \
  -noout \
  -dates

You should see something like:

notBefore=...
notAfter=...

Open the site in a browser:

https://blog.uw.cz

Automatic Certificate Renewal

acme.sh usually installs a cron job automatically. Verify it:

crontab -l

You should see something similar to:

15 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

This job runs daily, but certificates are renewed only when they are close to expiration. 

If cron job is not there, just add it ...

crontab -e

15 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

List managed certificates:

acme.sh --list

Test Renewal Manually

You can force a renewal test:

acme.sh \
  --renew \
  -d blog.uw.cz \
  --ecc \
  --force

Expected flow:

Renew certificate
Install renewed certificate
Reload NGINX

Conclusion

This setup provides a clean FreeBSD-based web service with NGINX, HTTP, HTTPS, automatic TLS certificate issuance, and automatic renewal using the Active24 DNS API.

The main advantage of the DNS-01 challenge is that certificate validation does not depend on public HTTP access. This makes the solution suitable for internal services, wildcard certificates, servers behind NAT, and enterprise-style deployments.

No comments:

Post a Comment