> ## Documentation Index
> Fetch the complete documentation index at: https://docs.avibe.bot/llms.txt
> Use this file to discover all available pages before exploring further.

# Reverse proxy & custom domains

> Serve your local Avibe Web UI behind your own reverse proxy on a custom domain by registering the proxy as a trusted source for forwarded host and origin checks.

# Reverse proxy & custom domains

Avibe's Web UI runs on your machine, listening on `127.0.0.1:5123` by default. The simplest way to reach it from elsewhere is the [avibe.bot tunnel](/concepts/remote-ui). If you'd rather front it yourself — for example with **nginx on your own domain** — Avibe needs to know it can trust the host your proxy forwards.

## Why a plain reverse proxy gets blocked

Avibe checks that each request's origin matches the address it is actually being served on. That check is what stops a malicious page from forging requests to your local control panel.

Since **PR #781**, Avibe **does not trust the `X-Forwarded-Host` header by default**. Unless a request arrives from a proxy you have explicitly registered, Avibe ignores the forwarded host and computes the origin from the direct connection it sees — e.g. `http://127.0.0.1:5123`.

So if nginx serves `https://avibe.example.com` but the proxy is not registered, the browser sends `avibe.example.com` while Avibe still believes it is `127.0.0.1`. The two don't match, and the request is refused:

* state-changing actions return **`403` (`invalid origin`)**;
* depending on your avibe.bot remote-access configuration, the page load itself may return **`503` (host mismatch)**.

## Make it work

Two things are required: register your proxy's IP as trusted, and forward the right headers.

### 1. Register the proxy as trusted

Set `VIBE_UI_TRUSTED_PROXY_IPS` to the address Avibe sees your proxy connecting **from** — the direct peer, not the browser:

* **nginx on the same machine**, proxying to Avibe's loopback listener → `127.0.0.1`
* **nginx on another host or container** → its real IP, or a CIDR range

Separate multiple entries with commas; plain IPs and CIDR ranges are both accepted:

```bash theme={null}
VIBE_UI_TRUSTED_PROXY_IPS=127.0.0.1
# or, proxy on the LAN:
VIBE_UI_TRUSTED_PROXY_IPS=10.0.0.0/24,192.168.1.5
```

Set it in the environment where the `vibe` service runs — your shell profile, service-manager unit, or container env — then restart Avibe. When the value is empty (the default), no proxy is trusted and forwarded hosts are ignored.

<Note>
  A future release may let you set trusted proxies from the Web UI settings instead of an environment variable. Until then, use `VIBE_UI_TRUSTED_PROXY_IPS`.
</Note>

### 2. Forward the headers from nginx

A trusted proxy must pass the browser's host and scheme through, or Avibe has nothing to trust:

```nginx theme={null}
proxy_set_header Host              $host;
proxy_set_header X-Forwarded-Host  $host;
proxy_set_header X-Forwarded-Proto $scheme;
```

If you serve on a non-standard external port, also forward `proxy_set_header X-Forwarded-Port $server_port;`.

### Full nginx example

```nginx theme={null}
server {
    listen 443 ssl;
    server_name avibe.example.com;

    # ssl_certificate / ssl_certificate_key ...

    location / {
        proxy_pass http://127.0.0.1:5123;   # your Avibe Web UI address

        proxy_set_header Host              $host;
        proxy_set_header X-Forwarded-Host  $host;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Live updates use WebSockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
```

<Warning>
  **Only trust `127.0.0.1` if you are not running the avibe.bot tunnel.**

  The tunnel's `cloudflared` also connects to Avibe from `127.0.0.1`. If you trust loopback while the tunnel is running, a request arriving through the tunnel can forge `X-Forwarded-Host` — reopening exactly the origin-forgery hole that PR #781 closed, this time for your public tunnel.

  If you need **both** a reverse proxy and the tunnel, have nginx reach Avibe over a **non-loopback** address (bind Avibe to a LAN or bridge interface and point nginx there), and register only that address in `VIBE_UI_TRUSTED_PROXY_IPS`. Leave `127.0.0.1` out.
</Warning>

## Verify

Restart Avibe, then load the Web UI on your custom domain and sign in. If you still get `403 invalid origin` or a `503` host mismatch:

* confirm the browser's address matches the host nginx forwards (`$host`);
* confirm the proxy's real source IP is the one you registered — a malformed value is skipped with an `Ignoring invalid VIBE_UI_TRUSTED_PROXY_IPS entry` warning in Avibe's logs;
* confirm you restarted Avibe after setting the variable.

## Upgrading from before PR #781

This is a **breaking change** for self-hosted setups that put Avibe behind a reverse proxy on a custom domain. Before PR #781, Avibe accepted `X-Forwarded-Host` from any source; after it, forwarded hosts are ignored unless the proxy is registered — so an upgrade turns a previously-working custom domain into `403`/`503` until you migrate.

To migrate:

1. Set `VIBE_UI_TRUSTED_PROXY_IPS` to your proxy's IP (see above), minding the loopback/tunnel warning.
2. Make sure nginx forwards `Host`, `X-Forwarded-Host`, and `X-Forwarded-Proto`.
3. Restart Avibe.

The avibe.bot tunnel ([`vibe remote`](/concepts/remote-ui)) is unaffected and needs no changes — it authenticates its own public origin and does not rely on `X-Forwarded-Host`.
