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

# Configuration Reference

> Every Conduit environment variable.

All configuration beyond these environment variables — identity providers,
connectors, email, telemetry exporters, access policies — is managed in the
admin UI and stored in Conduit's database.

## Core

| Variable | Default | Description |
| - | - | - |
| `CONDUIT_BASE_URL` | `http://localhost:7272` | Externally reachable URL of the instance. Used for OAuth callbacks and MCP discovery — set it to the address users and AI clients actually reach. |
| `CONDUIT_ADDR` | `:7272` | Listen address. |
| `CONDUIT_DATA_DIR` | `/data` (Docker) | Directory for the embedded database and generated encryption key. Mount a volume here. |
| `CONDUIT_DATABASE_URL` | unset | Storage backend selector. Unset runs the embedded database in the data directory (the default). A `postgres://` URL runs Conduit on an operator-supplied PostgreSQL (14 or newer) instead — required for multi-replica deployments, and requires `CONDUIT_ENCRYPTION_KEY` (plus `CONDUIT_ADMIN_PASSWORD` until setup completes). |
| `CONDUIT_DATABASE_MAX_CONNS` | CPU-derived | Maximum PostgreSQL connections per instance. |
| `CONDUIT_DATABASE_AUTH` | unset | How Conduit authenticates to `CONDUIT_DATABASE_URL`. Unset uses the credentials in the URL. `rds-iam` authenticates to AWS RDS or Aurora with IAM: each new connection uses a short-lived token minted from the AWS identity the instance runs as, and the URL carries no password — see [Deployment Tiers](/docs/conduit/deploy/availability#iam-authentication-on-aws). With `rds-iam` the URL's `sslmode` must leave no plaintext path (`verify-full` recommended; `prefer`, the default, is refused). An invalid value, or a URL that could connect unencrypted, refuses to boot. |
| `CONDUIT_WORKSPACE_MODE` | `single` | `single` (one workspace — the self-host default) or `multi` (many workspaces/tenants). Fixed per deployment; an invalid value refuses to boot. |

## Bootstrap admin

| Variable | Default | Description |
| - | - | - |
| `CONDUIT_ADMIN_EMAIL` | `admin@localhost` | Email for the first-run bootstrap sign-in. After setup, when set together with the password, also acts as a break-glass recovery login for the bootstrap admin. In a multi-workspace deployment, keep it at a domain no workspace verifies: the login page sends an email at a verified domain to that workspace's provider, and offers the password field only when that provider can't be reached. |
| `CONDUIT_ADMIN_PASSWORD` | random, printed to logs | Password for the first-run bootstrap sign-in. Leave both unset after setup for normal operation. |

## Security

| Variable | Default | Description |
| - | - | - |
| `CONDUIT_ENCRYPTION_KEY` | unset | 32-byte key (base64 or hex) for encrypting stored secrets. When unset, a key is auto-generated at `<data-dir>/conduit.key` on first boot — back it up; secrets are unrecoverable without it. Setting the variable keeps the key out of the data volume and its backups. |
| `CONDUIT_TLS_CERT_FILE` | unset | TLS certificate for native TLS termination. Must be set together with the key file; otherwise run behind a TLS-terminating proxy. |
| `CONDUIT_TLS_KEY_FILE` | unset | TLS private key, paired with the certificate file. |
| `CONDUIT_TRUSTED_PROXIES` | loopback only | Comma-separated reverse-proxy IPs and CIDRs whose `X-Forwarded-For` / `X-Real-Ip` headers are trusted for client-IP attribution and per-IP rate limiting. **Set this if a reverse proxy fronts your instance** — see [Client IP attribution](#client-ip-attribution). Set to an empty value to trust no proxy. |
| `CONDUIT_CSP` | `enforce` | Content-Security-Policy delivery for the web UI: `enforce`, `report-only`, or `off`. An invalid value refuses to boot. |
| `CORS_ALLOWED_ORIGINS` | unset | Comma-separated origins allowed to call the API cross-origin. Leave unset unless you serve the UI from a different origin. |
| `CONDUIT_DISABLE_API_CLIENTS` | `false` | Instance-wide kill switch for workspace API clients: after restart, no client can mint a token and existing machine tokens are rejected instance-wide. Break-glass control for a suspected compromise; per-client disable (in workspace settings) is the everyday control. |
| `CONDUIT_SAFEHTTP_ALLOWED_PRIVATE_HOSTS` | unset | Exact hostnames of trusted services that resolve to private addresses — a private endpoint or gateway such as AWS PrivateLink, an enterprise egress proxy, or an MCP server on your own network — exempted from outbound SSRF protection. HTTPS is still required. See [Outbound requests](#outbound-requests). |
| `CONDUIT_SAFEHTTP_ALLOW_LOCALHOST` | `false` | Development only: allows plain-HTTP loopback for outbound connections (e.g. a local identity provider). Never enable in production. See [Outbound requests](#outbound-requests). |

Which MCP clients may connect is not an instance setting: each workspace
decides it in Settings → MCP Clients (see
[Governing connected clients](/docs/conduit/use/mcp-authorization#governing-connected-clients)).
An instance that sets `CONDUIT_CIMD_ALLOWED_DOMAINS` refuses to boot until the
variable is unset, since it would otherwise admit every URL-based client the
operator meant to restrict.

### Client IP attribution

Conduit records a client IP on audit-log entries and keys its per-IP rate limits
(sign-in, sign-up, OAuth, failed MCP auth) on it. `X-Forwarded-For` and
`X-Real-Ip` are set by whoever sends the request, so Conduit honors them **only
when the connection's peer address is a proxy you have declared** in
`CONDUIT_TRUSTED_PROXIES`. Otherwise it uses the peer address and logs a warning
once per process.

By default Conduit trusts loopback only (`127.0.0.0/8` and `::1`). Because
Conduit runs in a container, a loopback peer is by definition inside its own
network namespace: Conduit itself, or a sidecar sharing the pod — the
service-mesh topology, where the mesh proxy forwards over loopback. A pod-mate
can already read Conduit's environment and service account, so trusting its
forwarded header grants nothing extra; the pod is the unit of trust.

If you run the Conduit binary directly on a host with other users or processes,
that no longer holds — any local process could forge the header. Set
`CONDUIT_TRUSTED_PROXIES=` (empty) there to trust nothing.

**Every other proxy needs configuring, including in-cluster ones.** A Kubernetes
ingress controller and a `docker run -p` bridge gateway both arrive from a
private-range address, which Conduit does not trust by default because an
attacker's pod or another host on the same network is indistinguishable from
them.

The value is a comma-separated list of IPv4/IPv6 addresses and CIDR ranges. It
**replaces** the loopback default rather than adding to it, so list `127.0.0.0/8`
and `::1/128` too if you need both. Unparseable entries are ignored.

### What to set

| Your deployment | Value |
| - | - |
| No proxy — direct, or [native TLS](#security) | leave unset |
| A proxy sidecar in the same pod | leave unset (it arrives over loopback) |
| Kubernetes ingress controller | your pod CIDR, e.g. `10.42.0.0/16` |
| `docker run -p` behind a proxy on the host | the Docker bridge subnet, e.g. `172.17.0.0/16` |
| docker-compose with a proxy service | the compose network subnet, e.g. `172.18.0.0/16` |
| Behind a CDN or WAF | the provider's published egress ranges |
| The binary on a host shared with other users | empty (`CONDUIT_TRUSTED_PROXIES=`) |

There is deliberately no shorthand for "all private ranges" or "everything".
Trusting a whole private range is the misconfiguration this setting exists to
prevent — on a Kubernetes cluster without NetworkPolicies, a Docker bridge, or an
office LAN, it trusts every peer that shares the network, including one an
attacker controls. Trusting everything is worse still: it would leave only the
attacker-controlled end of the forwarded chain to read.

### Finding your proxy's address

You don't have to guess. Start Conduit, send a request through your proxy, and
read the warning it logs:

```
WARN ignoring forwarded client-IP header from an untrusted peer; if a reverse
     proxy fronts this instance, list its address in CONDUIT_TRUSTED_PROXIES
     peer=10.42.3.17
```

That `peer=` value is your proxy. Trust the range it belongs to — proxy pods and
containers get new addresses when they restart, so use the CIDR rather than the
single address you happened to see:

```bash theme={null}
# Kubernetes: the cluster's pod CIDR
kubectl cluster-info dump | grep -m1 cluster-cidr

# Docker: the subnet of the network Conduit is attached to
docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
```

If you never see that warning, nothing is sending forwarded headers and there is
nothing to configure.

### Two consequences worth knowing

* **If a proxy fronts your instance and you don't configure it,** every request
  resolves to that proxy's address. Audit entries all show one IP, and each
  per-IP rate limit becomes a single instance-wide bucket — enough to throttle
  legitimate sign-ins during a login spike.
* **List your proxy chain, and nothing beyond it.** Conduit walks the forwarded
  chain right to left and returns the first address that is *not* trusted. So
  every intermediary must be listed for the walk to reach the real client — with
  a load balancer in front of your ingress controller, list both — while an
  address that *is* listed can never be reported as a client. Trusting a range
  that contains real users silently attributes their requests to the proxy.

### Outbound requests

Every request Conduit makes to another service goes through one hardened HTTP
client that blocks private and other special-use addresses, refuses redirects,
and requires `https`. The two variables above are its only exemptions.

[Network Access](/docs/conduit/deploy/network) is the full picture: every host Conduit
connects to, what each is used for, and when it is contacted.

## Documentation

| Variable | Default | Description |
| - | - | - |
| `CONDUIT_DOCS_DIR` | `/srv/docs` (Docker) | Directory of the embedded docs site, served at `/docs/`. The Docker image ships the docs matching its version. |
| `CONDUIT_DOCS_URL` | `https://pipedream.com/docs/conduit` | Where `/docs/` requests redirect when no embedded docs directory is present. In the `cloud` edition, pages only the self-hosted edition has also redirect here. |
| `CONDUIT_DOCS_EDITION` | `self-hosted` | Which edition of the embedded docs `/docs/` serves: `self-hosted` (the full docs) or `cloud` (without the pages about running the instance). Any other value refuses to boot. |

## Observability

| Variable | Default | Description |
| - | - | - |
| `CONDUIT_LOG_LEVEL` | `info` | Console log level: `debug`, `info`, `warn`, or `error`. |
| `CONDUIT_LOG_FORMAT` | `text` | Console log format: `text` or `json`. |
| `CONDUIT_OTEL_EXPORTER_NAME` | `Environment` | Display name for an OpenTelemetry exporter configured via the standard `OTEL_EXPORTER_OTLP_*` variables (which Conduit honors alongside exporters configured in the admin UI). |
| `CONDUIT_OTEL_LOG` | unset | Set to `1` to echo traces and events to stderr for local debugging. |
| `CONDUIT_DEBUG_ADDR` | unset | Starts a second listener serving Go pprof profiles and runtime/DB-pool stats (`/debug/pprof/`, `/debug/vars`) for profiling and load analysis. Unauthenticated — bind it to localhost or a private interface only (e.g. `localhost:6060`), never a public address. |
| `CONDUIT_METRICS_ADDR` | unset | Starts a dedicated listener serving Prometheus metrics at `/metrics` (e.g. `0.0.0.0:9464`). Unauthenticated — restrict access by network position and never expose it publicly. See [Monitoring](/docs/conduit/deploy/monitoring). |

## Data retention

| Variable | Default | Description |
| - | - | - |
| `CONDUIT_USAGE_RAW_RETENTION_DAYS` | `30` | How long raw tool-call usage rows are kept (the recompute window for aggregates). |
| `CONDUIT_USAGE_AGG_RETENTION_DAYS` | `365` | How long usage aggregates — what the dashboards read — are kept. |

## Conduit CLI

The CLI setup UI is feature-flagged and hidden by default.

Read by the `conduit` CLI on users' machines, not by the server.

| Variable | Default | Description |
| - | - | - |
| `CONDUIT_TOKEN` | unset | Bearer token override for the CLI. Set together with `CONDUIT_BASE_URL` in CI/headless contexts to skip the `conduit login` step; otherwise the CLI uses its stored credentials. |
| `CONDUIT_NO_BROWSER` | unset | Set to `1` to stop `conduit login` from opening a browser (headless/SSH hosts); the verification URL and code are still printed. |
| `CONDUIT_MCP_RESUME` | unset | Internal handshake between a running `conduit mcp` and the upgraded binary it re-execs into (the MCP session resumes without a client restart). Never set it yourself. |

## Internal

| Variable | Default | Description |
| - | - | - |
| `CONDUIT_WEB_DIR` | `/srv/web` (Docker) | Directory of the built web UI. Only relevant when running the binary outside the Docker image. |
| `CONDUIT_CLI_DIR` | `/srv/cli` (Docker) | Directory of the prebuilt `conduit` CLI binaries served under `/cli/` with the install script. Absent (e.g. a source checkout) the CLI install path on the home page reports itself unavailable. |
