SSL certificates for web servers
This guide explains how to request and install TLS certificates for NGINX at LEF.
Choose the issuer
Section titled “Choose the issuer”| Hostname | Use | Example |
|---|---|---|
| Public internet domain | Let’s Encrypt (Certbot) | hook.lef.software |
| Internal-only hostname | LEF Root CA (internal) | <internal-hostname> |
Prerequisites
Section titled “Prerequisites”- DNS record points to this server (see
dns.core.lefand Domains). - NGINX serves
/.well-known/acme-challenge/from/var/www/certbot. - For internal certificates, clients that need to trust the hostname have the LEF Root CA installed (see LEF Root CA (internal)).
NGINX snippet (add to the port 80 server block that matches the hostname):
location /.well-known/acme-challenge/ {
root /var/www/certbot;
allow all;
}Public domains (Let’s Encrypt with Certbot)
Section titled “Public domains (Let’s Encrypt with Certbot)”- Ensure the hostname resolves to this server and port 80 is reachable from the internet.
- Issue the certificate:
sudo certbot certonly --webroot \
-w /var/www/certbot \
-d <public-domain>- Point NGINX at the generated files:
ssl_certificate /etc/letsencrypt/live/<public-domain>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<public-domain>/privkey.pem;- Reload NGINX:
sudo systemctl reload nginxRenewal
Section titled “Renewal”- Verify the Certbot timer:
systemctl list-timers | grep certbot - Smoke-test renewal:
sudo certbot renew --dry-run
Internal domains (LEF Root CA)
Section titled “Internal domains (LEF Root CA)”Use this for hostnames that are only meant to be trusted inside LEF (LAN/VPN).
- Ensure internal DNS resolves correctly (split-horizon may apply): see DNS split horizon.
- Issue the certificate using the Root CA tooling (example script): see LEF Root CA (internal).
./sign-cert.sh <basename> <commonName> <dns1> <dns2> ...- Install into NGINX paths and reload:
sudo mkdir -p /etc/nginx/ssl
sudo install -m 0644 <basename>.cert.pem /etc/nginx/ssl/<basename>.cert.pem
sudo install -m 0600 <basename>.key.pem /etc/nginx/ssl/<basename>.key.pem- Point NGINX at the installed files:
ssl_certificate /etc/nginx/ssl/<basename>.cert.pem;
ssl_certificate_key /etc/nginx/ssl/<basename>.key.pem;- Reload NGINX:
sudo nginx -t && sudo systemctl reload nginxRenewal
Section titled “Renewal”- Check expiry with:
openssl x509 -in <basename>.cert.pem -noout -enddate - Re-issue before expiry (example: renew within 30 days): see LEF Root CA (internal)
- Never commit private keys or issued certificates to Git.
Validate
Section titled “Validate”- Open the site and confirm the certificate subject/SAN matches the hostname.
- For internal certs, confirm the chain roots in the LEF internal CA.
Known risks / failure modes
Section titled “Known risks / failure modes”- DNS points to the wrong host (ACME challenge validates the wrong server).
- NGINX does not serve the challenge path (404/unauthorized).
- Internal CA is unreachable (VPN/DNS issue) or the wrong ACME directory is used.
- Internal CA certificates are not publicly trusted (expected); don’t use them for public hostnames.