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

# Reverse Tunnel connector configuration

> Configure CodeRabbit Reverse Tunnel Connector with a multi-route configuration file so one connector serves several private destinations, including internal MCP servers.

A single Reverse Tunnel Connector can serve several private destinations at once - the same connector that carries Git traffic can also carry CodeRabbit's calls to an MCP server that has no public address and no inbound firewall rule.

Instead of configuring one route through environment variables, you point the connector at a configuration file that declares every route it should open. Each route gets its own session, its own credentials, and its own origin settings, and one failing route does not affect the others.

<Info>
  MCP access over CodeRabbit Reverse Tunnel was introduced in connector image `20260818224116`. Run that image or a newer one to serve MCP routes; earlier images have no purpose-aware routing.
</Info>

## Before you begin

You need the following before you write a configuration file:

* A route key and a connector token for each destination. CodeRabbit issues these when it provisions a route for your workspace. Contact [CodeRabbit Support](/support) or [CodeRabbit Sales](https://www.coderabbit.ai/contact-us/sales) to have a route provisioned.
* Outbound HTTPS from the connector to the CodeRabbit gateway. No inbound ports are opened.
* HTTPS reachability from the connector to each destination you want to expose.

## Enable the configuration file

Set `REVERSE_TUNNEL_CONFIG_FILE` to the path of your configuration file:

```bash theme={null}
REVERSE_TUNNEL_CONFIG_FILE=/etc/coderabbit/reverse-tunnel/config.yaml
```

Earlier connector images were configured entirely through environment variables and served a single route. That mode still works: if `REVERSE_TUNNEL_CONFIG_FILE` is unset or blank, the connector behaves exactly as before. When the variable is set, the connector loads the file instead and serves every route it declares.

A few properties of the loader are worth knowing:

* Both YAML and JSON are accepted. The examples here use YAML.
* Parsing is strict. An unknown field or a duplicate key is an error, not a warning, which means a typo fails loudly instead of being silently ignored.
* If the file cannot be read or fails validation at startup, the connector exits. It does not fall back to environment variables.

## Configuration schema

### Top level

| Field                                              | Type   | Required | Notes                                                      |
| -------------------------------------------------- | ------ | -------- | ---------------------------------------------------------- |
| <code style={{color: "#FF570A"}}>version</code>    | int    | Yes      | Must be `1`.                                               |
| <code style={{color: "#FF570A"}}>gatewayUrl</code> | string | Yes      | The CodeRabbit gateway address, using the `wss://` scheme. |
| <code style={{color: "#FF570A"}}>connector</code>  | object | No       | Process-wide connector settings.                           |
| <code style={{color: "#FF570A"}}>defaults</code>   | object | No       | Values inherited by every route that does not set its own. |
| <code style={{color: "#FF570A"}}>routes</code>     | array  | Yes      | At least one route is required.                            |

### connector

Settings that apply to the connector process as a whole.

| Field               | Type     | Required | Default              | Notes                                                                                                                                                                  |
| ------------------- | -------- | -------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                | string   | No       | The machine hostname | Give each running replica a unique value.                                                                                                                              |
| `metricsListenAddr` | string   | No       | `127.0.0.1:8092`     | Address for the metrics listener, which serves `/metrics`, `/healthz`, and `/readyz` on this single port. Set to `disabled`, `off`, or `none` to turn the listener off |
| `logLevel`          | string   | No       | `info`               | An invalid value stops the connector at startup.                                                                                                                       |
| `heartbeatInterval` | duration | No       | `30s`                | Advanced. Interval between tunnel heartbeats.                                                                                                                          |
| `handoffTimeout`    | duration | No       | `30s`                | Advanced. How long a session handoff may take.                                                                                                                         |

### defaults

Optional values that every route inherits unless it sets its own. `defaults` holds two blocks, `origin` and `reconnect`.

| Field       | Type   | Notes                                                                                                                             |
| ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------- |
| `origin`    | object | Origin and TLS settings shared by all routes. Accepts `caBundleFile`, `readTimeout`, `connectTimeout`, and `tlsHandshakeTimeout`. |
| `reconnect` | object | Reconnection backoff shared by all routes. Accepts `initial` and `max`.                                                           |

There is no top-level `origin` or `reconnect` key. Both appear only inside `defaults` and inside each route.

#### origin

Origin settings control how the connector connects to your internal destination. They appear in two places: under `defaults.origin`, where they apply to every route, and under `routes[].origin`, where they override the default for that one route. `serverName` and `hostHeader` are route-only and cannot be set under `defaults`.

| Field                 | Type     | Default | Notes                                                                                                           |
| --------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------- |
| `caBundleFile`        | path     | Unset   | Path to a PEM bundle for verifying the destination's certificate. Use this for a private certificate authority. |
| `readTimeout`         | duration | `30s`   | How long the connector waits for the destination to respond.                                                    |
| `connectTimeout`      | duration | `10s`   | Advanced. Connection establishment timeout.                                                                     |
| `tlsHandshakeTimeout` | duration | `10s`   | Advanced. TLS handshake timeout.                                                                                |
| `serverName`          | string   | Unset   | Route only. Overrides the TLS server name used for verification. Must not contain whitespace or newlines.       |
| `hostHeader`          | string   | Unset   | Route only. Overrides the `Host` header sent to the destination. Must not contain whitespace or newlines.       |

#### reconnect

Set these under `defaults.reconnect` to apply to every route, or under `routes[].reconnect` for a single route.

| Field     | Type     | Default | Notes                                                                        |
| --------- | -------- | ------- | ---------------------------------------------------------------------------- |
| `initial` | duration | `2s`    | Initial backoff after a lost session.                                        |
| `max`     | duration | `30s`   | Maximum backoff. If `initial` is greater than `max`, it is lowered to `max`. |

### routes

Each entry in `routes` describes one destination.

| Field           | Type      | Required | Default                             | Notes                                                                                                                                                            |
| --------------- | --------- | -------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`          | string    | Yes      | —                                   | 2 - 32 characters, lowercase letters, digits, and hyphens, starting and ending with a letter or digit. Must be unique. Used in logs, metrics, and health output. |
| `routeKey`      | string    | Yes      | —                                   | The opaque route key CodeRabbit issued for this destination. Must be unique across routes.                                                                       |
| `token`         | string    | Yes      | —                                   | The connector token CodeRabbit issued. This is the only field that accepts an environment variable reference.                                                    |
| `targetBaseUrl` | string    | Yes      | —                                   | The internal address the connector forwards to. Must not embed a username or password.                                                                           |
| `allowedHosts`  | string\[] | Yes      | —                                   | Hosts this route may forward to. Must not be empty.                                                                                                              |
| `origin`        | object    | No       | Inherited from `defaults.origin`    | Per-route origin and TLS settings. See [origin](#origin), including the route-only `serverName` and `hostHeader`.                                                |
| `reconnect`     | object    | No       | Inherited from `defaults.reconnect` | Per-route reconnection backoff. See [reconnect](#reconnect).                                                                                                     |

To keep a token out of the file itself, reference an environment variable as the entire value:

```yaml theme={null}
token: ${GHES_CONNECTOR_TOKEN}
```

This substitution works only for `token`, and only when the reference is the whole value.

`allowedHosts` is matched exactly and case-insensitively. There is no subdomain or glob matching, so `internal.example.com` does not cover `mcp.internal.example.com`. A single `*` entry allows every host.

### Durations and inheritance

Every duration is a string such as `30s`, `5m`, or `15m`, and must be positive. A bare number is rejected.

Settings resolve in this order: the value on the route, then the value under `defaults`, then the built-in default.

## Example configuration

This connector serves two destinations — a GitHub Enterprise Server instance and an internal MCP server — from one process:

```yaml theme={null}
version: 1
gatewayUrl: wss://tunnel.coderabbit.ai

connector:
  id: connector-a
  metricsListenAddr: 127.0.0.1:8092
  logLevel: info

defaults:
  origin:
    caBundleFile: /etc/coderabbit/tls/internal-ca.pem
    readTimeout: 30s

routes:
  - name: ghes
    routeKey: rk_EXAMPLE_GHES_ROUTE_KEY
    token: ${GHES_CONNECTOR_TOKEN}
    targetBaseUrl: https://ghe.internal.example.com
    allowedHosts: [ghe.internal.example.com]

  - name: confluence-mcp
    routeKey: rk_EXAMPLE_MCP_ROUTE_KEY
    token: ${CONFLUENCE_MCP_TOKEN}
    targetBaseUrl: https://confluence.internal.example.com
    allowedHosts: [confluence.internal.example.com]
    origin:
      readTimeout: 15m
```

## MCP route settings

| Requirement         | Detail                                                                                                                                                                                                                                                                                 |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| HTTPS origin        | An MCP route's target must be reachable over HTTPS. Plain-HTTP origins are rejected when the route is created.                                                                                                                                                                         |
| Longer read timeout | Set `origin.readTimeout` to about `15m` for MCP routes. MCP servers pause while a model is working, and the Git default of `30s` cuts those calls short. Keep Git routes at `30s` so they still fail fast.                                                                             |
| Host validation     | Tunnelled requests carry the origin's own host rather than `localhost`. MCP servers that validate the `Host` header reject these with `421 Invalid Host header`. Either add the origin host to the server's allowed hosts, or set `origin.hostHeader` to the value the server expects. |
| Transports          | Streamable HTTP and SSE both work over the tunnel. WebSocket transport is not supported, and CodeRabbit rejects an MCP server URL that resolves to it.                                                                                                                                 |

You do not choose a transport. CodeRabbit derives it from the server URL you register.

## Reload behavior

A file-configured connector re-reads its configuration about every 30 seconds. A connector configured through environment variables never reloads. Polling rather than signalling is what lets a mounted `ConfigMap` change take effect on its own, without an exec or a restart.

| Change                                                                                               | Effect                                                                                      |
| ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| Adding a route                                                                                       | The route starts on the next reload.                                                        |
| Removing a route                                                                                     | The route stops. Other routes keep their sessions.                                          |
| Changing a route's settings                                                                          | That route restarts. Routes that did not change are untouched.                              |
| Rotating a token or CA bundle                                                                        | Applied without a restart.                                                                  |
| Changing `gatewayUrl`, `connector.id`, `metricsListenAddr`, `heartbeatInterval`, or `handoffTimeout` | Requires a restart. The connector logs a warning and keeps running with the previous value. |

If a reload fails to parse or validate, the connector logs the failure and keeps the configuration it is already running. A broken edit does not take down live routes.

## Health and readiness

The connector serves `/healthz` and `/readyz` on the metrics listener. Setting `metricsListenAddr` to `disabled` removes both endpoints along with metrics.

| Endpoint   | Status                                                          | Meaning                                                                                                                                                                        |
| ---------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `/healthz` | Always `200` while the process is alive                         | Liveness only. It stays healthy even when routes are disconnected, so that one unreachable destination cannot restart the container and take down every working route with it. |
| `/readyz`  | `200` when at least one route is connected, `503` when none are | Readiness. Use this to gate traffic, not liveness.                                                                                                                             |

Both endpoints return the same body, so you can see per-route state from either:

```json theme={null}
  {
    "source": "file",
    "connectorId": "connector-a",
    "routesConfigured": 2,
    "routesConnected": 2,
    "routes": [
      { "name": "ghes", "targetBaseUrl": "https://ghe.internal.example.com", "connected": true },
      { "name": "confluence-mcp", "targetBaseUrl": "https://confluence.internal.example.com", "connected": true }
    ]
  }
```

`source` is `file` or `environment`, which is a quick way to confirm that a connector actually picked up the configuration file you intended.

## Recommended topology

Routes in one connector process are isolated from each other, but they still share runtime, credentials, and network egress identity. Running Git and MCP traffic as separate deployments of the same image is the safer default: a restart or a bad configuration edit on the MCP side then cannot disturb pull request reviews.

Use one process for both when the operational simplicity matters more, such as in a small environment or during evaluation.

## What's next

<CardGroup cols={1}>
  <Card title="Connect an MCP server" href="/integrations/mcp-servers" icon="plug" horizontal>
    Add the MCP server in CodeRabbit and set its connection mode to Reverse tunnel.
  </Card>

  <Card title="Reverse Tunnel overview" href="/self-hosted/coderabbit-reverse-tunnel" icon="network" horizontal>
    Review the architecture, components, and traffic paths behind the tunnel.
  </Card>
</CardGroup>
