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.

Read-only

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]

Safe / low risk

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-only

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]

Read-only

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
  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]

    • Yes, proxy 502 with working NPMWhat upstream target does the proxy host record?
    • No, a different observationInvestigate the actual NPM observation
  2. 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.1Replace the localhost forward address
    • A container or service nameMake the container name resolvable for the proxy
    • A LAN IP or fully qualified nameCan the recorded target be reached from a network context equivalent to NPM?
    • Address type is unclearCollect an NPM 502 evidence packet
  3. 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 contextRecover the upstream application first
    • Answers elsewhere but fails from NPM-equivalent contextWhich signature appears in the proxy host error log?
    • Answers from NPM-equivalent context tooWhich signature appears in the proxy host error log?
    • Cannot test from NPM-equivalent contextCollect an NPM 502 evidence packet
  4. 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 refusedDoes anything listen on the recorded target from the NPM network view?
    • host not found in upstreamGive the proxy a resolvable upstream name
    • TLS handshake failureAlign the scheme and TLS negotiation with the upstream
    • No matching signatureCollect an NPM 502 evidence packet
  5. 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 thereRestore the stopped upstream listener
    • It listens on a different portCorrect the forward port to the serving port
    • Cannot confirm the listenerCollect an NPM 502 evidence packet
  6. 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]

  7. 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]

  8. 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]

  9. 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]

  10. 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]

  11. 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]

  12. 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]

  13. 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]

  14. 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

Read-only

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]

Read-only

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]

Read-only

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]

Read-only

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

Potentially disruptive

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]

Potentially disruptive

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]

Potentially disruptive

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]

Potentially disruptive

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]

Potentially disruptive

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]

Read-only

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

Do not disable TLS verification, expose the admin UI, delete certificates or NPM data, or reset the NPM database to fix a proxy 502. None of these addresses the upstream exchange, and several destroy configuration.[1][2]
A localhost forward address inside containerized NPM means the NPM container itself. Do not treat host-side listening evidence as proof that the recorded target is correct without checking the NPM container's network view.[2][7]

Sources

Links were reviewed on 2026-09-10. Reachability and automated validation do not replace editorial verification of each claim.

  1. Nginx Proxy Manager guide: forwarding and setup
    Nginx Proxy Manager · Tier A · accessed 2026-09-10
  2. Nginx Proxy Manager advanced configuration
    Nginx Proxy Manager · Tier A · accessed 2026-09-10
  3. Module ngx_http_proxy_module: proxy_pass and upstream handling
    NGINX · Tier A · accessed 2026-09-10
  4. Issue 3961: 502 Bad Gateway with upstream TLS handshake and connection failures
    Nginx Proxy Manager · Tier B · accessed 2026-09-10
  5. Issue 633: unresolvable forward hostname in proxy configuration
    Nginx Proxy Manager · Tier B · accessed 2026-09-10
  6. Nginx Proxy Manager cannot reach Docker containers, localhost returns 502
    Docker Community Forums · Tier C · accessed 2026-09-10
  7. Nginx Proxy Manager proxy host returns 502 for containerized destination
    Stack Overflow · Tier C · accessed 2026-09-10

Still troubleshooting?