Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

If NGINX returns 502 Bad Gateway only for HTTPS requests while the same URL works over HTTP, the problem is usually in the HTTPS server block or in NGINX’s separate TLS connection to the upstream. Check the active port-443 configuration, confirm the upstream scheme and port, test the upstream directly from the NGINX host, and read the error log while reproducing one request. A public certificate that works between the browser and NGINX does not prove that NGINX can authenticate or negotiate TLS with the backend.

What a 502 means in this situation

HTTP status 502 Bad Gateway means that a server acting as a gateway or proxy received an invalid response from its upstream server. NGINX did not receive a valid HTTP response that it could return to the client. If the upstream simply fails to respond before the gateway timeout condition is reached, the result is generally closer to 504 Gateway Timeout.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When HTTP succeeds and HTTPS fails, there are two separate connections to consider:

  • Client to NGINX: the browser establishes TLS with the certificate configured on the HTTPS listener.
  • NGINX to upstream: NGINX makes a second connection using the scheme and port in proxy_pass. That connection may be clear-text HTTP or HTTPS.

Those hops can use different protocols, certificates, hostnames, headers, and timeout settings. A valid public certificate on NGINX validates only the first hop. The second hop can still fail because of a wrong scheme, an incorrect port, an untrusted private CA, a hostname or SNI mismatch, a refused connection, or an upstream that closes before sending valid HTTP headers.

A valid application response such as a normal 404 or 500 is not the same as a gateway 502. If the origin sends a complete HTTP error response, NGINX can normally pass it through. A 502 indicates that NGINX could not obtain a valid upstream response.

Start by proving which hop fails

Do not change several directives at once. First test the backend from the machine running NGINX, then compare that result with a request through the public HTTPS endpoint.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Test the upstream directly. For a TLS backend, run curl -vk https://backend.example.com/health from the NGINX host. For a clear-text listener, use the matching http:// URL and port, such as curl -v http://127.0.0.1:8080/health. Record whether DNS, TCP connection, TLS negotiation, and HTTP response all succeed.
  2. Inspect the TLS handshake when necessary. Run openssl s_client -connect backend.example.com:443 -servername backend.example.com. The -servername value tests the SNI name that many virtual-hosted services require.
  3. Test the public endpoint. Run curl -vk https://public.example.com/health. If the direct backend request succeeds but the public request returns 502, focus on the loaded NGINX configuration, headers, path rewriting, or NGINX’s upstream TLS settings.
  4. Reproduce once while watching the error log. The exact error-log line usually identifies the failing layer more reliably than the browser’s generic error page.

A direct request must use the same backend hostname, port, path, and protocol that the HTTPS location is configured to use. Testing a different service can create a false sense that the proxy is healthy.

Inspect the configuration NGINX actually loaded

Editing a file is not the same as changing the active configuration. Includes, duplicate server names, and distribution-specific file layouts can cause NGINX to select a different block than the one you inspected.

  1. Run nginx -t. This checks syntax and reports whether the configuration test succeeds.
  2. Run nginx -T and save or inspect the complete expanded configuration, including included files. Find every listen 443 ssl block and the matching server_name.
  3. Confirm the HTTPS block’s certificate files, selected location, upstream name, upstream port, and proxy_pass URL.
  4. Compare all relevant proxy_set_header, proxy_ssl_*, client-certificate, rewrite, and timeout directives with the working HTTP block.
  5. After a valid change, reload NGINX using your operating system’s normal service command, then repeat one controlled request and read the new log entry.

NGINX selects a server block using the listening address and port, TLS state, and requested name. It is therefore possible for port 80 and port 443 to reach different blocks even when their server_name values look identical. A more-specific location on 443 can also select a different upstream from the one used on HTTP.

Match the upstream protocol and port

The scheme in proxy_pass controls the protocol NGINX uses on the second hop. Use http:// for a clear-text HTTP listener and https:// only when the selected endpoint actually speaks TLS.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Backend reality Correct proxy form Typical result when mismatched
Clear-text HTTP on port 8080 proxy_pass http://backend:8080; Using https:// can produce a TLS error such as “wrong version number” and a 502.
TLS-enabled HTTP service on port 443 proxy_pass https://backend:443; Using http:// sends plain HTTP to a TLS listener and fails before a valid HTTP response exists.
TLS service on a nonstandard port proxy_pass https://backend:8443; Using the wrong port may connect to another service, receive an unexpected protocol, or be refused.

