Configuration Reference
Global configuration is provided through environment variables or a YAML config file. When deploying on Kubernetes, use a ConfigMap.
Required Variables
These variables must be set for Outpost to start:
| Variable | Description |
|---|---|
AES_ENCRYPTION_SECRET | 16, 24, or 32 byte key for AES encryption of sensitive data |
API_JWT_SECRET | Secret for signing and verifying JWTs |
API_KEY | API key for authenticating requests to the Outpost API |
REDIS_HOST | Hostname of the Redis server (default: 127.0.0.1) |
REDIS_PORT | Port of the Redis server (default: 6379) |
REDIS_DATABASE | Redis database number (default: 0) |
REDIS_TLS_ENABLED | Optional. Enable TLS for the Redis connection (default: false). |
REDIS_TLS_VERIFY | Optional. Verify the Redis server's TLS certificate against the system CA pool (default: false, i.e. the certificate is not verified). For self-signed certificates, point SSL_CERT_FILE or SSL_CERT_DIR at your CA. |
REDIS_CLUSTER_ENABLED | Optional. Enable Redis cluster mode (default: false). |
REDIS_POOL_SIZE | Optional. Connection pool size per Redis client (per node in cluster mode); default 0 uses go-redis's default of 10 per GOMAXPROCS. Raise it when Redis round-trip latency limits throughput; lower it to shrink the pool on hosts with many CPUs. |
Message Queue
Choose one message queue provider. The selected provider is used for both event delivery and log queues.
RabbitMQ:
| Variable | Description |
|---|---|
RABBITMQ_SERVER_URL | RabbitMQ connection URL (e.g., amqp://user:pass@host/vhost) |
RABBITMQ_EXCHANGE | Exchange name (default: outpost) |
NATS JetStream:
| Variable | Description |
|---|---|
NATS_SERVER_URL | NATS server connection URL (e.g., nats://host:4222) |
NATS_STREAM | Stream name (default: outpost) |
NATS_DELIVERY_SUBJECT | Subject for delivery events (default: outpost.delivery) |
NATS_LOG_SUBJECT | Subject for log events (default: outpost.log) |
NATS_DELIVERY_DLQ | Subject for delivery messages that exhaust all delivery attempts (default: dlq.outpost-delivery) |
NATS_LOG_DLQ | Subject for log messages that exhaust all delivery attempts (default: dlq.outpost-log) |
NATS_DELIVERY_SUBJECT and NATS_LOG_SUBJECT must start with NATS_STREAM followed by a . — the main stream only claims subjects under <stream>.>. NATS servers default max_payload to 1 MiB; raise it in your server configuration if you deliver larger events.
AWS SQS:
| Variable | Description |
|---|---|
AWS_SQS_ACCESS_KEY_ID | AWS Access Key ID (optional; omit to use the AWS SDK default credential chain, e.g. an IAM role) |
AWS_ | AWS Secret Access Key (optional; omit to use the AWS SDK default credential chain, e.g. an IAM role) |
AWS_SQS_REGION | AWS Region |
Whichever way you authenticate, the principal needs these actions on the Outpost queues: sqs:GetQueueUrl, sqs:SendMessage, sqs:ReceiveMessage, sqs:DeleteMessage, and sqs:ChangeMessageVisibility (the batch API variants are covered by the same actions). With auto-provisioning enabled (the default, MQS_AUTO_PROVISION=true), it also needs sqs:CreateQueue and sqs:GetQueueAttributes. If you manage the queues yourself, the first list is sufficient.
GCP Pub/Sub:
| Variable | Description |
|---|---|
GCP_PUBSUB_PROJECT | GCP Project ID |
GCP_ | Service account JSON string or file path |
Azure Service Bus:
| Variable | Description |
|---|---|
AZURE_ | Azure Service Bus namespace |
AZURE_ | Azure Active Directory tenant ID |
AZURE_ | Service principal client ID |
AZURE_ | Service principal client secret |
Publish Queue
Optional. Configures the queue Outpost consumes published events from; see Publishing Events for each provider's variables.
| Variable | Default | Description |
|---|---|---|
PUBLISH_MAX_REDELIVERIES | -1 | Maximum number of times a failed message is redelivered before Outpost stops redelivering it. -1 (or unset) redelivers without limit; 0 never redelivers. It counts attempts, not time: without backoff on the queue, a short outage can use it up. RabbitMQ and Azure Service Bus reject the message (dead-lettered if configured); AWS SQS and GCP Pub/Sub have no reject, so Outpost acks it and it is deleted. Invalid messages are rejected on the first failure regardless on RabbitMQ and Azure Service Bus. A broker-side delivery limit also applies, and the lower one fires first. See the Failed messages section of each publish guide, e.g. Publish from RabbitMQ. |
PUBLISH_PROXY_URL | — | HTTP CONNECT forward proxy for the publish queue connection, e.g. http://user:pass@proxy:8080. Multiple whitespace-separated URLs are tunneled in order. RabbitMQ only; other providers connect directly and ignore it. See Publish from RabbitMQ. |
Log Storage
Choose one for event log persistence:
| Variable | Description |
|---|---|
POSTGRES_URL | PostgreSQL connection URL |
CLICKHOUSE_ADDR | ClickHouse address (e.g., localhost:9000) |
CLICKHOUSE_ | Days to retain event and delivery logs in ClickHouse (default: 0, retained indefinitely). No PostgreSQL equivalent; see the Event & Delivery Log guide. |
Delivery
| Variable | Default | Description |
|---|---|---|
DELIVERY_MAX_CONCURRENCY | 1 | Max concurrent delivery attempts |
DELIVERY_TIMEOUT_SECONDS | 5 | HTTP request timeout for webhook delivery |
MAX_RETRY_LIMIT | 10 | Max retry attempts before giving up |
RETRY_INTERVAL_SECONDS | 30 | Base interval for exponential backoff retries |
RETRY_SCHEDULE | — | Comma-separated retry delays in seconds (overrides interval/limit) |
RETRY_POLL_BACKOFF_MS | 0 (auto) | Maximum time the retry monitor sleeps between polls while idle. 0 sleeps until the next retry comes due, capped at the shorter of 30 seconds and your shortest configured retry delay, so a retry is never late. An explicit positive value is honored as a fixed maximum, which can delay a retry scheduled while the monitor is already sleeping by up to that much. |
Topics
| Variable | Default | Description |
|---|---|---|
TOPICS | — | Comma-separated list of topics your instance supports |
TOPICS_ALLOW_WILDCARDS | false | Allow * inside destination topic subscriptions, such as user.*. When disabled, stored wildcard patterns are ignored but not deleted. |
Portal
| Variable | Default | Description |
|---|---|---|
PORTAL_REFERER_URL | — | Required. URL to redirect users to when JWT expires |
PORTAL_REFRESH_URL | — | URL in your app to silently re-authenticate and generate a new JWT |
PORTAL_ORGANIZATION_NAME | — | Organization name shown in the portal header |
PORTAL_ACCENT_COLOR | — | Primary brand color (hex code, e.g., #6122E7) |
PORTAL_LOGO | — | URL for the light-mode portal logo |
PORTAL_LOGO_DARK | — | URL for the dark-mode portal logo |
PORTAL_FAVICON_URL | — | URL for the portal favicon |
PORTAL_FORCE_THEME | — | Force portal theme: light or dark |
PORTAL_ | false | Remove the "Powered by Outpost" footer |
PORTAL_ | false | Show filter configuration UI per destination |
PORTAL_ | false | Allow tenants to set custom HTTP headers on webhook destinations |
Alerts
| Variable | Default | Description |
|---|---|---|
ALERT_ | 100 | Consecutive delivery failures before alerting on a destination (and disabling it when ALERT_ is true). Leave unset for the default of 100; set to an empty string to disable consecutive-failure alerting entirely. |
ALERT_ | false | Auto-disable a destination once ALERT_ is reached. Has no effect when consecutive-failure alerting is disabled. |
ALERT_ | 3600 | Suppression window (seconds) for exhausted_retries alerts: the first exhaustion per destination alerts and subsequent ones within the window are suppressed (0 = no suppression, alert on every exhaustion). Leave unset for the default of 3600; set to an empty string to disable exhausted_retries alerting entirely. |
Destinations
| Variable | Default | Description |
|---|---|---|
MAX_ | 20 | Maximum destinations each tenant may create. Set as low as is practical for your product to limit abuse and load; lowering this value later does not remove destinations that already exist. |
DESTINATIONS_PROXY_URL | — | HTTP CONNECT forward proxy for destination connections, e.g. http://user:pass@proxy:8080. Multiple whitespace-separated URLs are tunneled in order. Applies to webhook, RabbitMQ and Kafka destinations; other destination types connect directly. The deprecated DESTINATIONS_, when set, takes precedence for webhooks; there is no way to proxy RabbitMQ and Kafka without also proxying webhooks. See Webhook Forward Proxy. |
DESTINATIONS_ | — | Optional. Filesystem path to a directory of custom destination metadata (per-type metadata.json and instructions.md). Non-core fields such as label, description, icon, and instructions can be customized; config_fields and credential_fields cannot be overridden. |
DESTINATIONS_ | outpost | Source set on every event published by AWS EventBridge destinations. Must not be empty or start with aws.. |
Webhook Behavior
| Variable | Default | Description |
|---|---|---|
DESTINATIONS_ | default | Set to standard for Standard Webhooks compliance |
DESTINATIONS_ | — | Deprecated: use DESTINATIONS_PROXY_URL. Forward proxy for webhook deliveries, e.g. http://user:pass@proxy:8080; when set, it overrides DESTINATIONS_PROXY_URL for webhooks. See Webhook Forward Proxy. |
DESTINATIONS_ | x-outpost- / webhook- | Prefix for system webhook headers (event id, topic, timestamp, signature). Unless overridden, defaults to x-outpost- when DESTINATIONS_ is default and webhook- when standard. |
DESTINATIONS_ | — | Complete name of the event ID header. Unset uses the default <prefix>event-id; an explicit value pins that exact name; an empty string disables the header. Only applies to default mode. |
DESTINATIONS_ | — | Complete name of the signature header. Unset uses the default <prefix>signature; an explicit value pins that exact name; an empty string disables the header. Only applies to default mode. |
DESTINATIONS_ | — | Complete name of the timestamp header. Unset uses the default <prefix>timestamp; an explicit value pins that exact name; an empty string disables the header. Only applies to default mode. |
DESTINATIONS_ | — | Complete name of the topic header. Unset uses the default <prefix>topic; an explicit value pins that exact name; an empty string disables the header. |
DESTINATIONS_ | rfc3339 / unix | Format of the timestamp header: rfc3339, unix (seconds since the epoch) or iso8601_milli_no_offset (UTC with milliseconds and no offset, e.g. 2026-10-05T15:02:25.447). Only applies to default mode. |
DESTINATIONS_ | hmac-sha256 | Signature algorithm. Only applies to default mode. |
DESTINATIONS_ | hex | Encoding: hex or base64. Only applies to default mode. |
DESTINATIONS_ | raw | How the HMAC key is derived from the destination secret: raw uses the secret string as-is, base64 and hex decode it. Only applies to default mode. |
DESTINATIONS_ | — | Prefix stripped from the destination secret before decoding, e.g. whsec_. Ignored when the secret encoding is raw. Only applies to default mode. |
DESTINATIONS_ | — | Name of the compat signature header. Setting it enables the compat signature: a second signature in your previous format, sent alongside the primary one while receivers migrate. See Change Webhook Signature Scheme. |
DESTINATIONS_ | {{.Body}} | Template for the content signed by the compat signature |
DESTINATIONS_ | v0={{.Signatures | join ","}} | Template for the compat signature header value |
DESTINATIONS_ | hex | Compat signature encoding: hex or base64 |
DESTINATIONS_ | hmac-sha256 | Compat signature algorithm |
DESTINATIONS_ | raw | How the compat signature derives its HMAC key from the destination secret: raw, base64 or hex |
DESTINATIONS_ | — | Prefix stripped from the destination secret before decoding for the compat signature |
DESTINATIONS_ | — | Extra headers sent with the compat signature, as comma-separated name=template pairs ({{.EventID}}, {{.Topic}}, {{.Timestamp}}). \, is a literal comma. |
DESTINATIONS_ | 131072 (128 KiB) | Max bytes of a destination response body stored on the delivery attempt. Larger responses are replaced with a placeholder so the attempt log stays under the event queue's per-message size limit. Set to 0 to disable the cap. |
Supervisor
The supervisor can restart a worker whose run fails, such as a queue consumer losing its connection to the broker. Restarts are off by default: a worker is reported failed on its first failure and /healthz returns HTTP 503 until the process restarts.
To turn restarts on, list the workers in SUPERVISOR_, for example SUPERVISOR_. The workers that support restarts are:
publishmq: the publish queue consumer, shown aspublishmq-consumerin/healthzdeliverymq: the delivery queue consumer, shown asdeliverymq-consumerlogmq: the log queue consumer, shown aslogmq-consumerretrymq: the retry scheduler, shown asretrymq-consumer
The HTTP server (http-server) is never restarted: it fails when it can't bind its port, which a restart doesn't fix.
The limits cover a worker's runs, which start by subscribing to the queue. Connecting to the internal queues when Outpost boots happens before the workers start: if it fails, the process exits, whatever these settings are.
With restarts on, /healthz reports a failing worker as degraded (HTTP 200) while it is within its restart budget. Once the budget is spent, it reports failed (HTTP 503). The supervisor keeps restarting a failed worker every 60 seconds, so it returns to healthy once the cause is fixed, without a process restart.
A worker is healthy again once a restarted run has stayed connected for 30 seconds. Until then it keeps its degraded or failed status, so /healthz can return 503 for up to 30 seconds after the worker has recovered. If a liveness probe checks /healthz, allow for that in its failure threshold.
A worker is in the startup phase until it has stayed connected for 30 seconds once, and in the recovery phase after that. Each phase has two limits, and the first one reached ends the budget. -1 disables a limit. Restarts back off from 1 second, doubling up to 60 seconds.
| Variable | Default | Description |
|---|---|---|
SUPERVISOR_ | empty | Comma-separated names of the workers to restart instead of reporting them failed at once. An unknown name fails startup. |
SUPERVISOR_ | 5 | Restarts allowed in the startup phase. With the backoff, 5 reports a worker that can't start as failed about 31 seconds after its first failure, plus the time each failed attempt takes. |
SUPERVISOR_ | -1 | In the startup phase, the worker is reported failed if no restart has succeeded within this many seconds of its first failure. |
SUPERVISOR_ | -1 | Restarts allowed in the recovery phase. |
SUPERVISOR_ | 120 | In the recovery phase, the worker is reported failed if no restart has succeeded within this many seconds of its first failure. Restarts are at most 60 seconds apart, so a broker that is back after 70 seconds may not be retried until after this limit: allow for that when you set it. |
These timings assume a failed run ends quickly. With restarts on, a queue consumer ends a run after 3 consecutive receive errors instead of 10. The retry scheduler keeps retrying Redis for about a minute inside each run, so during a Redis outage it shows degraded after about a minute and reaches failed later than the limits suggest: about 3 to 3.5 minutes in recovery and about 6 minutes at startup with the defaults.
Each listed worker can override any of these limits. Replace <WORKER> with the worker's name in uppercase, for example SUPERVISOR_. An unset override inherits the global value. Overrides only apply to workers listed in SUPERVISOR_; for other workers they have no effect.
| Variable | Overrides |
|---|---|
SUPERVISOR_ | SUPERVISOR_ |
SUPERVISOR_ | SUPERVISOR_ |
SUPERVISOR_ | SUPERVISOR_ |
SUPERVISOR_ | SUPERVISOR_ |
Setting a listed worker's four limits to -1 keeps its failures from ever failing /healthz. For example, with all four SUPERVISOR_PUBLISHMQ_* limits at -1, the publish queue consumer is still restarted and shows as degraded with the error in the logs, but your orchestrator won't restart or unroute the instance because of it.
Observability
| Variable | Description |
|---|---|
OTEL_SERVICE_NAME | Enables OpenTelemetry when set. All three signals (traces, metrics, and logs) are exported by default; see OpenTelemetry for per-signal control |
LOG_LEVEL | Log verbosity: trace, debug, info, warn, error (default: info) |
DISABLE_TELEMETRY | Set to true to disable anonymous usage telemetry to Hookdeck |
YAML Configuration
All environment variables can also be specified in a YAML config file using snake_case keys:
aes_encryption_secret: "your-secret-here"
api_jwt_secret: "your-jwt-secret"
api_key: "your-api-key"
topics: "user.created,user.updated,order.placed"
redis:
host: "127.0.0.1"
port: 6379
database: 0
# Choose one message queue:
rabbitmq:
server_url: "amqp://user:pass@localhost/vhost"
delivery:
max_concurrency: 5
timeout_seconds: 10
portal:
referer_url: "https://yourapp.com/settings/webhooks"
organization_name: "Acme Corp"
accent_color: "#6122E7"
alert:
consecutive_failure_count: 50
exhausted_retries_window_seconds: 3600
supervisor:
restart_workers:
- publishmq
- deliverymq
startup:
max_attempts: 5
max_duration_seconds: -1
recovery:
max_attempts: -1
max_duration_seconds: 120
workers:
publishmq:
recovery:
max_duration_seconds: 300