Nginx Proxy Manager / Troubleshooting
Nginx Proxy Manager 502 Bad Gateway: Diagnose the Upstream
NPM opens and the proxy host exists, but requests through it return 502 Bad Gateway. Compare upstream reachability from the NPM network context and match the forward address and the proxy error log against a stopped upstream, a wrong port, a localhost or name-resolution mismatch, or a TLS scheme failure.
A 502 from an NPM proxy host means nginx received the visitor request but could not complete the exchange with the configured upstream. The proxy host record defines that upstream with a forward hostname or IP, a forward port, and an http or https scheme; the official guide describes proxy hosts as forwarding domains and the reference compose pins the current 2.15.1 image.[1][3]
Direct reachability is a comparative signal, not proof of the cause: a check from a browser or another machine does not repeat the NPM container's network path. Distinguish four vantage points — the client or another external machine, the Docker host, the NPM container or an equivalent network namespace, and the upstream listener itself. If the upstream fails from every relevant vantage point including the NPM network context, investigate the upstream first; if it answers elsewhere but fails from the NPM network context, investigate the NPM-to-upstream path: address, port, Docker network attachment, name resolution, routing or firewall boundary, and TLS scheme.[2][4][3]
Sections
Applicability
- Products
- Nginx Proxy Manager
- Scope
- For Nginx Proxy Manager 2.15.x (2.15.1 current in the official compose reference) where a proxy host record exists, the NPM admin UI opens, and requests through the proxy host return HTTP 502 Bad Gateway. Whether the upstream answers is not assumed in advance; reachability is evaluated during diagnosis, starting from a network context equivalent to NPM. This page does not cover certificate issuance or renewal failures, Cloudflare Tunnel errors, NPM installation, DNS-only problems, or generic Docker networking.[1][2]
- Last verified
Symptoms
- The NPM admin UI opens and the proxy host record exists, but requests through the proxy hostname return HTTP 502 Bad Gateway; whether the upstream answers on its own is still undetermined at this point. An NPM login failure, a certificate renewal error, or a tunnel-specific error page is a different observation.[1][4]
Quick diagnosis
Compare upstream reachability from an NPM-equivalent network context, then match the forward address and the proxy error log before changing anything.
Record the exact 502 and where it appears
Record whether the 502 appears on the proxied public hostname, in the NPM admin UI itself, or both, with the full response text. A 502 only on proxied traffic keeps this page applicable; a 502 on the admin UI or a renewal error belongs elsewhere. Do not proceed on a remembered paraphrase.[1]
Contact the upstream and note where you tested from
Request the upstream application directly at its own address and port, then repeat the check from a network context equivalent to NPM where possible: the Docker host with NPM's network view, the NPM container or an equivalent network namespace, or the upstream listener itself. A result seen only from a browser or another machine is a comparative signal, not proof of the cause, because it does not repeat the NPM container's path. Use only a normal non-destructive request the application already serves.[4]
Read the proxy host error log
Open the error log for the failing proxy host in the NPM data directory and look for the upstream exchange: a connect refused line naming an address and port, a host-not-found line naming an upstream name, or a TLS handshake failure line. The official documentation confirms NPM rotates per-host access and error logs. Match the observed signature before choosing a branch.[2][4][5]
Do not change the proxy host, upstream, or TLS settings before classification
Do not edit the forward hostname, port, or scheme, restart the upstream, or change TLS settings before comparing reachability from the NPM network context and confirming the exact log signature. A change made before classification can hide which upstream boundary actually failed.[2]
Interactive troubleshooter
Your answers stay in this browser tab. The tool does not connect to your systems or send diagnostic results.
Guided check / step 1
Does the request through the NPM proxy host return 502 while NPM itself opens?
Confirm the NPM admin UI opens and the proxy host record exists, while requests through the proxy hostname return HTTP 502 Bad Gateway. A failing admin UI, a renewal error, or a tunnel-specific error page is a different observation.[1]
Read the complete diagnostic tree without using the controls
- Does the request through the NPM proxy host return 502 while NPM itself opens?
Confirm the NPM admin UI opens and the proxy host record exists, while requests through the proxy hostname return HTTP 502 Bad Gateway. A failing admin UI, a renewal error, or a tunnel-specific error page is a different observation.[1]
- Yes, proxy 502 with working NPM → What upstream target does the proxy host record?
- No, a different observation → Investigate the actual NPM observation
- What upstream target does the proxy host record?
Read the recorded forward hostname or IP and port before any reachability conclusion: this record selects which comparison applies next. A localhost address is the NPM container itself, a container name needs a shared Docker network, and a LAN IP or fully qualified name still needs a check from the NPM network context.[2]
- localhost or 127.0.0.1 → Replace the localhost forward address
- A container or service name → Make the container name resolvable for the proxy
- A LAN IP or fully qualified name → Can the recorded target be reached from a network context equivalent to NPM?
- Address type is unclear → Collect an NPM 502 evidence packet
- Can the recorded target be reached from a network context equivalent to NPM?
Test the recorded address and port from the Docker host with NPM's network view, from the NPM container or an equivalent network namespace, or at the upstream listener itself. A browser or other-machine result alone is a comparative signal: it does not repeat the NPM container's path, so reachability from elsewhere never proves the NPM-to-upstream path.[2][4]
- Fails from every vantage point, including NPM-equivalent context → Recover the upstream application first
- Answers elsewhere but fails from NPM-equivalent context → Which signature appears in the proxy host error log?
- Answers from NPM-equivalent context too → Which signature appears in the proxy host error log?
- Cannot test from NPM-equivalent context → Collect an NPM 502 evidence packet
- Which signature appears in the proxy host error log?
Match the error-level log line exactly: a refused connection naming an address and port, a host-not-found line naming an upstream, or a TLS handshake failure. Each signature selects a different branch.[4][5]
- connection refused → Does anything listen on the recorded target from the NPM network view?
- host not found in upstream → Give the proxy a resolvable upstream name
- TLS handshake failure → Align the scheme and TLS negotiation with the upstream
- No matching signature → Collect an NPM 502 evidence packet
- Does anything listen on the recorded target from the NPM network view?
Confirm from a vantage point sharing the NPM container's network view whether anything accepts connections on the recorded address and port. Nothing listening means the upstream target is wrong or stopped; a listener on a different port means the recorded forward port is wrong.[4][2]
- Nothing listens there → Restore the stopped upstream listener
- It listens on a different port → Correct the forward port to the serving port
- Cannot confirm the listener → Collect an NPM 502 evidence packet
- Recover the upstream application first
The recorded target fails from every relevant vantage point, including a network context equivalent to NPM, so investigate the upstream application with its owner before any proxy diagnosis. No proxy-host change belongs on this branch.[4]
- Replace the localhost forward address
Point the proxy host at an address reachable from inside the NPM container: the Docker host address where appropriate, or the container service name on a shared Docker network with its internal port. Never assume host-side listening proves the recorded target.[2]
- Make the container name resolvable for the proxy
Join NPM and the upstream to a shared Docker network and use the service name with its internal port, or switch to a DNS-resolvable name or IP. In some configurations an unresolved upstream hostname can additionally cause nginx configuration loading or reload failures; confirm the actual NPM/nginx log before assuming wider impact.[2][5]
- Restore the stopped upstream listener
Start or repair the upstream so it listens on the recorded target, verify it answers directly, then retest through the proxy hostname. The proxy record does not change on this branch.[4]
- Correct the forward port to the serving port
Change the recorded forward port to the port the application actually serves, distinguishing internal container ports from published host ports. Retest through the proxy hostname afterwards.[2]
- Give the proxy a resolvable upstream name
Replace the unresolvable forward name with a service name on a shared Docker network or a DNS-resolvable name or IP. Verify the name resolves from the NPM host before retesting.[5]
- Align the scheme and TLS negotiation with the upstream
Set the recorded scheme to the protocol the upstream serves and resolve the handshake failure the log names. Never disable TLS verification as a fix.[4]
- Investigate the actual NPM observation
A failing admin UI needs NPM service investigation. A renewal error needs the certificate renewal diagnosis. A tunnel-specific error needs tunnel diagnosis. Installation and DNS-only problems each need their own procedure.[1]
- Collect an NPM 502 evidence packet
Preserve the exact proxy response, the NPM version, the proxy forward hostname, port, and scheme, the reachability result from each vantage point tested, and the full proxy error log lines. Where an otherwise answering upstream stays unreachable from the NPM network context alone, keep the Docker network attachment and any routing or firewall boundary between NPM and the upstream inside the investigation scope. Send the sanitized evidence to the operator; no documented branch remains.[1][4]
Detailed diagnosis
1. Compare reachability from the NPM network context
Contact the recorded upstream target from a network context equivalent to NPM: the Docker host with NPM's network view, the NPM container or an equivalent network namespace, or the upstream listener itself. If the target fails from every relevant vantage point including the NPM network context, investigate the upstream first; if it answers elsewhere but fails from the NPM network context, continue onto forward-address and log reasoning for the NPM-to-upstream path. A browser-only or other-machine-only result never ends diagnosis by itself.[4]
2. Classify what the forward address means from inside the NPM container
Read the recorded forward hostname or IP and forward port, then interpret each from the NPM container's network namespace, not the host's. A localhost or 127.0.0.1 address means the NPM container itself; a container name resolves only on a shared Docker network; a LAN IP or fully qualified name resolves through normal DNS. The official advanced configuration demonstrates the shared-network service-name pattern and warns that unpublished container ports stay reachable only inside that network.[2][6][7]
3. Match the proxy error log signature
Match the error-level log line exactly: a connect refused line naming an address and port means nothing accepted the connection there; a host-not-found line naming an upstream means the name did not resolve when nginx started or connected; a TLS handshake failure means the scheme or TLS negotiation toward the upstream disagrees. Each signature selects a different documented branch.[4][5][3]
4. For a refused connection, separate a stopped listener from a wrong port
Confirm whether anything listens on the recorded target from a vantage point that shares the NPM container's network view. Nothing listening means the upstream is stopped or bound elsewhere; a listener on a different port means the recorded forward port is wrong. Do not infer from host-side listening alone when NPM runs containerized.[4][2]
Supported scenarios
These observations narrow the next investigation; they do not establish a unique cause.
The upstream application is stopped or not listening on the recorded target
The proxy error log shows a refused connection to the recorded address and port, and no listener answers there. Nginx forwards the request to the configured upstream; when nothing accepts it, the client sees 502. The upstream may be stopped, crashed, or bound to a different interface.[4][3]
How to check: Confirm the refused address and port in the log match the proxy host record, then confirm whether anything listens on that target from a vantage point sharing the NPM container's network view. A failure seen only from elsewhere does not establish this cause.[4]
The recorded forward port is not the application's port
The forward port names a port nothing serves, while the application listens on a different one — commonly a container's published host port recorded instead of its internal port, or vice versa. The official advanced configuration shows container ports as internal to their image and reachable by service name only inside a shared network.[4][2]
How to check: Compare the recorded forward port against the port the application actually serves, distinguishing published host ports from internal container ports.[2]
The forward address means something different inside the NPM container
A localhost or 127.0.0.1 forward address resolves to the NPM container itself, not the Docker host or another container. Reported cases show users pointing NPM at localhost expecting the host, then seeing 502 while the application answers elsewhere. Container names likewise resolve only within a shared Docker network.[2][6][7]
How to check: Read the recorded forward address and determine what it resolves to from inside the NPM container's network namespace before changing it.[2]
The forward hostname does not resolve for the proxy
The proxy log shows a host-not-found failure for the recorded upstream name. A container name works only on a shared Docker network, and any other name needs working DNS from the NPM host. In one reported case, nginx failed to start when a recorded container hostname vanished; confirm the actual log before assuming wider impact.[5][2]
How to check: Confirm the exact unresolved name in the log, then confirm whether that name should resolve via the shared Docker network or via DNS.[5]
The recorded scheme or TLS negotiation disagrees with the upstream
The proxy log shows a TLS handshake failure toward the upstream, for example a protocol-version alert when the upstream accepts only a newer TLS version than offered. The recorded http or https scheme must also match what the upstream serves; nginx passes the request to the configured upstream and the handshake must complete.[4][3]
How to check: Confirm the TLS failure signature in the log and compare the recorded scheme against the protocol the upstream actually serves.[4]
Next actions and procedure boundaries
Stopped upstream: restore the application listener on its documented target
Before changing anything
- Risk
- Starting or restarting the upstream application interrupts whatever that application serves. Confirm the correct application and host before acting.[4]
- Safer check
- Confirm the refused address and port in the proxy log match this upstream, and confirm the target fails from a network context equivalent to NPM — including the NPM container's view — before treating the upstream as the cause.[4]
- Expected result
- After the repair, the upstream answers directly on the recorded target and the proxy host returns the application instead of 502.[4]
- Backup / recovery access
- Record the current upstream state, the proxy forward address and port, and the log signature before acting. Preserve the application configuration so the previous state can be restored.[4]
- Rollback
- If the application misbehaves after the change, restore its previous configuration and startup state from the recorded values, then re-collect the proxy log before further changes.[4]
Start or repair the upstream application so it listens on the address and port the proxy host already records, then verify it answers directly before retesting through NPM. This branch changes the upstream, not the proxy record.[4]
Wrong port: correct the forward port to the serving port
Before changing anything
- Risk
- Editing the proxy host changes what the public hostname reaches. An incorrect edit can move the outage to the wrong backend instead of fixing it.[2]
- Safer check
- Prove the serving port from a vantage point that shares the NPM container's network view, and record the current forward hostname, port, and scheme before editing.[2]
- Expected result
- After the correction, the recorded forward port and the proven serving port agree, and the proxy hostname returns the application.[2]
- Backup / recovery access
- Record the full current proxy host record, including forward hostname, port, and scheme, before changing it.[2]
- Rollback
- Restore the recorded prior proxy host values if the hostname does not recover, then re-collect the proxy log before further changes.[2]
Edit the proxy host record so the forward port matches the port the application actually serves, distinguishing internal container ports from published host ports. Retest through the proxy hostname after the correction.[2][4]
Namespace mismatch: address the upstream the way the NPM container sees it
Before changing anything
- Risk
- Changing the forward address and Docker network membership changes what the proxy can reach. An incorrect address can break the proxy host entirely, including at NPM startup for unresolvable names.[2][5]
- Safer check
- Confirm what the current forward address resolves to from inside the NPM container, and record the current proxy host record and container network attachments before editing.[2]
- Expected result
- After the correction, the forward address resolves inside the NPM container's network to the serving upstream, and the proxy hostname returns the application.[2]
- Backup / recovery access
- Record the full current proxy host record and the container network configuration before changing either.[2]
- Rollback
- Restore the recorded prior proxy host values and network attachments if the hostname does not recover, then re-collect the proxy log before further changes.[2]
Replace a localhost forward address with an address reachable from inside the NPM container: the Docker host address where appropriate, or the container service name after joining NPM and the upstream to a shared Docker network, using the internal container port. The official advanced configuration demonstrates exactly this service-name pattern for upstream services on the same Docker host.[2][6]
Unresolvable name: give the proxy a name it can resolve
Before changing anything
- Risk
- An unresolved upstream hostname can cause nginx configuration loading or reload failures in some configurations. Confirm the actual NPM/nginx log before assuming broader impact.[5]
- Safer check
- Confirm the exact unresolved name in the proxy log and confirm whether it should resolve via the shared Docker network or via DNS before editing.[5]
- Expected result
- After the correction, the forward name resolves from the NPM host and the proxy hostname returns the application.[2]
- Backup / recovery access
- Record the full current proxy host record before changing it.[2]
- Rollback
- Restore the recorded prior proxy host values if the hostname does not recover, then re-collect the proxy log before further changes.[2]
Point the proxy host at a name that resolves from the NPM host: join NPM and a containerized upstream to a shared Docker network and use the service name, or use a DNS-resolvable fully qualified name or IP. The official advanced configuration documents the shared-network service-name pattern; in one reported case, nginx failed when a recorded container hostname vanished.[2][5]
TLS or scheme mismatch: align the recorded scheme with the upstream
Before changing anything
- Risk
- Scheme and TLS changes alter how the proxy authenticates and encrypts the upstream exchange. A wrong change can downgrade security or keep the outage while hiding its cause.[4]
- Safer check
- Confirm the exact TLS failure signature in the proxy log and the protocol the upstream actually serves before changing the scheme.[4]
- Expected result
- After the correction, the upstream handshake completes and the proxy hostname returns the application over the intended scheme.[4]
- Backup / recovery access
- Record the current scheme and any advanced TLS settings on the proxy host record before changing them.[4]
- Rollback
- Restore the recorded prior scheme and TLS settings if the hostname does not recover, then re-collect the proxy log before further changes.[4]
Set the proxy host scheme to the protocol the upstream actually serves, and resolve the handshake failure the log names: a protocol-version alert points at TLS version negotiation between NPM and the upstream, which needs upstream-side or advanced-configuration handling, not a blind scheme toggle. Never disable TLS verification as a fix.[4][3]
If no documented branch matches: preserve the evidence
Record the exact proxy response, the NPM version, the proxy forward hostname, port, and scheme, the reachability result from each vantage point tested (client, Docker host, NPM-equivalent network context, upstream listener), and the full proxy error log lines. Where an otherwise answering upstream stays unreachable from the NPM network context alone, keep the Docker network attachment and any routing or firewall boundary between NPM and the upstream inside the investigation scope. Send the sanitized evidence to the operator; the documented branches above cover the reported upstream patterns, not every possible backend failure.[1][4]
Warnings and boundaries
Sources
Links were reviewed on 2026-09-10. Reachability and automated validation do not replace editorial verification of each claim.
- Nginx Proxy Manager guide: forwarding and setup
Nginx Proxy Manager · Tier A · accessed 2026-09-10 - Nginx Proxy Manager advanced configuration
Nginx Proxy Manager · Tier A · accessed 2026-09-10 - Module ngx_http_proxy_module: proxy_pass and upstream handling
NGINX · Tier A · accessed 2026-09-10 - Issue 3961: 502 Bad Gateway with upstream TLS handshake and connection failures
Nginx Proxy Manager · Tier B · accessed 2026-09-10 - Issue 633: unresolvable forward hostname in proxy configuration
Nginx Proxy Manager · Tier B · accessed 2026-09-10 - Nginx Proxy Manager cannot reach Docker containers, localhost returns 502
Docker Community Forums · Tier C · accessed 2026-09-10 - Nginx Proxy Manager proxy host returns 502 for containerized destination
Stack Overflow · Tier C · accessed 2026-09-10