← Blog
odooproxynginxdockerdeployment

Odoo proxy_mode: Run Odoo Behind a Reverse Proxy

Set proxy_mode = True in odoo.conf so Odoo trusts X-Forwarded headers behind nginx, Traefik, or Docker. What it does, how to set it, and the pitfalls.

ODXProxy Team · Jul 8, 2026 · 6 min read

Odoo proxy_mode: Run Odoo Behind a Reverse Proxy — ODXProxy blog cover

The moment you put Odoo behind nginx, Traefik, or a Docker load balancer, one setting decides whether your links, redirects, and logged client IPs come out right: proxy_mode. Leave it off and Odoo generates http:// redirect URLs on an HTTPS site, logs the proxy's IP as every visitor, and can send users to the wrong host after login. Turn it on and Odoo starts trusting the X-Forwarded-* headers your reverse proxy sets. This guide explains exactly what odoo proxy_mode does, how to enable it in odoo.conf, in Docker, and on the command line, and the security pitfall you must avoid.

What proxy_mode actually does

When a request reaches Odoo through a reverse proxy, the TCP connection Odoo sees comes from the proxy, not from the browser. So without help, Odoo believes:

  • the client IP is the proxy's IP,
  • the scheme is http (the proxy usually terminates TLS and forwards plaintext), and
  • the host is whatever the proxy used to reach Odoo (often localhost:8069).

proxy_mode fixes this by activating Werkzeug's ProxyFix middleware, which tells Odoo to read the real values from headers the proxy adds:

  • X-Forwarded-For → the real client IP.
  • X-Forwarded-Proto → the real scheme (https), so Odoo builds https:// URLs.
  • X-Forwarded-Host → the real public hostname, so redirects and email links point at the right domain.

The visible symptoms of leaving it off are the classic "works locally, breaks behind the proxy" bugs: a login that bounces to http:// and warns about an insecure connection, password-reset emails linking to localhost, and every audit-log entry showing the same internal IP.

proxy_mode only changes how Odoo interprets incoming headers. It does not make Odoo add security or terminate TLS — that is still the reverse proxy's job. The two must be configured together.

Enabling it in odoo.conf

The setting lives in the [options] section of your Odoo configuration file:

[options]
proxy_mode = True

Restart Odoo after changing it. That is the whole switch — but it is only half the job. proxy_mode tells Odoo to trust the forwarded headers; your reverse proxy still has to set them.

Setting the headers on the proxy side

If your reverse proxy doesn't send the X-Forwarded-* headers, enabling proxy_mode does nothing — Odoo has no truthful values to read. A minimal nginx location block for Odoo looks like this:

location / {
    proxy_pass http://127.0.0.1:8069;
    proxy_set_header Host              $host;
    proxy_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_redirect off;
}

The pairing is the point: nginx sets X-Forwarded-Proto $scheme and X-Forwarded-Host $host, and proxy_mode = True tells Odoo to believe them. Get the full production config — TLS, gzip, the websocket/longpolling route, and asset caching — in Putting Odoo behind an nginx reverse proxy.

Don't forget the chat/bus route. Odoo's live features run over a websocket (the gevent worker, port 8072 on older longpolling setups). Proxy that path too, or notifications and Discuss will hang even with proxy_mode correct.

proxy_mode in Docker

The official odoo image reads the same odoo.conf, so the cleanest approach is to mount a config file that sets proxy_mode = True:

services:
  odoo:
    image: odoo:18
    volumes:
      - ./config/odoo.conf:/etc/odoo/odoo.conf:ro
    depends_on:
      - db
  proxy:
    image: nginx:stable
    ports:
      - "443:443"
    volumes:
      - ./nginx/odoo.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - odoo

With that odoo.conf containing the proxy_mode = True line from above. If you'd rather not mount a file, you can pass it as a startup flag instead (see below) or via the image's command. Whichever you choose, the reverse-proxy container still has to set the X-Forwarded-* headers — the same rule applies inside Docker as outside it.

The command-line flag

For quick tests or ephemeral containers, Odoo accepts the equivalent flag without any config file:

odoo-bin --proxy-mode -c /etc/odoo/odoo.conf

This is handy for confirming a fix, but keep the setting in odoo.conf for anything long-lived so it survives restarts and is captured in version control.

The security pitfall: only trust a real proxy

There is a real risk here, and it is worth stating plainly. When proxy_mode is on, Odoo believes the X-Forwarded-For header. If a client can reach Odoo's HTTP port directly — bypassing the proxy — it can forge that header and spoof its IP, defeating any IP-based logging or rate limiting.

The rule follows directly: enable proxy_mode only when Odoo is genuinely unreachable except through your trusted proxy. In practice that means binding Odoo to localhost or a private network and letting only the reverse proxy connect to it:

[options]
proxy_mode = True
; Only accept connections from the local reverse proxy, not the public internet
http_interface = 127.0.0.1

If Odoo's port is exposed publicly, turning on proxy_mode trades one problem for a worse one.

Two different kinds of "proxy" in front of Odoo

It is worth separating two things that both get called a "proxy," because proxy_mode only concerns the first:

  • A web reverse proxy (nginx, Traefik, Caddy) sits in front of Odoo's web server — terminating TLS, serving the UI, and forwarding browser traffic. This is what proxy_mode exists for.
  • An API-layer proxy sits in front of Odoo's External API — the programmatic execute_kw surface your integrations call. ODXProxy is this second kind: it gives one JSON-RPC 2.0 endpoint in front of one or more Odoo instances so your services never hold database credentials or hardcode per-instance URLs. It is orthogonal to proxy_mode — you can run both, and many deployments do: nginx (with proxy_mode = True) fronting the web UI, and an API proxy fronting machine traffic.

If your goal is programmatic access rather than serving the web client, the API-layer path is covered in The Odoo External API: a JSON-RPC integration guide.

When it's the proxy, not proxy_mode

If you have proxy_mode set correctly and still see 502/504 errors, the cause is usually the proxy layer — timeouts, upstream failures, or a misrouted websocket — not the proxy_mode flag. That is a separate class of problem, walked through in Fixing Odoo 502 and 504 gateway errors.

Checklist

  • Set proxy_mode = True in odoo.conf (or --proxy-mode).
  • Make the reverse proxy set X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host.
  • Bind Odoo so it is reachable only through that proxy.
  • Proxy the websocket/longpolling route too.
  • Restart Odoo, then confirm redirects use https:// and logs show real client IPs.

Get those five right and Odoo behaves correctly behind any reverse proxy. For the end-to-end nginx setup, continue with Putting Odoo behind an nginx reverse proxy, and for the programmatic side, the API reference documents the External API surface in full.