Configuration Reference
This page provides a comprehensive reference for every configuration field in Passage. For a beginner-friendly introduction, see Configuration Basics.
Configuration Structure
Section titled “Configuration Structure”Passage uses a layered configuration system supporting YAML, TOML, and JSON formats. The overall structure:
# Core settingsaddress: "0.0.0.0:25565"timeout: 120max_packet_length: 10000auth_cookie_expiry: 21600auth_secret: "your-secret"
# Optional global featuressentry: { ... }otel: { ... }rate_limiter: { ... }proxy_protocol: { ... }
# Routes (per-hostname adapter configuration)routes:- hostname: "mc.example.net" status: { type: fixed, ... } authentication: { type: mojang, ... } discovery: { type: dns_discovery, ..., actions: [...] } localization: { type: fixed, ... }Core Settings
Section titled “Core Settings”address
Section titled “address”| Type | string (socket address) |
| Default | "0.0.0.0:25565" |
| Environment | PASSAGE_ADDRESS |
The network address and port that Passage binds to for incoming Minecraft client connections.
# Listen on all interfaces, standard Minecraft portaddress: "0.0.0.0:25565"
# Listen on specific interfaceaddress: "192.168.1.100:25565"
# Use custom portaddress: "0.0.0.0:25566"timeout
Section titled “timeout”| Type | integer (seconds) |
| Default | 120 |
| Environment | PASSAGE_TIMEOUT |
Maximum time in seconds to wait for client responses during the connection flow. If the client does not respond within this time, the connection is dropped with a timeout message.
timeout: 120 # 2 minutes (default)timeout: 60 # shorter for high-performance scenariostimeout: 300 # longer for slow connectionsmax_packet_length
Section titled “max_packet_length”| Type | integer (bytes) |
| Default | 10000 |
| Environment | PASSAGE_MAX_PACKET_LENGTH |
The maximum packet size in bytes that Passage will accept. Packets exceeding this size are rejected. The default of 10,000 bytes is sufficient for normal Minecraft handshake and login packets.
max_packet_length: 10000auth_cookie_expiry
Section titled “auth_cookie_expiry”| Type | integer (seconds) |
| Default | 21600 (6 hours) |
| Environment | PASSAGE_AUTH_COOKIE_EXPIRY |
How long authentication cookies remain valid in seconds. When a player connects with a valid cookie, Passage can skip the Mojang authentication step. See Authentication Cookies for details.
auth_cookie_expiry: 21600 # 6 hours (default)auth_cookie_expiry: 3600 # 1 hour (more frequent re-auth)system_observer_interval
Section titled “system_observer_interval”| Type | integer (seconds, optional) |
| Default | 20 |
| Environment | PASSAGE_SYSTEM_OBSERVER_INTERVAL |
The interval in seconds at which system metrics (CPU, memory, swap) are observed and reported via OpenTelemetry. Set to null to disable system metric collection.
auth_secret
Section titled “auth_secret”| Type | string (optional) |
| Default | null (disabled) |
| Environment | PASSAGE_AUTH_SECRET |
Secret key for signing authentication cookies (HMAC-SHA256). If not set, authentication cookies are disabled and players must authenticate with Mojang on every connection.
Recommended approach — use a separate secret file:
# Generate a secretopenssl rand -base64 32 > config/auth_secret
# Or specify custom path via environment variableexport AUTH_SECRET_FILE=/run/secrets/passage-authThe AUTH_SECRET_FILE environment variable (default: config/auth_secret) points to a plain text file whose entire contents become the auth_secret value.
Rate Limiter
Section titled “Rate Limiter”| Type | object (optional) |
| Enabled by | Presence of the section |
| Environment prefix | PASSAGE_RATE_LIMITER_ |
Per-IP connection rate limiting. If omitted, rate limiting is disabled.
Fields
Section titled “Fields”| Field | Type | Default | Description |
|---|---|---|---|
duration | integer (seconds) | 60 | Time window for counting connections. |
limit | integer | 60 | Maximum connections allowed per IP within the time window. |
rate_limiter: duration: 60 # 60-second window limit: 60 # max 60 connections per IP per minuteBehavior: If an IP exceeds limit connections within duration seconds, subsequent connections are rejected until the window expires.
Tuning guidelines:
| Scenario | duration | limit |
|---|---|---|
| Strict (DDoS protection) | 60 | 30 |
| Balanced (default) | 60 | 60 |
| Permissive (shared IPs) | 120 | 200 |
PROXY Protocol
Section titled “PROXY Protocol”| Type | object (optional) |
| Enabled by | Presence of the section |
| Environment prefix | PASSAGE_PROXY_PROTOCOL_ |
PROXY protocol support for preserving real client IP addresses when Passage is behind a load balancer. If omitted, PROXY protocol is disabled.
Fields
Section titled “Fields”| Field | Type | Default | Description |
|---|---|---|---|
allow_v1 | boolean | true | Accept PROXY protocol v1 (text) headers. |
allow_v2 | boolean | true | Accept PROXY protocol v2 (binary) headers. |
proxy_protocol: allow_v1: true allow_v2: trueWhen to enable:
- Behind HAProxy with
send-proxyorsend-proxy-v2 - Behind AWS Network Load Balancer (NLB) with proxy protocol enabled
- Behind NGINX with
proxy_protocolconfigured - Behind other PROXY protocol-compatible load balancers
Sentry
Section titled “Sentry”| Type | object (optional) |
| Enabled by | Presence of the section |
| Environment prefix | PASSAGE_SENTRY_ |
Error tracking with Sentry. The release version is automatically inferred from the build. If omitted, Sentry is disabled.
Fields
Section titled “Fields”| Field | Type | Default | Description |
|---|---|---|---|
debug | boolean | false | Enable Sentry SDK debug logging. |
environment | string | "" | Environment tag for Sentry events (e.g., "production", "staging"). |
address | string | "" | Sentry DSN (Data Source Name) URL. |
sentry: debug: false environment: "production" address: "https://examplePublicKey@o0.ingest.sentry.io/0"OpenTelemetry
Section titled “OpenTelemetry”| Type | object |
| Environment prefix | PASSAGE_OTEL_ |
OpenTelemetry configuration for traces, metrics, and logs. Each signal type (traces, metrics, logs) has its own endpoint and can be enabled independently.
Fields
Section titled “Fields”| Field | Type | Default | Description |
|---|---|---|---|
environment | string | "" | Environment label added to all telemetry data. |
traces | object (optional) | null | Traces endpoint configuration. |
metrics | object (optional) | null | Metrics endpoint configuration. |
logs | object (optional) | null | Logs endpoint configuration. |
Each endpoint object has:
| Field | Type | Default | Description |
|---|---|---|---|
address | string | "" | OTLP HTTP/protobuf endpoint URL. |
token | string | "" | Base64-encoded basic auth token. |
otel: environment: "production" traces: address: "https://otlp-gateway.grafana.net/otlp/v1/traces" token: "base64_encoded_token" metrics: address: "https://otlp-gateway.grafana.net/otlp/v1/metrics" token: "base64_encoded_token" logs: address: "https://otlp-gateway.grafana.net/otlp/v1/logs" token: "base64_encoded_token"Generating a token:
echo -n "user:password" | base64Supported backends: Grafana Cloud, Datadog, New Relic, Honeycomb, or any OTLP-compatible collector.
See Observability for detailed setup guides.
Routes
Section titled “Routes”| Type | array of route objects |
| Default | [] (empty) |
Routes define per-hostname adapter configurations. When a player connects, Passage matches the connection’s hostname against each route’s hostname regex pattern and uses the first match.
Route Fields
Section titled “Route Fields”| Field | Type | Default | Description |
|---|---|---|---|
hostname | string (regex) | "" | Regex pattern to match the server hostname from the client handshake. |
status | StatusAdapter | fixed | Server list status configuration. |
authentication | AuthenticationAdapter | mojang | Player authentication configuration. |
discovery | DiscoveryAdapter | fixed_discovery | Backend server discovery and action pipeline. |
localization | LocalizationAdapter | fixed | Disconnect message localization. |
routes:- hostname: "mc\\.example\\.net" status: type: fixed name: "My Network" authentication: type: mojang discovery: type: fixed_discovery targets: - identifier: "lobby-1" address: "10.0.1.10:25565" localization: type: fixed default_locale: "en"Status Adapters
Section titled “Status Adapters”Selected via type within routes[].status. See Status Adapter for detailed documentation.
Fixed Status (type: fixed)
Section titled “Fixed Status (type: fixed)”Static server status from configuration.
| Field | Type | Default | Description |
|---|---|---|---|
name | string | "Passage" | Server name in the server list. |
description | string (optional) | "\"Minecraft Server Transfer Router\"" | MOTD as JSON text component. |
favicon | string (optional) | Passage logo | Base64-encoded PNG (data:image/png;base64,...). |
enforces_secure_chat | boolean (optional) | true | Whether secure chat is enforced. |
preferred_version | integer | 769 (1.21.4) | Protocol version shown to clients. |
min_version | integer | 0 | Minimum supported protocol version. 0 = no minimum. |
max_version | integer | 1000 | Maximum supported protocol version. |
status: type: fixed name: "My Network" description: "{\"text\":\"Welcome!\",\"color\":\"gold\"}" enforces_secure_chat: true preferred_version: 769 min_version: 766 max_version: 1000HTTP Status (type: http)
Section titled “HTTP Status (type: http)”Fetches status from an HTTP endpoint with caching.
| Field | Type | Default | Description |
|---|---|---|---|
address | string | "http://localhost:8080" | HTTP endpoint URL. |
cache_duration | integer (seconds) | 60 | Cache duration. Must be greater than zero. |
status: type: http address: "https://api.example.com/minecraft/status" cache_duration: 30gRPC Status (type: grpc)
Section titled “gRPC Status (type: grpc)”Fetches status via a custom gRPC service.
| Field | Type | Default | Description |
|---|---|---|---|
address | string | "" | gRPC service endpoint URL. |
status: type: grpc address: "http://status-service:50051"Authentication Adapters
Section titled “Authentication Adapters”Selected via type within routes[].authentication. See Authentication Adapter for detailed documentation.
| Type | Description |
|---|---|
mojang | Standard Mojang/Microsoft authentication (default). |
disabled | No authentication. For testing only. |
fixed | Fixed player profile for all connections. |
grpc | Custom authentication via gRPC service. |
Discovery Adapter
Section titled “Discovery Adapter”The discovery section has two parts: a discovery adapter (provides the initial target list) and an actions pipeline (transforms the list). The adapter type is set via type, and actions are listed in actions[].
See Target Discovery and Discovery Actions for detailed documentation.
Fixed Discovery (type: fixed_discovery)
Section titled “Fixed Discovery (type: fixed_discovery)”Static target list from configuration.
| Field | Type | Default | Description |
|---|---|---|---|
targets | array | [] | List of backend server targets. |
Each target:
| Field | Type | Default | Description |
|---|---|---|---|
identifier | string | required | Unique server identifier. |
address | string | required | Socket address (host:port). |
priority | integer | 0 | Priority (lower = preferred). |
meta | map | {} | Key-value metadata. |
discovery: type: fixed_discovery targets: - identifier: "lobby-1" address: "10.0.1.10:25565" meta: type: "lobby" players: "15"DNS Discovery (type: dns_discovery)
Section titled “DNS Discovery (type: dns_discovery)”Discovers targets via DNS SRV or A/AAAA records with periodic refresh.
| Field | Type | Default | Description |
|---|---|---|---|
domain | string | "" | DNS domain to query. |
refresh_interval | integer (seconds) | 30 | How often to re-query DNS. |
record_type | string | "srv" | Record type: "srv" or "a". |
port | integer | 25565 | Default port (only for record_type: a). |
# SRV recordsdiscovery: type: dns_discovery domain: "_minecraft._tcp.servers.example.net" record_type: srv refresh_interval: 30
# A/AAAA recordsdiscovery: type: dns_discovery domain: "mc.example.net" record_type: a port: 25565 refresh_interval: 30Agones Discovery (type: agones_discovery)
Section titled “Agones Discovery (type: agones_discovery)”Discovers game servers via Agones GameServerAllocation in Kubernetes.
| Field | Type | Default | Description |
|---|---|---|---|
namespace | string (optional) | null | Kubernetes namespace. null = search all namespaces. |
selectors | array | [] | GameServerAllocation selector templates. |
priorities | array | [] | Priority templates for allocation. |
scheduling | string (optional) | null | Agones scheduling strategy. |
metadata | object (optional) | null | Metadata template for allocation. |
backoff | object | see below | Exponential backoff configuration. |
Template variables (replaced in string fields if they exactly match):
{{ .Client.ProtocolVersion }}— client protocol version{{ .Client.ServerAddress }}— server address from handshake{{ .Client.ServerPort }}— server port from handshake{{ .Client.Address }}— client IP (with optional proxy protocol){{ .Request.TraceId }}— OpenTelemetry trace ID
Backoff configuration:
| Field | Type | Default | Description |
|---|---|---|---|
initial_secs | integer | 2 | Wait time for first retry. |
max_secs | integer | 60 | Maximum wait time between retries. |
max_attempts | integer | 10 | Maximum retry attempts. |
factor | float | 2.0 | Multiplicative backoff factor. |
jitter | float | 0.1 | Random jitter added (seconds). |
gRPC Discovery (type: grpc_discovery)
Section titled “gRPC Discovery (type: grpc_discovery)”Dynamic discovery via a custom gRPC service.
| Field | Type | Default | Description |
|---|---|---|---|
address | string | "" | gRPC service endpoint URL. |
discovery: type: grpc_discovery address: "http://discovery-service:50051"Discovery Actions (actions)
Section titled “Discovery Actions (actions)”An optional array of actions that process the discovered target list sequentially. See Discovery Actions for the full reference.
Available action types: meta_filter, player_allow_filter, player_block_filter, player_fill_strategy, grpc.
discovery: type: dns_discovery domain: "servers.example.net" record_type: srv actions: - type: meta_filter rules: - key: "status" op: equals value: "online" - type: player_fill_strategy field: "players" max_players: 50Localization Adapters
Section titled “Localization Adapters”Selected via type within routes[].localization. See Localization for detailed documentation.
Fixed Localization (type: fixed)
Section titled “Fixed Localization (type: fixed)”Static disconnect messages from configuration.
| Field | Type | Default | Description |
|---|---|---|---|
default_locale | string | "en_US" | Default locale for unknown clients. |
messages | map | 6 built-in locales | Locale-specific messages. |
warn_unknown_keys | boolean | true | Warn about unrecognized message keys in logs. |
Default message keys:
| Key | When shown |
|---|---|
disconnect_timeout | Connection timed out (keep-alive timeout). |
disconnect_no_target | No backend server available. |
disconnect_unauthenticated | Authentication failed. |
Messages use Minecraft JSON text component format:
localization: type: fixed default_locale: "en" messages: en: locale: "English" disconnect_timeout: '{"text":"Disconnected: Connection timed out"}' disconnect_no_target: '{"text":"Disconnected: No server available"}' disconnect_unauthenticated: '{"text":"Disconnected: Authentication failed"}' de: locale: "Deutsch" disconnect_timeout: '{"text":"Verbindung getrennt: Zeitüberschreitung"}' disconnect_no_target: '{"text":"Verbindung getrennt: Kein Server verfügbar"}' disconnect_unauthenticated: '{"text":"Verbindung getrennt: Authentifizierung fehlgeschlagen"}'gRPC Localization (type: grpc)
Section titled “gRPC Localization (type: grpc)”Delegates localization to a custom gRPC service.
| Field | Type | Default | Description |
|---|---|---|---|
address | string | "" | gRPC service endpoint URL. |
Complete Example
Section titled “Complete Example”A production-ready configuration with DNS discovery, rate limiting, and observability:
# yaml-language-server: $schema=./schema.json
address: "0.0.0.0:25565"timeout: 120
rate_limiter: duration: 60 limit: 60
proxy_protocol: allow_v1: true allow_v2: true
sentry: environment: "production" address: "https://examplePublicKey@o0.ingest.sentry.io/0"
otel: environment: "production" traces: address: "https://otlp-gateway.grafana.net/otlp/v1/traces" token: "base64_token" metrics: address: "https://otlp-gateway.grafana.net/otlp/v1/metrics" token: "base64_token"
routes:- hostname: "mc\\.example\\.net" status: type: http address: "https://example.net/status" cache_duration: 30 authentication: type: mojang server_id: "" discovery: type: dns_discovery domain: "servers.example.net" record_type: srv actions: - type: meta_filter name: "server-filter" rules: - key: "status" op: equals value: "online" - type: player_fill_strategy name: "player-fill" field: "players" max_players: 50 localization: type: fixed default_locale: "en"Configuration Layers
Section titled “Configuration Layers”Passage uses a layered configuration system. Upper layers override lower layers:
- Environment variables (highest priority) — format:
PASSAGE_<FIELD>with_as separator - Auth secret file — sets only
auth_secret(default path:config/auth_secret) - Configuration file — your deployment config (default path:
config/config) - Default values (lowest priority) — built into Passage
Environment Variables
Section titled “Environment Variables”Override any configuration value:
export PASSAGE_ADDRESS="0.0.0.0:25565"export PASSAGE_TIMEOUT=120export PASSAGE_RATE_LIMITER_DURATION=60export PASSAGE_RATE_LIMITER_LIMIT=100Change the environment variable prefix:
export ENV_PREFIX=MYAPPexport MYAPP_ADDRESS="0.0.0.0:25565"Configuration File Formats
Section titled “Configuration File Formats”Passage auto-detects the format from the file extension:
CONFIG_FILE=config/config.yaml passage # YAMLCONFIG_FILE=config/config.toml passage # TOMLCONFIG_FILE=config/config.json passage # JSON