All pages
On this page

Reaching the relay through a Cloudflare Tunnel

A Cloudflare Tunnel gives your relay a public HTTPS address without a server of your own and without opening a port on your router. OAR can run Cloudflare's cloudflared program for you: it starts it with the relay, restarts it when it drops and shows its state in the status dot. Choose it when you have a domain on Cloudflare and want to reach the relay from a phone or another network, or when you need HTTPS for installing the page as an app and push notifications.

cloudflared connects outward to Cloudflare. The relay keeps listening on this machine only (localhostOnly stays true), and Cloudflare carries requests for your hostname down that connection to the relay's port.

What you need #

  • A Cloudflare account with Zero Trust, and a domain (a zone) on it for the public hostname.
  • cloudflared installed on the machine that runs the relay. OAR does not include it and does not install it.
  • A tunnel that you create in Cloudflare. OAR runs it from the tunnel's token.

The relay runs the program named in cloudflaredTunnel.binary, or else the cloudflared it finds on its PATH. Install it with:

System Install
Windows winget install --id Cloudflare.cloudflared
macOS brew install cloudflared
Linux Cloudflare's package repository (Debian, Ubuntu, RHEL): pkg.cloudflare.com

On Windows, a .cmd or .bat launcher does not work. OAR starts a .exe or .com file.

One kind of tunnel

OAR supports a tunnel that runs from a token, the kind Cloudflare calls a remotely managed tunnel. There is no setting for a credentials file or a tunnel name, and none for a quick tunnel with a random address. If you run such a tunnel yourself, start cloudflared outside OAR. OAR then knows nothing about it.

Setting it up #

  1. In your Cloudflare Zero Trust account, create a tunnel. Copy its token.
  2. Give the tunnel a public hostname on your zone, for example relay.example.com, and point it at http://localhost:3333. If you changed port in config.json, use that port. This routing lives in Cloudflare, not on your machine.
  3. Add the cloudflaredTunnel block to config.json with the token (see Config keys).
  4. Restart the relay with oar restart.

Open https://relay.example.com/ in a browser. You sign in with the access token as usual.

The config block #

{
  "cloudflaredTunnel": {
    "mode": "managed",
    "required": false,
    "token": "<tunnel token>",
    "binary": "cloudflared",
    "extraArgs": []
  }
}
Key Type Default What it does
mode "disabled" or "managed" "disabled" managed makes the relay run cloudflared.
token string none The tunnel's token. Required when managed; without it the tunnel stays off and the log says why.
required boolean false While the tunnel is not connected, the relay pauses taking messages from the queue. See Required tunnel.
binary string cloudflared The program: an absolute path, or a name looked up on PATH. A path must point at an executable file. A relative path with a folder in it counts from the relay's program folder, so use an absolute one.
extraArgs string array [] Arguments added after cloudflared tunnel run --token <token>. Empty entries are dropped.

The old form "enabled": true still works for mode: "managed". Three environment variables override the file: COPILOT_CLOUDFLARED_MODE, COPILOT_CLOUDFLARED_TOKEN and COPILOT_CLOUDFLARED_BINARY. The config.json reference lists the keys with the other tunnel settings, and the environment variables page lists the variables.

The relay hands the token to cloudflared as a command-line argument (cloudflared tunnel run --token <token>), not through the environment. On a machine with other users, the token can therefore show up in the list of running processes. The relay's log shows it as <redacted>.

How it behaves #

  • Start and stop. The relay starts cloudflared when it starts and stops it (a termination signal) when it shuts down.
  • Connected. The tunnel counts as connected when cloudflared reports a registered connection, or, failing that, when it has run for five seconds.
  • Drops. When cloudflared exits, the relay starts it again after a wait of about 5, 10, 20, 40 and then 60 seconds, each with up to 20 percent added. The steps start over after a connection that lasted more than 30 seconds.
  • Bad token or deleted tunnel. If cloudflared exits within 10 seconds three times in a row, the relay reports the error auth-or-config and from then on retries only about once a minute.
  • No cloudflared. The relay starts as usual and the tunnel stays off. It looks again every minute and starts the tunnel once the program is there. If you installed it into a folder that is not on the relay's PATH, restart the relay.

Required tunnel #

