Skip to content

Odoo SSL Setup with Let's Encrypt: Complete Guide

DeployMonkey Team · March 22, 2026 10 min read

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-nginx

Step 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 nginx

Step 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.com

Certbot 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.timer

Certificates 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 SSL

Complete 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

IssueFix
Certbot fails: "Could not connect"Ensure port 80 is open and DNS A record points to server
Mixed content warningsSet proxy_mode = True in odoo.conf
Certificate not renewingCheck certbot.timer is active: systemctl status certbot.timer
"Not Secure" still showingEnsure 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.