Why SSL Matters for Odoo
Running Odoo without SSL means: login credentials sent in plain text, customer data exposed to interception, browsers showing "Not Secure" warnings, and Google ranking penalties. Let's Encrypt provides free, auto-renewing SSL certificates.
Prerequisites
- Odoo running on a server with a public IP
- A domain name pointing to your server (A record in DNS)
- Nginx installed as reverse proxy
- Port 80 and 443 open in firewall
Step 1: Install Certbot
sudo apt install -y certbot python3-certbot-nginxStep 2: Configure Nginx (Without SSL First)
# /etc/nginx/sites-available/odoo
server {
listen 80;
server_name your-domain.com;
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;
}
}
# Enable the site
ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginxStep 3: Obtain SSL Certificate
sudo certbot --nginx -d your-domain.com
# For multiple domains:
sudo certbot --nginx -d your-domain.com -d www.your-domain.comCertbot automatically modifies your nginx configuration to add SSL.
Step 4: Verify Auto-Renewal
# Test renewal
sudo certbot renew --dry-run
# Certbot creates a systemd timer for auto-renewal
systemctl status certbot.timerCertificates auto-renew 30 days before expiry. No manual intervention needed.
Step 5: Add Security Headers
# Add to nginx SSL server block:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;Step 6: Update Odoo Configuration
# odoo.conf
proxy_mode = True # Required when behind nginx with SSLComplete Nginx SSL Configuration
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
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 https;
location /websocket {
proxy_pass http://127.0.0.1:8072;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
location /web/database {
deny all;
return 404;
}
location / {
proxy_pass http://127.0.0.1:8069;
proxy_read_timeout 720s;
client_max_body_size 200m;
}
location ~* /web/static/ {
proxy_pass http://127.0.0.1:8069;
expires 7d;
add_header Cache-Control "public, immutable";
}
}Troubleshooting
| Issue | Fix |
|---|---|
| Certbot fails: "Could not connect" | Ensure port 80 is open and DNS A record points to server |
| Mixed content warnings | Set proxy_mode = True in odoo.conf |
| Certificate not renewing | Check certbot.timer is active: systemctl status certbot.timer |
| "Not Secure" still showing | Ensure HTTP→HTTPS redirect is in nginx config |
DeployMonkey
DeployMonkey handles SSL automatically — certificates are obtained and renewed without any configuration. Custom domains get SSL within minutes of DNS pointing. No nginx configuration needed.