You don't need a control panel to run HTTPS. With Certbot or acme.sh you can get free Let's Encrypt certificates for any site on Nginx, issue wildcard certificates such as *.example.com through the Cloudflare DNS API, and renew them automatically. This guide covers both tools on Debian/Ubuntu and Rocky Linux/AlmaLinux, the Nginx HTTPS configuration, sites behind the Cloudflare proxy, and how to check that renewal really works.
dig +short example.com.Certbot can request the certificate and edit your Nginx server block for you, including the HTTP to HTTPS redirect.
# Debian / Ubuntu
apt update
apt install -y certbot python3-certbot-nginx
# Rocky Linux / AlmaLinux (EPEL)
dnf install -y epel-release
dnf install -y certbot python3-certbot-nginx
# Request and install a certificate for the domain and www
certbot --nginx -d example.com -d www.example.com \
--agree-tos -m [email protected] --redirect
# Renewal is scheduled automatically; confirm the timer and run a test renewal
systemctl list-timers | grep -i certbot
certbot renew --dry-run
Certificates are stored in /etc/letsencrypt/live/example.com/. If you prefer to keep your Nginx file untouched, use certbot certonly --nginx -d example.com and add the certificate paths yourself as shown in the Nginx HTTPS configuration below.
acme.sh is a single shell script that runs as a cron job. Note that its default certificate authority is ZeroSSL; switch it to Let's Encrypt if you prefer.
# Install (creates ~/.acme.sh and a daily cron job)
curl https://get.acme.sh | sh -s [email protected]
source ~/.bashrc
# Use Let's Encrypt as the default CA
acme.sh --set-default-ca --server letsencrypt
# Issue using your site's web root (HTTP-01 validation)
acme.sh --issue -d example.com -d www.example.com -w /var/www/example
# Install the certificate where Nginx expects it and reload Nginx on every renewal
mkdir -p /etc/nginx/ssl
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com.crt \
--reloadcmd "systemctl reload nginx"
Never point Nginx directly at files inside ~/.acme.sh; always use --install-cert, which copies the files and runs the reload command after each renewal.
Wildcard certificates (*.example.com) require DNS validation. If your domain uses Cloudflare DNS, create an API token in the Cloudflare dashboard under My Profile → API Tokens using the "Edit zone DNS" template, limited to the zone you need.
# acme.sh: dns_cf reads the token from the environment and saves it for renewals
export CF_Token="your-cloudflare-api-token"
export CF_Zone_ID="your-zone-id" # shown on the domain's Overview page in Cloudflare
acme.sh --issue --dns dns_cf -d example.com -d '*.example.com'
# Certbot alternative
apt install -y python3-certbot-dns-cloudflare
mkdir -p ~/.secrets && chmod 700 ~/.secrets
echo 'dns_cloudflare_api_token = your-cloudflare-api-token' > ~/.secrets/cloudflare.ini
chmod 600 ~/.secrets/cloudflare.ini
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
-d example.com -d '*.example.com'
DNS validation also works when port 80 is closed or the site is not reachable yet, which makes it useful for internal services and new servers.
If you issued the certificate with certonly or acme.sh, add an HTTPS server block yourself. Adjust the certificate paths to the tool you used.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on; # Nginx 1.25.1+; older versions: "listen 443 ssl http2;"
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # acme.sh: /etc/nginx/ssl/example.com.crt
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # acme.sh: /etc/nginx/ssl/example.com.key
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
root /var/www/example;
index index.html index.php;
}
nginx -t && systemctl reload nginx
With the orange cloud enabled, HTTP validation normally still works because Cloudflare forwards /.well-known/acme-challenge/ requests to your server. Set the SSL/TLS mode in Cloudflare to Full (strict) once your origin has a valid certificate; "Flexible" sends traffic to your server unencrypted and often causes redirect loops. You can also use DNS validation, or a free Cloudflare Origin Certificate if the site is only ever served through Cloudflare. To stop visitors bypassing Cloudflare, see hiding your origin IP.
# Expiry date of the certificate your site actually serves
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
# Certbot: all certificates and their expiry
certbot certificates
# acme.sh: list certificates and force a test renewal
acme.sh --list
acme.sh --renew -d example.com --force
Port 80 is blocked, the DNS record points somewhere else, or another server block answers for the domain. Check the firewall, run dig +short example.com, and make sure /.well-known/acme-challenge/ is not redirected or denied in your Nginx configuration. Otherwise switch to DNS validation.
Let's Encrypt limits how many certificates you can issue per week for the same domain names. Use --dry-run (Certbot) or --staging (acme.sh) while experimenting and only request a real certificate once the setup works.
Yes. Add each name with its own -d option. Wildcards cover only one level, so *.example.com matches shop.example.com but not a.shop.example.com or example.com itself; add the bare domain separately.
Still stuck after following these steps? Open a support ticket and the IMIDC 24/7 technical team will help. Include the server IP, OS version, your domain, the command you ran and the full error output so we can pinpoint the issue faster.