Free SSL Certificates with Let’s Encrypt
Issue and auto-renew free TLS certificates with Let's Encrypt and Certbot for Nginx or Apache on Ubuntu, Fedora, and Arch Linux.
Before you start
- ▸A domain name with a public DNS A record pointing to your server
- ▸Nginx or Apache installed and listening on port 80
- ▸Ports 80 and 443 open in your cloud provider's security group or network ACL
- ▸sudo or root access on the server
Let's Encrypt is a free, automated certificate authority run by the Internet Security Research Group (ISRG). Combined with Certbot, the official ACME client, you can issue trusted TLS certificates in minutes and have them renew automatically — no annual fees, no manual renewal rituals. This guide covers installing Certbot, issuing certificates for Nginx and Apache, and verifying that automatic renewal works correctly.
How Let's Encrypt Works
Let's Encrypt uses the ACME protocol to verify that you control the domain you're requesting a certificate for. The most common method is the HTTP-01 challenge: Certbot places a temporary file under /.well-known/acme-challenge/ on your web server, and Let's Encrypt fetches it over port 80 to confirm ownership. Once verified, a 90-day certificate is issued. Certbot installs a systemd timer or cron job that renews certificates automatically before they expire.
Prerequisites
- A public-facing server with ports 80 and 443 open in your firewall.
- A domain name with a DNS A record pointing to your server's IP address.
- Nginx or Apache already installed and serving traffic on port 80.
- Root or sudo access.
Step 1: Open Firewall Ports
Before Certbot runs, confirm ports 80 and 443 are reachable from the internet. Use whichever firewall your distro defaults to.
ufw (Debian/Ubuntu)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
firewalld (Fedora/RHEL/Rocky)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
nftables (Arch / manual setups)
sudo nft add rule inet filter input tcp dport { 80, 443 } accept
Persist that rule in /etc/nftables.conf and reload with sudo systemctl restart nftables.
Step 2: Install Certbot
Install both Certbot and the appropriate web-server plugin for your stack. The plugin handles server config changes automatically.
Debian / Ubuntu
# For Nginx
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
# For Apache
sudo apt install -y certbot python3-certbot-apache
Fedora / RHEL 9 / Rocky 9
# Enable EPEL first on RHEL/Rocky
sudo dnf install -y epel-release
# For Nginx
sudo dnf install -y certbot python3-certbot-nginx
# For Apache
sudo dnf install -y certbot python3-certbot-apache
Arch Linux
# For Nginx
sudo pacman -S certbot certbot-nginx
# For Apache
sudo pacman -S certbot certbot-apache
Alternatively, Certbot's maintainers recommend the snap package for always-current versions on Ubuntu:
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Step 3: Issue a Certificate — Nginx
The --nginx plugin reads your existing server blocks, obtains the certificate, and edits the config to enable HTTPS automatically. Replace example.com with your actual domain.
sudo certbot --nginx -d example.com -d www.example.com
Certbot prompts for an email address (used for expiry warnings) and asks you to agree to the Terms of Service. When asked whether to redirect HTTP to HTTPS, choose Redirect (option 2) unless you have a specific reason not to. Certbot rewrites your Nginx config in place and reloads the service.
After completion your /etc/nginx/sites-enabled/example.com (or equivalent) will contain SSL directives and a 301 redirect block added by Certbot. Review it with:
sudo nginx -t && sudo systemctl reload nginx
Step 4: Issue a Certificate — Apache
The process mirrors Nginx. Certbot edits your VirtualHost blocks and reloads Apache.
sudo certbot --apache -d example.com -d www.example.com
Certbot creates a new *-le-ssl.conf VirtualHost file alongside your original and inserts a rewrite rule for HTTP→HTTPS. Verify Apache is happy:
sudo apachectl configtest && sudo systemctl reload apache2 # Debian/Ubuntu
sudo apachectl configtest && sudo systemctl reload httpd # Fedora/RHEL/Rocky
Step 5: Verify the Certificate
Check that the certificate is valid and the chain is complete from the command line:
curl -vI https://example.com 2>&1 | grep -E 'SSL|issuer|expire'
You should see issuer: C=US; O=Let's Encrypt and a future expiry date. You can also use the online SSL Labs server test to get a full grade report — a correctly configured Certbot setup typically earns an A.
List all certificates Certbot is managing:
sudo certbot certificates
Output will show the domain(s), certificate path, expiry date, and which private key is in use. Output varies by system.
Step 6: Confirm Automatic Renewal
Certbot installs a systemd timer on systemd-based distros (which is almost everything modern). Confirm it is active:
sudo systemctl status certbot.timer
The timer fires twice daily. Certbot only requests a new certificate when the existing one has fewer than 30 days remaining, so near-daily checks are safe and keep rate-limit consumption low.
Do a dry run to make sure renewal would succeed without actually replacing any certificate:
sudo certbot renew --dry-run
A clean dry run prints Congratulations, all simulated renewals succeeded. If it fails, fix the underlying issue before your real certificate expires.
On older systems or non-snap installs that use cron instead of systemd, check:
cat /etc/cron.d/certbot
Troubleshooting
Challenge fails — port 80 not reachable
Let's Encrypt must reach your server on port 80 during issuance. Cloud providers (AWS, GCP, Azure) have security groups or firewall rules separate from the OS firewall. Check those first. Also confirm your DNS A record has propagated: dig +short example.com should return your server's public IP.
Rate limit errors
Let's Encrypt enforces a limit of 5 duplicate certificates per week per registered domain. If you hit it during testing, use the staging environment to avoid real limits:
sudo certbot --nginx --staging -d example.com
Staging certificates are signed by a fake CA and won't be trusted by browsers, but they let you test your setup without burning production quota.
Certbot edits broke my Nginx/Apache config
Certbot backs up configs before editing them. Look in /etc/letsencrypt/renewal/ and the server's config directory for .bak or timestamped copies. For Nginx, Certbot marks its blocks with # managed by Certbot comments, making them easy to identify and revert manually.
Certificate not renewing automatically
Run sudo systemctl list-timers | grep certbot to confirm the timer is scheduled. If the timer is missing, enable it:
sudo systemctl enable --now certbot.timer
Also check /var/log/letsencrypt/letsencrypt.log for renewal errors from previous attempts.
Wildcard certificates
Wildcard certs (*.example.com) require DNS-01 challenge instead of HTTP-01. This means Certbot must create a TXT record in your DNS zone, which typically requires a DNS provider API plugin. Automatic renewal also requires the plugin. This is more involved; see the Certbot DNS plugins documentation for your provider.
Frequently asked questions
- How long do Let's Encrypt certificates last, and how does renewal work?
- Certificates are valid for 90 days. Certbot's systemd timer runs twice daily and renews any certificate with fewer than 30 days remaining, so you never need to renew manually.
- Can I get a wildcard certificate with Certbot?
- Yes, but wildcards require the DNS-01 challenge instead of HTTP-01. You need a Certbot DNS plugin that can create TXT records via your DNS provider's API, and automatic renewal requires the same plugin to be configured.
- What happens if my server is behind a load balancer or CDN?
- If the CDN terminates TLS before your origin, you may not need a Let's Encrypt certificate on your origin at all. If you do, ensure port 80 traffic is forwarded to your server for the ACME challenge, or switch to the DNS-01 challenge method.
- Is it safe to run Certbot on a live production server?
- Yes. Certbot reloads the web server gracefully rather than stopping it, so there is no downtime during certificate issuance or renewal. It also backs up config files before modifying them.
- What are Let's Encrypt's rate limits?
- The most relevant limit is 5 duplicate certificates per registered domain per week. Use the --staging flag while testing to avoid consuming this quota with failed or experimental runs.
Related guides
Configure Prometheus Alertmanager
Configure Prometheus Alertmanager with routing trees, receivers, inhibition rules, grouping, Go templates, and PagerDuty/Slack on-call integrations.
Build an Intranet Server on Linux
Set up a complete small-office intranet on one Linux box: Nginx web server, dnsmasq local DNS, Samba file sharing, and a Wiki.js team wiki.
Build an nftables Firewall Script
Build a complete nftables firewall from scratch: tables, chains, sets, default-deny input policy, service allowlisting, and persistent systemd configuration.
Caddy as a Reverse Proxy
Set up Caddy as a reverse proxy with automatic HTTPS, load balancing, WebSocket passthrough, reusable snippets, and header control — no certbot required.