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

# Running VARIOS AI Behind a Reverse Proxy

> Publish VARIOS AI through an existing reverse proxy of your company, for example with client certificate authentication

Many companies publish internal applications through a central reverse proxy that terminates HTTPS and enforces additional access controls such as client certificates. VARIOS AI can run behind such a proxy. This page describes what VARIOS AI expects from the proxy and which changes to `docker-compose.yml` are required.

> [!NOTE]
>
> Every proxy environment is set up differently. The configuration examples on this page use nginx and illustrate the requirements of VARIOS AI. Apply them accordingly to your product, for example Apache, HAProxy, F5 or a web server with its own proxy module.

## Architecture

```text theme={null}
Browser ──HTTPS──▶ Reverse proxy ──HTTPS or HTTP──▶ Traefik (VARIOS AI server) ──▶ VARIOS AI
```

* The domain in `PROJECT_DOMAIN` resolves in DNS to the **reverse proxy**, not to the VARIOS AI server.
* The reverse proxy presents the certificate your users see and checks client certificates if required.
* Traefik stays in place on the VARIOS AI server and receives the requests from the proxy.
* The VARIOS AI server does not need a publicly trusted certificate. Let's Encrypt is disabled.

## Reverse proxy requirements

| Requirement | Background |
| - | - |
| **Domain identical to `PROJECT_DOMAIN`** | VARIOS AI builds links, the WebSocket address `wss://<PROJECT_DOMAIN>/ws` and the sign-in redirect from this value. The proxy must serve VARIOS AI via HTTPS under exactly this domain. |
| **Pass the `Host` header unchanged** | Traefik routes requests using the rule ``Host(`${PROJECT_DOMAIN}`)``. If a different host arrives, Traefik responds with `404`. |
| **Allow WebSocket on `/ws`** | Chat responses are delivered via WebSocket. The proxy must pass through the HTTP upgrade (`Upgrade` and `Connection` headers, HTTP/1.1). |
| **Long timeouts** | Language model responses can take several minutes. VARIOS AI itself waits up to 3600 seconds. Set the proxy's read and send timeouts to the same value. |
| **Upload size** | VARIOS AI accepts requests up to 512 MB, for example for knowledge base documents. A lower limit on the proxy causes large uploads to fail with `413`. |
| **No response buffering** | Streamed responses should reach the browser without delay. Disable response buffering on the proxy for VARIOS AI. |

VARIOS AI evaluates `X-Forwarded-*` headers; `docker-compose.yml` already sets `FLOW_HTTP_TRUSTED_PROXIES: "*"` for this. How these headers pass through Traefik depends on the connection you choose, see below.

## Adjusting the VARIOS AI server

Choose how the reverse proxy reaches Traefik. We recommend **HTTPS on port 443**: traffic on the network stays encrypted and the fewest changes are required.

**HTTPS on port 443 (recommended)**

The proxy forwards to `https://<VARIOS AI server>:443`. Traefik sets `X-Forwarded-Proto: https` itself because the connection arrives via HTTPS.

**1. Disable Let's Encrypt on the router**

Remove the certificate resolver label from the `php` service. All other labels stay unchanged:

```yaml docker-compose.yml theme={null}
php:
  [...]
  labels:
    - "traefik.enable=true"
    # removed: traefik.http.routers.variosai.tls.certresolver=le
    - "traefik.http.routers.variosai.tls=true"
    - "traefik.http.routers.variosai.rule=Host(`${PROJECT_DOMAIN}`)"
    - "traefik.http.routers.variosai.entrypoints=websecure"
    - "traefik.http.services.variosai.loadbalancer.server.port=80"
    - "traefik.http.routers.http-variosai.middlewares=redirect-https"
    - "traefik.http.routers.http-variosai.rule=Host(`${PROJECT_DOMAIN}`)"
    - "traefik.http.routers.http-variosai.entrypoints=web"
    - "traefik.http.middlewares.redirect-https.redirectscheme.scheme=https"
    - "traefik.http.middlewares.redirect-https.redirectscheme.permanent=true"
```

