Quick Answer
SSL/TLS encrypts all data between browser and server, preventing interception. The problem: User logs in to Odoo, without SSL/TLS = unencrypted transmission = anyone on network intercepts login credentials (readable text), customer data (readable text), payment information (readable text), API keys (readable text) = complete data breach possible. The solution: SSL/TLS encrypted transmission = all data encrypted end-to-end, eavesdroppers see gobbledygook, only user and Odoo can decrypt, browser shows π padlock = data secure in transit. FREE with Let's Encrypt: Trusted certificate authority, automated, 90-day expiry with auto-renewal. Setup steps: (1) Install Certbot: sudo apt-get install certbot python3-certbot-nginx. (2) Get certificate: sudo certbot certonly --nginx -d odoo.example.com. (3) Configure Nginx: TLS 1.2+, HSTS header (force HTTPS always), HTTPβHTTPS 301 redirect, security headers (X-Frame-Options, X-Content-Type-Options). (4) Automatic renewal: Certbot timer runs twice daily, certbot renew command. Certificate files: fullchain.pem (certificate + chain), privkey.pem (private key, SECRET). Security headers: HSTS max-age=31536000 (1 year), X-Frame-Options SAMEORIGIN (prevent clickjacking), X-XSS-Protection. Testing: SSL Labs (https://www.ssllabs.com/ssltest/) for A+ rating. Impact: Proper SSL/TLS = compliant, users trust system, zero data breaches in transit. Without = data interceptable, $100k-$500k in compliance fines and lost customer trust.
The SSL/TLS Security Gap
Your D2C user logs in to Odoo. Their login credentials:
Username: john@company.com
Password: SuperSecret123!
Without SSL/TLS
User β Odoo (unencrypted transmission)
Anyone on the network can intercept:
- - Login credentials (readable text)
- - Customer data (readable text)
- - Payment information (readable text)
- - API keys (readable text)
Result: Complete data breach possible
With SSL/TLS
User β Odoo (encrypted transmission)
All data encrypted end-to-end:
- - Eavesdroppers see: gobbledygook
- - Only user and Odoo can decrypt
- - Browser shows π padlock
Result: Data secure in transit
All your data interceptable vs. protected
And it's FREE (Let's Encrypt)
We've implemented 150+ Odoo systems. The ones with proper SSL/TLS? Compliant, users trust the system, zero data breaches in transit. The ones without? Data interceptable, staff loses confidence, potential regulatory fines, customers avoid the system. That's $100,000-$500,000 in compliance fines and lost customer trust.
Understanding SSL/TLS
What it does: Encrypts all data between browser and server.
How It Works
1. Browser connects to https://odoo.example.com
2. Server sends certificate (proves it's legit)
3. Browser verifies certificate with trusted authority
4. They agree on encryption key
5. All data encrypted with key
6. Data travels encrypted across internet
7. Only browser and server can decrypt
Result: Eavesdroppers see garbage, not data
SSL vs TLS
| Protocol | Status | Description |
|---|---|---|
| SSL | Old (insecure, deprecated) | Do not use |
| TLS | Modern (secure, current standard) | Modern Odoo uses TLS 1.2+ |
Getting a Free Certificate (Let's Encrypt)
What it is: Free, automated, trusted certificate authority.
Requirements
β Domain name (must own/control it)
β Server with port 80/443 open
β Nginx or Apache web server
Install Certbot
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx
# Verify installation
certbot --version
Get Free Certificate
# Generate certificate for domain
sudo certbot certonly --nginx -d odoo.example.com -d www.odoo.example.com
# Interactive prompts:
# - Email for renewal notifications
# - Accept terms
# - Certbot auto-configures Nginx
# Certificate stored at:
# /etc/letsencrypt/live/odoo.example.com/
Certificate Files
/etc/letsencrypt/live/odoo.example.com/
βββ cert.pem # Certificate
βββ chain.pem # Intermediate certs
βββ fullchain.pem # cert + chain (use this!)
βββ privkey.pem # Private key (SECRET!)
βββ README # Documentation
Configure Nginx for HTTPS
# Redirect HTTP to HTTPS
server {
listen 80;
listen [::]:80;
server_name odoo.example.com www.odoo.example.com;
# Certbot validation
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# Redirect all HTTP to HTTPS
location / {
return 301 https://$server_name$request_uri;
}
}
# HTTPS server
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name odoo.example.com www.odoo.example.com;
# SSL certificates (from Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/odoo.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/odoo.example.com/privkey.pem;
# SSL configuration (secure)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# HSTS (Force HTTPS always)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Other security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
# Proxy to Odoo
location / {
proxy_pass http://127.0.0.1:8069;
# Headers for Odoo
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;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Longpolling (chat/notifications)
location /longpolling {
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_set_header Host $host;
}
}
Enable Configuration
# Test Nginx config
sudo nginx -t
# Enable site
sudo ln -s /etc/nginx/sites-available/odoo.example.com /etc/nginx/sites-enabled/
sudo systemctl restart nginx
# Verify
curl https://odoo.example.com # Should work
Test SSL Configuration
# Check certificate validity
openssl s_client -connect odoo.example.com:443
# Online SSL test
# https://www.ssllabs.com/ssltest/analyze.html?d=odoo.example.com
Automatic Certificate Renewal (Critical!)
Problem: Let's Encrypt certificates expire in 90 days.
Solution: Certbot auto-renews (already set up).
Verify Renewal Cron
# Check cron job
sudo systemctl list-timers
# Look for certbot timer
# certbot.timer (runs twice daily)
Manual Renewal (For Testing)
# Renew all certificates
sudo certbot renew --dry-run
# In production (if needed)
sudo certbot renew
Create Renewal Script (Backup Automation)
#!/bin/bash
# /usr/local/bin/renew-ssl.sh
# Renew all certificates
certbot renew --quiet
# Restart Nginx to load new certificates
systemctl restart nginx
# Log renewal
echo "SSL renewed on $(date)" >> /var/log/ssl-renewal.log
Schedule Cron Job
# Run script daily at 2 AM
sudo crontab -e
# Add line:
0 2 * * * /usr/local/bin/renew-ssl.sh
Complete Secure Setup
Architecture
User (HTTPS only)
β (encrypted)
Nginx (SSL termination)
β (HTTP internal)
Odoo (unencrypted, internal network)
β
PostgreSQL
Step-by-Step Setup
# 1. Install Certbot
sudo apt-get install certbot python3-certbot-nginx
# 2. Get certificate
sudo certbot certonly --nginx \
-d odoo.example.com \
-d www.odoo.example.com \
--email admin@example.com \
--agree-tos \
--non-interactive
# 3. Configure Nginx (use config above)
sudo nano /etc/nginx/sites-available/odoo.example.com
# 4. Test Nginx
sudo nginx -t
# 5. Enable site
sudo ln -s /etc/nginx/sites-available/odoo.example.com /etc/nginx/sites-enabled/
# 6. Restart
sudo systemctl restart nginx
# 7. Verify
curl https://odoo.example.com # Should show Odoo login page
Certificate Dashboard
# View all certificates
sudo certbot certificates
# Output:
# Found the following certs:
# Certificate Name: odoo.example.com
# Serial Number: abc123
# Key Type: RSA
# Expiry Date: 2026-03-22
# Auto Renewal: Enabled
# Renewal Count: 3
Security Headers Explained
HSTS (HTTP Strict Transport Security)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
β Tells browser: Always use HTTPS
β Prevents downgrade attacks
β max-age: How long to remember (1 year)
β includeSubDomains: Apply to all subdomains
β preload: Add to browser preload list
X-Frame-Options
add_header X-Frame-Options "SAMEORIGIN" always;
β Prevents clickjacking
β SAMEORIGIN: Only embed from same domain
β DENY: Never embed
Content-Security-Policy
add_header Content-Security-Policy "default-src 'self'" always;
β Prevents XSS attacks
β Controls where resources can load from
Action Items: Implement SSL/TLS
Immediate (1 hour)
β Install Certbot
β Generate Let's Encrypt certificate
β Configure Nginx (use config above)
β Test HTTPS connection
Test (30 minutes)
β Access via https://odoo.example.com
β Verify padlock in browser
β Check SSL Labs rating
β Test on mobile device
Ongoing (Automated)
β Certbot handles renewal automatically
β Monitor certificate expiry (email alerts)
β Test renewal monthly: certbot renew --dry-run
Frequently Asked Questions
How do I get a free SSL certificate for Odoo?
Use Let's Encrypt with Certbot for free automated certificates. Requirements: Domain name you own/control, server with port 80/443 open, Nginx or Apache web server. Installation: sudo apt-get install certbot python3-certbot-nginx. Get certificate: sudo certbot certonly --nginx -d odoo.example.com -d www.odoo.example.com. Interactive prompts for email (renewal notifications), accept terms. Certificate location: /etc/letsencrypt/live/odoo.example.com/. Files: fullchain.pem (certificate + chain, use this in Nginx), privkey.pem (private key, keep SECRET). Expiry: 90 days. Auto-renewal: Certbot timer runs twice daily, certbot renew command. Cost: FREE. Trusted: Let's Encrypt is trusted by all major browsers (Chrome, Firefox, Safari, Edge). Verification: Test at https://www.ssllabs.com/ssltest/ for A+ rating.
How do I configure Nginx for HTTPS with Odoo?
Configure Nginx as SSL termination proxy with security headers. HTTP redirect: listen 80, return 301 https://$server_name$request_uri (redirect all HTTP to HTTPS). HTTPS server: listen 443 ssl http2, ssl_certificate fullchain.pem, ssl_certificate_key privkey.pem. SSL protocols: TLSv1.2 TLSv1.3 only (disable old SSL/TLS 1.0/1.1). Proxy to Odoo: proxy_pass http://127.0.0.1:8069, proxy_set_header X-Forwarded-Proto $scheme. Security headers: HSTS (Strict-Transport-Security max-age=31536000), X-Frame-Options SAMEORIGIN, X-Content-Type-Options nosniff, X-XSS-Protection. WebSocket support: proxy_http_version 1.1, proxy_set_header Upgrade, Connection "upgrade". Longpolling: Separate location /longpolling proxy to port 8072. Enable: sudo nginx -t, sudo systemctl restart nginx. Verify: curl https://odoo.example.com shows Odoo login.
What are security headers and why do I need them?
Security headers protect against common web attacks. HSTS (Strict-Transport-Security): Forces browser to always use HTTPS, prevents downgrade attacks, max-age=31536000 (1 year), includeSubDomains applies to all subdomains. X-Frame-Options SAMEORIGIN: Prevents clickjacking (embedding your site in iframe), only allows same-origin embedding. X-Content-Type-Options nosniff: Prevents MIME-type sniffing attacks, browser respects declared content-type. X-XSS-Protection: Enables browser XSS filter, blocks reflected XSS attacks. Referrer-Policy: Controls referer header leakage. Content-Security-Policy: Prevents XSS by controlling resource loading sources. Permissions-Policy: Disables browser features (geolocation, microphone, camera). Implementation: Add add_header directives in Nginx server block. Testing: Use https://securityheaders.com/ to scan and verify all headers present. Impact: Proper headers = A+ SSL Labs rating, protection from clickjacking/XSS/downgrade attacks.
How often do SSL certificates need to be renewed?
Let's Encrypt certificates expire every 90 days but auto-renew automatically. Expiry: 90 days from issuance date. Auto-renewal: Certbot creates systemd timer (certbot.timer) that runs twice daily, attempts renewal when cert has <30 days remaining. Verification: sudo systemctl list-timers shows certbot.timer scheduled. Manual test: sudo certbot renew --dry-run (simulates renewal without actually renewing). Manual renewal: sudo certbot renew (if auto-renewal fails). Email alerts: Let's Encrypt sends expiry warnings to email address provided during setup. Monitoring: sudo certbot certificates shows expiry dates. Backup cron: Create /usr/local/bin/renew-ssl.sh script, schedule with crontab (0 2 * * *) for daily 2 AM renewal check + Nginx restart. Best practice: Test renewal monthly with --dry-run to catch issues before actual expiry. Result: Set-and-forget automatic renewal, zero downtime, always valid certificates.
Free Security Setup Consultation
Stop running insecure HTTP connections. We'll install Let's Encrypt certificate, configure Nginx for HTTPS, set up security headers, enable automatic renewal, and test and verify. Most D2C brands run without proper SSL/TLS. Adding it is free and takes 1 hour.
