Skip to content
Troubleshooting

Odoo 502 Bad Gateway Nginx: Diagnosis and Fix

2026-07-15 · 10 min read

Last updated: 2026-08-09

502 Bad Gateway
nginx

Short answer: Nginx got a response it couldn't relay from whatever is listening (or not listening) on the upstream port, almost always because the Odoo process itself crashed, isn't running, or is taking longer to respond than Nginx's timeout allows. This is an upstream problem, not an Nginx configuration problem, in the large majority of cases.

Causes, ranked by how often they're actually it

1. The Odoo service isn't running or just crashed

By far the most common cause, and the first thing to rule out. Check immediately:

sudo systemctl status odoo
sudo journalctl -u odoo -n 100 --no-pager

Look for a Python traceback near the end of the journal output. A common crash cause is an unhandled exception in a cron job or a module that failed to load after a bad deployment. If systemctl status shows active (running) but you're still getting 502s, don't stop here, the process can be alive but stuck (see cause 3 and cause 5 below), which looks identical to "running fine" from systemd's point of view.

A specific pattern worth knowing: if the service shows activating (auto-restart) in a loop, that's not a one-off crash, it's Odoo failing to start at all, usually from a bad -u upgrade left half-applied or a syntax error in a module that got deployed. Check the very first lines of the journal after a restart, not just the tail:

sudo journalctl -u odoo --since "10 minutes ago" | head -50

2. Nginx is pointed at the wrong port or the port isn't listening

sudo ss -tlnp | grep -E '8069|8072'

If nothing is listening on 8069 (or your configured xmlrpc_port), Odoo isn't actually up regardless of what systemctl status claims, or your Nginx upstream block points at the wrong port. A common variant of this: Odoo is listening on 127.0.0.1:8069 but your Nginx upstream block references localhost:8069 and something in /etc/hosts or a container network resolves localhost differently than expected. Confirm the exact bound address, not just the port:

sudo ss -tlnp | grep 8069
# expect: LISTEN 0 128 127.0.0.1:8069 ... users:(("python3",pid=NNNN,...))

If you're running Odoo in Docker and Nginx on the host (or vice versa), also confirm the container's published port actually maps where Nginx expects it: docker ps and check the PORTS column matches your upstream block, this is a very common miss after a docker-compose change that wasn't followed by an Nginx reload.

3. Worker timeout under load (limit_time_real exceeded)

If Odoo is up but a specific request takes longer than limit_time_real in your Odoo config, the worker handling it gets killed and restarted, and Nginx sees the connection drop mid-request as a 502. Check:

sudo journalctl -u odoo | grep -i "limit_time_real|WorkerTimeout"

This is the cause most often mistaken for a generic "Nginx problem" because the error surfaces as a 502 in the browser, not as anything Nginx-specific. If you see repeated WorkerTimeoutError entries tied to the same endpoint (a specific report, a large export, a heavy search), that's your actual bottleneck, and raising limit_time_real without investigating the slow query first just delays the same failure under slightly higher load. See our dedicated worker timeout post for the correct values and how to tell a genuine bug from a limit that's simply too low for your workload.

4. Out of memory, worker killed by the OOM killer

sudo dmesg | grep -i "killed process"
free -h

If you see an Odoo worker process in the OOM killer log, this is a memory sizing problem, not an Nginx problem. Check your limit_memory_hard/limit_memory_soft settings against actual available RAM, see our workers formula post for correct values. A telltale sign this is your specific cause rather than cause 1: the service auto-restarts cleanly and runs fine for a while, then dies again under the next burst of concurrent requests or a large report export, rather than failing immediately on start.

5. PostgreSQL connection exhaustion

sudo -u postgres psql -c "SELECT count(*) FROM pg_stat_activity;"
sudo -u postgres psql -c "SHOW max_connections;"

If the first number is close to or at the second, Odoo workers can't open new database connections, requests hang, and eventually time out into a 502. This shows up most often after adding more Odoo workers without raising PostgreSQL's max_connections to match, each worker holds its own connection pool, so scaling workers without scaling the database side just moves the bottleneck. Confirm which database is holding the connections before assuming it's Odoo itself:

