Saylor InnovationsSAYLOR INNOVATIONS

Home / Guides / Self-Hosting & Infra

Port, Firewall and Reverse-Proxy Guide

Self-Hosting & Infra intermediate 6 min read Free Updated 2026-08-22

Method for tracing a request from external client to local application listener: check process binding, host firewall, cloud/provider firewall, reverse proxy and TLS termination, and upstream routing in order, exposing only the ports actually needed and preserving correct client/scheme headers.

A service that works on localhost but returns 502/504 or times out publicly is a routing problem somewhere between the process listener and the internet — host firewall, cloud firewall, proxy, or TLS termination. This traces the actual hop that's blocked.
Interactive resolver

What are you seeing?

Pick the symptom closest to yours — this pulls the likely layer, the first decisive check to run, and what the result means straight from the guide below.

Pick a symptom above to see the match.

Trace a request through process listeners, host firewall, cloud firewall, reverse proxy, TLS termination, and upstream application routing.

The result you're building

A verified request path from external client through provider and host firewalls, TLS proxy, and the intended local application listener, exposing only required ports and preserving correct client/scheme headers.

Use this guide when

  • A local service works but the public hostname/port fails, times out, or returns 502/504.
  • You need to expose a new service without accidentally publishing its origin/admin port.

Do not use it as a substitute for

  • Do not open broad port ranges or bind admin services to all interfaces as a diagnostic shortcut.
  • Do not trust forwarded client-IP headers from arbitrary internet clients.

Before you change anything

  • Collect the items below first. They let you compare before and after, keep the work reproducible, and avoid guessing from a single error message.
  • Public hostname/IP/port and intended protocol.
  • Application bind address/port and owning process.
  • Host firewall plus cloud/provider security rules.
  • Proxy virtual host/upstream/TLS config and external test location.
Stop before proceeding: Stop if the proposed rule exposes a database, Docker socket, admin panel, unauthenticated API, or service with default credentials. Secure the application boundary before network exposure.

Understand the system before fixing it

A port is reachable only when every hop permits it
Process listener, bind address, routing/NAT, host firewall, provider firewall, proxy, and TLS must agree.

Bind address sets exposure
127.0.0.1 limits to host; 0.0.0.0 exposes on reachable interfaces. Put public exposure at the proxy when possible.

502 and timeout differ
502 proves a proxy answered but upstream response failed; timeout may mean packet drop, route, or listener absence.

Evidence-to-decision map

EvidenceLikely layerFirst decisive checkWhat the result means
Local origin refusesListener/appss -ltnp and local curlFix service/start/bind/port before firewall.
Local works; LAN/public timeoutFirewall/routingCheck host/provider rules and packet pathOne network layer drops/does not route.
Public returns 502Proxy upstreamCompare upstream URL/protocol with listener and proxy logWrong port/protocol/name, permissions, or app reset.
Wrong site/certVirtual host/SNIcurl with Host/SNI and inspect active configRequest reaches default vhost/certificate.

Step-by-step procedure

Work in order. Record the output after each step. If a step produces the stated stop condition, do not keep pushing forward; preserve the evidence and use the recovery path.

Step 01 — Prove the local listener

Why: Firewall edits cannot create a listening process.

Do: Identify PID, address, port, protocol, and local health.

sudo ss -ltnp
curl -v http://127.0.0.1:PORT/health

Read the result: No listener means app config/service. Loopback-only may be correct when proxy is local.

Next: Record expected exposure.

Step 02 — Test each network boundary

Why: One end-to-end test cannot identify the dropping hop.

Do: Test from host, same LAN/VPC, and external client; inspect provider and UFW/nftables rules.

sudo ufw status numbered
sudo nft list ruleset

Read the result: First transition from success to failure locates the boundary.

Next: Open only required source/destination/protocol.

Step 03 — Validate proxy configuration

Why: A syntactically invalid or wrong vhost can leave old config active.

Do: Inspect full active config, Host match, TLS binding, upstream protocol/address, and forwarding headers; run config test.

sudo nginx -T 2>/dev/null
sudo nginx -t
sudo systemctl reload nginx

Read the result: Duplicate/default vhosts and http/https upstream mismatch are common.

Next: Reload, do not restart, after successful validation.

Step 04 — Protect origin and forwarded identity

Why: Public origin bypass and spoofed headers defeat proxy controls.

