Required packages (Debian 9/10)

Wildcard (DNS, Manual)

sudo certbot --server https://acme-v02.api.letsencrypt.org/directory \
    --manual \
    --preferred-challenges dns \
    --register-unsafely-without-email \
    -d *.example.com -d example.com certonly


sudo certbot certonly --webroot -w /var/www/_certbot --register-unsafely-without-email \
    -d example.com

HTTP (used by Haproxy examples)

sudo certbot certonly --standalone --preferred-challenges http \
    --server https://acme-v02.api.letsencrypt.org/directory --http-01-port 12345 \
    --register-unsafely-without-email \
    -d example.com

If you do not have a web server (such as Nginx) on your server and you don’t plan to, replace 12345 and 80 and you can use Certbot standalone with HTTP challenge.

DH params

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

Nginx Sites-available

server {
        # SSL configuration
        listen 443 ssl http2;
        listen [::]:443 ssl http2;

        server_name example.com;

        include snippets/ssl-params.conf;
        include snippets/ssl/example.com.conf;

        root /var/www/example.com;

        # Add index.php to the list if you are using PHP
        index index.php index.html;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;


sudo mkdir /etc/nginx/snippets/ssl/
sudo mkdir /etc/nginx/sites-available/_utilities
sudo rm /etc/nginx/sites-enabled/default -rf
sudo mv /etc/nginx/sites-available/default /etc/nginx/sites-available/old_default
sudo nano /etc/nginx/snippets/ssl-params.conf

sudo ln -s /etc/nginx/sites-available/_utilities/http-redirect /etc/nginx/sites-enabled/
sudo nano /etc/nginx/sites-available/_utilities/http-redirect

HTTP redirect

filename: /etc/nginx/sites-available/_utilities/http-redirect

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        server_name _;

        access_log off;
        error_log off;

        location / {
                return 301 https://$host$request_uri;

        location /.well-known/acme-challenge {
                root /var/www/_certbot/;
                try_files $uri $uri/ =404;

Nginx per-certificate configuration

filename: /etc/nginx/snippets/ssl/example.com.conf

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

# Normal HSTS policy. Remove if you use preload one.
add_header Strict-Transport-Security "max-age=63072000" always;

# This forces your domain's all subdomains to HTTPS.
# Please submit to your domain to https://hstspreload.org/ if you select this option.
#add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

SSL params

filename: /etc/nginx/snippets/ssl-params.conf

# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.10.3&openssl=1.1.0f&hsts=yes&profile=modern
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

# modern configuration. tweak to your needs.
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;

# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;

# Replace with your own resolvers if preferred
# This example is using UncensoredDNS, see https://uncensoreddns.org/ for details.
resolver valid=300s;
resolver_timeout 5s;

add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

# User-agent Blocklist
# https://wiki.lelux.fi/nginx#useragent-blocklist
# include snippets/useragent-blocklist/nginx.conf;

# Block dotfiles, except .well-known
location ~ /\.well-known {
    allow all;

location ~ /\. {
    deny all;