development
Tunnel URL vs. Stable Subdomain
Separate the public-name decision from the connectivity decision, compare current ngrok development domains with owned hostnames, and choose an appropriate route to a local or hosted service.
- Written by
- 1990Company Editorial Desk
- Published
- Updated
- Reviewed
Source review: Current ngrok dev-domain behavior, free-plan domain limits, endpoint timeout statement, and custom-domain availability checked against official ngrok documentation. Public-hostname routing and DNS behavior checked against current Cloudflare Tunnel documentation. Example names and addresses follow IETF documentation ranges.
A tunnel and a subdomain solve different problems:
- a tunnel carries traffic from a public edge to a service that may not have a public address
- a subdomain is a DNS name that clients and integrations use
They are not replacements for each other. A local application can use a provider-assigned tunnel domain, an owned subdomain routed through a tunnel, or a hosted preview with ordinary DNS. The right comparison separates address stability from transport.
Separate naming from connectivity
Answer these questions independently:
Public name
- May a provider choose the hostname?
- Must your organization control the hostname?
- Will a webhook provider, OAuth client, teammate, or document store the URL?
- Should the URL survive a move to another tunnel or hosting provider?
Origin connectivity
- Is the service running only on a laptop or private network?
- Can it accept inbound Internet traffic directly?
- Will a tunnel agent run continuously?
- Is this a short test, a shared preview, or an operated service?
Owning preview.example.com does not make localhost:3000 reachable. DNS still needs a routable platform, reverse proxy, or tunnel behind it.
What ngrok’s free domain provides now
Current ngrok documentation states that every account receives an automatically generated Dev Domain. On the free plan:
- one assigned development domain is available
- the domain name cannot be customized
- random domain generation is not available
- a user-owned custom domain is not available
- the assigned domain can be used for public endpoints
The free-plan documentation also says endpoints do not have timeouts, although usage quotas and other plan limits still apply. It is therefore inaccurate to describe every current free ngrok session as receiving a newly randomized URL on each restart.
A typical account-provided name follows an ngrok-managed pattern such as:
https://your-assigned-name.ngrok-free.app
That name can be suitable for development callbacks when provider branding and lack of naming control are acceptable. Check the current limits page before relying on a quota or feature in an automated workflow.
What an owned subdomain changes
An owned hostname such as preview.example.com gives the domain operator control over:
- the label users and systems store
- DNS routing
- migration to a different origin or tunnel provider
- lifecycle and revocation of the public name
It does not remove the need for connectivity. An owned hostname can point to:
- a hosted preview environment
- a load balancer or reverse proxy
- a tunnel provider’s supported custom-domain endpoint
- a Cloudflare Tunnel published application
For ngrok, bringing a user-owned domain is plan-dependent; the current domains documentation lists it for the Pay-as-you-go plan. Do not present an owned ngrok custom domain as a free-plan feature.
Three workable architectures
Assigned development domain plus tunnel
Public URL: account-assigned ngrok Dev Domain
Transport: ngrok agent
Origin: http://localhost:3000
Use this when fast local reachability matters and the assigned provider hostname is acceptable.
Owned subdomain plus tunnel
Cloudflare Tunnel can map a public hostname to a local service:
Public hostname: preview.example.com
Service: http://localhost:3000
Cloudflare creates or uses a CNAME pointing the hostname to a <UUID>.cfargotunnel.com tunnel target. The DNS record and running tunnel are independent: if the tunnel stops, the record remains and Cloudflare documents that visitors can receive error 1016.
Other tunnel providers can offer a similar owned-domain pattern under their own plans and routing rules.
Owned subdomain plus hosted origin
Public hostname: preview.example.com
Destination: provider-documented hosting target
Use this when the preview already runs on a public hosting platform. Follow the platform’s custom-domain process and the subdomain DNS, routing, and HTTPS guide rather than adding a tunnel that the architecture does not need.
Illustrated architecture comparison
Illustrative example using reserved example domains and IPs. The following SVG is a constructed comparison, not a capture from an ngrok account, Cloudflare account, or live deployment. Provider-formatted labels are non-live placeholders.
Illustrative example using reserved example domains and IPs. It contains no active tunnel URL, secret, account identifier, or production endpoint.
Read the diagram as a comparison of public contracts, not as evidence that one transport is always temporary or one hostname is always highly available.
Decision matrix
| Requirement | Assigned ngrok Dev Domain | Owned subdomain through a tunnel | Owned subdomain to hosted preview |
|---|---|---|---|
| Reach a local service without inbound port forwarding | Yes, while the agent is connected | Yes, while the tunnel connector is connected | Not applicable |
| Choose the public label | No on ngrok Free | Yes | Yes |
| Keep the public contract when changing the backend | Limited by provider domain | Yes, by changing tunnel or DNS routing | Yes, by changing platform binding or DNS |
| Requires a local connector process | Yes | Yes | No |
| Appropriate for a short webhook test | Often | Possible but may be extra setup | Only if a preview already exists |
| Appropriate for a shared, named environment | If provider naming is acceptable | Yes, with connector operations and access controls | Yes, with hosting operations |
The table compares architecture, not pricing. Provider limits and plan features can change, so use the linked official documentation for the current commercial boundary.
Put callback configuration behind one public variable
For an assigned development domain:
PUBLIC_BASE_URL=https://your-assigned-name.ngrok-free.app
WEBHOOK_CALLBACK_URL=${PUBLIC_BASE_URL}/webhooks
For an owned hostname:
PUBLIC_BASE_URL=https://preview.example.com
WEBHOOK_CALLBACK_URL=${PUBLIC_BASE_URL}/webhooks
Centralizing the base URL reduces configuration drift, but it does not make a URL stable by itself. The DNS record, tunnel or host process, TLS, and external callback registration all need coordinated ownership.
For local-only naming before anything is public, see local development with custom domains. That workflow changes local resolution and should not be confused with publishing an Internet endpoint.
Operational checks for a longer-lived tunnel
If a tunnel-backed hostname will be shared beyond a short test:
- run the connector under a supervised service rather than an interactive shell
- restrict access with application authentication or an access policy
- avoid exposing debug consoles, development secrets, or unrestricted administrative routes
- log requests without storing credentials or sensitive payloads
- monitor connector health and the upstream service separately
- document who owns DNS, the tunnel account, and the local process
- define what happens when the machine sleeps, loses connectivity, or changes networks
A stable name can make an unstable origin easier to depend on accidentally. Availability comes from operating the connector and service, not from the hostname alone.
Avoid these category errors
Assuming every ngrok restart creates a new random hostname
That does not match the current free Dev Domain model. Verify the assigned domain and plan behavior in the account and current documentation.
Publishing DNS without a route to localhost
An A or CNAME record cannot reach a service bound only to a private interface. Add a supported tunnel or deploy the service to a public environment.
Treating the tunnel target as the user-facing contract
If third parties need an organization-controlled URL, route an owned hostname through a supported custom-domain or tunnel configuration rather than copying an internal provider target into documentation.
Treating a persistent hostname as persistent service availability
The name can remain valid while the tunnel connector or local application is offline. Monitor both.
Choose based on the dependency
- Use the assigned ngrok Dev Domain for a low-setup local test when its name and current limits are acceptable.
- Use an owned subdomain through a tunnel when systems need an organization-controlled URL but the origin remains private or local.
- Use an owned subdomain with a hosted preview when the workload already has a durable public environment.
If Cloudflare is authoritative for the owned hostname, the Cloudflare DNS guide explains how proxy status and public DNS answers interact with the rest of the route.
Sources and further reading
Vendor behavior can change. Use these primary sources to confirm the current product-specific details.