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

Ben
Ben
@benjislab

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:

  1. Provide your email address for renewal notifications
  2. Accept the terms of service
  3. 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:

  1. Visit SSL Labs
  2. Enter your domain name
  3. Check the rating and recommendations

Troubleshooting

Certificate Issuance Failed

If certificate issuance fails:

  1. Check the error message:

    sudo certbot --apache -d yourdomain.com --debug-challenges
    
  2. Verify domain ownership:

    • Make sure DNS records point to your Raspberry Pi
    • Ensure port 80 is accessible from the internet
  3. Check for rate limits:

Certificate Not Renewed

If automatic renewal fails:

  1. Check renewal logs:

    sudo journalctl -u certbot.service
    
  2. Try manual renewal with increased verbosity:

    sudo certbot renew --force-renewal --verbose
    
  3. 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.

Additional Resources