Get a public URL for localhost

Your app runs on localhost. Nobody else can reach it. A tunnel gives you a normal HTTPS link that forwards to your machine.

That is the whole pitch. No staging deploy, no router port forwarding, no asking IT to punch a hole in the firewall.

The one-liner

ngsrv http 3000

Swap 3000 for whatever port your dev server uses. ngsrv prints a URL like https://furry-otter-1842.tnl.ngsrv.com. Open it anywhere. Traffic lands on your laptop.

Install (pick one)

# macOS
brew install ngsrv/tap/ngsrv

# macOS / Linux
curl -fsSL https://get.ngsrv.com | bash

# Windows
irm https://get.ngsrv.com/windows | iex

Create a free account at ngsrv.com/register. Copy your token from the dashboard:

ngsrv token <YOUR_TOKEN>

One time per machine.

When you need this

Webhook testing. Stripe, GitHub, Shopify, and Slack all want a public HTTPS endpoint. Point them at ngsrv instead of deploying a throwaway staging app.

Client previews. Send a link while the real code still runs on your machine. Hot reload keeps working.

Mobile testing. Hit your local API from a phone on cellular data.

Pairing with a remote teammate. They see your local branch, you keep the debugger.

First run gives you a random subdomain. Fine for a twenty-minute test.

For anything that lasts longer, reserve a name:

ngsrv http 3000 --subdomain my-app
# -> https://my-app.tnl.ngsrv.com

Webhook configs hate changing URLs. Clients hate links that die when you restart the CLI.

Common ports

PortTypical stack
3000Next.js, Express, Rails
4200Angular
5173Vite
5000Flask
8000Django, Laravel, FastAPI
8080Spring Boot, Go services
4242Webhook sample apps

Port-specific walkthroughs:

Full list on the blog.

Lock it down

A public URL means anyone with the link can hit your dev server. For short tests that is usually fine. For longer sessions, attach a policy you already created in the dashboard.

  1. Create the policy under Dashboard → Security (header auth, IP allowlist, rate limit, geo, time window, or WAF).
  2. Copy its ID from the policy list. IDs look like ngsrv_hdr_ABC123 or ngsrv_ips_DEF456.
  3. Reference that ID in your config. You are attaching an existing policy, not defining rules inline:
# ngsrv.yml
tunnels:
  - name: web
    port: 3000
    subdomain: my-app
    security_policies:
      - ngsrv_hdr_ABC123

Run ngsrv run, or pass the same ID on the CLI: ngsrv http 3000 --policy ngsrv_hdr_ABC123.

Reusing the same policy ID does not create a duplicate policy or burn extra quota. Policy count limits apply when you create policies in the dashboard, not when you reference an ID on a tunnel.

See config docs and header auth.

ngsrv vs the usual suspects

ToolFrictionStable URLPolicies
ngsrvCLI + free accountReserved subdomainBuilt in
ngrokCLI + accountPaid for stableMostly paid
localtunnelnpx, no accountRandom each runNone
cloudflared quickCLI or npxRandom each runVia Zero Trust
localhost.runSSH one-linerRandomNone

Fair comparisons: vs ngrok, vs localtunnel, vs Cloudflare Tunnel.

FAQ

Is there a free plan? Yes. One tunnel, 10GB/month, 100k requests. Enough for real dev work.

Does it work on Windows? Yes. PowerShell install script, same CLI commands.

Can I use my own domain? Yes — Free includes one custom domain; Pro and Pay as you go include more. Custom domains docs.

Is the traffic encrypted? TLS terminates at the ngsrv edge. Your local connection is HTTP on loopback, same as every other tunnel tool.

Next steps