Deploy custom error pages with your logo, your messages, your way

Here's a common request we hear at ngrok: You want to give your customers a more cohesive experience than an ngrok-branded error page if your agents or upstream services go offline. 

Until now, getting custom error pages meant discovering a particular landing page, filling out a form, and waiting for us to respond and help set you up. Turns out you don't actually need to fill out a form and wait for one of us to get in touch to build yourself custom error pages with ngrok. That's part of the power of endpoints and the Traffic Policy system.

Let me get you caught up and on your way—no permission slip required. Here's what you'll set up:

  1. A "shape" of using ngrok that involves using a Cloud Endpoint and one or more internal Agent Endpoints.
  2. The forward-internal Traffic Policy action to forward traffic from your cloud endpoint to your agent(s).
  3. The custom-response Traffic Policy action to your cloud endpoint as a fallback mechanism if either the agent or upstream service goes offline for any reason.

Here's what that looks like:

Start with your cloud endpoint

If you're already using cloud and internal endpoints together in the shape illustrated above, you can skip ahead to creating a custom error page.

If you already have an agent endpoint attached to a public URL, like https://your-company.com, you'll need to stop the agent before you can get started. Yes, that equates to downtime for your upstream service, so I recommend reading through the rest of this section before you jump in.

Create a cloud endpoint in the dashboard and attach it to a domain you've reserved. If you're a fan of ngrok's API, you can also create a cloud endpoint programmatically.

If you hit your endpoint, ngrok will try to forward traffic to an internal endpoint that doesn't exist, which in turn sends you to the default cloud endpoint response. You've actually demonstrated exactly how this shape and set of Traffic Policy actions should behave—let's make it production-ready.

Bring an agent endpoint into the picture

Create an internal agent endpoint with the ngrok CLI to point to your upstream service.

ngrok http <PORT> --url https://<SERVICE_NAME>.internal

Of course, you can also create agent endpoints with our Kubernetes Operator or SDKs if the agent CLI isn't right for you.

Head over to your cloud endpoint and update the default forward-internal rule to forward traffic to https://<SERVICE_NAME>.internal—that gets your upstream service back online.

on_http_request:
  - actions:
      - type: forward-internal
        config:
          url: https://<SERVICE_NAME>.internal
          on_error: continue

Tie things up with your custom error page

Whether you just created your first cloud endpoint or they're old hat for you by now, take note of the last line in the YAML snippet just above: on_error: continue. What's the difference between continue and the default: halt?

With the halt default, forward-internal responds with an ngrok-branded error page if it can't forward the request to your internal agent endpoint. By changing that to continue, you can chain another action onto the request—notably, custom-response.

Whether you're editing the default Traffic Policy rules applied to every cloud endpoint or have already tweaked it to your needs, you can edit the content field of the custom-response action to send out the exact custom error page you'd like your users to see instead of ngrok's. Along the way, you can customize CSS to match your brand and use CEL interpolation to enrich the response with details about the user or their attempted connection.

on_http_request:
 - actions:
     - type: forward-internal
       config:
         url: https://<SERVICE_NAME>.internal
         on_error: continue
     - type: custom-response
       config:
         status_code: 503
         headers:
           content-type: text/html
         content: |
           <!doctype html>
           <html>
           <head>
             <meta charset="UTF-8" />
             <meta name="viewport" content="width=device-width, initial-scale=1" />
             <title>Error at ${req.host}!</title>
             <style>
               body { font-family: system-ui, sans-serif; padding: 2rem; background: #fff; }
               code { font-family: monospace; background: #eee; padding: 0.2em 0.4em; border-radius: 4px; }
               .container { max-width: 600px; margin: 0 auto; }
             </style>
           </head>
           <body>
             <div class="container">
               <h1>Sorry, something went wrong</h1>
               <p>We're having trouble reaching <strong>${req.host}</strong>.</p>
               <ul>
                 <li>Time: <code>${timestamp(time.now)}</code></li>
                 <li>Path: <code>${req.url.path}</code></li>
                 <li>Method: <code>${req.method}</code></li>
                 <li>Region: <code>${conn.server_region}</code></li>
               </ul>
             </div>
           </body>
           </html>

With the above policy, if either your agent endpoint or upstream service isn't responsive, your users will see a custom page.

It's not (yet) beautiful, but it's a starting point—entirely yours to customize.

Your permission slip for better error handling

Custom error pages with ngrok don't just give you a consistent UX for your users. How about also: 

  • Saying goodbye to that forgotten S3 bucket or languishing reverse proxy whose only job is to serve custom HTML error pages… and simplifying your infrastructure along the way?
  • Chaining the log action before custom-response to pipe enriched events over to your observability platform and help you debug exactly when, where, and how things went wrong?
  • Using the shape of cloud and internal endpoints to add powerful layers of composability to your API gateway?

You can build custom error pages on any account, so snag a free one if you haven't already.

Check out the custom-response docs for more options. For everything else, our customer success team is here for you—no permission slip needed to ask for help, either.

Share this post
Joel Hans
Joel Hans is a Senior Developer Educator. Away from blog posts and demo apps, you might find him mountain biking, writing fiction, or digging holes in his yard.
API gateway
Traffic Policy
Features
Gateways
Production