Confirm the listener from the backend service configuration or with direct curl tests. Do not infer the protocol from the fact that the public site uses HTTPS; TLS termination at NGINX commonly leaves the internal hop as HTTP.

Pattern: HTTPS at NGINX, clear-text HTTP to the application

server {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate     /etc/ssl/app/fullchain.pem;
    ssl_certificate_key /etc/ssl/app/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

This is valid when the application listens for ordinary HTTP on port 8080. The browser-to-NGINX hop is encrypted; the local NGINX-to-application hop is not. Whether that is acceptable depends on the network boundary and the application’s security requirements.

Validate upstream certificate trust, hostname, and SNI

When the upstream uses HTTPS, NGINX must complete a TLS handshake before it can send or receive HTTP. A private or self-signed certificate requires a trusted CA configured for NGINX. A certificate issued to api.example.com may also fail validation if NGINX connects to an IP address or a different name.

  • Trust chain: configure the CA certificate that issued the upstream certificate with proxy_ssl_trusted_certificate when the service uses a private CA. Ensure the file contains the required issuer chain and is readable by the NGINX worker.
  • Identity: use the service hostname that appears in the certificate, rather than substituting an IP address merely because it resolves to the same machine.
  • SNI: enable proxy_ssl_server_name on; when the upstream selects its certificate or virtual host by TLS server name. Set proxy_ssl_name to the expected TLS name when it differs from the address in proxy_pass.
  • HTTP host header: preserve the application’s expected virtual-host name with an explicit proxy_set_header Host .... TLS SNI and the HTTP Host header are related but separate values.
  • Verification policy: do not disable certificate verification as the first fix. Correct the CA, hostname, chain, or SNI configuration instead; disabling verification hides an identity failure and weakens the upstream connection.

Pattern: HTTPS upstream with a private CA and SNI

location / {
    proxy_pass https://api.example.com;
    proxy_ssl_server_name on;
    proxy_ssl_name api.example.com;
    proxy_ssl_trusted_certificate /etc/nginx/ca/upstream-ca.pem;
    proxy_ssl_verify on;
    proxy_set_header Host api.example.com;
}

Use the upstream’s actual TLS name, trust chain, and verification policy. If the backend requires a client certificate, also verify the client-certificate directives and key permissions in the active HTTPS block; a server certificate alone does not satisfy mutual-TLS authentication.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the error log to classify the failure

Capture the exact line generated by one failed request. These signatures point to different remedies:

Error-log signature What it usually means Next check
SSL_do_handshake() failed TLS negotiation, certificate, protocol, or SNI failure on the upstream hop. Test with openssl s_client; verify hostname, SNI, trust, and TLS compatibility.
certificate verify failed NGINX cannot validate the upstream certificate chain or issuer. Check proxy_ssl_trusted_certificate, chain completeness, hostname, and file permissions.
wrong version number NGINX is probably attempting HTTPS against a clear-text HTTP service, or using the wrong port. Confirm the backend listener and change the proxy_pass scheme or port.
connect() failed (111: Connection refused) No process is listening at the selected address and port, or a firewall is rejecting the connection. Check the service bind address, port, container or load-balancer mapping, and firewall rules from the NGINX host.
upstream prematurely closed connection The upstream closed the connection before returning valid response headers. Inspect application logs, crashes, worker limits, protocol expectations, and request-specific failures.
upstream timed out The response exceeded the relevant timeout or packets were delayed or blocked. Investigate backend latency, network filtering, and timeout values. A genuine no-response condition is closer to 504 semantics than a malformed response.

The browser may display the same 502 page for all of these cases, but changing TLS settings will not repair a refused TCP connection, and increasing a timeout will not repair a certificate-name mismatch.

Compare the working HTTP and failing HTTPS blocks

Make a deliberate diff instead of assuming that the two listeners are equivalent. Check each of the following:

  • Listener and name: listen 80 versus listen 443 ssl, and the exact server_name selected for the request.
  • Location selection: URI prefixes, regular-expression locations, and trailing-slash behavior can route HTTPS requests elsewhere.
  • Upstream address: hostname, IP family, port, and any upstream group name.
  • Proxy scheme: http:// versus https://.
  • Headers: Host, Connection, X-Forwarded-Proto, client IP headers, and any application-specific authentication headers. NGINX changes some proxy headers by default, so set the values your application requires explicitly.
  • TLS-to-upstream directives: trusted CA, verification, SNI name, client certificate, and protocol settings.
  • Path handling: a slash or URI component in proxy_pass changes how NGINX replaces the matching location prefix. A path that works on port 80 can reach a different backend endpoint on port 443.
  • Timeouts and buffering: HTTPS may use a different include file or location-level timeout, causing a slow backend to fail only on that listener.

Check reachability, firewall rules, and service behavior

If the log shows connection refusal or a timeout, verify the network path from the NGINX machine, not from your workstation. A backend bound only to 127.0.0.1 is reachable from a local NGINX process but not from a separate host. Conversely, a container or virtual machine address may change while the configuration still points to an old address.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Confirm that the backend process is listening on the configured address and port.
  • Check host firewalls, security groups, network policies, and container port mappings between NGINX and the backend.
  • Verify DNS resolution from the NGINX host, including whether it returns an IPv6 address that the service does not accept.
  • Inspect backend logs at the same timestamp. An application crash, worker exhaustion, or protocol rejection can cause an early close even though the TCP connection succeeds.

Do not increase timeouts merely to suppress an error. First establish whether the upstream is slow, unreachable, or closing the connection. Timeout changes should reflect measured application behavior and should be made in the block that actually handles the request.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

A safe fix-and-verify workflow

  1. Preserve the failing log line and request details. Note the URL, method, timestamp, selected host, and exact NGINX error.
  2. Run the direct backend test. Use the configured scheme, hostname, port, and path from the NGINX host.
  3. Print the effective configuration. Use nginx -t and nginx -T; identify the exact 443 block and location.
  4. Correct one class of problem. Start with scheme and port, then trust and SNI, then headers and path handling, and finally reachability or timeout issues as indicated by the log.
  5. Test syntax before reload. A failed syntax test leaves the running configuration unchanged; do not reload an invalid file.
  6. Reload and reproduce once. Use a single curl -vk request so the resulting log entry is unambiguous.
  7. Verify the response path. Confirm that the client receives the expected status and that the backend logs show the request with the intended host, path, and forwarded-protocol values.

If a change makes the result worse, restore the last known-good configuration, run nginx -t, reload, and continue from the captured evidence rather than stacking additional speculative directives.

Common fixes that do not solve the underlying problem

Replacing the public certificate

If HTTP works and the browser completes the TLS handshake with NGINX, replacing the public certificate will not fix an upstream handshake or port mismatch. Investigate the second TLS hop instead.

Changing every backend URL to HTTPS

HTTPS at the edge does not require HTTPS internally. Use encryption on the internal hop when the network and threat model require it, but configure the protocol the backend actually serves.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Disabling upstream certificate verification

This may hide a missing CA or hostname error while leaving the connection vulnerable to an untrusted endpoint. Install the correct CA and preserve identity validation whenever possible.

Increasing all proxy timeouts

A timeout does not repair a refused connection, a TLS failure, or an upstream that sends no valid headers. Change only the relevant timeout after confirming that the application’s response time is the real cause.

Testing only from a laptop

Your laptop validates the client-to-NGINX path. The decisive test for an upstream problem must run from the NGINX host or its network namespace, where DNS, routes, firewall rules, and certificates may differ.

Quick decision checklist

  • Does the direct request from NGINX to the backend succeed with the same scheme, host, port, and path?
  • Does nginx -T show the HTTPS server block you expected?
  • Does proxy_pass match the backend’s real protocol and listener?
  • If the backend is HTTPS, is its CA trusted and its certificate name aligned with SNI and the connection name?
  • Is the HTTP Host header the one required by the backend virtual host?
  • Does the error log identify a handshake, verification, protocol, refusal, premature close, or timeout failure?
  • Are path rewriting, forwarded-protocol headers, client certificates, and timeouts different between ports 80 and 443?

Once these checks agree, HTTPS and HTTP should follow the same intended application route, with the only deliberate difference being whether NGINX encrypts the client-facing connection and, if configured, the upstream connection.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.