Get started
BETA
Browse docs
Troubleshooting

Local target unreachable

What 'target unreachable' means, why it almost always points at your local server, and how to diagnose it in under a minute.

If a request to your tunnel URL returns target unreachable (or you see <host>:<port> is not reachable in the CLI logs), the failure is between the CLI and your local server — not between the caller and the tunnel.

The flow is:

  1. Caller hits https://your-name.justtunnel.com/path.
  2. Edge forwards the request to your CLI over the WebSocket.
  3. CLI tries to proxy it to the local target you specified (e.g. http://localhost:8080/path).
  4. Step 3 fails. The CLI sends an error frame back to the edge, which returns 502 to the caller.

Almost every cause is in step 3. Here's how to diagnose.

Quickest sanity check

Hit the local target directly, on the same machine the CLI is running on:

curl -v http://localhost:8080/

If curl fails the same way, the CLI is fine and your local server is the problem. Fix the local server first.

If curl works but the tunnel says target unreachable, read on.

Cause 1: Wrong port

You started the tunnel pointing at the wrong port. The CLI accepts the port as the first positional argument:

justtunnel 8080

If your local server listens on 3000, you need justtunnel 3000. Check the local server's startup output — frameworks usually print the port they bound to.

Cause 2: Server bound to a different interface

This is the second most common cause. Your server is listening, but only on a specific interface that excludes the loopback the CLI dials. Examples:

  • A Docker container that exposes port 8080 to the host but the host process binds 127.0.0.1 — the CLI on the host can hit it, but if the CLI is also in a container it can't.
  • A development server that binds 0.0.0.0 and another that binds 127.0.0.1 — the CLI defaults to localhost.
  • IPv6-only binds (::1 but not 127.0.0.1).

How to fix. Either rebind the local server to the loopback the CLI uses, or pass an explicit target:

justtunnel http://192.168.1.10:8080

The CLI takes either a port (uses http://localhost:<port>) or a full URL.

Cause 3: Local server crashed or not started yet

The CLI doesn't health-check the target on startup — it only proxies on demand. So you can start the tunnel before starting your local server (or after it crashed) and only learn about it when a request hits.

How to fix. Check that the local server is running. Make starting it part of the same shell setup if you forget:

# in one terminal
npm run dev
 
# in another
justtunnel 3000

Cause 4: Local server is too slow (504, not 502)

If you see HTTP 504 / tunnel client timeout instead of 502 / target unreachable, the local server is reachable but isn't responding fast enough. The default per-request timeout is 30 seconds. Raise it with --local-timeout:

justtunnel 8080 --local-timeout 120s

Or fix the slow handler — if it hangs forever, raising the timeout just delays the same failure.

See Local timeout for the full guide.

Cause 5: TLS mismatch

If your local server speaks HTTPS and you pointed the CLI at http://... (or vice versa), the proxy connection fails. Match the scheme:

# local server is HTTPS on 8443, with a self-signed cert
justtunnel https://localhost:8443

Most local development runs HTTP on the loopback; you only hit this if you've gone out of your way to run TLS locally.

Cause 6: Firewall blocking loopback

Rare but real. Some host-based firewalls block connections to localhost from non-default ports. If curl http://localhost:8080 works from a shell but curl http://127.0.0.1:8080 doesn't (or the reverse), you have a name-resolution or firewall quirk specific to your machine.

How to fix. Use whichever address actually works as the explicit target:

justtunnel http://127.0.0.1:8080

A 30-second diagnosis script

# 1. Is something on the port?
lsof -iTCP -sTCP:LISTEN -P | grep :8080
 
# 2. Can we reach it?
curl -v http://localhost:8080/
 
# 3. What did the CLI try?
justtunnel 8080 -v

If step 1 shows nothing, your local server isn't running. If step 2 fails, fix the bind. If both pass and step 3 still fails, open an issue with the verbose output.

Still stuck?

Open an issue with the output of all three commands above and the exact justtunnel ... invocation you ran.

On this page