AlmaLinux 9: configuring and verifying nginx TLS
Test scope
Section titled “Test scope”In an AlmaLinux 9.8 privileged container (nginx 1.20.1 + OpenSSL): openssl req -x509, a conf.d/lab.conf, nginx -t, starting nginx, curl -sk and openssl s_client. Log: plans/content-expansion/evidence/logs/alma-nginx-tls.log.
The certbot/Let’s Encrypt part was not executed here (it needs a public domain and ports 80/443) and follows the official flow.
The three classic mistakes
Section titled “The three classic mistakes”- Path: the file behind
ssl_certificatedoes not exist →nginx -tfails immediately; - Key mismatch: certificate and key are not a pair →
nginx -treportskey values mismatch; - Incomplete chain: shipping only the leaf certificate breaks some clients → concatenate the intermediates into the same file.
All three are caught by nginx -t, so the first command after editing is always nginx -t.
Minimal self-signed check
Section titled “Minimal self-signed check”sudo dnf install -y nginx opensslsudo openssl req -x509 -nodes -newkey rsa:2048 -days 7 \ -subj "/CN=lab.local" \ -keyout /etc/pki/tls/private/lab.key \ -out /etc/pki/tls/certs/lab.crt-rw-r--r-- 1 root root 1115 ... /etc/pki/tls/certs/lab.crtSelf-signed is only for proving the configuration starts; browsers will flag it and production needs an ACME certificate.
Configure and validate
Section titled “Configure and validate”server { listen 8443 ssl; server_name lab.local; ssl_certificate /etc/pki/tls/certs/lab.crt; ssl_certificate_key /etc/pki/tls/private/lab.key; location / { return 200 "ok\n"; }}sudo nginx -t && sudo nginxnginx: configuration file /etc/nginx/nginx.conf test is successfulVerify the handshake
Section titled “Verify the handshake”curl -sk https://127.0.0.1:8443/echo | openssl s_client -connect 127.0.0.1:8443 -servername lab.local 2>/dev/null | grep -E "Protocol|Cipher"okNew, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384Protocol : TLSv1.3The s_client output confirms TLSv1.3 and the cipher; seeing TLSv1.2 means the configuration restricts protocols.
certbot: EPEL first, sign, then test renewal
Section titled “certbot: EPEL first, sign, then test renewal”sudo dnf install -y epel-releasesudo dnf install -y certbot python3-certbot-nginxsudo certbot --nginx -d example.comsudo certbot renew --dry-runcertbot comes from EPEL; --nginx edits the configuration and reloads, provided nginx runs, DNS points here and port 80 is reachable. The renew --dry-run validates the renewal path that keeps you out of trouble long term.
Common traps
Section titled “Common traps”- Editing the certificate without reloading: nginx keeps the old certificate;
- Private key at 644: should be 600 so other users cannot read it;
- Testing only 443:
curl -ksucceeding does not prove the chain is right; inspect it withopenssl s_client -showcerts.
Practice: self-signed 8443 plus a failure case
Section titled “Practice: self-signed 8443 plus a failure case”sudo dnf install -y nginx opensslsudo openssl req -x509 -nodes -newkey rsa:2048 -days 7 -subj "/CN=lab.local" \ -keyout /etc/pki/tls/private/lab.key -out /etc/pki/tls/certs/lab.crtsudo tee /etc/nginx/conf.d/lab.conf >/dev/null <<'EOF'server { listen 8443 ssl; server_name lab.local; ssl_certificate /etc/pki/tls/certs/lab.crt; ssl_certificate_key /etc/pki/tls/private/lab.key; location / { return 200 "ok\n"; }}EOFsudo nginx -t && sudo nginxcurl -sk https://127.0.0.1:8443/sudo sed -i 's#lab.crt#nope.crt#' /etc/nginx/conf.d/lab.confsudo nginx -t # expected to failChecks:
- The first
nginx -tsucceeds andcurl -skreturnsok s_clientshowsTLSv1.3- Breaking the path makes
nginx -tfail clearly - Restoring the path makes
nginx -tpass again
常见问题
What causes nginx -t to report key values mismatch?
The certificate and private key are not a pair (for example a new certificate with the old key). Compare `openssl x509 -noout -modulus` with `openssl rsa -noout -modulus`.
What does an incomplete chain look like?
Browsers and curl may work while some clients or Android devices report certificate errors. Check with `openssl s_client -showcerts` whether the intermediate is included.
Does nginx need a manual reload after certbot renews?
certbot deploy hooks usually reload automatically; with webroot setups lacking a hook, add `systemctl reload nginx` or a cron entry yourself.
Next steps
Section titled “Next steps”- Opening 443: firewall-cmd rules
- Container services: Quadlet services
- Post-install checks: 7 checks after install