# Remote access with Cloudflare Tunnel and Access

Expose your *arr stack through a Cloudflare Tunnel without forwarding a port, gate it with Cloudflare Access, and configure Kochab's service-token support.

Canonical: https://kochab.io/docs/remote-access-cloudflare-tunnel/

import Callout from '@components/Callout.astro';

Cloudflare Tunnel gives your stack a public hostname without opening a port on your router. Run
`cloudflared` on your network, and it makes an outbound connection to Cloudflare instead of
waiting for an inbound one - useful when you are behind CGNAT, a double NAT, or a router that
will not forward ports at all.

Cloudflare Access can sit in front of the tunnel as a login gate. This guide covers the Kochab
side of both. For installing `cloudflared` and configuring Access policies, see the
[Cloudflare Tunnel docs](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/)
and [Cloudflare Access docs](https://developers.cloudflare.com/cloudflare-one/policies/access/).

## Minimal tunnel config

```yaml
tunnel: <your-tunnel-id>
credentials-file: /root/.cloudflared/<your-tunnel-id>.json

ingress:
  - hostname: sonarr.example.com
    service: http://localhost:8989
  - hostname: radarr.example.com
    service: http://localhost:7878
  - service: http_status:404
```

One hostname per service is the simplest shape, and it needs no base path configuration on the
service side. This `config.yml` is for a **locally-managed** tunnel; a dashboard-managed tunnel
has no config file, and you add hostnames as Public Hostnames in the Zero Trust dashboard
instead.

<Callout>

Either way, the last rule has to be a catch-all - `cloudflared` refuses a config that ends on a
hostname-specific rule.

</Callout>

## Add the tunnel hostname in Kochab

Whether the tunnel hostname can carry a Cloudflare Access **service token** in Kochab depends on
which address field it goes in.

### You also have a LAN address (recommended)

Add the service normally with its LAN address as the primary address, then add the tunnel
hostname under **Advanced > External address**. See
[Reverse proxies and remote access](/docs/remote-access/#home-and-away) for how Kochab picks
between the two. This shape is what makes a service token possible below - Kochab only ever
attaches proxy authentication to the external address.

### Tunnel-only (CGNAT, no usable LAN address)

Kochab's primary address field is required, so the tunnel hostname has to go there even with
nothing behind it at home. In this shape there is no external address for a service token to
attach to - use the API-path bypass policy under **Gating with Cloudflare Access** below instead.

Either way, enter the tunnel hostname as `https://sonarr.example.com`, with no base path for the
one-hostname-per-service shape above. Cloudflare issues a real certificate for the tunnel
hostname, so Kochab validates it the same as any other reverse proxy - see
[Certificates](/docs/remote-access/#certificates).

## Gating with Cloudflare Access

Add an Access application in front of the tunnel hostname the same way you would for any other
service. Kochab will fail its connection test against a gated hostname until it is given a way
through - a browser sign-in does not help, because Kochab has no browser session to reuse.
Cloudflare Access is one of two gates Kochab can authenticate against directly with a service
token instead of a bypass rule - the other is Pangolin. A token needs the LAN-plus-external
shape above; tunnel-only setups use Option 2.

### Option 1: a service token (needs an external address)

Create a **Service Auth** token in Access and pair it with a policy that accepts it. In Kochab,
set **External proxy authentication** to **Cloudflare Access** - on the **Credentials** step
while adding the service, or beside the external address under **Advanced** when editing one you
already have - then enter the token's Client ID and Client Secret in the `CF-Access-Client-Id`
and `CF-Access-Client-Secret` fields. Kochab sends both headers on every request to the external
address, and Access lets the request through with no browser and no saved session. This only
works for the LAN-plus-external shape above; Kochab refuses to save proxy authentication with no
external address configured.

### Option 2: a bypass policy on the API path

Add an Access policy that allows unauthenticated traffic to the API path while keeping the login
page on everything else, the same shape as the Authelia example in
[Reverse proxies and remote access](/docs/remote-access/#the-fix-let-the-api-through). The
service's own API key still guards that path - you are removing Access's second lock, not the
service's own. This option works regardless of which address field carries the tunnel hostname.

## Verify and troubleshoot

Run **Test & Add**. If it fails, work through
[Why won't Kochab connect to my service?](/docs/troubleshooting/service-wont-connect/). If the
tunnel hostname loads fine in a browser but Kochab still reports the service offline, Access is
likely recognizing your signed-in browser but not Kochab - see
[It works in a browser but Kochab says it's offline](/docs/troubleshooting/works-in-browser-not-kochab/).