sudo -u postgres psql -c "SELECT datname, count(*) FROM pg_stat_activity GROUP BY datname ORDER BY count(*) DESC;"

6. Client body or header too large for Nginx's default limits

Less common, but worth ruling out if the 502 (or sometimes a 413) happens specifically on file uploads or large attachment saves, never on ordinary page loads:

sudo tail -50 /var/log/nginx/error.log | grep -i "client intended to send too large body"

If you see that line, it's not really a 502 cause in the strict sense but presents similarly to users, the fix is raising client_max_body_size in the relevant Nginx server block to match what Odoo's own attachment size limits allow.

A worked example

A recent case: a client's Odoo 17 instance started throwing intermittent 502s only during month-end, when several users ran large accounting reports at once. systemctl status showed the service healthy. ss -tlnp showed 8069 listening correctly. The actual cause was cause 3 and cause 5 compounding, each report held a worker for close to the full limit_time_real window, and with only 4 workers configured against a server that could support 6, the remaining requests queued until PostgreSQL's connection pool from those same workers was saturated. The fix wasn't a single setting, it was recalculating the worker count against actual CPU cores (see the workers formula post), then raising max_connections to match the new worker count, not raising limit_time_real in isolation, which would have just made users wait longer before the same failure.

The fix

Once you've identified which of the above is your actual cause, the immediate fix is usually one of:

# Restart a crashed service
sudo systemctl restart odoo

# Confirm the correct upstream port in your Nginx config
sudo nano /etc/nginx/sites-available/odoo
# upstream odoo { server 127.0.0.1:8069; }

# Reload Nginx after any config change
sudo nginx -t && sudo systemctl reload nginx

If the root cause is a timeout or memory limit, restarting the service only clears the symptom, fix the underlying limit_time_real/limit_memory_hard values or the query causing the slow request, or the 502s will return under the next load spike.

How to verify

curl -I https://yourdomain.com/web/login
# expect: HTTP/1.1 200 OK

Also tail both logs during a manual retry to confirm the request completes cleanly end to end:

sudo journalctl -u odoo -f
sudo tail -f /var/log/nginx/error.log

Still stuck

If the service is running, the port is listening, memory and connections look healthy, and you're still seeing intermittent 502s, work through these before assuming it's unfixable:

  • WebSocket or longpolling traffic specifically. If the 502s only affect chat, notifications or live updates while normal page loads work fine, that's a different, very common misconfiguration covered in our bus.Bus and Nginx post and our WebSocket connection post.
  • A reverse proxy in front of Nginx. If you're behind Cloudflare or another CDN/proxy layer, confirm the 502 is actually coming from your own Nginx and not being generated upstream, check /var/log/nginx/error.log for a matching timestamp. If nothing logs at that time, the failure may be happening between the proxy and your origin, not inside your own stack at all.
  • Multiple Odoo instances behind one Nginx, only one affected. Confirm you're reading the right upstream block and the right systemd unit, it's an easy mix-up on multi-tenant boxes where several odoo-<client>.service units run side by side.
  • Intermittent, no clear pattern, low traffic. Check disk space on the server and the PostgreSQL data volume specifically, a full disk causes PostgreSQL to reject writes in ways that can surface as a generic 502 rather than a clear database error: df -h.

If none of the above matches, capture the exact timestamp of the next 502, then correlate journalctl -u odoo, /var/log/nginx/error.log and pg_stat_activity at that same second, the answer is almost always visible once you have all three logs lined up against the same moment rather than checked separately after the fact.

Sources: Nginx documentation, Odoo documentation.

Talal Yousaf, Senior DevOps Engineer at DevFusion Tech. 70+ Odoo deployments across Community and Enterprise, versions 13 through 19. More about DevFusion · LinkedIn

Published 2026-07-15 · updated 2026-08-09

ShareLinkedInXWhatsApp

Hit the same wall in production?

Tell us what you're running and where it breaks. A 30 minute call, no pitch deck, and a straight answer on whether we can help.