Bridge Plugin
Velocity proxy plugin that connects to the Nimbus cloud system with in-game commands, player routing, permission integration, and proxy sync.
The Nimbus Bridge is a Velocity proxy plugin that connects the proxy to the Nimbus cloud system. It provides in-game cloud management commands, automatic player routing, permission integration, and proxy synchronization features.
Installation
The bridge is automatically deployed to every proxy service at runtime.
On each service prepare, ServiceFactory.resolveModulePlugins() copies
nimbus-bridge.jar into the proxy's plugins/ directory with
REPLACE_EXISTING — so deletions self-heal on next start and updates roll
out automatically. Templates are user-owned; the bridge JAR is never
written into templates/global_proxy/plugins/.
If a proxy service's plugins/nimbus-bridge.jar is missing, it's redeployed
on the next service start.
Configuration
The bridge reads its API connection from plugins/nimbus-bridge/bridge.json:
{
"api_url": "http://127.0.0.1:8080",
"token": "your-api-token"
}This file is auto-generated by Nimbus Core during deployment. The values come from your config/nimbus.toml API configuration.
Alternatively, the bridge auto-discovers its connection from JVM system properties and environment variables (set by Nimbus when launching the proxy process):
| Source | Key | Description |
|---|---|---|
| Env var | NIMBUS_API_TOKEN | Bearer token (preferred, hidden from ps) |
| System property | nimbus.api.url | API base URL |
| System property | nimbus.api.token | Bearer token (fallback) |
The bridge checks for the environment variable first, then falls back to the system property. If either is set, bridge.json is not read.
Commands
All commands require the base permission nimbus.cloud. The /cloud command is also available as /nimbus.
Dynamic command discovery — most /cloud subcommands are not implemented in the Bridge itself. On startup (and on controller reconnect), the Bridge calls GET /api/commands to fetch all Controller commands that have a non-empty permission field. Each discovered command is forwarded automatically via POST /api/commands/{name}/execute. This means new Controller commands appear in-game without Bridge updates, and the response formatting is handled by the Controller's CommandOutput interface.
Only maintenance (Velocity-local login gate) and events (local WebSocket subscriber list) are implemented directly in the Bridge.
Service management
| Command | Permission | Description |
|---|---|---|
/cloud list [group] | nimbus.cloud.list | List running services, optionally filtered by group |
/cloud info <service> | nimbus.cloud.info | Show detailed info for a service |
/cloud start <group> | nimbus.cloud.start | Start a new instance of a group |
/cloud stop <service> | nimbus.cloud.stop | Stop a running service |
/cloud restart <service> | nimbus.cloud.restart | Restart a service |
/cloud exec <service> <command> | nimbus.cloud.exec | Execute a console command on a service |
Player management
| Command | Permission | Description |
|---|---|---|
/cloud players | nimbus.cloud.players | List all online players and their current servers |
/cloud send <player> <service> | nimbus.cloud.send | Transfer a player to another service |
/cloud broadcast [--group <g>] <msg> | nimbus.cloud.broadcast | Broadcast a message to all players or a specific group |
Network management
| Command | Permission | Description |
|---|---|---|
/cloud status | nimbus.cloud.status | Network overview (services, players, memory) |
/cloud groups | nimbus.cloud.groups | List all configured groups |
/cloud setstate <service> <state> | nimbus.cloud.setstate | Set a service's custom state |
/cloud reload | nimbus.cloud.reload | Reload Nimbus configuration |
Permission management
| Command | Permission | Description |
|---|---|---|
/cloud perms group list | nimbus.cloud.perms | List permission groups |
/cloud perms group info <group> | nimbus.cloud.perms | Show group details |
/cloud perms group create <name> | nimbus.cloud.perms | Create a permission group |
/cloud perms group delete <name> | nimbus.cloud.perms | Delete a permission group |
/cloud perms group addperm <group> <perm> | nimbus.cloud.perms | Add permission to group |
/cloud perms group removeperm <group> <perm> | nimbus.cloud.perms | Remove permission from group |
/cloud perms group setdefault <group> <true/false> | nimbus.cloud.perms | Set as default group |
/cloud perms group addparent <group> <parent> | nimbus.cloud.perms | Add parent (inheritance) |
/cloud perms group removeparent <group> <parent> | nimbus.cloud.perms | Remove parent |
/cloud perms group setprefix <group> <prefix> | nimbus.cloud.perms | Set group prefix |
/cloud perms group setsuffix <group> <suffix> | nimbus.cloud.perms | Set group suffix |
/cloud perms group setpriority <group> <n> | nimbus.cloud.perms | Set group priority |
/cloud perms user list | nimbus.cloud.perms | List users with groups |
/cloud perms user info <player> | nimbus.cloud.perms | Show player's groups |
/cloud perms user addgroup <player> <group> | nimbus.cloud.perms | Add player to group |
/cloud perms user removegroup <player> <group> | nimbus.cloud.perms | Remove player from group |
Maintenance management
| Command | Permission | Description |
|---|---|---|
/cloud maintenance status | nimbus.cloud.maintenance | Show maintenance status (global + groups) |
/cloud maintenance on | nimbus.cloud.maintenance | Enable global maintenance |
/cloud maintenance off | nimbus.cloud.maintenance | Disable global maintenance |
/cloud maintenance on <group> | nimbus.cloud.maintenance | Enable maintenance for a group |
/cloud maintenance off <group> | nimbus.cloud.maintenance | Disable maintenance for a group |
/cloud maintenance list | nimbus.cloud.maintenance | Show whitelisted players |
/cloud maintenance add <player> | nimbus.cloud.maintenance | Add player to maintenance whitelist |
/cloud maintenance remove <player> | nimbus.cloud.maintenance | Remove player from whitelist |
Hub command
| Command | Aliases | Description |
|---|---|---|
/hub | /lobby, /l | Send the player to a lobby server |
The hub command finds the lobby server with the fewest players (least-players load balancing) and connects the player. If the player is already on any lobby, they're told they're already there.
Connection handling
The bridge manages player connections automatically:
Initial connection
When a player joins the proxy, the bridge detects the connection type via Velocity's internal ConnectionType (set during the FML handshake). Connection types are:
| Type | Description |
|---|---|
VANILLA | Standard Minecraft client (including Fabric+Sodium — Fabric appears as vanilla) |
LEGACY_FORGE | Forge client using the legacy FML handshake (1.12.2 and older) |
MODERN_FORGE | Forge/NeoForge client using the modern FML handshake (1.13+) |
Modded clients (LEGACY_FORGE or MODERN_FORGE) are routed using mod list matching:
- Filter modded groups by protocol version (client protocol must match the group's MC version)
- Filter by connection type compatibility (
LEGACY_FORGEonly matches Forge;MODERN_FORGEmatches Forge or NeoForge) - Read the client's mod list via
player.getModInfo()and compute a match score against each group's server mod list:|clientMods ∩ serverMods| / |serverMods| - The group with the highest score (minimum 0.5) wins — the client is sent to the least-loaded instance of that group
- If no group scores above 0.5 but exactly one group matches protocol + type, route there (fallback for older Forge versions that don't report mod lists)
- If no match is found, fall back to lobby
Vanilla clients are routed to the lobby with the fewest players. If no suitable server is available, the player is disconnected with an error message.
The modded groups cache (including mod IDs from ModScanner) is fetched from GET /api/groups on startup and refreshed on controller reconnect.
Kicked from server
When a modded client is kicked from a modded server:
- The bridge tries to find an alternate modded group at the same protocol version
- If an alternate exists, the client is redirected there
- If no alternate is found, the client is disconnected (not sent to a vanilla lobby where they'd get kicked again)
When a vanilla client is kicked from a non-lobby server:
- The bridge attempts to redirect them to the lobby with the fewest players
- If a lobby is available, the player is sent there with a message
- If no lobby is available, the player is disconnected
When kicked from a lobby server (e.g. during a restart), the bridge redirects the player to a different lobby. If no other lobby is available, the player is disconnected with the kick reason.
Permission integration
The bridge integrates with Nimbus's permission system by providing a custom Velocity PermissionProvider:
- On login -- Fetches the player's permissions from the Nimbus API
- On permission check -- Resolves permissions including wildcard matching
- On disconnect -- Invalidates the permission cache
- On permission update -- WebSocket events trigger real-time cache refresh
Permission changes (via /cloud perms or the API) are pushed to all proxies instantly. No restart or rejoin required.
Proxy synchronization
The bridge handles real-time synchronization of:
Tab list
- Applies header/footer from
config/modules/syncproxy/tablist.tomlto all players - Formats player display names using the configured
player_format - Supports per-player overrides via the SDK's
Nimbus.setTabName() - Refreshes periodically (default: every 5 seconds)
- Placeholders:
{player},{prefix},{suffix},{server},{group},{online},{max}
MOTD
- Intercepts proxy ping events and applies the configured MOTD
- Supports MiniMessage formatting
- Configurable
max_playersandplayer_count_offset - Placeholders:
{online},{max}
Chat format
- Formats chat messages using the configured format (when
enabled = true) - Supports prefix/suffix from permission groups
- Supports MiniMessage and legacy
&color codes
Maintenance mode
- Global maintenance: Overrides the MOTD with a maintenance message, sets the version protocol to show a red "x" in the server list, and disconnects non-whitelisted players on join
- Group maintenance: Blocks players from connecting to servers of a specific group (e.g. during template updates), redirects them back to the lobby
- Players with
nimbus.maintenance.bypasspermission or on the whitelist can bypass both - Configuration is part of
config/modules/syncproxy/motd.tomlunder the[maintenance]section
Real-time updates
All proxy sync settings are updated in real-time via WebSocket events:
TABLIST_UPDATED-- Tab config changedMOTD_UPDATED-- MOTD config changedCHAT_FORMAT_UPDATED-- Chat format changedPLAYER_TAB_UPDATED-- Per-player tab override changedMAINTENANCE_ENABLED-- Maintenance enabled (global or group)MAINTENANCE_DISABLED-- Maintenance disabled (global or group)PERMISSION_GROUP_UPDATED-- Permission group changed (re-fetch display info)PLAYER_PERMISSIONS_UPDATED-- Player permissions changed
Architecture
NimbusBridgePlugin (entry point)
├── CloudCommand Dynamic forwarding via /api/commands; maintenance + events are Bridge-local
├── HubCommand Uses ProxyServer to find lobby
├── ConnectionListener Handles initial connect + kick fallback + maintenance blocking
├── MaintenanceHandler Proxy-side maintenance state cache (synced via API + events)
├── PermissionListener Injects NimbusPermissionProvider
├── ProxySyncListener Tab list + MOTD + chat sync + maintenance MOTD override
└── Shared clients:
├── NimbusApiClient HTTP client (bridge-specific, returns Result)
├── NimbusClient SDK HTTP client (shared with CloudCommand)
└── NimbusEventStream WebSocket event stream (shared across features)The bridge uses a single shared NimbusEventStream connection for all features (permissions, proxy sync, cloud command). This minimizes WebSocket connections to the Nimbus API.
Next steps
- SDK -- Backend server plugin API
- Proxy Setup -- Proxy configuration guide
- Permissions -- Permission system configuration