Skip to content

ngrok Integration

ngrok is a popular tunneling service that creates secure ingress to your local PRX instance. It is the fastest way to get started with webhooks and external integrations -- a single command gives you a public HTTPS URL pointing to your local agent.

Overview

ngrok is best suited for:

  • Development and testing -- get a public URL in seconds with no account setup
  • Webhook prototyping -- quickly test Telegram, Discord, GitHub, or Slack integrations
  • Demos and presentations -- share a temporary public URL to showcase your agent
  • Environments where Cloudflare or Tailscale are not available

For production deployments, consider Cloudflare Tunnel or Tailscale Funnel which offer better reliability, custom domains, and zero-trust access controls.

Prerequisites

  1. ngrok CLI installed on the machine running PRX
  2. An ngrok account with an auth token (free tier is sufficient)

Installing ngrok

bash
# Debian / Ubuntu (via snap)
sudo snap install ngrok

# macOS
brew install ngrok

# Binary download (all platforms)
# https://ngrok.com/download

# Authenticate (one-time setup)
ngrok config add-authtoken <YOUR_AUTH_TOKEN>

Get your auth token from the ngrok dashboard.

Configuration

Basic Setup

toml
[tunnel]
backend = "ngrok"
local_addr = "127.0.0.1:8080"

[tunnel.ngrok]
# Auth token. Can also be set via NGROK_AUTHTOKEN environment variable.
# If omitted, ngrok uses the token from its local config file.
authtoken = ""

# Region for the tunnel endpoint.
# Options: "us", "eu", "ap", "au", "sa", "jp", "in"
region = "us"

Custom Domain (Paid Plans)

ngrok paid plans support persistent custom domains:

toml
[tunnel]
backend = "ngrok"
local_addr = "127.0.0.1:8080"

[tunnel.ngrok]
authtoken = "${NGROK_AUTHTOKEN}"

# Custom domain (requires ngrok paid plan)
domain = "agent.example.com"

# Alternatively, use a static ngrok subdomain (free on some plans)
# subdomain = "my-prx-agent"

Reserved Domain

For stable URLs on the free tier, ngrok offers reserved domains:

toml
[tunnel.ngrok]
authtoken = "${NGROK_AUTHTOKEN}"

# Reserved domain assigned by ngrok (e.g., "example-agent.ngrok-free.app")
domain = "example-agent.ngrok-free.app"

Configuration Reference

ParameterTypeDefaultDescription
authtokenstring--ngrok authentication token
regionstring"us"Tunnel region: "us", "eu", "ap", "au", "sa", "jp", "in"
domainstring--Custom domain or reserved domain (paid feature)
subdomainstring--Fixed subdomain on ngrok-free.app
ngrok_pathstring"ngrok"Path to the ngrok binary
inspectbooleantrueEnable the ngrok inspection dashboard (localhost:4040)
log_levelstring"info"ngrok log level: "debug", "info", "warn", "error"
metadatastring--Arbitrary metadata string attached to the tunnel session
basic_authstring--HTTP Basic Auth in user:password format
ip_restrictionslist[]List of allowed CIDR ranges (e.g., ["203.0.113.0/24"])
circuit_breakerfloat--Error rate threshold (0.0-1.0) to trigger circuit breaker
compressionbooleanfalseEnable response compression

How PRX Manages ngrok

When the tunnel starts, PRX spawns ngrok as a child process:

bash
ngrok http 127.0.0.1:8080 \
  --authtoken=<token> \
  --region=us \
  --log=stdout \
  --log-format=json

PRX then queries the ngrok local API (http://127.0.0.1:4040/api/tunnels) to retrieve the assigned public URL. This URL is stored and used for webhook registration and channel configuration.

URL Extraction

ngrok exposes a local API at port 4040. PRX polls this endpoint with a timeout:

GET http://localhost:4040/api/tunnels

The response contains the public URL:

json
{
  "tunnels": [
    {
      "public_url": "https://abc123.ngrok-free.app",
      "config": {
        "addr": "http://localhost:8080"
      }
    }
  ]
}

If the API is not available within startup_timeout_secs, PRX falls back to parsing stdout for the URL.

Free Tier Limitations

The ngrok free tier has several limitations to be aware of:

LimitationFree TierImpact on PRX
Concurrent tunnels1Only one PRX instance per ngrok account
Connections per minute40May throttle high-traffic webhooks
Custom domainsNot availableURL changes on each restart
IP restrictionsNot availableCannot restrict source IPs
BandwidthLimitedLarge file transfers may be throttled
Interstitial pageShown on first visitMay interfere with some webhook providers

The interstitial page (ngrok's browser warning page) does not affect API/webhook traffic -- it only appears for browser-initiated requests. However, some webhook providers may reject responses that include it. Use a paid plan or a different backend for production.

ngrok Inspection Dashboard

When inspect = true (the default), ngrok runs a local web dashboard at http://localhost:4040. This dashboard provides:

  • Request inspector -- view all incoming requests with headers, body, and response
  • Replay -- replay any request for debugging
  • Tunnel status -- connection health, region, and public URL

This is invaluable for debugging webhook integrations during development.

Security Considerations

  • Auth token protection -- the ngrok auth token grants tunnel creation access to your account. Store it in the PRX secrets manager or pass it via the NGROK_AUTHTOKEN environment variable.
  • Free tier URLs are public -- anyone with the URL can reach your agent. Use basic_auth or ip_restrictions (paid) to restrict access.
  • URL rotation -- free tier URLs change on restart. If webhook providers cache the old URL, they will fail to deliver events. Use reserved domains or a different backend for stable URLs.
  • TLS termination -- ngrok terminates TLS at its edge. Traffic between ngrok and your local PRX travels through ngrok's infrastructure.
  • Data inspection -- ngrok's inspection dashboard shows request/response bodies. Disable it in production with inspect = false if sensitive data is transmitted.

Webhook Integration Pattern

A common pattern for development: start PRX with ngrok, register the webhook URL, and test:

bash
# 1. Start PRX (tunnel starts automatically)
prx start

# 2. PRX logs the public URL
# [INFO] Tunnel started: https://abc123.ngrok-free.app

# 3. Register the webhook URL with your service
# Telegram: https://abc123.ngrok-free.app/webhook/telegram
# GitHub:   https://abc123.ngrok-free.app/webhook/github

# 4. Inspect requests at http://localhost:4040

Comparison with Other Backends

FeaturengrokCloudflare TunnelTailscale Funnel
Setup timeSecondsMinutesMinutes
Custom domainPaidFree (with zone)MagicDNS only
Zero-trustNoYes (Access)Yes (ACLs)
Free tierYes (limited)YesYes (personal)
Inspection dashboardYesNoNo
Production readyPaid plansYesYes

Troubleshooting

SymptomCauseResolution
"authentication failed"Invalid or missing auth tokenRun ngrok config add-authtoken <token>
URL not detectedngrok API not responding on :4040Check that port 4040 is not in use by another process
"tunnel session limit"Free tier allows 1 tunnelStop other ngrok sessions or upgrade
Webhooks return 502PRX gateway not listeningVerify local_addr matches your gateway
Interstitial page shownFree tier browser warningUse --domain or upgrade to paid plan
Random disconnectionsFree tier connection limitsUpgrade or switch to Cloudflare/Tailscale

Released under the Apache-2.0 License.