Running Odoo without SSL is a security risk you cannot afford — login credentials, customer data, and invoice details all transit in plaintext over HTTP. Let's Encrypt provides free, trusted SSL certificates that auto-renew every 90 days. Here's how to set it up in under 20 minutes.
Prerequisites
- A Linux server with Nginx installed (see Odoo Nginx reverse proxy setup)
- A domain name pointing to your server's IP (DNS must be propagated before running Certbot)
- Ports 80 and 443 open in your firewall
- Odoo running on localhost (typically port 8069)
Step 1: Install Certbot
# Ubuntu/Debian
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
# RHEL/AlmaLinux/Rocky
sudo dnf install -y certbot python3-certbot-nginx
Step 2: Basic HTTP Nginx Config (Pre-SSL)
Before running Certbot, you need a working Nginx server block for your domain. Create /etc/nginx/sites-available/odoo:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# Required for Certbot ACME challenge
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
proxy_pass http://127.0.0.1:8069;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
sudo ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 3: Obtain the SSL Certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Certbot will:
- Verify you control the domain via an HTTP challenge
- Issue a certificate from Let's Encrypt
- Automatically modify your Nginx config to enable HTTPS
- Redirect HTTP to HTTPS
Step 4: Full Nginx HTTPS Config for Odoo
After Certbot runs, your Nginx config will be updated. Review and enhance it to include Odoo-specific settings and strong SSL parameters:
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;
# Modern SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;
# Security headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
# Odoo proxy settings
proxy_read_timeout 720s;
proxy_connect_timeout 720s;
proxy_send_timeout 720s;
client_max_body_size 100m;
location / {
proxy_pass http://127.0.0.1:8069;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /longpolling {
proxy_pass http://127.0.0.1:8072;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
Step 5: Enable proxy_mode in Odoo
Odoo must be told it's running behind a reverse proxy. In /etc/odoo/odoo.conf:
proxy_mode = True
Without this, Odoo generates HTTP links instead of HTTPS in emails, payment redirects, and portal URLs. Restart Odoo after this change.
Step 6: Configure Auto-Renewal
Certbot automatically installs a systemd timer or cron job on installation. Verify it:
# Check the timer
systemctl status certbot.timer
# Test renewal (dry run)
sudo certbot renew --dry-run
If the dry run succeeds, your certificates will renew automatically every 60 days (well before the 90-day expiry). Add a post-renewal hook to reload Nginx after each renewal:
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/bash
systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Step 7: Validate with SSL Labs
After completing the setup, test your SSL configuration at SSL Labs SSL Test. Enter your domain and aim for an A or A+ rating. The configuration above should achieve A+.
Common issues flagged by SSL Labs:
- TLS 1.0/1.1 enabled: Disable in
ssl_protocols - HSTS not set: Add the
Strict-Transport-Securityheader - OCSP stapling misconfigured: Verify
ssl_stapling onand thatssl_trusted_certificatepoints to the chain file
How DeployMonkey Handles SSL
DeployMonkey automatically provisions and renews Let's Encrypt certificates for every managed Odoo instance. SSL is enabled the moment you add a custom domain — no Certbot commands, no Nginx config editing, no renewal cron jobs. Certificates renew silently in the background, and you're alerted if a renewal fails. Get started free.
Frequently Asked Questions
How often do Let's Encrypt certificates expire?
Let's Encrypt certificates expire every 90 days. Certbot auto-renews them at the 60-day mark. You should never need to manually renew unless auto-renewal is broken.
What happens if Certbot auto-renewal fails?
Let's Encrypt sends a reminder email 20 days before expiry. If renewal still fails, your certificate expires and browsers show a security warning to visitors. Monitor with certbot renew --dry-run in a cron job that sends alerts on failure.
Can I use Let's Encrypt with a wildcard certificate?
Yes, but wildcard certificates (*.yourdomain.com) require DNS-01 challenge validation rather than HTTP-01. This requires API access to your DNS provider. Certbot supports this via DNS plugins (e.g., certbot-dns-cloudflare).
Why does Odoo still show HTTP links in emails after enabling SSL?
Two likely causes: (1) proxy_mode = True is not set in odoo.conf, or (2) web.base.url in Settings > Technical > System Parameters still starts with http://. Update both. See also our guide on fixing Odoo HTTPS errors.
Does this work for Odoo running in Docker?
Yes. Run Certbot on the host machine (not inside the container), mount the certificate directory into the Nginx container, and expose port 443 from the Nginx container. Alternatively, use a Nginx container with automatic Let's Encrypt support such as nginx-proxy with acme-companion.