Authentication

tunnel-me answers three different access questions, and each has its own knob:

Question Answered by Where it lives
Who may open the admin panel? The server's --auth setting Server command line
Who may open a tunnel as a visitor? The tunnel's sign-in setting Panel → Agents → your tunnel → Authentication
Which machines may join a tunnel as agents? Tunnel tokens Panel → Agents → your tunnel → Tokens

1. Who may open the admin panel

The panel (and the API behind it) is protected by the --auth flag on the server. All methods below protect the panel only — they never affect who can visit your tunnels.

static — the default, and it means off

tunnel-me serve --auth static

static performs no credential check. It exists for setups where something in front of the server does the authentication. Out of the box, anyone who can reach the server can open the panel.

Before exposing the port to the internet, switch to one of the methods below.

basic — username and password

tunnel-me serve \
  --auth basic \
  --auth.basic.username me \
  --auth.basic.password s3cret

The browser shows its native login prompt. Defaults are admin/admin — change them. The browser resends the credentials on every request; there is no session to expire and no lockout on wrong tries.

file — many users from an htpasswd file

tunnel-me serve --auth file --auth.file.filename /etc/tunnel-me/panel.htpasswd

The file uses the standard htpasswd format — plain name:password-hash lines, inherited from the Apache web server and still the lingua franca of self-hosting (htpasswd -B /etc/tunnel-me/panel.htpasswd somebody adds a user). It is read once at startup — adding or removing users means restarting the server. If the file is missing, the server refuses to start.

oidc — sign in through your identity provider

tunnel-me serve \
  --auth oidc \
  --auth.oidc.server-url https://tunnels.example.com \
  --auth.oidc.issuer-url https://idp.example.com/realms/main \
  --auth.oidc.client-id tunnel-me-panel \
  --auth.oidc.client-secret <secret>

webauth — let the proxy in front decide

tunnel-me serve --auth webauth --auth.web.header X-Panel-User

tunnel-me reads the named header and treats it as the signed-in user; a request without it gets rejected. This is for setups where the reverse proxy authenticates users (SSO plugins, forward auth) and injects the username.

Only safe when the server sits directly behind a proxy that authenticates and overwrites that header — otherwise a client could set the header itself and walk in. If your tunnels forward usernames to your apps, pick a header name that the proxy always overwrites (see the X-User note below).

2. Who may visit a tunnel

Each tunnel picks its own sign-in rule in the panel: Public, OIDC, or Internal. A tunnel that belongs to you can safely serve the public internet only if you decide so — there is no global default.

Public

No sign-in. Anyone with the address is in. Good for things meant to be open (a public website, a share link).

OIDC — sign in with an identity provider

OIDC is the machinery behind every "Sign in with Google" button: you register tunnel-me at your provider once, and from then on visitors sign in with accounts they already have.
In tunnel-me, add the provider on the OIDC page: label, issuer URL, client ID, client secret, scopes (default openid, profile, groups, email). It needs a redirect URI pointing back at your server — the page gives you two ready-to-copy values:

Then, on the tunnel's Authentication tab, pick OIDC, choose the provider, and optionally restrict it to specific groups. With no groups selected, any authenticated user of that provider gets in.

When a visitor opens the tunnel, they are redirected to the provider's login page and returned to the exact URL they wanted.

Internal — built-in users and groups

No external services needed: you manage accounts yourself, right in the panel.

Wrong passwords do not go unpunished: after several failed tries the visitor's IP is blocked temporarily. The Security page shows currently blocked addresses, when each block expires, and an Unblock button for each.

The X-User header — telling your app who is visiting

On the tunnel's Authentication tab there is a Forward authenticated user switch (on by default). While it is on:

Turn it off if your app uses that header for its own purposes.

Visitor sessions

Signing in to a tunnel sets a cookie scoped to that tunnel's own address (myapp.tunnels.example.com) — every tunnel has its own, so being signed in to one tunnel never unlocks another. Sessions last 7 days.

Restart behavior differs by method:

3. Which machines may connect as agents

Tunnels are joined by machines presenting a token. Tokens are created per tunnel (Agents → your tunnel → Tokens) and belong to that tunnel only.