-
Notifications
You must be signed in to change notification settings - Fork 1
Configuration Guide
Complete reference for every setting in
navigator.toml— v4.0.0
The configuration file navigator.toml is organized into these sections:
-
[commands]— Player commands, aliases, permissions, cooldown -
[messages]— All player-facing messages with MiniMessage formatting -
[routing]— Selection algorithm, lobby pool, and core routing behavior -
[circuit_breaker]— Automatic failure detection -
[degradation]— Fallback behavior when all health checks fail -
[routing.affinity]— Player Affinity (Sticky Sessions) configuration -
[geo_routing]— Geo-based routing (experimental) -
[routing.contextual]— Context-aware routing groups -
[health_checks]— Server monitoring configuration -
[update_checker]— Update check settings -
[metrics]— bStats integration -
[debug]— Verbose logging
Top-level: notify_on_startup, notify_admins_on_join
Controls what players type and what permissions are required.
[commands]
primary = "lobby"
aliases = ["hub", "spawn"]
permission = "velocitynavigator.use"
admin_aliases = ["velocitynavigator", "vn"]
cooldown_seconds = 3
reconnect_if_same_server = false| Setting | Type | Default | Description |
|---|---|---|---|
primary |
string | "lobby" |
The main command players type (e.g. /lobby). |
aliases |
string[] | ["hub", "spawn"] |
Alternative commands that map to the primary. |
permission |
string | "velocitynavigator.use" |
Permission required to use the lobby command. Set to "none" to allow all players. |
admin_aliases |
string[] | ["velocitynavigator", "vn"] |
Aliases for the admin command. |
cooldown_seconds |
int | 3 |
Anti-spam cooldown in seconds between lobby commands. |
reconnect_if_same_server |
boolean | false |
Whether to reconnect a player even if they're already on the selected lobby. |
All player-facing messages support MiniMessage rich text formatting and placeholders.
[messages]
connecting = "<aqua>Sending you to <server>...</aqua>"
alreadyConnected = "<yellow>You are already connected to <server>.</yellow>"
noLobbyFound = "<red>No available lobby could be found. (<reason>)</red>"
playerOnly = "<gray>This command can only be used by a player.</gray>"
cooldown = "<yellow>Please wait <time> more second(s).</yellow>"
reloadSuccess = "<green>VelocityNavigator reloaded.</green>"
reloadFailed = "<red>Reload failed. Check console for details.</red>"
retrying = "<yellow>Retrying connection... (<attempt>/<max>)</yellow>"| Setting | Type | Default | Placeholders | Description |
|---|---|---|---|---|
noLobbyFound |
string | "<red>No available lobby could be found. (<reason>)</red>" |
<reason>, <mode>, <player>
|
Shown when no lobby is available. |
cooldown |
string | "<yellow>Please wait <time> more second(s).</yellow>" |
<time>, <player>
|
Shown when cooldown is active. |
alreadyConnected |
string | "<yellow>You are already connected to <server>.</yellow>" |
<server>, <player>
|
Shown when player is already on the selected lobby. |
connecting |
string | "<aqua>Sending you to <server>...</aqua>" |
<player>, <server>
|
Shown while connecting. |
retrying |
string | "<yellow>Retrying connection... (<attempt>/<max>)</yellow>" |
<attempt>, <max>, <player>, <server>
|
Shown on each retry attempt. New in v4. |
Available placeholders in v4:
<server>,<time>,<reason>,<mode>,<player>,<attempt>,<max>. Not all placeholders are available in every message — see the table above for which ones apply to each message.
Controls the selection algorithm and lobby pool.
[routing]
selection_mode = "least_players"
cycle_when_possible = true
balance_initial_join = true
default_lobbies = ["lobby-1", "lobby-2"]
max_retries = 2| Setting | Type | Default | Accepted Values | Description |
|---|---|---|---|---|
selection_mode |
string | "least_players" |
least_players, round_robin, random, power_of_two, weighted_round_robin, least_connections, consistent_hash
|
The algorithm used to select a lobby. See Routing Algorithms. |
cycle_when_possible |
boolean | true |
— | Prevents routing a player to the same server they're already on. |
balance_initial_join |
boolean | true |
— | Applies routing when players first connect to the proxy. |
default_lobbies |
LobbyEntry[] | ["lobby-1", "lobby-2"] |
See below | The pool of lobby servers. |
max_retries |
int | 2 |
0–10
|
Number of retry attempts on connection failure. New in v4. |
Each lobby entry can be a plain string or an inline table:
Plain string (backward compatible):
default_lobbies = ["lobby-1", "lobby-2"]Inline table (v4 — adds max_players and weight):
default_lobbies = [
{ server = "lobby-1", max_players = 100, weight = 3 },
{ server = "lobby-2", max_players = 50, weight = 1 },
"lobby-3", # mixing is fine — this uses defaults
]| Field | Type | Default | Description |
|---|---|---|---|
server |
string | (required) | Server name — must match velocity.toml. |
max_players |
int |
-1 (uncapped) |
Maximum players before the server is considered "full" and skipped. -1 = no limit. |
weight |
int | 1 |
Relative weight for weighted_round_robin. Higher = more traffic. Only used by WRR. |
Tip: You can mix plain strings and inline tables. Plain strings use
max_players = -1(uncapped) andweight = 1.
Automatic server failure detection. When a server fails repeated health checks, the circuit breaker opens and that server is skipped until it recovers.
[circuit_breaker]
enabled = true
failure_threshold = 3
cooldown_seconds = 30
half_open_max_tests = 1| Setting | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Whether the circuit breaker is active. |
failure_threshold |
int | 3 |
Consecutive failures before the circuit opens (server is excluded). |
cooldown_seconds |
int | 30 |
Seconds before an OPEN circuit transitions to HALF_OPEN (allows test requests). |
half_open_max_tests |
int | 1 |
Number of test requests allowed in HALF_OPEN state before deciding to close or re-open. |
CLOSED ──(failures ≥ threshold)──► OPEN
▲ │
│ (cooldown elapses)
│ ▼
└──(test requests succeed)── HALF_OPEN
│
(test requests fail)
│
▼
OPEN
- CLOSED: Normal operation. Failures are tracked.
- OPEN: Server is excluded from routing. No traffic sent.
- HALF_OPEN: A limited number of test requests are allowed. If they succeed → CLOSED. If they fail → OPEN again.
Graceful degradation when all health checks fail. Instead of showing "No lobby found", falls back to selecting from configured lobbies using a simpler mode that ignores health status.
[degradation]
enabled = true
mode = "random"| Setting | Type | Default | Accepted Values | Description |
|---|---|---|---|---|
enabled |
boolean | true |
— | Whether degradation mode is active. |
mode |
string | "random" |
random, round_robin
|
Algorithm used when degrading. random is recommended for safety. |
When this triggers: Only when ALL candidate servers fail health checks. If even one server is healthy, normal routing continues.
Player affinity (sticky sessions) ensures players preferentially return to the same lobby they were last connected to during their proxy session. In v4.0.0, this is fully configurable under the [routing.affinity] TOML section.
[routing.affinity]
enabled = true
stickiness = 0.7| Setting | Type | Default | Accepted Values | Description |
|---|---|---|---|---|
enabled |
boolean | true |
— | Whether player affinity is active. |
stickiness |
double | 0.7 |
0.0–1.0
|
Probability factor for session stickiness. 0.7 means a 70% chance of returning to the previous lobby and a 30% chance of running normal routing. |
How it works: When a player runs the lobby command, VelocityNavigator checks if they have a saved session affinity record. If stickiness is set to
0.7, there is a 70% chance they are immediately routed to their previous lobby (provided it is online and healthy), and a 30% chance the global selection algorithm is run.Important Notes:
- Session affinity records are stored in memory and are automatically cleaned up when a player disconnects from the proxy.
- Player affinity is naturally bypassed when using the
consistent_hashmode, as consistent hashing provides its own deterministic, hash-based player stickiness.- If the player's stickied lobby goes offline or trips the circuit breaker, the affinity system will safely skip it and route the player using the standard active algorithm.
⚠️ Experimental — This feature is a stub in v4.0.0 and requires a GeoLite2 database to function. Without the database, geo-routing is silently skipped.
Geo-based routing sends players to lobbies closest to their geographic location.
[geo_routing]
enabled = false
database_path = ""| Setting | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Whether geo-routing is active. |
database_path |
string | "" |
Path to the GeoLite2-Country.mmdb file. Relative to the plugin directory. Example: "GeoLite2-Country.mmdb". |
Config key note: The config section is
[geo_routing](with underscore), not[routing.geo].
See Database Setup for step-by-step instructions.
Context-aware routing maps players leaving specific game servers to dedicated lobby pools.
[routing.contextual]
enabled = false
fallback_to_default = true
[routing.contextual.groups.bedwars_lobbies]
servers = [
{ server = "bw-lobby-1", weight = 2 },
{ server = "bw-lobby-2", weight = 1 },
]
mode = "consistent_hash"
[routing.contextual.groups.survival_lobbies]
servers = ["surv-hub-1", "surv-hub-2"]
[routing.contextual.sources]
"bedwars-1" = "bedwars_lobbies"
"bedwars-2" = "bedwars_lobbies"
"survival-1" = "survival_lobbies"
[routing.contextual.fallback_chain]
bedwars_lobbies = ["survival_lobbies"]| Setting | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | false |
Whether contextual routing is active. |
fallback_to_default |
boolean | true |
Fall back to default_lobbies when no contextual group matches. |
groups |
map | — | Named groups of lobby servers. Each group can have servers (LobbyEntry[]) and optional mode. |
sources |
map | — | Maps source server names to group names. |
fallback_chain |
map | — | Maps group names to ordered lists of fallback group names. |
Each group can specify its own mode, overriding the global selection_mode:
[routing.contextual.groups.bedwars_lobbies]
servers = ["bw-1", "bw-2"]
mode = "consistent_hash" # Overrides global selection_mode for this groupIf mode is omitted, the global selection_mode is used.
When a group's servers are all unavailable, the fallback chain determines which groups to try next:
[routing.contextual.fallback_chain]
bedwars_lobbies = ["survival_lobbies"]
survival_lobbies = ["bedwars_lobbies"]The chain is walked in order. If no fallback group has available servers and fallback_to_default = true, the default lobby pool is used as a last resort.
See Contextual Routing Guide for a full tutorial.
Controls how the proxy monitors backend server availability. When health checks are enabled, VelocityNavigator pings backend servers and uses live player counts from RegisteredServer.getPlayersConnected() for routing decisions, ensuring accurate load balancing even when cache entries are stale.
[health_checks]
enabled = true
timeout_ms = 2500
cache_seconds = 60| Setting | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Whether health checks are performed. |
timeout_ms |
int | 2500 |
Milliseconds to wait for a ping response before considering a server unhealthy. |
cache_seconds |
int | 60 |
How long health check results are cached before re-checking. |
Controls the update checker. In v4, the update checker runs a one-time check on startup and can be triggered manually with /vn updatecheck.
[update_checker]
channel = "release"| Setting | Type | Default | Accepted Values | Description |
|---|---|---|---|---|
channel |
string | "release" |
release, beta, alpha
|
Which release channel to check against. |
v4 changes:
-
enabledfield removed — the checker always runs on startup (once, 5 seconds after proxy start) -
notifyConsolefield removed — update notifications are always logged to console -
startupDelaySecondsfield removed — fixed at 5 seconds - Use
/vn updatecheckto manually check for updates at any time
Tip: Set
notify_on_startup = falseto suppress the startup notification. Setnotify_admins_on_join = falseto suppress in-game admin notifications.
notify_on_startup = true
notify_admins_on_join = true
[debug]
verbose_logging = false| Setting | Type | Default | Description |
|---|---|---|---|
notify_on_startup |
boolean | true |
Whether to run an update check and log to console when the proxy starts. |
notify_admins_on_join |
boolean | true |
Whether to notify admins with velocitynavigator.admin permission about available updates when they join the server. |
verbose_logging |
boolean | false |
Enable debug-level logging for routing decisions. Located under [debug], not a top-level setting. |
# VelocityNavigator v4.0.0 Configuration
# https://github.com/sdemonzdevelopment-spec/VelocityNavigator/wiki
notify_on_startup = true
notify_admins_on_join = true
[commands]
primary = "lobby"
aliases = ["hub", "spawn"]
permission = "velocitynavigator.use"
admin_aliases = ["velocitynavigator", "vn"]
cooldown_seconds = 3
reconnect_if_same_server = false
[routing]
selection_mode = "power_of_two"
cycle_when_possible = true
balance_initial_join = true
max_retries = 2
default_lobbies = [
{ server = "lobby-1", max_players = 100, weight = 2 },
{ server = "lobby-2", max_players = 100, weight = 2 },
{ server = "lobby-3", max_players = 50, weight = 1 },
]
[routing.affinity]
enabled = true
stickiness = 0.7
[routing.contextual]
enabled = true
fallback_to_default = true
[routing.contextual.groups.bedwars_lobbies]
servers = ["bw-hub-1", "bw-hub-2"]
mode = "consistent_hash"
[routing.contextual.sources]
"bedwars-1" = "bedwars_lobbies"
"bedwars-2" = "bedwars_lobbies"
[routing.contextual.fallback_chain]
bedwars_lobbies = ["survival_lobbies"]
[health_checks]
enabled = true
timeout_ms = 2500
cache_seconds = 60
[messages]
connecting = "<aqua>Sending you to <server>...</aqua>"
alreadyConnected = "<yellow>You are already connected to <server>.</yellow>"
noLobbyFound = "<red>No available lobby could be found. (<reason>)</red>"
playerOnly = "<gray>This command can only be used by a player.</gray>"
cooldown = "<yellow>Please wait <time> more second(s).</yellow>"
reloadSuccess = "<green>VelocityNavigator reloaded.</green>"
reloadFailed = "<red>Reload failed. Check console for details.</red>"
retrying = "<yellow>Retrying connection... (<attempt>/<max>)</yellow>"
[update_checker]
channel = "release"
[metrics]
enabled = true
[circuit_breaker]
enabled = true
failure_threshold = 3
cooldown_seconds = 30
half_open_max_tests = 1
[degradation]
enabled = true
mode = "random"
[geo_routing]
enabled = false
database_path = ""
[debug]
verbose_logging = falseHome · Quick Start · Configuration · Operations · FAQ
GitHub · Support / Discord · Report a Bug
VelocityNavigator v4.3.0 · by DemonZ Development
![]()
Getting Started
Routing
- Routing Algorithms
- Algorithm Visualizations
- Initial Join Balancing
- Contextual Routing Guide
- Player Affinity
- Health & Circuit Breakers
- Retries & Fallbacks
Player Experience
Configuration
Network & Operations
- Advanced Proxy Systems
- Redis & Multi-Proxy
- Storage & Databases
- Server Management
- Backend Lifecycle States
- HTML Dashboard
- Operations Runbook
- Prometheus & Grafana Setup
- Troubleshooting Guide
- FAQ
VelocityNavigator 4.3.0