· NGSRV Team

How to expose localhost:4200 for client previews

ngsrv creates a public preview link for your local service. Port 4200 is the Angular CLI default — every ng serve lands there — which makes it the port most agencies and freelancers want to share with clients during a sprint.

ngsrv helps developers expose local services, share preview links, test webhooks, and get feedback faster. This post is the short version for Angular teams.

TL;DR

# Already running ng serve? Open a second terminal:
ngsrv http 4200 --subdomain client-preview
# -> https://client-preview.tnl.ngsrv.com

Send that URL to your client. They open a normal HTTPS link in their browser, see your local Angular app, and leave comments while you keep coding.

Why port 4200

Angular CLI (ng serve) listens on 4200 by default. So does Storybook in some Angular setups. The same workflow works for any other port — ng serve --port 5000 becomes ngsrv http 5000 — but 4200 is what most teams hit first.

Step 1 — Have ng serve running

ng serve
# ✔ Compiled successfully.
# ** Angular Live Development Server is listening on localhost:4200 **

Leave it running.

Step 2 — Install and authenticate ngsrv

# macOS
brew install ngsrv/tap/ngsrv

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

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

Then, with the token from your dashboard:

ngsrv token <YOUR_TOKEN>

Step 3 — Tunnel with a reserved subdomain

ngsrv http 4200 --subdomain client-preview

You get back:

forwarding  https://client-preview.tnl.ngsrv.com -> http://localhost:4200

Reserved subdomains stay the same between restarts on Pro and above, so the link you sent on Monday still works on Friday.

Step 4 — Tell Angular about the new hostname

Angular CLI rejects requests with a different Host: header by default. You'll see:

Invalid Host header

Fix: pass the disable flag:

ng serve --disable-host-check

Or in angular.json, under the serve options for your project:

{
  "serve": {
    "options": {
      "disableHostCheck": true
    }
  }
}

Don't ship that to production — it's a dev-only setting and ngsrv adds its own auth at the edge.

If you're using Angular dev-server with WebSocket HMR (which is the default), enable it through ngsrv by not blocking WS in any of your security policies. ngsrv proxies WebSockets natively.

Step 5 — Lock the preview down

Two cheap protections for client previews:

Header auth. Create the policy in Dashboard → Security, then attach its ID:

tunnels:
  - name: preview
    port: 4200
    subdomain: client-preview
    security_policies:
      - ngsrv_hdr_ABC123

IP allowlist. Create the policy under IP security, then reference its ID:

security_policies:
  - ngsrv_ips_client_office

You create each policy once in the dashboard. Reusing the same ID on multiple tunnels does not create duplicates.

What your client experiences

A regular HTTPS site. The ngsrv edge handles TLS so the padlock is real. On Pro and Pay as you go there is no warning interstitial — just your app. Free tier may show a one-time security notice; upgrade for client-facing previews without it.

When to switch to a custom domain

*.tnl.ngsrv.com is fine for internal use. When a URL becomes part of the deliverable for a client engagement, swap in your own domain:

tunnels:
  - name: preview
    port: 4200
    domain: preview.your-agency.com

See /docs/cli/domains for the DNS setup. Custom domains are included on Pro.