Overview
Free SSL certificates for Nginx HTTP/2 based SSL are available on Centmin Mod LEMP web stack thanks to Let's Encrypt. Let's Encrypt is a free, automated, and open Certificate Authority (CA) that provides Domain Validation (DV) SSL/TLS certificates at no cost.
Centmin Mod integrates Let's Encrypt through the addons/acmetool.sh addon script, which wraps the acme.sh client. This integration supports multiple Certificate Authority providers including Let's Encrypt, ZeroSSL, and Google Public CA.
If your Centmin Mod Nginx domain is behind Cloudflare's orange cloud proxy with Full or Full Strict SSL mode enabled, use the Cloudflare DNS API domain validation method for issuing SSL certificates on your origin server.
Key features of the Let's Encrypt integration:
- Automated SSL certificate issuance and configuration for Nginx vhosts
- Support for dual RSA 2048-bit + ECC 256-bit ECDSA certificates
- DNS-based domain validation via Cloudflare DNS API
- Webroot-based domain validation (default method)
- Automatic certificate renewal via cron
- Alternative CA providers: ZeroSSL and Google Public CA
Prerequisites
Domain DNS Requirements
To use Let's Encrypt SSL certificate support in Centmin Mod Nginx, ensure your domain name's DNS A records for the apex domain.com, www.domain.com, and/or any subdomain.domain.com point to your Centmin Mod server's IP address.
DNS propagation can take up to 24-48 hours. Verify your DNS records resolve correctly before attempting to issue SSL certificates. Let's Encrypt must be able to reach your server on port 80 for webroot validation.
By default, Let's Encrypt domain validation is done via the webroot authentication method, where the client automatically generates a challenge file at:
https://yourdomain.com/.well-known/acme-challenge/*
For domains behind a CDN or proxy, use DNS-based validation instead.
Issuing SSL Certificate
Enable Let's Encrypt Support
To enable native Let's Encrypt SSL certificate support, set the following variable in the persistent config file /etc/centminmod/custom_config.inc (create the file if it does not already exist):
LETSENCRYPT_DETECT='y'
This allows Centmin Mod Nginx's vhost creation routines to use addons/acmetool.sh to obtain free Let's Encrypt SSL certificates for the desired Nginx vhost domain name.
If LETSENCRYPT_DETECT is not set, Nginx vhost generation will default to creating self-signed SSL certificates. These are not browser-trusted but are useful for development testing without entries appearing in public SSL certificate transparency logs.
Using acmetool.sh
The primary tool for managing Let's Encrypt certificates is the acmetool.sh addon script located at:
/usr/local/src/centminmod/addons/acmetool.sh
For full details on usage, refer to the official community forum discussion thread.
Dual RSA + ECDSA Certificates
Centmin Mod Nginx uses OpenSSL 1.1.1+ which supports dual RSA 2048-bit + ECC 256-bit ECDSA SSL certificates. When enabled, two SSL certificates are issued: one RSA 2048-bit and one ECC 256-bit. Nginx will serve the ECC certificate to browsers that support it (better performance), falling back to RSA for browsers that don't.
To enable dual certificate support, add both variables to /etc/centminmod/custom_config.inc:
LETSENCRYPT_DETECT='y'
DUALCERTS='y'
ECC 256-bit ECDSA certificates offer smaller key sizes and faster TLS handshakes compared to RSA, improving site performance for modern browsers. See the Security Headers and SSL Testing sections below for more on SSL/TLS configuration.
ZeroSSL Alternative
ZeroSSL is an alternative free CA provider supported by Centmin Mod's acmetool.sh. Key differences from Let's Encrypt:
- No rate limits for SSL certificate issuance
- GUI-based management console for issued certificates
- Better backward compatibility with older devices via cross-signed root certificates
Switching to ZeroSSL
Step 1. Register an account at ZeroSSL.com and obtain EAB credentials from app.zerossl.com/developer. Alternatively, register directly via the command line with your email:
acme.sh --register-account -m myemail@example.com --server zerossl
Step 2. If you obtained EAB credentials manually, register them with the acme.sh client:
acme.sh --register-account --server zerossl \
--eab-kid xxxxxxxxxxxx \
--eab-hmac-key xxxxxxxxx
Step 3. Set ZeroSSL as the default CA in /etc/centminmod/custom_config.inc:
ACME_DEFAULT_CA='zerossl'
To switch back to Let's Encrypt, remove the variable or set it explicitly:
ACME_DEFAULT_CA='letsencrypt'
Step 4. Reissue existing certificates using ZeroSSL with the reissue-only option (this only touches SSL certificate configuration, leaving the rest of your Nginx vhost config intact):
/usr/local/src/centminmod/addons/acmetool.sh reissue-only yourdomain.com live
DNS Validation
Cloudflare DNS API Validation
Centmin Mod's acmetool.sh supports DNS domain validation via the Cloudflare DNS API. Instead of webroot URL authentication, the client automatically generates a DNS TXT record through your Cloudflare API, and Let's Encrypt reads that record to validate your domain.
This method is recommended if your Centmin Mod Nginx domain is behind Cloudflare's orange cloud proxy with Full or Full Strict SSL mode enabled.
Add these variables to /etc/centminmod/custom_config.inc:
LETSENCRYPT_DETECT='y'
CF_DNSAPI_GLOBAL='y'
CF_Token="YOUR_CF_TOKEN"
CF_Account_ID="YOUR_CF_ACCOUNT_ID"
Creating a Cloudflare API Token
Create your Cloudflare API Token at dash.cloudflare.com/profile/api-tokens with the following permissions:
- Read access to
Zone.Zone - Edit/write access to
Zone.DNS - Apply across all Zones
Your Cloudflare Account ID can be found on any of your Cloudflare domain's main dashboard in the right-side column.
Only one Cloudflare Account is supported per configuration. All intended domains must be within the same Cloudflare Account, unless you have a Cloudflare Account with invited administrator access to other accounts and can generate a CF API Token that includes access to those accounts.
Wildcard Certificates
Wildcard certificates (e.g., *.domain.com) require DNS-based validation. Webroot validation cannot be used for wildcard certificates. Configure the Cloudflare DNS API as described above, then use acmetool.sh to issue the wildcard certificate with DNS validation mode.
DNS propagation for TXT records may take a few minutes. The acme.sh client includes built-in wait and retry logic, but if validation fails, ensure the DNS TXT record has fully propagated before retrying.
Certificate Renewal
Automatic Renewal
Let's Encrypt SSL certificates are valid for 90 days. The acme.sh client installs a cron job that automatically renews certificates before they expire. No manual intervention is required for routine renewals.
The acme.sh cron job runs daily and will attempt renewal when a certificate has fewer than 30 days remaining. Nginx is automatically reloaded after a successful renewal.
Manual Renewal
To manually reissue an existing certificate, use the reissue-only option:
/usr/local/src/centminmod/addons/acmetool.sh reissue-only yourdomain.com live
Checking Certificate Dates
To list all SSL certificates and their expiry dates for all Nginx-configured sites on the server:
/usr/local/src/centminmod/addons/acmetool.sh checkdates
Example output showing both Nginx-installed and acme.sh-obtained certificates with their expiry dates and SHA1 fingerprints:
----------------------------------------------
nginx installed
----------------------------------------------
/usr/local/nginx/conf/ssl/domain.com/domain.com-acme.cer
SHA1 Fingerprint=06FE84519E09ACB75BBE11EDF26F7D41D0Bxxxxx
certificate expires in 83 days on 25 Dec 2021
----------------------------------------------
acme.sh obtained
----------------------------------------------
/root/.acme.sh/domain.com/domain.com.cer
SHA1 Fingerprint=06FE84519E09ACB75BBE11EDF26F7D41D0Bxxxxx
certificate expires in 83 days on 25 Dec 2021
Let's Encrypt has rate limits on certificate issuance. Avoid excessive manual reissuance. The default limit is 50 certificates per registered domain per week. ZeroSSL has no such rate limits.
Troubleshooting
Domain validation fails
Ensure your domain's DNS A record correctly points to your server's IP address. Verify with:
dig +short yourdomain.com A
dig +short www.yourdomain.com A
Port 80 not accessible
For webroot validation, Let's Encrypt needs to reach your server on port 80. Check that your firewall (CSF or iptables) allows incoming connections on port 80 and that Nginx is listening on port 80 for the domain.
Rate limit exceeded
Let's Encrypt limits certificate issuance to 50 per registered domain per week. If you hit this limit, wait for the window to reset or consider switching to ZeroSSL which has no rate limits.
ZeroSSL: "no eab credentials found"
This means you haven't registered your EAB credentials with the acme.sh client. Either register via the command line with your email address or manually provide the EAB key ID and HMAC key from the ZeroSSL developer portal.
Certificate behind Cloudflare proxy
If your domain is behind Cloudflare's orange cloud proxy, webroot validation will fail because requests are intercepted by Cloudflare. Switch to Cloudflare DNS API validation instead.
Certificate not auto-renewing
Check that the acme.sh cron job is installed and running. View the cron job with:
crontab -l | grep acme
For additional support, visit the official community forum discussion thread or the Cloudflare DNS API validation thread.
Security Headers
Security headers provide an additional layer of protection for your HTTPS site. Add these headers to your Nginx HTTPS server block to improve security.
HSTS (HTTP Strict Transport Security)
HSTS tells browsers to always use HTTPS for your domain, preventing protocol downgrade attacks and cookie hijacking:
# max-age=31536000 = 1 year
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
HSTS is difficult to undo
Once HSTS is set with a long max-age, browsers will refuse to load your site over HTTP for that duration. Only enable HSTS when you are committed to HTTPS long-term. Start with a short max-age=300 for testing.
Clearing HSTS for a Domain
If you need to undo HSTS after enabling it, follow these steps. Start with the server-side fix, then clear the cached policy in each browser that visited your site.
Server-Side (Recommended First Step)
Send a header with max-age=0 over HTTPS to immediately expire the cached HSTS policy. Per the MDN specification, this tells browsers to stop enforcing HSTS for your domain.
# Set max-age=0 to expire HSTS policy immediately
add_header Strict-Transport-Security "max-age=0" always;
The max-age=0 header must be served over HTTPS. Browsers will not accept HSTS headers delivered over plain HTTP by design.
Browser-Specific Clearing
After updating the server header, clear the cached HSTS policy in each browser that has visited your site:
Google Chrome / Chromium
- Navigate to
chrome://net-internals/#hsts - Under "Delete domain security policies", enter your domain
- Click Delete
- Restart the browser
Microsoft Edge
- Navigate to
edge://net-internals/#hsts - Under "Delete domain security policies", enter your domain
- Click Delete, then restart the browser
Brave
- Navigate to
brave://net-internals/#hsts - Under "Delete domain security policies", enter your domain
- Click Delete, then restart the browser
Opera
- Navigate to
opera://net-internals/#hsts - Under "Delete domain security policies", enter your domain
- Click Delete, then restart the browser
Firefox
Method 1 — Forget Site:
- Open History (Ctrl+Shift+H / Cmd+Shift+H)
- Search for your domain
- Right-click the entry → Forget About This Site
Method 2 — Edit profile file:
- Navigate to
about:support→ click Open Profile Folder - Close Firefox, then edit
SiteSecurityServiceState.txt - Delete the line containing your domain, save the file
- Restart Firefox
Safari (macOS)
- Close Safari completely
- Delete
~/Library/Cookies/HSTS.plist - Reopen Safari
Note: This clears HSTS for all sites, not just your domain.
HSTS Preload List Removal
If your domain was submitted to the HSTS preload list, additional steps are required:
- Remove the
preloaddirective from your HSTS header - Submit a removal request at hstspreload.org/removal
Preload list updates ship with browser releases, so removal can take weeks to months to propagate to all users.
Additional Security Headers
Other recommended security headers to add to your HTTPS vhost:
# Prevent MIME-type sniffing
add_header X-Content-Type-Options "nosniff" always;
# Prevent clickjacking - restrict iframe embedding
add_header X-Frame-Options "SAMEORIGIN" always;
# XSS protection (legacy browsers)
add_header X-XSS-Protection "1; mode=block" always;
# Referrer policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Content Security Policy (customize per your needs)
# add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
Content Security Policy
CSP headers need to be customized for each site. A misconfigured CSP can break your website. Use Mozilla's CSP documentation as a guide, and test with Content-Security-Policy-Report-Only before enforcing.
SSL Testing
After configuring SSL/TLS, test your setup using these tools to verify your configuration is secure and correctly implemented.
Recommended Testing Tools
- Qualys SSL Labs — The most comprehensive SSL/TLS test. Aim for an A+ rating. Tests protocol support, cipher suites, key exchange, and certificate chain.
- GlobalSign SSL Check — Verifies certificate installation and chain completeness.
- GeoCerts SSL Checker — Quick certificate validity and expiration check.
Achieving an A+ Rating
To get an A+ on SSL Labs, you need: TLS 1.2/1.3 only (no TLS 1.0/1.1), HSTS header with max-age of at least 6 months, forward secrecy cipher suites, and OCSP stapling enabled.
Command-Line Testing
You can also test your SSL configuration directly from the server via SSH:
# Test TLS connection and view certificate details
openssl s_client -connect domain.com:443 -tls1_2 -tlsextdebug -status
# Check certificate expiration date
echo | openssl s_client -servername domain.com -connect domain.com:443 2>/dev/null | openssl x509 -noout -dates
# Verify Nginx config before restarting
nginx -t