Server administration Setting Up a Mail Server from Scratch – Part 6: Using Let's Encrypt

  • Thread starter D•Jass
  • Start date
  • Tags
    server
D•Jass

D•Jass

Staff member
Verified
  • #1

Using Let's Encrypt for SSL Certificates​

We’ll use Let's Encrypt to obtain free SSL/TLS certificates. Certbot will verify domain ownership via Nginx.

6.1. Configuring Nginx Server Blocks​

Create configuration files for your domains in /etc/nginx/sites-available/.

6.1.1.
Please, Login or Register to view URLs content!
(Simple Website)​

/etc/nginx/sites-available/www.example.com:
server {
listen 80;
# listen [::]:80; # For IPv6
server_name www.example.com; # Replace with your domain
root /var/www/html/www; # Set the web root
index index.html index.htm;

location / {
    try_files $uri $uri/ =404;
}

# Location for Let's Encrypt verification
location ~ /.well-known/acme-challenge/ {
    allow all;
    root /var/www/html/www; # Must match the root
}
}

Create the web root directory:
mkdir -p /var/www/html/www
chown www-data:www-data /var/www/html/www
echo "WWW OK" > /var/www/html/www/index.html

6.1.2. mail.example.com (Roundcube Webmail)​

/etc/nginx/sites-available/mail.example.com:
server {
listen 80;
# listen [::]:80; # For IPv6
server_name mail.example.com; # Replace with your mail domain
root /var/www/html/roundcube; # Path to Roundcube
index index.php index.html;

# Location for Let's Encrypt verification
location ~ /.well-known/acme-challenge/ {
    allow all;
    root /var/www/html/roundcube; # Ensure Nginx can read this
}

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php$ {
    try_files $uri =404; # Important for security
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php-fpm.sock; # Confirm PHP-FPM socket path
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_index index.php;
}

# Block access to hidden files and configs
location ~ /\.ht {
    deny all;
}
location ~ /(config|temp|logs)/ {
    deny all;
}
}
The /var/www/html/roundcube directory will be created during the Roundcube installation.

6.1.3. Enabling Server Blocks​

Create symbolic links and reload Nginx:
ln -s /etc/nginx/sites-available/www.example.com /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/mail.example.com /etc/nginx/sites-enabled/

Test Nginx config
nginx -t

If no errors, reload
systemctl reload nginx

6.2. Obtaining Certificates with Certbot​

Certbot will automatically retrieve certificates and configure Nginx to use them with HTTPS and redirection.

For www.example.com
certbot --nginx -d www.example.com --agree-tos --email your-email@example.com --no-eff-email

For mail.example.com
certbot --nginx -d mail.example.com --agree-tos --email your-email@example.com --no-eff-email

Optional: additional domains without changing Nginx config
certbot certonly --nginx -d api.example.com --agree-tos --email your-email@example.com --no-eff-email
Replace your-email@example.com with your actual email to receive expiry notices.

Certbot will automatically configure HTTPS and add a cron job for auto-renewal.

6.3. Automating Certificate Renewal for Postfix/Dovecot​

Create a deploy hook that copies updated certificates for Postfix and Dovecot and reloads them.

Create /etc/letsencrypt/renewal-hooks/deploy/postfix_dovecot.sh:
#!/bin/bash

Domain used for the certificate
DOMAIN="mail.example.com"

LIVE_DIR="/etc/letsencrypt/live/$DOMAIN"
POSTFIX_SSL_DIR="/etc/postfix/ssl"

echo "Running Let's Encrypt deploy hook for $DOMAIN..."

Check that certificate directory exists
if [ ! -d "$LIVE_DIR" ]; then
echo "Error: Certificate directory $LIVE_DIR not found." >&2
exit 1
fi

Ensure target directory exists
mkdir -p "$POSTFIX_SSL_DIR"

Copy the certificates
echo "Copying certificates..."
cp "$LIVE_DIR/fullchain.pem" "$POSTFIX_SSL_DIR/"
cp "$LIVE_DIR/privkey.pem" "$POSTFIX_SSL_DIR/"

Set permissions
echo "Setting permissions..."
chown root:postfix "$POSTFIX_SSL_DIR/"*.pem
chmod 640 "$POSTFIX_SSL_DIR/privkey.pem"
chmod 644 "$POSTFIX_SSL_DIR/fullchain.pem"

Reload services
echo "Reloading Postfix..."
if systemctl is-active --quiet postfix; then
postfix reload || echo "Error reloading Postfix." >&2
else
echo "Postfix is not active, skipping reload."
fi

echo "Reloading Dovecot..."
if systemctl is-active --quiet dovecot; then
systemctl reload dovecot || echo "Error reloading Dovecot." >&2
else
echo "Dovecot is not active, skipping reload."
fi

echo "Deploy hook finished for $DOMAIN."
exit 0

Make the script executable:
chmod +x /etc/letsencrypt/renewal-hooks/deploy/postfix_dovecot.sh
Now the script will automatically run after every successful renewal and reload the mail services.

Run the first copy manually:
/etc/letsencrypt/renewal-hooks/deploy/postfix_dovecot.sh
 
Last edited by a moderator:
Top