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

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 buildshttps://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 = TrueRestart 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.
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:
- odooWith 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.confThis 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.1If 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_modeexists for. - An API-layer proxy sits in front of Odoo's External API — the programmatic
execute_kwsurface 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 toproxy_mode— you can run both, and many deployments do: nginx (withproxy_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 = Trueinodoo.conf(or--proxy-mode). - Make the reverse proxy set
X-Forwarded-For,X-Forwarded-Proto, andX-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.