Skip to content

Expose your gateway with a tunnel

Make the gateway reachable from the internet with Cloudflare, Tailscale, ngrok, Pinggy, OpenVPN, or a custom command.

By default the Revka gateway binds to 127.0.0.1 and is reachable only from the machine it runs on. To accept webhooks, pair a phone over the internet, or reach the dashboard from another network, you need a public ingress. Revka ships a built-in tunnel layer that wraps an external tunnel tool — Cloudflare, Tailscale, ngrok, Pinggy, OpenVPN, or any command you supply — and starts and stops it in lockstep with the daemon.

This guide explains the two ways to reach the gateway from outside (allow_public_bind for trusted LANs, a tunnel for the public internet), then walks through configuring each provider. For the gateway server itself see Run the dashboard and revka gateway, daemon & service.

The gateway never reaches the public internet on its own. You choose one of two exposure models in [gateway] and [tunnel]:

  • Direct public bind — bind the listener to a non-loopback address (0.0.0.0, [::], or a LAN IP). Use this on a trusted LAN or inside Docker, where the network boundary is your firewall. Controlled by allow_public_bind.
  • Tunnel — keep the gateway on 127.0.0.1 and let a tunnel provider forward an internet-facing URL to it. This is the recommended way to expose Revka to the public internet, because the listener itself stays on loopback.

You can combine them, but you rarely need to: a tunnel forwards to localhost just fine.

The listen address comes from [gateway].host. Any address other than loopback (127.0.0.1, localhost, ::1) is treated as a public bind.

[gateway]
host = "127.0.0.1" # default — localhost only
port = 42617
allow_public_bind = false # guard against accidental exposure
KeyTypeDefaultMeaning
hoststring"127.0.0.1"Bind address. 0.0.0.0 = all IPv4 interfaces, [::] = all IPv6 interfaces. Env: REVKA_GATEWAY_HOST
portint42617Listen port. Env: REVKA_GATEWAY_PORT
allow_public_bindboolfalseAcknowledge a non-loopback bind. Env: REVKA_ALLOW_PUBLIC_BIND

On the CLI you can override the host and port per run:

Terminal window
revka daemon --host 127.0.0.1 # localhost only (default)
revka daemon --host 0.0.0.0 # all interfaces, LAN access
revka daemon --port 9090 # override the gateway port

When you start the gateway on a public address without a configured tunnel and without allow_public_bind = true, Revka logs a warning at startup pointing you at the three safe options: stay on 127.0.0.1, configure a tunnel, or set allow_public_bind = true to acknowledge the exposure and silence the warning. Configuring a tunnel suppresses the warning automatically.

A tunnel wraps an external tool. Revka spawns the binary (or, for Pinggy, an SSH session), watches its output for the public URL, prints it, and terminates it cleanly when the daemon shuts down. Select a provider with tunnel.provider and supply that provider’s sub-section.

[tunnel]
provider = "cloudflare" # none | cloudflare | tailscale | ngrok | openvpn | pinggy | custom
[tunnel.cloudflare]
token = "eyJhIjoiMTI..."
FieldTypeDefaultMeaning
tunnel.providerstring"none"Which provider to start. Empty string is the same as "none".

The provider value is matched case-insensitively, so legacy PascalCase configs such as "CloudFlare" still work — but use the canonical lowercase form in new configs. If provider is anything other than "none", the matching sub-section must be present and its required fields set, or the daemon refuses to start with an error such as tunnel.provider = "ngrok" but [tunnel.ngrok] section is missing.

You can configure the common providers interactively in step 5 of revka onboard (Cloudflare, Tailscale, ngrok, and Custom). OpenVPN and Pinggy are configured by editing config.toml.

Wraps the cloudflared binary and a Cloudflare Zero Trust tunnel token. On start Revka runs cloudflared tunnel --no-autoupdate run against your local port and reads the public URL from stderr (up to a 30-second wait).

[tunnel]
provider = "cloudflare"
[tunnel.cloudflare]
token = "eyJhIjoiMTI..." # required — from the Zero Trust dashboard
FieldTypeRequiredMeaning
tokenstringyesCloudflare tunnel token from the Zero Trust dashboard

Requires cloudflared installed and on PATH. Note that cloudflared prints its URL to stderr, not stdout.

  1. Install the provider’s tool. Cloudflare needs cloudflared; Tailscale needs tailscale; ngrok needs ngrok; OpenVPN needs openvpn. Pinggy and Custom (with an SSH-based command) only need ssh.

  2. Add the [tunnel] section to ~/.revka/config.toml with your provider and its credentials, using the examples above.

  3. Keep the gateway on localhost. Leave [gateway].host = "127.0.0.1" — the tunnel forwards to the local port, so you do not need allow_public_bind.

  4. Start the daemon. Revka launches the tunnel alongside the gateway and prints the public URL.

    Terminal window
    revka daemon
    # 🔗 Starting cloudflare tunnel...
    # 🌐 Public URL: https://your-tunnel.example.com
  5. Pair over the public URL. Open the printed URL and complete pairing. The 6-digit code is shown in your terminal (not in a remote browser) — see Run the dashboard for the remote pairing flow.

Check that the gateway answers locally first — the health endpoint needs no auth and leaks no secrets:

Terminal window
curl http://127.0.0.1:42617/health
# {"status":"ok","paired":true,"require_pairing":true,...}

Then hit the same path through the tunnel URL. If the local check passes but the tunnel does not:

  • The daemon exits with a missing-section error. provider is set but the matching [tunnel.<provider>] sub-section (or a required field like token / auth_token / config_file) is absent. Add it.
  • No public URL is printed. The provider tool is not on PATH, or it did not emit a URL inside the timeout (30s Cloudflare, 15s ngrok/Pinggy). Run the tool by hand to confirm it works, then check the daemon logs.
  • The dashboard says it can’t reach the gateway from another machine. You are binding loopback with no tunnel. Add a [tunnel] section, or set allow_public_bind = true for a trusted LAN.

Run revka doctor for structured diagnostics. For network-deployment specifics (LAN binding, reverse proxies, Raspberry Pi) see Network deployment, Raspberry Pi & proxy.