Secure Your Raspberry Pi Web Services: Complete Guide to Certbot SSL Certificate Setup

Securing your Raspberry Pi web services with SSL certificates is essential for encrypted connections and establishing trust with users. Let's Encrypt provides free SSL certificates, and Certbot makes the process of obtaining and renewing these certificates straightforward, even on a Raspberry Pi. This guide walks you through the complete process of installing and configuring Certbot on Raspberry Pi OS.
Prerequisites
Before we begin, ensure you have:
- A Raspberry Pi running Raspberry Pi OS (formerly Raspbian)
- A domain name pointing to your Raspberry Pi's IP address
- SSH or direct access to your Raspberry Pi
- A web server installed (this guide covers Apache and Nginx)
- Root or sudo access
Understanding Certbot and Let's Encrypt
Let's Encrypt is a free, automated, and open certificate authority that provides SSL certificates valid for 90 days. Certbot is an easy-to-use client that fetches and deploys these certificates automatically.
Using SSL certificates offers several benefits:
- Encrypted connections between users and your services
- Improved security for data transmission
- Browser trust indicators (padlock icon)
- Potential SEO advantages
Installation
Step 1: Update your system
Always start with a system update:
sudo apt update
sudo apt upgrade -y
Step 2: Install Certbot
Certbot is available in the Raspberry Pi OS repositories:
sudo apt install certbot -y
Step 3: Install the appropriate plugin
Depending on your web server, you'll need a specific plugin:
For Apache:
sudo apt install python3-certbot-apache -y
For Nginx:
sudo apt install python3-certbot-nginx -y
If you're using another web server or want standalone mode:
sudo apt install python3-certbot -y
Obtaining SSL Certificates
Method 1: Automatic Configuration (Recommended)
The automatic method will configure your web server automatically:
For Apache:
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com
For Nginx:
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Follow the on-screen prompts:
- Provide your email address for renewal notifications
- Accept the terms of service
- Choose whether to redirect HTTP traffic to HTTPS (recommended)
Method 2: Standalone Mode
If you don't have a web server installed or prefer not to use the automatic configuration:
sudo certbot certonly --standalone -d yourdomain.com -d www.yourdomain.com
Note: This method temporarily stops your web server on port 80 during verification.
Method 3: Manual Method (Webroot)
If you want to keep your web server running during verification:
sudo certbot certonly --webroot -w /var/www/html -d yourdomain.com -d www.yourdomain.com
Replace /var/www/html
with your web root directory.
Certificate Location
After successful installation, your certificates will be stored in:
-
/etc/letsencrypt/live/yourdomain.com/fullchain.pem
(certificate file) -
/etc/letsencrypt/live/yourdomain.com/privkey.pem
(private key)
Automatic Renewal
Let's Encrypt certificates are valid for 90 days. Certbot installs a cron job or systemd timer automatically to handle renewal. You can test the automatic renewal process with:
sudo certbot renew --dry-run
To check the renewal timer status (if using systemd):
systemctl status certbot.timer
Manual Renewal
If needed, you can manually renew all certificates:
sudo certbot renew
Common Issues on Raspberry Pi
1. Time synchronization problems
Let's Encrypt validation requires accurate system time. Ensure your Raspberry Pi's clock is synchronized:
sudo apt install ntpdate -y
sudo ntpdate -u time.google.com
Consider installing the NTP service for continuous synchronization:
sudo apt install ntp -y
2. Port 80 accessibility
Certbot needs port 80 accessible for domain validation. Ensure:
- Your router forwards port 80 to your Raspberry Pi
- No firewall is blocking port 80
- No other service is using port 80
To check if port 80 is in use:
sudo netstat -tulpn | grep :80
3. Limited resources
If your Raspberry Pi has limited RAM, consider closing unnecessary applications before running Certbot.
4. DNS propagation
If you've recently set up your domain, DNS changes might not have propagated yet. Check propagation with:
dig yourdomain.com +short
Configuring Web Servers Manually
If automatic configuration failed, you can configure your web server manually:
Apache
Edit your virtual host configuration:
sudo nano /etc/apache2/sites-available/yourdomain.com.conf
Add these lines:
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
Restart Apache:
sudo systemctl restart apache2
Nginx
Edit your server block:
sudo nano /etc/nginx/sites-available/yourdomain.com
Add these lines within the server block:
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
Restart Nginx:
sudo systemctl restart nginx
Using Certificates with Other Services
Node.js
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/fullchain.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Hello secure world!');
}).listen(443);
Python Flask
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello secure world!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=443, ssl_context=(
'/etc/letsencrypt/live/yourdomain.com/fullchain.pem',
'/etc/letsencrypt/live/yourdomain.com/privkey.pem'
))
Docker
When using Docker, mount the certificate directories as volumes:
docker run -p 443:443 \
-v /etc/letsencrypt/live/yourdomain.com:/etc/certs \
-v /etc/letsencrypt/archive/yourdomain.com:/etc/archive \
your-docker-image
Advanced Configurations
Wildcard Certificates
For securing all subdomains:
sudo certbot certonly --manual --preferred-challenges=dns \
-d yourdomain.com -d *.yourdomain.com
This requires DNS verification by adding TXT records.
Certificate Revocation
If your private key is compromised:
sudo certbot revoke --cert-path /etc/letsencrypt/live/yourdomain.com/cert.pem
Using External DNS Validation
For automated DNS validation with providers like Cloudflare:
sudo apt install python3-certbot-dns-cloudflare -y
Create a configuration file:
sudo mkdir -p /etc/letsencrypt/dns-credentials
sudo nano /etc/letsencrypt/dns-credentials/cloudflare.ini
Add your Cloudflare API credentials:
dns_cloudflare_email = [email protected]
dns_cloudflare_api_key = your-api-key
Secure the file:
sudo chmod 600 /etc/letsencrypt/dns-credentials/cloudflare.ini
Obtain a certificate:
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/dns-credentials/cloudflare.ini \
-d yourdomain.com -d *.yourdomain.com
Optimizing SSL Security
After getting your certificates, optimize SSL security:
Apache
Create a strong SSL configuration:
sudo nano /etc/apache2/conf-available/ssl-params.conf
Add:
SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM
SSLHonorCipherOrder on
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
SSLCompression off
SSLSessionTickets off
Enable the configuration:
sudo a2enconf ssl-params
sudo systemctl restart apache2
Nginx
Edit your Nginx configuration:
sudo nano /etc/nginx/nginx.conf
Add in the http section:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM";
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
Restart Nginx:
sudo systemctl restart nginx
Testing Your SSL Configuration
Test your SSL setup with the SSL Labs tool:
- Visit SSL Labs
- Enter your domain name
- Check the rating and recommendations
Troubleshooting
Certificate Issuance Failed
If certificate issuance fails:
-
Check the error message:
sudo certbot --apache -d yourdomain.com --debug-challenges
-
Verify domain ownership:
- Make sure DNS records point to your Raspberry Pi
- Ensure port 80 is accessible from the internet
-
Check for rate limits:
- Let's Encrypt limits to 5 identical certificates per week
- Check: https://letsencrypt.org/docs/rate-limits/
Certificate Not Renewed
If automatic renewal fails:
-
Check renewal logs:
sudo journalctl -u certbot.service
-
Try manual renewal with increased verbosity:
sudo certbot renew --force-renewal --verbose
-
Verify the renewal timer:
sudo systemctl list-timers | grep certbot
Conclusion
With Certbot and Let's Encrypt, securing your Raspberry Pi web services with SSL certificates is straightforward. The automatic renewal ensures your certificates remain valid without manual intervention. This setup provides encrypted connections for your users, enhancing security and trust for your Raspberry Pi-hosted services.
Remember to check that automatic renewal is working periodically, especially after system updates. With proper configuration, your Raspberry Pi can host secure web services with professional-grade encryption that major browsers will trust.