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:

VariableDescription
AES_ENCRYPTION_SECRET16, 24, or 32 byte key for AES encryption of sensitive data
API_JWT_SECRETSecret for signing and verifying JWTs
API_KEYAPI key for authenticating requests to the Outpost API
REDIS_HOSTHostname of the Redis server (default: 127.0.0.1)
REDIS_PORTPort of the Redis server (default: 6379)
REDIS_DATABASERedis database number (default: 0)
REDIS_TLS_ENABLEDOptional. Enable TLS for the Redis connection (default: false).
REDIS_TLS_VERIFYOptional. 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_ENABLEDOptional. Enable Redis cluster mode (default: false).
REDIS_POOL_SIZEOptional. 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:

VariableDescription
RABBITMQ_SERVER_URLRabbitMQ connection URL (e.g., amqp://user:pass@host/vhost)
RABBITMQ_EXCHANGEExchange name (default: outpost)

NATS JetStream:

VariableDescription
NATS_SERVER_URLNATS server connection URL (e.g., nats://host:4222)
NATS_STREAMStream name (default: outpost)
NATS_DELIVERY_SUBJECTSubject for delivery events (default: outpost.delivery)
NATS_LOG_SUBJECTSubject for log events (default: outpost.log)
NATS_DELIVERY_DLQSubject for delivery messages that exhaust all delivery attempts (default: dlq.outpost-delivery)
NATS_LOG_DLQSubject 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:

VariableDescription
AWS_SQS_ACCESS_KEY_IDAWS Access Key ID (optional; omit to use the AWS SDK default credential chain, e.g. an IAM role)
AWS_SQS_SECRET_ACCESS_KEYAWS Secret Access Key (optional; omit to use the AWS SDK default credential chain, e.g. an IAM role)
AWS_SQS_REGIONAWS 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:

VariableDescription
GCP_PUBSUB_PROJECTGCP Project ID
GCP_PUBSUB_SERVICE_ACCOUNT_CREDENTIALSService account JSON string or file path

Azure Service Bus:

VariableDescription
AZURE_SERVICEBUS_NAMESPACEAzure Service Bus namespace
AZURE_SERVICEBUS_TENANT_IDAzure Active Directory tenant ID
AZURE_SERVICEBUS_CLIENT_IDService principal client ID
AZURE_SERVICEBUS_CLIENT_SECRETService principal client secret

Publish Queue

Optional. Configures the queue Outpost consumes published events from; see Publishing Events for each provider's variables.

VariableDefaultDescription
PUBLISH_MAX_REDELIVERIES-1Maximum 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:

VariableDescription
POSTGRES_URLPostgreSQL connection URL
CLICKHOUSE_ADDRClickHouse address (e.g., localhost:9000)
CLICKHOUSE_LOG_RETENTION_TTL_DAYSDays to retain event and delivery logs in ClickHouse (default: 0, retained indefinitely). No PostgreSQL equivalent; see the Event & Delivery Log guide.

Delivery

VariableDefaultDescription
DELIVERY_MAX_CONCURRENCY1Max concurrent delivery attempts
DELIVERY_TIMEOUT_SECONDS5HTTP request timeout for webhook delivery
MAX_RETRY_LIMIT10Max retry attempts before giving up
RETRY_INTERVAL_SECONDS30Base interval for exponential backoff retries
RETRY_SCHEDULE—Comma-separated retry delays in seconds (overrides interval/limit)
RETRY_POLL_BACKOFF_MS0 (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

VariableDefaultDescription
TOPICS—Comma-separated list of topics your instance supports
TOPICS_ALLOW_WILDCARDSfalseAllow * inside destination topic subscriptions, such as user.*. When disabled, stored wildcard patterns are ignored but not deleted.

Portal

VariableDefaultDescription
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_DISABLE_OUTPOST_BRANDINGfalseRemove the "Powered by Outpost" footer
PORTAL_ENABLE_DESTINATION_FILTERfalseShow filter configuration UI per destination
PORTAL_ENABLE_WEBHOOK_CUSTOM_HEADERSfalseAllow tenants to set custom HTTP headers on webhook destinations

Alerts

VariableDefaultDescription
ALERT_CONSECUTIVE_FAILURE_COUNT100Consecutive delivery failures before alerting on a destination (and disabling it when ALERT_AUTO_DISABLE_DESTINATION is true). Leave unset for the default of 100; set to an empty string to disable consecutive-failure alerting entirely.
ALERT_AUTO_DISABLE_DESTINATIONfalseAuto-disable a destination once ALERT_CONSECUTIVE_FAILURE_COUNT is reached. Has no effect when consecutive-failure alerting is disabled.
ALERT_EXHAUSTED_RETRIES_WINDOW_SECONDS3600Suppression 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

VariableDefaultDescription
MAX_DESTINATIONS_PER_TENANT20Maximum 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_WEBHOOK_PROXY_URL, when set, takes precedence for webhooks; there is no way to proxy RabbitMQ and Kafka without also proxying webhooks. See Webhook Forward Proxy.
DESTINATIONS_METADATA_PATH—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_AWS_EVENTBRIDGE_SOURCEoutpostSource set on every event published by AWS EventBridge destinations. Must not be empty or start with aws..

Webhook Behavior

VariableDefaultDescription
DESTINATIONS_WEBHOOK_MODEdefaultSet to standard for Standard Webhooks compliance
DESTINATIONS_WEBHOOK_PROXY_URL—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_WEBHOOK_HEADER_PREFIXx-outpost- / webhook-Prefix for system webhook headers (event id, topic, timestamp, signature). Unless overridden, defaults to x-outpost- when DESTINATIONS_WEBHOOK_MODE is default and webhook- when standard.
DESTINATIONS_WEBHOOK_EVENT_ID_HEADER_NAME—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_WEBHOOK_SIGNATURE_HEADER_NAME—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_WEBHOOK_TIMESTAMP_HEADER_NAME—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_WEBHOOK_TOPIC_HEADER_NAME—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_WEBHOOK_TIMESTAMP_FORMATrfc3339 / unixFormat 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_WEBHOOK_SIGNATURE_ALGORITHMhmac-sha256Signature algorithm. Only applies to default mode.
DESTINATIONS_WEBHOOK_SIGNATURE_ENCODINGhexEncoding: hex or base64. Only applies to default mode.
DESTINATIONS_WEBHOOK_SIGNATURE_SECRET_ENCODINGrawHow 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_WEBHOOK_SIGNATURE_SECRET_PREFIX—Prefix stripped from the destination secret before decoding, e.g. whsec_. Ignored when the secret encoding is raw. Only applies to default mode.
DESTINATIONS_WEBHOOK_COMPAT_SIGNATURE_HEADER_NAME—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_WEBHOOK_COMPAT_SIGNATURE_CONTENT_TEMPLATE{{.Body}}Template for the content signed by the compat signature
DESTINATIONS_WEBHOOK_COMPAT_SIGNATURE_HEADER_TEMPLATEv0={{.Signatures | join ","}}Template for the compat signature header value
DESTINATIONS_WEBHOOK_COMPAT_SIGNATURE_ENCODINGhexCompat signature encoding: hex or base64
DESTINATIONS_WEBHOOK_COMPAT_SIGNATURE_ALGORITHMhmac-sha256Compat signature algorithm
DESTINATIONS_WEBHOOK_COMPAT_SIGNATURE_SECRET_ENCODINGrawHow the compat signature derives its HMAC key from the destination secret: raw, base64 or hex
DESTINATIONS_WEBHOOK_COMPAT_SIGNATURE_SECRET_PREFIX—Prefix stripped from the destination secret before decoding for the compat signature
DESTINATIONS_WEBHOOK_COMPAT_HEADERS—Extra headers sent with the compat signature, as comma-separated name=template pairs ({{.EventID}}, {{.Topic}}, {{.Timestamp}}). \, is a literal comma.
DESTINATIONS_WEBHOOK_MAX_RESPONSE_BODY_BYTES131072 (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_RESTART_WORKERS, for example SUPERVISOR_RESTART_WORKERS=publishmq,deliverymq. The workers that support restarts are:

  • publishmq: the publish queue consumer, shown as publishmq-consumer in /healthz
  • deliverymq: the delivery queue consumer, shown as deliverymq-consumer
  • logmq: the log queue consumer, shown as logmq-consumer
  • retrymq: the retry scheduler, shown as retrymq-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.

VariableDefaultDescription
SUPERVISOR_RESTART_WORKERSemptyComma-separated names of the workers to restart instead of reporting them failed at once. An unknown name fails startup.
SUPERVISOR_STARTUP_MAX_ATTEMPTS5Restarts 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_STARTUP_MAX_DURATION_SECONDS-1In the startup phase, the worker is reported failed if no restart has succeeded within this many seconds of its first failure.
SUPERVISOR_RECOVERY_MAX_ATTEMPTS-1Restarts allowed in the recovery phase.
SUPERVISOR_RECOVERY_MAX_DURATION_SECONDS120In 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_PUBLISHMQ_RECOVERY_MAX_DURATION_SECONDS. An unset override inherits the global value. Overrides only apply to workers listed in SUPERVISOR_RESTART_WORKERS; for other workers they have no effect.

VariableOverrides
SUPERVISOR_<WORKER>_STARTUP_MAX_ATTEMPTSSUPERVISOR_STARTUP_MAX_ATTEMPTS
SUPERVISOR_<WORKER>_STARTUP_MAX_DURATION_SECONDSSUPERVISOR_STARTUP_MAX_DURATION_SECONDS
SUPERVISOR_<WORKER>_RECOVERY_MAX_ATTEMPTSSUPERVISOR_RECOVERY_MAX_ATTEMPTS
SUPERVISOR_<WORKER>_RECOVERY_MAX_DURATION_SECONDSSUPERVISOR_RECOVERY_MAX_DURATION_SECONDS

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

VariableDescription
OTEL_SERVICE_NAMEEnables OpenTelemetry when set. All three signals (traces, metrics, and logs) are exported by default; see OpenTelemetry for per-signal control
LOG_LEVELLog verbosity: trace, debug, info, warn, error (default: info)
DISABLE_TELEMETRYSet 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