Skip to main content

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.

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.

Illustrated comparison of a provider-assigned tunnel URL and an owned preview hostname

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

RequirementAssigned ngrok Dev DomainOwned subdomain through a tunnelOwned subdomain to hosted preview
Reach a local service without inbound port forwardingYes, while the agent is connectedYes, while the tunnel connector is connectedNot applicable
Choose the public labelNo on ngrok FreeYesYes
Keep the public contract when changing the backendLimited by provider domainYes, by changing tunnel or DNS routingYes, by changing platform binding or DNS
Requires a local connector processYesYesNo
Appropriate for a short webhook testOftenPossible but may be extra setupOnly if a preview already exists
Appropriate for a shared, named environmentIf provider naming is acceptableYes, with connector operations and access controlsYes, 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.

Continue learning

  1. 01
    Local Development with Custom Domains

    Use custom domains locally without turning your setup into a guessing game. This guide covers hosts files, local DNS, HTTPS, and when to use a real public subdomain.

    Read
  2. 02
    Cloudflare DNS: Records, Proxy Status, and Verification

    Configure a Cloudflare DNS record with an explicit target, proxy decision, accurate TTL expectations, and checks for both DNS and the public application path.

    Read
  3. 03
    Subdomain Naming Rules for Public Projects

    Choose a public hostname with a purpose-owner-lifecycle worksheet, a practical naming rubric, and an expiry plan for previews and temporary environments.

    Read