Run an Authenticated ngrok Tunnel to a Local Development Service
Expose a localhost service over HTTPS with ngrok v3, authenticate with an authtoken, and restrict access with a traffic policy before sharing the public URL.
03 Nov 2025, 10:54 UTC

The problem: your local service has no public address
You are developing an API on localhost:8080 and an external service needs to send webhooks to it, or a teammate needs to review a preview build. Your laptop is behind a router or corporate firewall, so there is no public inbound port. Opening a port on your network would expose the service to the entire internet, often without authentication, and many local services assume they are only reachable from the machine they run on.
Useful takeaway: run the ngrok v3 agent to create an HTTPS tunnel to your local service, authenticate the agent with an authtoken, and apply an access policy before sharing the public URL. Verify the tunnel with curl and the local inspector, then treat the URL as temporary unless you reserve a domain.
Desired outcome
- A public HTTPS URL that forwards traffic to a local service listening on a known port.
- The ngrok agent is authenticated with an authtoken, not an anonymous session.
- Access to the tunnel is restricted by a policy appropriate to your plan.
- Requests are visible in the local inspector for debugging webhooks or integrations.
Prerequisites
- An ngrok account and an authtoken from the dashboard.
- The ngrok v3 agent installed on the machine running the local service.
- A local service already listening on a port, for example
8080. - Terminal access to that machine.
- Never store the authtoken in source control, shell history, or CI logs.
Install and authenticate the agent
Run these commands in a terminal on the machine hosting the local service. You need normal user permissions; moving the binary into a system PATH may require elevated permissions.
# Confirm you are using the v3 agent. Expected output begins with "ngrok version 3".
ngrok version
# Store the authtoken in the user config file. Replace with your dashboard token.
# Risk: the token may be written to shell history. In CI, use NGROK_AUTHTOKEN as a secret instead.
ngrok config add-authtoken ""
The command writes to the user ngrok configuration directory, typically ~/.config/ngrok/ngrok.yml on Linux and macOS. If you suspect the token was exposed, rotate it in the ngrok dashboard and update every config file and environment variable that contains it.
Define the tunnel
You can start a tunnel ad hoc or declare it in ngrok.yml. Declaring it makes the setup repeatable and easier to review before sharing.
version: "2"
tunnels:
local-dev:
addr: 8080
proto: http
This forwards public HTTPS traffic to http://localhost:8080. The proto: http setting tells ngrok to accept HTTPS on the public side and speak HTTP to your local service.
Start the tunnel and capture the public URL
# Start the named tunnel from the config file.
ngrok start local-dev
# Alternative: start an anonymous tunnel without a config file.
# ngrok http 8080
Expected result: the agent prints a public forwarding URL such as https://.ngrok-free.app. The exact hostname is ephemeral and changes when you restart the agent unless you reserve a domain. Do not invent or hardcode a URL; copy it from the command output, the agent log, or the local inspector.
Verify the tunnel works
- From a separate terminal, request the public URL over HTTPS:
curl -I https://Expect the same status and headers you receive fromcurl -I http://localhost:8080, served through the tunnel's TLS certificate. - Open the local inspector at
http://127.0.0.1:4040. This is a local, unauthenticated view of full request and response data. Confirm the request appears with the correct method, path, headers, and response status. Do not expose port 4040 to your network or the internet. - Use the inspector's replay button to resend a captured request while debugging a webhook integration.
Apply and test an access policy
A guessable URL is not access control. Choose an access layer your plan supports: HTTP Basic Auth, IP allowlisting, or OAuth/OIDC. Exact configuration steps depend on your plan and are managed in the ngrok dashboard or agent configuration; confirm availability before you share the URL.
| Method | Best for | Limitation |
|---|---|---|
| HTTP Basic Auth | Quick access for a small team | Manage credentials separately; rotate if leaked |
| IP allowlisting | Callers with static IP addresses | Does not work for mobile clients or dynamic webhook sources |
| OAuth/OIDC | Team members with an identity provider | Requires IdP setup and plan support |
After applying a policy, test both sides:
- An allowed client receives the local service's response.
- A disallowed client receives a rejection, typically
401or403.
Limitations
- Public URLs are ephemeral by default. Anything depending on a fixed address needs a reserved domain or stable edge, which is plan-gated.
- The agent counts tunnels against plan limits. Check the dashboard if startup fails with a limit error.
- Treat all tunnel traffic as public. Do not point a tunnel at a service holding production credentials or secrets.
- This guide assumes ngrok agent v3. Do not mix v2 commands or config syntax with a v3 agent.
Recovery and rollback
Starting a tunnel changes state by exposing a public address. To roll back:
- Press
Ctrl+Cin the agent terminal. The public tunnel stops accepting traffic immediately. - If the authtoken may have leaked, rotate it in the ngrok dashboard, then update
ngrok.yml, environment variables, and CI secrets. - Search your repository and CI configuration for the token string to confirm it is not committed anywhere.
- If the local service no longer needs exposure, confirm no ngrok agent is running in the background before closing the machine.
Practical check
Run ngrok version, start the tunnel, curl the public URL, confirm the request in http://127.0.0.1:4040, replay it once, then deny a test client and confirm a 401 or 403. If all four checks pass, the tunnel is authenticated, reachable, inspectable, and access-controlled.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.