With required: true the relay does not take messages from the queue while the tunnel is not connected. That includes the time before it first connects and a missing cloudflared or token. Use it when the relay is only useful if you can reach it from outside. Messages wait in the queue and run once the tunnel is connected (see turns and the queue).

Seeing the state #

Where What it shows
Status dot Amber, tooltip Web relay reachable via Cloudflare Tunnel, while the tunnel is connected. Green when it is set up but not connected: the tooltip says Web relay reachable; Cloudflare tunnel disconnected (), or Cloudflare tunnel off: when cloudflared is missing. The relay still answers. See the menu and appearance.
oar status A Tunnel: line when the tunnel is on: running, not connected, not connected (<reason>) or off: <reason>. With the relay stopped, it shows the same wording as oar doctor. See oar status.
oar doctor disabled, managed (cloudflared: <path>) or managed, cannot start: <reason>. It reads the config only and changes nothing. See oar doctor.
The log Lines that start with [cloudflared-tunnel]: the command (the token shown as <redacted>), Tunnel connected, exits and reconnect delays, and cloudflared's own output.

The relay does not know your public hostname, because the routing lives in Cloudflare, so none of these shows it.

Telling tunnel traffic apart #

Cloudflare adds a cf-ray header to every request it forwards. The relay uses it to tell a request that came through the tunnel from one made on this machine. To also treat the headers your own edge adds this way, list them in tunnelMarkerHeaders. publicHostnames lists the hostnames that reach the relay, and trustProxy says which proxies the relay believes about the forwarded address. The default, "loopback", suits cloudflared on the same machine. All three are in the config.json reference.

A second hostname for previews #

Previews need their own hostname, so a previewed app never shares a login cookie with the relay. Add it to the same tunnel as a second public hostname that points at the preview listener (http://127.0.0.1:3334 by default). The previews page has the ingress example and the previews block. Put the relay's hostname into publicHostnames.

Cloudflare Access in front of the relay #

A Cloudflare Access application over the relay's hostname applies to every visitor, including viewers of a shared conversation. Without an exception they are asked to sign in and the link does not work. Let /shared/* and /api/shared/* through without a login.

Do not add a Cloudflare cache rule for /api/shared/*. A shared page reloads that address to follow the conversation, and a cached answer would keep showing an old state. The relay marks every API answer with Cache-Control: no-store, and every answer with CDN-Cache-Control and Cloudflare-CDN-Cache-Control set to no-store. Cloudflare obeys those two ahead of a cache rule in your zone.

Security #

A tunnel puts the relay on the public internet. The access token is what keeps others out. See The access token and who can reach the relay and What OAR exposes.

The relay's session workers connect over sockets that only run on this machine. Because a public tunnel forwards every path, the relay answers 403 to a request on those paths that carries cf-ray or one of your tunnelMarkerHeaders, and the log notes it with [tunnel-guard]. Shared links, which arrive over the tunnel without a login, are not affected.

Troubleshooting #

What you see What to do
The tooltip says Cloudflare tunnel off: cloudflared is not installed (followed by how to install it), or oar doctor says cloudflared is not installed Install cloudflared (see What you need). The tunnel starts within a minute.
cloudflared was not found as configured (<path>) cloudflaredTunnel.binary points at nothing. Correct the path, or clear the key to use cloudflared from PATH.
cloudflaredTunnel.token is required when cloudflaredTunnel.mode is "managed" Add the token to the config, or set COPILOT_CLOUDFLARED_TOKEN.
Tunnel: not connected (auth-or-config) cloudflared keeps exiting at once. Check the token and that the tunnel still exists in Cloudflare. The log has cloudflared's own message.
Tunnel: not connected (exit:<code>) cloudflared ended with that exit code. The relay is trying again; read the log.
The dot stays green although you opened the relay through the tunnel The tunnel is not connected from the relay's side. Read the tooltip and oar status.
Messages do not run and the queue is paused required is true and the tunnel is not connected. Fix the tunnel, or set required to false.
A shared link asks the viewer to sign in Cloudflare Access is in the way. Let /shared/* and /api/shared/* through.
A shared page shows an old state A cache rule covers /api/shared/*. Remove it.
403 on a session-worker path Expected: those paths are closed to tunnel traffic.
cloudflared is installed, but the tunnel does not start The relay may not see it on its PATH. Set binary to the full path and run oar restart.