Skip to content

Fix Odoo Mixed Content & Proxy Mode Issues: HTTPS Behind Nginx

DeployMonkey Team · March 23, 2026 8 min read

Mixed Content Problem

When Odoo runs behind Nginx with SSL termination, the browser loads the page over HTTPS but Odoo generates HTTP URLs for assets (CSS, JS, images). Browsers block these mixed content requests, breaking the page layout and functionality.

Symptoms

# Mixed content indicators:
# 1. Browser console shows:
#    "Mixed Content: The page was loaded over HTTPS
#     but requested an insecure resource http://..."
# 2. CSS/JS not loading (broken layout)
# 3. Images showing broken icons
# 4. Websocket connection failing
# 5. Login redirect loop (HTTP→HTTPS→HTTP)
# 6. Download links generating HTTP URLs

Root Cause

# How Odoo generates URLs:
# 1. Odoo sees incoming request on port 8069 (HTTP)
# 2. Generates all URLs as http://domain.com/...
# 3. But Nginx serves the page over HTTPS
# 4. Browser blocks HTTP resources on HTTPS page

# The fix requires:
# 1. Odoo knowing it's behind a proxy (proxy_mode)
# 2. Nginx passing the original protocol (X-Forwarded-Proto)
# 3. Odoo using forwarded headers for URL generation

Fix: Odoo Configuration

# /etc/odoo.conf — MUST enable proxy_mode
[options]
proxy_mode = True

# What proxy_mode does:
# - Trusts X-Forwarded-For header (real client IP)
# - Trusts X-Forwarded-Proto header (HTTPS detection)
# - Trusts X-Forwarded-Host header (domain name)
# - Uses these headers to generate correct URLs

# SECURITY WARNING:
# Only enable proxy_mode when behind a reverse proxy!
# Without proxy, attackers can spoof these headers

Fix: Nginx Configuration

# /etc/nginx/sites-available/odoo
server {
    listen 443 ssl;
    server_name odoo.example.com;

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

    location / {
        proxy_pass http://127.0.0.1:8069;

        # CRITICAL: Forward protocol information
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;

        # Buffer settings
        proxy_buffers 16 64k;
        proxy_buffer_size 128k;
    }

    location /websocket {
        proxy_pass http://127.0.0.1:8072;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
    }
}

# Force HTTPS redirect
server {
    listen 80;
    server_name odoo.example.com;
    return 301 https://$host$request_uri;
}

Redirect Loop Fix

# Problem: Page keeps redirecting HTTP→HTTPS→HTTP

# Cause: Odoo redirects to HTTP, Nginx redirects
# back to HTTPS, infinite loop

# Fix checklist:
# 1. proxy_mode = True in odoo.conf ✓
# 2. X-Forwarded-Proto $scheme in Nginx ✓
# 3. No duplicate redirects in Nginx config ✓
# 4. web.base.url set correctly:

# System Parameters (Settings → Technical):
# web.base.url = https://odoo.example.com
# web.base.url.freeze = True

# The freeze parameter prevents Odoo from
# auto-detecting and changing the base URL

Cloudflare Additional Fix

# If using Cloudflare proxy:
# Cloudflare → Nginx → Odoo

# Cloudflare SSL mode: Full (Strict)
# This ensures Cloudflare connects to Nginx via HTTPS

# Additional Nginx header for Cloudflare:
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
# Cloudflare sends its own X-Forwarded-Proto

# Or use CF-Visitor header:
set $real_scheme $scheme;
if ($http_cf_visitor ~ '"scheme":"https"') {
    set $real_scheme https;
}
proxy_set_header X-Forwarded-Proto $real_scheme;

DeployMonkey

DeployMonkey configures proxy_mode, Nginx headers, and SSL correctly for every Odoo deployment. No mixed content issues, no redirect loops.