service healthy but unreachable externally
vinceduong
PROOP

11 days ago

My backend service container is running and healthy, but no external traffic reaches it.

What works:

  • Container starts, healthcheck passes (Railway returns 200)

  • Other services in the same project (frontend, landing) work fine

What doesn't work:

  • Any external request to the Railway-generated *.up.railway.app domain → timeout (no response, not even a 502)

  • Custom domain → same timeout

What I've tried:

  • Multiple redeploys (CLI + dashboard)

  • Deleted service and recreated from scratch → same issue on the new service

  • Changed region

  • No code changes same code was working for 18h before the issue started

$20 Bounty

5 Replies

xmrafonso
FREETop 5% Contributor

11 days ago

Hey, make sure the correct port is binded in railway as in your app. In this case, make sure your app is on port 8080 (or whatever you prefer) and in the dashboard, in the public network, make sure that the service also has that same port configured. Also make sure the app is listening to 0.0.0.0.


xmrafonso

Hey, make sure the correct port is binded in railway as in your app. In this case, make sure your app is on port 8080 (or whatever you prefer) and in the dashboard, in the public network, make sure that the service also has that same port configured. Also make sure the app is listening to 0.0.0.0.

vinceduong
PROOP

11 days ago

Thanks for the suggestion. I checked both:

Port: I set the port explicitly to 8080 on the Railway domain (railway domain -p 8080). The app listens on PORT=8080 which Railway auto-injects.

Binding: I updated my app to explicitly bind to 0.0.0.0 (it was defaulting to :: IPv6 via Bun.serve). I can confirm via SSH that the server now listens on IPv4:

/proc/net/tcp:

0: 00000000:1F90 00000000:0000 0A  → 0.0.0.0:8080 LISTEN ✓

I also see active TCP connections from Railway's internal network (100.0.64.x), so the healthcheck and internal probes reach the container. But external traffic via the *.up.railway.app domain still times out no request ever hits the app logs.


vinceduong

Thanks for the suggestion. I checked both:Port: I set the port explicitly to 8080 on the Railway domain (railway domain -p 8080). The app listens on PORT=8080 which Railway auto-injects.Binding: I updated my app to explicitly bind to 0.0.0.0 (it was defaulting to :: IPv6 via Bun.serve). I can confirm via SSH that the server now listens on IPv4:/proc/net/tcp:0: 00000000:1F90 00000000:0000 0A  → 0.0.0.0:8080 LISTEN ✓I also see active TCP connections from Railway's internal network (100.0.64.x), so the healthcheck and internal probes reach the container. But external traffic via the *.up.railway.app domain still times out no request ever hits the app logs.

Verify there is an actual generated Railway domain listed for this service. ..if its genrated do either nslookup or dig your service url..what are you getting when you do curl -v ..your URL


dharmateja

Verify there is an actual generated Railway domain listed for this service. ..if its genrated do either nslookup or dig your service url..what are you getting when you do curl -v ..your URL

vinceduong
PROOP

11 days ago

Yes, the Railway domain is generated and listed:

$ railway domain -s backend --json

{

  "domains": [

    "https://backend-production-cef0.up.railway.app",

    "https://api.pullz.dev"

  ]

}

DNS resolves fine:

$ dig backend-production-cef0.up.railway.app +short

151.101.2.15

curl -v output — TLS handshake succeeds through Fastly, HTTP/2 request is sent, then it hangs until timeout with zero bytes received:

$ curl -sv --max-time 10 https://backend-production-cef0.up.railway.app/health

* Connected to backend-production-cef0.up.railway.app (151.101.2.15) port 443

* SSL connection using TLSv1.3

 Server certificate: CN=.up.railway.app (Certainly Intermediate R1)

* using HTTP/2

> GET /health HTTP/2

> Host: backend-production-cef0.up.railway.app

> User-Agent: curl/8.7.1

> Accept: /

>

* Operation timed out after 10002 milliseconds with 0 bytes received

No response at all not a 502, not a 404, just silence. The request reaches Fastly but never gets forwarded to the container.

just confirmed again via SSH — the server responds correctly from inside the container:

$ railway ssh -s backend

$ bun -e 'const r = await fetch("http://127.0.0.1:8080/health"); console.log(r.status, await r.text())'

200 {"status":"ok"}

Response includes proper headers (content-type, content-length, CORS). Also works on 0.0.0.0:8080. The app is healthy — it's the path between the Fastly edge and the container that's broken.


vinceduong
PROOP

10 days ago

Resolved! Root cause was the Bun version used by Railpack during the build.

My package.json had "packageManager": "bun@1.0.23". Railpack uses this to install Bun in the container. Containers built with Bun 1.0.23 have a networking issue where the Metal Edge proxy cannot route public traffic to them (internal healthchecks work fine since they use a different path).

How I diagnosed it:

  1. Created a new service test-backend and deployed via railway up (direct upload, no GitHub integration) — it worked publicly

  1. Linked the same service to GitHub repo (config-as-code) public traffic broke again

  1. Compared the two builds: railway up used Bun 1.3.9 (latest), GitHub deploy used Bun 1.0.23 (from packageManager field)

  1. Deployed again via railway up with "packageManager": "bun@1.3.9" in the deploy package worked

  1. Deployed via railway up without it (Railpack cached Bun 1.0.23) broke again

Fix: Bumped "packageManager": "bun@1.3.9" in package.json, regenerated lockfile, pushed. GitHub deploy now works with public routing.

TL;DR: If you're using Bun with Railpack and getting this symptom (healthy container, public timeout, zero bytes from edge), check your Bun version. Bun 1.0.23 produces containers that the Metal Edge proxy can't route to. Upgrading to 1.3.9 fixed it.


Loading...