Without a certificate of its own, Traefik serves its self-signed default certificate (`TRAEFIK DEFAULT CERT`). The proxy must either accept this certificate without verification, or you provide a certificate from your internal CA that the proxy trusts, see [Configuring a Custom HTTPS Certificate](https://docs.varios-ai.com/en/monthly/security/traefik-certificates.md).

**2. Optional: keep client IP addresses**

Traefik discards `X-Forwarded-For` from unknown senders. Without further configuration, logs therefore show the proxy's IP address instead of the user's. To make Traefik accept the proxy's headers, add the proxy's IP address to the `command` block of the `traefik` service:

```yaml docker-compose.yml theme={null}
traefik:
  command:
    [...]
    - "--entrypoints.websecure.address=:443"
    - "--entrypoints.websecure.forwardedHeaders.trustedIPs=<proxy IP address>"
```

Separate multiple addresses or networks with commas, for example `10.0.0.5,10.0.1.0/24`.

**3. Apply the changes**

```bash theme={null}
docker compose up -d
```

**HTTP on port 80**

The proxy forwards unencrypted to `http://<VARIOS AI server>:80`. Only use this option if the network path between the proxy and the VARIOS AI server is trusted.

**1. Remove the HTTPS redirect**

In the default configuration, the `http-variosai` router redirects every request to HTTPS. Behind a proxy that forwards via HTTP, this causes an endless redirect loop. Remove the redirect and the certificate resolver from the `php` service:

```yaml docker-compose.yml theme={null}
php:
  [...]
  labels:
    - "traefik.enable=true"
    # removed: traefik.http.routers.variosai.tls.certresolver=le
    - "traefik.http.routers.variosai.tls=true"
    - "traefik.http.routers.variosai.rule=Host(`${PROJECT_DOMAIN}`)"
    - "traefik.http.routers.variosai.entrypoints=websecure"
    - "traefik.http.services.variosai.loadbalancer.server.port=80"
    # removed: traefik.http.routers.http-variosai.middlewares=redirect-https
    - "traefik.http.routers.http-variosai.rule=Host(`${PROJECT_DOMAIN}`)"
    - "traefik.http.routers.http-variosai.entrypoints=web"
    # removed: traefik.http.middlewares.redirect-https.redirectscheme.scheme=https
    # removed: traefik.http.middlewares.redirect-https.redirectscheme.permanent=true
```

**2. Accept forwarded headers from the proxy**

Traefik replaces `X-Forwarded-Proto` from unknown senders with its own protocol, in this case `http`. VARIOS AI would then assume it is being accessed via HTTP. Add the proxy's IP address to the `command` block of the `traefik` service so that Traefik accepts its headers:

```yaml docker-compose.yml theme={null}
traefik:
  command:
    [...]
    - "--entrypoints.web.address=:80"
    - "--entrypoints.web.forwardedHeaders.trustedIPs=<proxy IP address>"
```

Separate multiple addresses or networks with commas, for example `10.0.0.5,10.0.1.0/24`.

> [!WARNING]
>
> Without this step, the proxy still has to send `X-Forwarded-Proto: https`, but Traefik overwrites the value. Sign-in redirects to `http://` are the result.

**3. Apply the changes**

```bash theme={null}
docker compose up -d
```

If Let's Encrypt is no longer used at all, you can also remove the `--certificatesresolvers.le.*` options from the `command` block of the `traefik` service.

> [!WARNING]
>
> Use a firewall to restrict access to ports 80 and 443 of the VARIOS AI server to the reverse proxy. Otherwise users can bypass the proxy, and with it the client certificate check, by connecting to the server directly.

## Example configuration for nginx

The example shows nginx as a reverse proxy with client certificate verification and forwarding via HTTPS. Replace the domain, certificate paths and server address with your values.

```nginx /etc/nginx/conf.d/varios-ai.conf theme={null}
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 443 ssl;
    server_name varios.example.com;

    ssl_certificate     /etc/nginx/certs/varios.example.com.crt;
    ssl_certificate_key /etc/nginx/certs/varios.example.com.key;

    # Verify client certificates
    ssl_client_certificate /etc/nginx/certs/client-ca.pem;
    ssl_verify_client on;

    client_max_body_size 512M;

    location / {
        proxy_pass https://<VARIOS-AI-server>;
        proxy_ssl_server_name on;
        proxy_ssl_name varios.example.com;
        proxy_ssl_verify off;

        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_buffering off;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}
```

`proxy_ssl_verify off` is only needed while Traefik serves its default certificate. If you have configured a certificate from your internal CA in Traefik, set `proxy_ssl_verify on` instead and point `proxy_ssl_trusted_certificate` to that CA.

## Access without a client certificate

With client certificate authentication, only devices with a deployed certificate can reach VARIOS AI. Some requests, however, do not come from a user's browser. Check which of them are used in your installation:

| Access | Path | Affected if | Solution |
| - | - | - | - |
| **Sign-in via Entra ID or Keycloak** | `/login`, `/oauth2` | Not affected: after sign-in, the browser returns to VARIOS AI with its certificate. | – |
| **User synchronization from Entra ID** | `/scim` | `SCIM_DIRECTION=push`: Entra ID sends from the Microsoft cloud and cannot present a client certificate. | Exempt the `/scim` path from the certificate requirement or switch to `SCIM_DIRECTION=pull`, see [Microsoft Entra ID](https://docs.varios-ai.com/en/monthly/installation/microsoft-entra-id.md). |
| **API access with API keys** | `/api` | External systems such as the [n8n node](https://docs.varios-ai.com/en/monthly/installation/n8n-node.md) or your own scripts call the API. | Issue a client certificate to these systems. An exception for `/api` opens the entire API, which the user interface also uses. |
| **Office add-ins** | `/office` and the remaining paths | Outlook and Word load the add-ins in their own browser component. Whether it presents the client certificate depends on the Office version and operating system. | Test on all platforms in use before rollout. |
| **Keycloak behind the same proxy** | Keycloak domain | VARIOS AI calls Keycloak server-side via `OIDC_CONFIGURATION_URL` and does not present a client certificate. | Publish the Keycloak domain without the certificate requirement or give VARIOS AI an internal route to Keycloak. |

In nginx, you can implement an exception for a single path with `ssl_verify_client optional`. The check then happens per `location`:

```nginx theme={null}
ssl_verify_client optional;

location /scim/ {
    # no client certificate, protected by SCIM_TOKEN
    proxy_pass https://<VARIOS-AI-server>;
    # [...] same proxy_* settings as in location /
}

location / {
    if ($ssl_client_verify != SUCCESS) {
        return 403;
    }
    proxy_pass https://<VARIOS-AI-server>;
    # [...]
}
```

## Verification

**1. Access through the proxy**

Open `https://<PROJECT_DOMAIN>` on a device with a client certificate and sign in.

> [!TIP]
>
> After signing in, you land on `https://<PROJECT_DOMAIN>` again, not on `http://` or an internal address.

**2. WebSocket**

Ask a question in the chat.

> [!TIP]
>
> The response appears continuously. In the browser's developer tools, the **Network** tab shows status `101` for `wss://<PROJECT_DOMAIN>/ws`.

**3. Direct access blocked**

From a workstation, open `https://<VARIOS AI server>` directly.

> [!TIP]
>
> The firewall rejects the connection.

## Troubleshooting

| Symptom | Cause | Solution |
| - | - | - |
| `404 page not found` from Traefik | The proxy forwards a different `Host` header | Pass the `Host` header unchanged, in nginx `proxy_set_header Host $host` |
| Browser stops with "too many redirects" | The proxy forwards via HTTP and Traefik redirects back to HTTPS | Remove the `redirect-https` redirect, see the **HTTP on port 80** tab |
| Redirect to `http://` after sign-in | `X-Forwarded-Proto` does not reach VARIOS AI as `https` | When forwarding via HTTP, set `forwardedHeaders.trustedIPs` on the `web` entrypoint |
| Chat responses do not appear or only at the end | The WebSocket upgrade is blocked or responses are buffered | Set the `Upgrade`/`Connection` headers and HTTP/1.1, disable buffering |
| Long responses stop after about 60 seconds | Default proxy timeout | Increase the read and send timeouts to 3600 seconds |
| Uploading large files fails with `413` | Proxy upload limit too low | Raise the limit to 512 MB, in nginx `client_max_body_size` |
| `unable to generate TLS certificate` in the Traefik log | Let's Encrypt resolver still active | Remove the `tls.certresolver=le` label from the `php` service |
| Proxy reports TLS handshake errors with Traefik | The proxy verifies Traefik's default certificate, or sends no SNI while `sniStrict` is active | Disable verification or provide an internal certificate; enable SNI, in nginx `proxy_ssl_server_name on` |
| User synchronization from Entra ID fails | The proxy requires a client certificate for `/scim` | Add an exception for `/scim` or use `SCIM_DIRECTION=pull` |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.