Environment Variables
The environment variables you set to run a Broch server.
Core Configuration
Section titled “Core Configuration”BROCH_MASTER_KEY, API__WILDCARDHOSTNAME and a database connection are required: the server won’t start without them. Your identity provider is also a boot input: the server starts without it, but no one can sign in until it’s set. The license isn’t a boot input. It’s activated in the app on first sign-in. See Licensing & Billing.
To check a configuration without starting the server, run the image with --check-config. It lists every configuration problem in the environment; on Docker Compose, docker compose run --rm --no-deps broch --check-config.
| Variable | Description | Default | Secret |
|---|---|---|---|
ASPNETCORE_ENVIRONMENT |
ASP.NET Core environment name | Production |
No |
ASPNETCORE_URLS |
HTTP listener binding (TLS terminated at ingress) | — (the image listens on 8080) | No |
BROCH_MASTER_KEY |
At-rest encryption root, at least 32 bytes. Wraps the Data Protection key ring. Generated at provision time or by you, depending on platform — see below | — | Yes |
API__WILDCARDHOSTNAME |
Wildcard hostname for tunnel subdomains (e.g., broch.{your-domain}) |
— | No |
At-Rest Encryption (BROCH_MASTER_KEY)
Section titled “At-Rest Encryption (BROCH_MASTER_KEY)”BROCH_MASTER_KEY is the customer-owned root of Broch’s at-rest encryption. It derives the key-encryption key that wraps the ASP.NET Data Protection key ring, which in turn protects the encrypted IdP refresh tokens, the persisted license token, and usage counters stored in your database. The server will not start without it.
- Generated in your environment. The
broch-deployTerraform modules generate the value: the AWS and Azure modules at provision time, into Secrets Manager or Key Vault; the DigitalOcean module on the Droplet at first boot, into its root-only.env, with a copy on the data volume. On Docker Compose and the Azure and AWS appliances, you generate it once withopenssl rand -base64 48and supply it at deploy time. Docker Compose keeps it in your env file; the appliances store it in Key Vault or Secrets Manager. Either way it stays in your environment, and Broch never receives a copy. See Architecture & Security. - Treat it like a database master password. Keep it in your secret store and back it up there. Together with your database connection, these are the secrets the server strictly requires to start.
- Rotation / loss is recoverable, not catastrophic. If the key is changed or lost, previously wrapped state becomes unreadable; Broch detects this, mints a fresh key ring, and the affected paths self-heal — users re-authenticate, the license token re-activates on the next refresh, and usage counters reset. No instance is ever bricked. Rotating the key therefore forces a one-time re-authentication for signed-in users.
- Unchanged across upgrades. Supply the same
BROCH_MASTER_KEYwhen you upgrade — it lives in your secret store, so this is automatic. The key ring stays readable and nobody re-authenticates. Changing it during an upgrade is what triggers the one-time re-auth above, not the upgrade itself. See Upgrading & Rollback.
On Docker Compose
Section titled “On Docker Compose”.env feeds the compose file, not Broch directly, and the compose file passes Broch only the variables it lists, some under Compose names: see Startup Settings and the rows below. To set any other variable, add it to the broch service’s environment: block or a docker-compose.override.yml, then run docker compose up -d; restart doesn’t apply environment changes.
Database
Section titled “Database”Required — The application will not start without a database connection.
| Variable | Description | Default | Secret |
|---|---|---|---|
DATABASE__PROVIDER |
Database provider (only PostgreSQL is supported) | PostgreSQL |
No |
ConnectionStrings__BrochConnection |
PostgreSQL connection string | — | Yes |
Example: Host=localhost;Database=broch;Username=postgres;Password=secret
Authentication
Section titled “Authentication”Part of the boot floor. Configure your identity provider here. The server starts without it, but no one can sign in until it’s set — there is no in-app bootstrap; the first admin authenticates through the IdP, and admin access is granted by a role in AUTHENTICATION__ADMINROLES. Once any of AUTHENTICATION__PROVIDER, CLIENTID, CLIENTSECRET, TENANTID or DOMAIN is set, Broch refuses to start until the provider, client ID, client secret and the provider’s own values below are all set. It checks after migrating the database, except for an unknown provider, which it refuses at once.
| Variable | Description | Default | Secret |
|---|---|---|---|
AUTHENTICATION__PROVIDER |
Identity provider type: AzureAd, EntraExternalId, Auth0, Okta, or Oidc (any standards-compliant OIDC issuer — set AUTHENTICATION__AUTHORITY) |
— | No |
AUTHENTICATION__CLIENTID |
OAuth client ID from your IdP | — | No |
AUTHENTICATION__CLIENTSECRET |
OAuth client secret from your IdP | — | Yes |
AUTHENTICATION__ADMINROLES |
Comma-separated role names that grant admin access | — | No |
BROCH_AUTH_CONFIG_RESET |
Break-glass: clears the persisted in-app IdP configuration at boot so the environment values above apply again. Set, restart, recover, then remove — see Recovering From a Broken IdP Configuration | — | No |
Provider-Specific Variables
Section titled “Provider-Specific Variables”Entra ID (AzureAd and EntraExternalId):
| Variable | Description | Default |
|---|---|---|
AUTHENTICATION__TENANTID |
Azure tenant ID. Required unless AUTHENTICATION__AUTHORITY is set. |
— |
AUTHENTICATION__INSTANCE |
Login endpoint: https://login.microsoftonline.com/ for AzureAd, https://<tenant>.ciamlogin.com/ for EntraExternalId. Required unless AUTHENTICATION__AUTHORITY is set. |
— |
Auth0:
| Variable | Description | Default |
|---|---|---|
AUTHENTICATION__DOMAIN |
Auth0 domain (e.g., {your-tenant}.auth0.com). Required unless AUTHENTICATION__AUTHORITY is set. |
— |
AUTHENTICATION__AUDIENCE |
Required. Identifier of the Auth0 API your Broch application has User Access to. The server refuses to start without it. See Auth0. | — |
AUTHENTICATION__SCOPES |
Additional OAuth scopes, appended to the always-requested openid,profile,email,offline_access |
— |
Okta:
| Variable | Description | Default |
|---|---|---|
AUTHENTICATION__DOMAIN |
Okta organization domain (e.g., {your-org}.okta.com). Required unless AUTHENTICATION__AUTHORITY is set. |
— |
AUTHENTICATION__SCOPES |
Additional OAuth scopes, appended to the always-requested openid,profile,email,offline_access |
— |
Generic OIDC (Oidc): for any standards-compliant issuer not listed above.
| Variable | Description | Default |
|---|---|---|
AUTHENTICATION__AUTHORITY |
Issuer URL — the base that serves /.well-known/openid-configuration. Required for Oidc. |
— |
AUTHENTICATION__SCOPES |
Additional OAuth scopes, appended to the always-requested openid,profile,email,offline_access |
— |
API & Networking
Section titled “API & Networking”| Variable | Description | Default | Required |
|---|---|---|---|
API__PUBLICIP |
The public IP advertised for automatic DNS records. Empty means the server detects its own egress IP; the appliances set it. Docker Compose: BROCH_PUBLIC_IP. |
— | No |
API__MAXTUNNELS |
Maximum concurrent tunnels. Empty or 0 means unlimited. |
— | No |
API__TRUSTEDPROXYCIDRS |
Trusted reverse-proxy ranges, seeded into the admin setting on first boot. An invalid value is logged and the whole seed skipped. Docker Compose: BROCH_TRUSTED_PROXY_CIDRS. See Configuration → Reverse Proxy |
Loopback only | No |
Licensing & Central Server
Section titled “Licensing & Central Server”The SSH host key for tunnel transport is generated by the server and stored encrypted in your database; it needs no configuration.
| Variable | Description | Default | Required |
|---|---|---|---|
CENTRALSERVER__VALIDATIONTIMEOUTSECONDS |
Timeout for license activation/refresh requests (seconds) | 30 |
No |
Logging (Optional)
Section titled “Logging (Optional)”Structured JSON always goes to stdout — collect it with your container platform’s log driver. A provider is an additional off-box sink, never a replacement for stdout. These variables seed the setting on first boot; after that, Configuration → Logging in the admin app wins.
| Variable | Description | Default | Required |
|---|---|---|---|
BROCHLOGGING__PROVIDER |
Additional log sink: DataDog, Seq, OpenTelemetry |
— (stdout only) | No |
BROCHLOGGING__MINIMUMLEVEL |
Minimum log level: Verbose, Debug, Information, Warning, Error, Fatal |
Information |
No |
DataDog Logging
Section titled “DataDog Logging”| Variable | Description | Default |
|---|---|---|
BROCHLOGGING__DATADOG__APIKEY |
DataDog API key | — |
BROCHLOGGING__DATADOG__SERVICENAME |
DataDog service name tag | broch-server |
BROCHLOGGING__DATADOG__ENVIRONMENT |
DataDog environment tag | production |
BROCHLOGGING__DATADOG__SITE |
DataDog site: datadoghq.com (US) or datadoghq.eu (EU) |
datadoghq.com |
Seq Logging
Section titled “Seq Logging”| Variable | Description | Default |
|---|---|---|
BROCHLOGGING__SEQ__SERVERURL |
Seq server URL | http://localhost:5341 |
OpenTelemetry (OTLP) Logging
Section titled “OpenTelemetry (OTLP) Logging”Routes structured logs to any OTLP-compatible collector — the vendor-neutral path into your SIEM or observability stack.
| Variable | Description | Default |
|---|---|---|
BROCHLOGGING__OTLP__ENDPOINT |
OTLP collector endpoint (e.g., http://collector:4317 for gRPC, http://collector:4318/v1/logs for HTTP) |
— |
BROCHLOGGING__OTLP__PROTOCOL |
OTLP transport: grpc or httpprotobuf |
grpc |
BROCHLOGGING__OTLP__HEADERS |
Comma-separated Key=Value headers sent with every export, for collectors that require authentication (e.g., Authorization=Bearer <token>). Treat as a secret |
— |
Common Configuration Examples
Section titled “Common Configuration Examples”Minimal Docker Compose .env (Bundled Database)
Section titled “Minimal Docker Compose .env (Bundled Database)”The with-postgres variant’s .env, using its Compose names (see On Docker Compose):
BROCH_MASTER_KEY=<openssl rand -base64 48>BROCH_WILDCARD_HOSTNAME=broch.{your-domain}CADDY_ACME_EMAIL=<your-email>CLOUDFLARE_API_TOKEN=<zone-dns-token>POSTGRES_PASSWORD=<openssl rand -base64 32>AUTHENTICATION__PROVIDER=AzureAdAUTHENTICATION__CLIENTID=<your-client-id>AUTHENTICATION__CLIENTSECRET=<your-client-secret>AUTHENTICATION__TENANTID=<your-tenant-id>AUTHENTICATION__INSTANCE=https://login.microsoftonline.com/AUTHENTICATION__ADMINROLES=broch_adminServer Environment with Logging
Section titled “Server Environment with Logging”The server’s own names, for a container you configure directly. The RDS certificate authority isn’t in the system trust store, so mount its bundle and name it in the connection string.
# CoreASPNETCORE_ENVIRONMENT=ProductionASPNETCORE_URLS=http://+:8080BROCH_MASTER_KEY=<generated-value>API__WILDCARDHOSTNAME=broch.{your-domain}
# Database (Managed)DATABASE__PROVIDER=PostgreSQLConnectionStrings__BrochConnection=Host=<rds-endpoint>;Database=broch;Username=<user>;Password=<password>;SSL Mode=VerifyFull;Root Certificate=/etc/broch/db-ca/rds-global-bundle.pem
# AuthAUTHENTICATION__PROVIDER=OktaAUTHENTICATION__DOMAIN={your-org}.okta.comAUTHENTICATION__CLIENTID=<your-client-id>AUTHENTICATION__CLIENTSECRET=<your-client-secret>AUTHENTICATION__ADMINROLES=broch_admin
# LoggingBROCHLOGGING__PROVIDER=DataDogBROCHLOGGING__DATADOG__APIKEY=<your-api-key>BROCHLOGGING__DATADOG__SERVICENAME=broch-prodBROCHLOGGING__DATADOG__ENVIRONMENT=productionSecrets Management
Section titled “Secrets Management”Never commit secrets (license keys, client secrets, connection strings, API keys) to version control. Use your platform’s secure secret storage:
- Docker Compose: the
.envnext todocker-compose.yml, mode600, never committed. Broch reads environment variables only, not Docker secrets files. - Kubernetes: Kubernetes secrets
- Azure: Azure Key Vault
- AWS: AWS Secrets Manager
- DigitalOcean: the Droplet’s root-only
.env
Questions?
Section titled “Questions?”Contact Broch at [email protected] for configuration questions or deployment guidance.