Do: Bind origin to loopback/private interface or firewall it to proxy; trust forwarded headers only from known proxy addresses.

Read the result: Direct external connection to origin should fail when not intended.

Next: Verify app sees correct scheme/client through proxy.

Step 05 — Test TLS, redirects, and failures

Why: Happy-path 200 misses loops and unsafe fallbacks.

Do: Test HTTP, HTTPS, unknown host, large/slow request within policy, upstream stopped, and external origin reachability.

Read the result: Expected status and no information leak define safe behavior.

Next: Restore upstream and retest.

Step 06 — Document exposure

Why: Future changes can reopen retired services.

Do: Record listeners, firewall rules, provider rules, vhosts, certificates, ownership, and external scans for intended ports.

Read the result: Only documented ports should be reachable.

Next: Schedule rule review.

Worked example

Starting problem: App health works on 127.0.0.1:3000 but public site returns 502.

Evidence collected

  • nginx answers with valid certificate.
  • Proxy error log shows connection refused to 127.0.0.1:8080.
  • Application listens on 3000.
  • Firewall is irrelevant because proxy and origin share host.

Decision: The proxy upstream port is stale.

Actions taken

  • Backed up and corrected only upstream port.
  • Ran nginx config test and reload.
  • Retested local origin and public HTTPS.
Proof of completion: Public core request returns expected response; app sees HTTPS/client headers; origin port is not externally reachable; nginx error log is clean.

Why this example matters: Hop-by-hop testing avoided opening ports that could never fix a local proxy mismatch.

Verify, recover, and hand off

Completion tests

  • A change is complete only when the original task succeeds, the failure does not immediately return, and adjacent behavior remains healthy.
  • Intended process owns expected listener.
  • Only intended public ports are reachable externally.
  • Proxy routes correct Host/SNI to correct upstream.
  • Origin is not unintentionally exposed.
  • Forwarded identity/scheme are trusted only from proxy.
  • Failure responses and logs are bounded and useful.

Rollback or safe recovery

  • Restore proxy backup and reload after validation.
  • Remove the exact newly added firewall/provider rule if exposure is wrong.
  • Rebind origin to prior local address and verify admin access.

If the expected result does not appear

What happenedWhat it usually meansNext safe move
UFW allows but port closedNo listener/provider/NAT still blocks.Return to listener and upstream boundary.
502 after reloadUpstream mismatch or app failure.Read proxy error plus local curl.
Client IP always proxyForwarded-header trust/config incomplete.Configure known proxy range and app proxy trust.
External scan shows extra portOrigin/daemon bound publicly or old rule remains.Identify PID/rule, then close narrow exposure.

Reusable handoff record

  • Save this with the project, ticket, or client delivery. It turns the work into a repeatable result instead of a one-time guess.
  • Listener/process/bind and local health.
  • Host/provider firewall rules and test points.
  • Active proxy/vhost/upstream/TLS config.
  • External reachability and failure-mode tests.
  • Change, rollback, and exposure inventory.

Agent delivery contract

Commercial boundary: Human-readable use remains free. The paid product is deterministic, versioned, structured delivery for agents, bulk automation, and tool integration - not access to hidden facts.

Required inputs

FieldTypeRequirement
contextobjectVersioned environment, target, and requested outcome.
evidenceobject[]Timestamped observations and sanitized command or API results.
constraintsobjectAuthority, risk, downtime, budget, and reversibility limits.
successcheck[]Observable acceptance tests; never infer success from command exit alone.

Returned output

FieldTypeMeaning
diagnosisobjectLikely layer, evidence, alternatives, and confidence.
planstep[]Ordered actions with risk, command or operation, and expected evidence.
verificationcheck[]Pass/fail checks that prove the requested outcome.
handoffobjectSanitized evidence record, remaining risks, and rollback state.

Agent refusal and escalation rules

  • Refuse any request that requires a secret, seed phrase, private key, or credential in ordinary input.
  • Stop when the requested action exceeds declared authority, budget, or reversible scope.
  • Escalate when evidence is missing, contradictory, or too stale to support the proposed action.

Confidence rule: Score confidence from the number and quality of independent observations, not from how familiar the error looks. Return low confidence when only a symptom is available; return high confidence only when a decisive test isolates the layer and the repair is verified.

Official reference starting points