ngrok and similar tools are great for providing public access to local services, often for development purposes. I primarily use it for exposing an API being developed locally so that a webhook callback can interact with it, for example an inbound email callback from mailgun - it's very useful for capturing or testing with the exact payload and structure.

ngrok used to let users customise their subdomains (along with a few other premium features) for a one off fee of $25 (I think) - I am on this (now grandfathered) plan.

Since then the cost model has changed - it's all gone a little more pro which is great to see, but starting at $60/year it's not a no-brainer for limited use.

I have no issue with paying for services, especially good ones, and those for regular business use, but this is something I use rarely and would prefer a pay-as-you-go model.

Even more rarely I need a deterministic domain name, for example in cases where it's tricky to change a callback setting, perhaps if I don't have direct access to a service account required to do so. In a few cases I have seen providers block ngrok domains on callbacks as they are fairly anonymous and transient - I'm still not sure I follow their logi for doing so since it's fairly easy to circumvent and domains are quite cheap, but this has been my main reason to alias ngrok.

The free / unregistered plan gives you a session for 8 hours on a random domain - so without a paid plan there are more reasons to do setup a hostname alias.

It's free (mostly)

To forward a domain I manage to ngrok I use AWS's CloudFront service along with ACM for an SSL certificate.

For simplicity I use a domain hosted in Route53 as the certificate validation is easier with one-click DNS record creation.

So there are costs, but they're almost certainly marginal.

CloudFront is priced on bandwidth and request volume where each GB of internet-bound traffic costs around $0.10 and 10,000 HTTP requests cost less than $0.20 (both vary by region). A Route53 zone costs no more than $0.50 per month and ACM is free.

Route53 is optional - CloudFlare is a good way to get a decent DNS service for free with this approach it's not likely to cost more than $0.01 for any reasonable amount of traffic.


CloudFront can be used by itself - the domains are also random, but static, e.g

CloudFront can work over HTTP only but HTTPS is available for free, so why not use that?

The built in domains have SSL so that could be enough, for something more memorable we first need to request a certificate using ACM in the us-east-1 region (as CloudFront is a global service):

aws acm request-certificate --domain-name '' --validation-method DNS

We can view the certificate status and verification records:

And create them in Route53 if the domain is hosted there:

Shortly after the DNS records are created the certificate should become available (unless the TTL is high):


For this use case the CloudFront setup is very simple, with or without the custom domain name:

Start by creating a (web) distribution, the origin domain is the target, the ngrok domain (e.g:

The defaults are fine but we can ensure better security by setting the Origin Protocol Policy to HTTPS Only, further down we can optionally enforce HTTPS for viewers with a redirect too.

The Cache Policy should be set to disabled:

Leaving the Origin Request Policy blank is important as some options forward all headers which would then send the SNI Host Header, meaning ngrok wouldn't recognise the request.

Finally, under the distribution settings we set our custom domain (if applicable) which involves selecting the SSL Certificate and setting the Alternate Domain Names:

Now the distribution can be created. Thanks to recent improvements by AWS this should only take a few minutes - often it starts responding correct before officially finishing.

Route 53 / DNS

If using a custom domain we need to add a DNS record to alias to the CloudFront distribution, our domain is

In Route53 we create an alias (a smart / flattened AWS CNAME effectively), for other providers a CNAME is fine unless its an apex record (i.e. the root of the domain, e.g.


To test we can run an nginx container:

docker run -it --rm -p 80:80 nginx

And ngrok:

ngrok http 80

It works via ngrok directly:

And via the custom domain:

When the ngrok domain changes

If or when the ngrok domain changes, for a new session or after the timeout we just need to update the origin (go in to the Distribution, then to Origins and Origin Groups, then Edit the existing origin):