A Dockerized management panel for dedicated Trackmania servers. Works both standalone and with existing stacks like PyPlanet or EvoSC and others.
TMControlPanel is a management panel designed for dedicated Trackmania servers. It provides an easy-to-use interface for managing server settings, players and maps. The panel can be run as a standalone service or integrated with other server controllers like PyPlanet or EvoSC.
You can use the free hosted panel at tmcontrolpanel.com or self-host it with Docker.
Manage all your dedicated servers from one panel and switch between them in a click. Group servers together, for example for a league or a team, and give people access per server or per group.
Create and delete Trackmania servers on Hetzner Cloud straight from the panel, together with databases, networks and volumes, and keep an eye on their metrics.
Change the server name, password, player and spectator limits and the other general settings from the browser.
Switch game modes, edit mode script settings, load and save match settings and manage the playlist without touching a file.
Add maps from the server, reorder the map list by dragging, jump to a map and queue the next ones in the jukebox.
Search maps and mappacks on Trackmania Exchange, or pull in seasonal campaigns, Track of the Day, weekly shorts and club campaigns and rooms, straight onto the server.
Follow rounds, checkpoints, scores and chat as they happen. Pause the match, set round, map and match points, and talk to players from the browser.
Kick, ban and force players to spectator, and keep the blacklist and guestlist in order across restarts.
Every round and finish is recorded. Browse match history per map, look up player results and export them to CSV.
Turn in-game widgets on per server, such as a match manager with pick and ban, live rankings, a Time Attack leaderboard and map and record info, and change their settings from the panel without a restart. Browse the plugin marketplace to install more, or upload your own privately. Plugins run in a sandbox with only the permissions you accept when you install them, and you can update or roll back a plugin from the server's Plugins page. See Plugins and the marketplace.
Browse, upload, delete and edit the server's files, match settings and scripts with a built-in code editor.
Give people access to exactly the servers and actions they need with roles and permissions on users, groups and servers. Every change is written to an audit log.
Server and group admins create API keys for external tools such as scoreboards, bots and tournament software. A server key reaches its server; a group key reaches every server in the group. Keys are limited to scopes, and stop working when their creator is no longer an admin. The versioned API lives at /api/v1, with an OpenAPI document at /api/v1/openapi.json and an interactive reference at /api/v1/docs. See the public API guide.
Self-hosters can add a second host that runs the web panel and GBX workers against the same database. If a worker goes down, another one takes over its servers. See the backup host guide.
An AI assistant for running your servers, in the panel and in game with the /co chat command. It uses an AI provider API key that you add per server or for the whole panel. It is still experimental, so expect rough edges.
TMControlPanel runs as two containers next to your database and Redis:
| Container | Image | What it does |
|---|---|---|
tmcontrolpanel |
marijnregterschot/tmcontrolpanel |
The web panel: UI, sign in, database, Nadeo, Trackmania Exchange, Hetzner and file manager. Runs the database migrations on start. Port 3000. |
gbx-service |
marijnregterschot/tmcontrolpanel-gbx-service |
Holds the connections to your dedicated servers, runs the in-game plugins and widgets, records matches and serves the live WebSockets to the browser. Port 3100. |
Both images come in a MariaDB/MySQL and a PostgreSQL (-postgres suffix) flavour. The two containers share the database and Redis, and authenticate to each other with GBX_SERVICE_TOKEN and WS_TICKET_SECRET.
- Browsers connect to port 3100 for the live pages, so
GBX_SERVICE_WS_URLmust be reachable from your users' browsers. Behind HTTPS it must be awss://URL, see Expose the GBX service. The service's main process is a front for the internal HTTP API and browser WebSockets. It never opens a GBX connection. It forks workers that hold GBX connections, run plugins and record matches. Redis leases assign each server to one worker. Commands, live events and status snapshots pass through Redis. Requests for a server with no owner return HTTP 503 (ServerUnavailable). A crashed or hung worker is restarted; other workers can take over its servers. Allow roughly 80–150 MB per worker, plus the front. Several containers sharing the database and Redis split servers by lease; see the backup host guide.GBX_SERVICE_ENABLED_SERVERSlimits which servers a container may claim. - Keep
/internal/*private. Only the web container calls those routes. Don't publish them through a reverse proxy.
The live pages, notifications and the server list connect from the browser straight to the GBX service. Make GBX_SERVICE_WS_URL reachable from your users' browsers:
- Plain setup: publish
3100and usews://<host>:3100. - HTTPS: a page served over HTTPS may only open
wss://sockets. Put a TLS-terminating reverse proxy in front of the service and setGBX_SERVICE_WS_URL=wss://.... The proxy must pass WebSocket upgrades. - Only expose
/ws/*and/health. The/internal/*routes are protected byGBX_SERVICE_TOKENbut are meant for the web container only; keep them off the public internet. - Add the web app's public origin (for example
https://panel.example.com) toWS_ALLOWED_ORIGINS. A socket from another origin is closed with code 4403. An empty value allows any origin.
-
Create a proxy host (for example
gbx.example.com) that forwards tohttp/gbx-service/3100. Use the host IP and port instead if NPM does not share a Docker network with the service. Turn on Websockets Support, request a certificate on the SSL tab and enable Force SSL. -
On the Advanced tab, add this custom configuration so that only
/ws/*and/healthpass through:location ~ ^/(?!(ws/|health$)) { return 404; }
Nginx checks regex locations before NPM's generated
location /. The negative lookahead keeps/ws/and/healthout of the regex, so they use the normal proxy block and everything else, including/internal/*, returns 404. To also hide/health, use(ws/). -
Set
GBX_SERVICE_WS_URL: wss://gbx.example.comon the web container andWS_ALLOWED_ORIGINS: https://panel.example.comon the service.GBX_SERVICE_URLstayshttp://gbx-service:3100because the web container talks to the service directly, not through NPM. -
Remove
ports: - 3100:3100from thegbx-servicecompose entry when NPM reaches it over the Docker network, or bind it to localhost with127.0.0.1:3100:3100when NPM runs on the host. Otherwise the port stays open and the proxy rules can be bypassed. -
Check it:
curl -i https://gbx.example.com/internal/servers # 404 curl -i https://gbx.example.com/health # 200 curl -i http://<server-ip>:3100/health # should fail from outside
In the browser dev tools the
/ws/live/...socket should show101 Switching Protocols. A close with code 4403 meansWS_ALLOWED_ORIGINSdoes not match the panel's origin exactly.
This repository provides a Docker Compose configuration to set up and run TMControlPanel and its dependencies using Docker containers.
Self-hosting takes some technical knowledge. You should be comfortable with Docker and Docker Compose, editing environment variables, running a database and Redis, and, if you expose the panel, putting it behind a reverse proxy with HTTPS. If that's new to you, ask in the Discord before you start.
You are responsible for your own deployment and any issues with it. Questions and help in the Discord are always welcome, but there is no guaranteed support.
To add a second host running only the web app and GBX workers against the same database and Redis, use the backup host guide. It covers the Docker and Coolify node stacks, private networking and failover checks. For option B, move the shared database and Redis off the primary with the database host guide.
Before using this docker-compose.yml file, ensure you have the following installed on your system:
- Docker: Install Docker
- Docker Compose: Install Docker Compose
You will also need some credentials for the Nadeo API to configure the TMControlPanel. You can obtain these credentials from the Nadeo API manager. Additionally, you will need a dedicated server login and password, which can be found in the dedicated server manager.
This guide will help you set up and run the services for both completely new stacks and with existing stacks like PyPlanet or EvoSC. There are also some boilerplate docker-compose.yml files available in the docker folder for a variety of server controllers. Just copy the compose file of your choice, plugin your own configurations and run the docker compose up -d command to start the services.
This section will guide you through setting up a new stack using the provided docker-compose.yml file.
First, copy the docker-compose.yml file from the repository to your desired directory. You can move it to any directory you want, the name of the directory will be the name of the stack.
Make sure to update or add the environment variables for the services in your docker-compose.yml file:
-
TMControlPanel Environment Variables:
NEXTAUTH_URL,NEXTAUTH_SECRET: NextAuth configuration for authentication.NEXTAUTH_SECRETcan be any random string, e.g.,VettePanel123.DEFAULT_ADMINS: Comma-separated list of default admin logins. Probably your own login, e.g.,v8vgGbx_TuKkBabAyn7nsQ.DEFAULT_PERMISSIONS: Comma-separated list of default permissions for new users. You can find a list of available permissions in the Permissions section.- NADEO Configuration: Make sure to update
NADEO_CLIENT_ID,NADEO_CLIENT_SECRET,NADEO_REDIRECT_URI,NADEO_SERVER_LOGIN,NADEO_SERVER_PASSWORDandNADEO_CONTACTwith your valid NADEO API credentials. Nadeo API credentials can be obtained from the Nadeo API manager. The server login and password can be obtained from the Dedicated Server Manager. HETZNER_KEY: Required for the Hetzner Cloud integration. Encrypts API tokens and SSH keys before they are stored in the database. Use a random string of at least 32 characters, for example fromopenssl rand -hex 32. When you change it, set the old value asHETZNER_KEY_PREVIOUSso stored values can still be decrypted.- GBX service connection:
GBX_SERVICE_URLis the address of thegbx-servicecontainer (http://gbx-service:3100).GBX_SERVICE_WS_URLis the address the browser uses to open the live WebSockets, so it must be reachable from your users (for examplews://<your-host>:3100, orwss://...behind HTTPS).GBX_SERVICE_TOKENandWS_TICKET_SECRETare secrets of at least 32 characters (openssl rand -base64 32) and must be identical in both containers. The panel refuses to start without them. - Codriver AI assistant (optional): the panel operator enables Codriver and stores the Anthropic API keys on the Codriver admin page.
SECRETS_KEY(at least 32 characters, shared with the GBX service) encrypts those keys and all stored dedicated/file-manager credentials; keep it stable, because changing it makes stored keys unreadable.ANTHROPIC_API_KEYis only a fallback for the shared key while none is stored. Optional Jev routing sends request text to TypeSafe and needs its own key, stored on the same page;TYPESAFE_API_KEYis its fallback while none is stored, likeANTHROPIC_API_KEY.PANEL_INTERNAL_TOKEN(at least 32 characters, the same in both containers) authenticates the GBX service when it forwards/cochat commands. Leave it empty to turn/cooff. The server Codriver page provides chat, usage and request history; operator-wide usage is under Admin → Codriver. Apply pending database migrations during upgrades, including the phase 5 model-call tracking column. MARKETPLACE_INDEX_URL(optional): The plugin marketplace the panel browses. Defaults to the official marketplace; set it to an empty value to turn browsing off. Uploading private plugins works either way.LOG_LEVEL: Set the log level for TMControlPanel. Supported values aretrace,debug,info,warn,errorandfatal. The default isinfo.PLAUSIBLE_API_HOST: Set the Plausible API host for analytics, e.g.,analytics.mywebsite.com. This is optional and can be left empty if you do not want to use Plausible analytics.- Sentry Configuration (Optional): TMControlPanel can send errors, performance traces, session replays and logs to Sentry. No Sentry configuration is required unless you want to enable telemetry.
NEXT_PUBLIC_SENTRY_ENABLED: Set totrueto enable Sentry.NEXT_PUBLIC_SENTRY_DSN: The Sentry DSN. Required when Sentry is enabled.SENTRY_SERVER_DSN(optional): Server-side DSN. Defaults toNEXT_PUBLIC_SENTRY_DSN.SENTRY_ENVIRONMENT(optional): Environment reported to Sentry. Defaults toNODE_ENV(production).SENTRY_TRACES_SAMPLE_RATE(optional): Performance trace sampling rate (0-1). Defaults to1.SENTRY_PROFILES_SAMPLE_RATE(optional): Profiling sampling rate (0-1). Defaults to1.NEXT_PUBLIC_SENTRY_REPLAYS_SESSION_SAMPLE_RATE(optional): Session Replay sampling rate (0-1). Defaults to1.NEXT_PUBLIC_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE(optional): Session Replay sampling rate when an error occurs (0-1). Defaults to1.SENTRY_SEND_DEFAULT_PII(optional): Whether to send personally identifiable information. Defaults tofalse.SENTRY_ATTACH_STACKTRACE(optional): Whether to attach stack traces to supported log messages. Defaults totrue.SENTRY_ENABLE_LOGS(optional): Whether to send application logs to Sentry. Defaults totrue.NEXT_PUBLIC_SENTRY_TUNNEL_ROUTE(optional): Optional tunnel route for browser events.SENTRY_TUNNEL_ROUTE(optional): Optional tunnel route for server-side events.SENTRY_MAX_BREADCRUMBS(optional): Maximum number of breadcrumbs attached to each event. Defaults to100.SENTRY_NORMALIZE_DEPTH(optional): Maximum object serialization depth. Defaults to3.SENTRY_IGNORE_ERRORS(optional): Comma-separated list of error messages that should not be reported.
-
GBX Service Environment Variables (
gbx-servicecontainer):DATABASE_URL,REDIS_URI: The same values as thetmcontrolpanelcontainer.GBX_SERVICE_TOKEN,WS_TICKET_SECRET: The same values as thetmcontrolpanelcontainer.WS_ALLOWED_ORIGINS: The origin(s) of the panel, comma separated, e.g.,https://panel.example.com. A browser socket from another origin is refused.NADEO_SERVER_LOGIN,NADEO_SERVER_PASSWORD,NADEO_CONTACT,NADEO_CLIENT_ID,NADEO_CLIENT_SECRET: The same values as thetmcontrolpanelcontainer.GBX_SERVICE_ENABLED_SERVERS(optional): Comma-separated server ids this container may claim. Empty allows every server in the database.GBX_WORKERS(default1): Worker processes. Set0to roll back to the single-process mode.GBX_NODE_ID(default hostname): Unique id per container.GBX_LEASE_TTL_MS(default15000, minimum6000): Lease lifetime in milliseconds. Workers renew every TTL/3.PANEL_INTERNAL_URL,PANEL_INTERNAL_TOKEN(optional): The panel address the service uses for Codriver/cocommands (http://tmcontrolpanel:3000), and the same token as thetmcontrolpanelcontainer. Empty turns/cooff.LOG_LEVEL,SENTRY_DSN,SENTRY_ENVIRONMENT(optional): Logging and error reporting of the service.MARKETPLACE_INDEX_URL,MARKETPLACE_CHECK_MINUTES(optional): The plugin marketplace the service checks for withdrawn plugin versions, and how often (default every 30 minutes). Empty URL turns the check off.
-
Dedicated Server Environment Variables:
TM_MASTERSERVER_LOGIN: Login for the dedicated server (same asNADEO_SERVER_LOGINin TMControlPanel).TM_MASTERSERVER_PASSWORD: Password for the dedicated server (same asNADEO_SERVER_PASSWORDin TMControlPanel).
Run the following command to start all services defined in the docker-compose.yml file:
docker compose up -dThat's it! You can now access your TMControlPanel at http://localhost:3000 or your own configured url.
This section will guide you through setting up the TMControlPanel with an existing PyPlanet or EvoSC stack.
First you need to navigate to your existing stack directory. Navigate to the directory where your docker-compose.yml file is located.
Paste the following configuration into your existing docker-compose.yml file.
tmcontrolpanel:
image: marijnregterschot/tmcontrolpanel:latest # Use marijnregterschot/tmcontrolpanel-postgres:latest if you are using PostgreSQL
ports:
- 3000:3000
restart: unless-stopped
environment:
NEXTAUTH_URL: http://localhost:3000
NEXTAUTH_SECRET:
DEFAULT_ADMINS:
DEFAULT_PERMISSIONS:
NADEO_CLIENT_ID:
NADEO_CLIENT_SECRET:
NADEO_REDIRECT_URI: http://localhost:3000/api/auth/callback/nadeo
NADEO_SERVER_LOGIN:
NADEO_SERVER_PASSWORD:
NADEO_CONTACT: TMControlPanel / <your contact info>
REDIS_URI: redis://redis:6379
DATABASE_URL: mysql://tmcontrolpanel:VettePanel123@db:3306/tmcontrolpanel
HETZNER_KEY:
GBX_SERVICE_URL: http://gbx-service:3100
GBX_SERVICE_WS_URL: ws://localhost:3100 # Must be reachable from the browser
GBX_SERVICE_TOKEN: # Same value as the GBX service, at least 32 characters
WS_TICKET_SECRET: # Same value as the GBX service, at least 32 characters
LOG_LEVEL: info
depends_on:
- db
- redis
gbx-service:
image: marijnregterschot/tmcontrolpanel-gbx-service:latest # Use marijnregterschot/tmcontrolpanel-gbx-service-postgres:latest if you are using PostgreSQL
ports:
- 3100:3100 # WebSockets for the browser; /internal routes require GBX_SERVICE_TOKEN
restart: unless-stopped
environment:
DATABASE_URL: mysql://tmcontrolpanel:VettePanel123@db:3306/tmcontrolpanel
REDIS_URI: redis://redis:6379
GBX_SERVICE_TOKEN: # Same value as the web app, at least 32 characters
WS_TICKET_SECRET: # Same value as the web app, at least 32 characters
WS_ALLOWED_ORIGINS: http://localhost:3000
NADEO_SERVER_LOGIN:
NADEO_SERVER_PASSWORD:
NADEO_CONTACT: TMControlPanel / <your contact info>
NADEO_CLIENT_ID:
NADEO_CLIENT_SECRET:
LOG_LEVEL: info
depends_on:
- db
- redis
- tmcontrolpanel # Runs the database migrations
filemanager:
image: marijnregterschot/trackmania-server-fm:latest
restart: unless-stopped
volumes:
# for PyPlanet the volume name is 'tmserverData', for EvoSC it is 'serverData' change accordingly
- tmserverData:/app/UserData
redis:
image: redis:latest
restart: unless-stopped
volumes:
- redisData:/dataAlso add the redis volume to the list of volumes at the bottom of your docker-compose.yml file:
volumes:
...
redisData: nullNote: Make sure you are using the correct volume names for the filemanger service. For PyPlanet, the volume name is usually
tmserverData, and for EvoSC, it isserverData.
Create a new database for TMControlPanel in your existing database service. For the default PyPlanet and EvoSC stacks, this is usually a MariaDB database.
The container name is likely something like <current-folder>-db-1.
- Log into the database container.
docker exec -it <container-name> mariadb -u root -pNote: The password
secretis the default, but it may differ depending on yourdocker-compose.ymlsetup.
- Create a new database:
CREATE DATABASE tmcontrolpanel;- Create a new user and grant permissions:
CREATE USER 'tmcontrolpanel'@'%' IDENTIFIED BY 'VettePanel123';
GRANT ALL PRIVILEGES ON tmcontrolpanel.* TO 'tmcontrolpanel'@'%';
FLUSH PRIVILEGES;Make sure to update or add the environment variables for the added services in your docker-compose.yml file:
-
TMControlPanel Environment Variables:
NEXTAUTH_URL,NEXTAUTH_SECRET: NextAuth configuration for authentication.NEXTAUTH_SECRETcan be any random string, e.g.,VettePanel123.DEFAULT_ADMINS: Comma-separated list of default admin logins.DEFAULT_PERMISSIONS: Comma-separated list of default permissions for new users. You can find a list of available permissions in the Permissions section.- NADEO Configuration: Make sure to update
NADEO_CLIENT_ID,NADEO_CLIENT_SECRET,NADEO_REDIRECT_URI,NADEO_SERVER_LOGIN,NADEO_SERVER_PASSWORDandNADEO_CONTACTwith your valid NADEO API credentials. Nadeo API credentials can be obtained from the Nadeo API manager. The server login and password can be found in your existing stack configuration under thededicatedortrackmaniaservice. HETZNER_KEY: Required for the Hetzner Cloud integration. Encrypts API tokens and SSH keys before they are stored in the database. Use a random string of at least 32 characters, for example fromopenssl rand -hex 32. When you change it, set the old value asHETZNER_KEY_PREVIOUSso stored values can still be decrypted.- GBX service connection:
GBX_SERVICE_URLis the address of thegbx-servicecontainer (http://gbx-service:3100).GBX_SERVICE_WS_URLis the address the browser uses to open the live WebSockets, so it must be reachable from your users (for examplews://<your-host>:3100, orwss://...behind HTTPS).GBX_SERVICE_TOKENandWS_TICKET_SECRETare secrets of at least 32 characters (openssl rand -base64 32) and must be identical in both containers. The panel refuses to start without them. MARKETPLACE_INDEX_URL(optional): The plugin marketplace the panel browses. Defaults to the official marketplace; set it to an empty value to turn browsing off. Uploading private plugins works either way.LOG_LEVEL: Set the log level for TMControlPanel. Supported values aretrace,debug,info,warn,errorandfatal. The default isinfo.PLAUSIBLE_API_HOST: Set the Plausible API host for analytics, e.g.,analytics.mywebsite.com. This is optional and can be left empty if you do not want to use Plausible analytics.- Sentry Configuration (Optional): TMControlPanel can send errors, performance traces, session replays and logs to Sentry. No Sentry configuration is required unless you want to enable telemetry.
NEXT_PUBLIC_SENTRY_ENABLED: Set totrueto enable Sentry.NEXT_PUBLIC_SENTRY_DSN: The Sentry DSN. Required when Sentry is enabled.SENTRY_SERVER_DSN(optional): Server-side DSN. Defaults toNEXT_PUBLIC_SENTRY_DSN.SENTRY_ENVIRONMENT(optional): Environment reported to Sentry. Defaults toNODE_ENV(production).SENTRY_TRACES_SAMPLE_RATE(optional): Performance trace sampling rate (0-1). Defaults to1.SENTRY_PROFILES_SAMPLE_RATE(optional): Profiling sampling rate (0-1). Defaults to1.NEXT_PUBLIC_SENTRY_REPLAYS_SESSION_SAMPLE_RATE(optional): Session Replay sampling rate (0-1). Defaults to1.NEXT_PUBLIC_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE(optional): Session Replay sampling rate when an error occurs (0-1). Defaults to1.SENTRY_SEND_DEFAULT_PII(optional): Whether to send personally identifiable information. Defaults tofalse.SENTRY_ATTACH_STACKTRACE(optional): Whether to attach stack traces to supported log messages. Defaults totrue.SENTRY_ENABLE_LOGS(optional): Whether to send application logs to Sentry. Defaults totrue.NEXT_PUBLIC_SENTRY_TUNNEL_ROUTE(optional): Optional tunnel route for browser events.SENTRY_TUNNEL_ROUTE(optional): Optional tunnel route for server-side events.SENTRY_MAX_BREADCRUMBS(optional): Maximum number of breadcrumbs attached to each event. Defaults to100.SENTRY_NORMALIZE_DEPTH(optional): Maximum object serialization depth. Defaults to3.SENTRY_IGNORE_ERRORS(optional): Comma-separated list of error messages that should not be reported.
-
GBX Service Environment Variables (
gbx-service): use the sameDATABASE_URL,REDIS_URI,GBX_SERVICE_TOKEN,WS_TICKET_SECRETand Nadeo values as thetmcontrolpanelservice, and setWS_ALLOWED_ORIGINSto the origin of the panel. See Architecture for what each variable does.
Note: Make sure you are using the correct service name for the dedicated server. For PyPlanet, the service name is usually
dedicated, and for EvoSC, it istrackmania.
Run the following command to start the services.
docker compose up -dThat's it! You can now access your TMControlPanel at http://localhost:3000 or your own configured url.
The TMControlPanel supports a permission system that allows you to manage user access to various features. You can set default permissions for new users using the DEFAULT_PERMISSIONS environment variable in your docker-compose.yml file. Here is a list of available permissions:
- users:view
- users:edit
- users:delete
- groups:view
- groups:create
- groups:edit
- groups:delete
- roles:view
- roles:create
- roles:edit
- roles:delete
- servers:view
- servers:create
- servers:edit
- servers:delete
- servers:clients:view
- servers:clients:manage
- hetzner:view
- hetzner:create
- hetzner:edit
- hetzner:delete
- hetzner:servers:view
- hetzner:servers:create
- hetzner:servers:delete
- audit-logs:view
- audit-logs:delete
- plugins:upload
- codriver:view
- codriver:edit
- api-keys:view
- api-keys:revoke
Back up your database first (mysqldump or pg_dump), then pull the new images and recreate the containers:
docker compose pull
docker compose up -dThe tmcontrolpanel container applies database migrations on start. Check the changelog before upgrading across several versions. Coming from an older deployment? Starting a new stack is recommended, and migrating is at your own risk. If you do migrate from the :beta images or the single-container dev branch, follow Upgrading from :beta to the release. To move a database to a new deployment with new SECRETS_KEY and HETZNER_KEY values, see Moving a database to a new deployment.
If you encounter any issues, check the logs of a specific service by running:
docker compose logs <service-name>For example, to view the logs of the TMControlPanel service:
docker compose logs tmcontrolpanelPlayers can type /version in game to receive the control panel app version in a
private chat reply. This native command works without plugins, even when /help
is disabled. The version comes from the root package.json and is bundled into
the GBX service build. /help version describes the command when help is enabled.
Other native commands also reply privately and work without plugins:
| Command | Information | Access |
|---|---|---|
/uptime |
Service uptime and duration of the current server connection | Everyone |
/status |
Connection state, game mode, drivers and spectators | Everyone |
/plugins |
Installed versions and disabled/running/not-running state | Everyone |
/ping |
Dedicated server XML-RPC round-trip time (not gameplay latency) | Everyone |
/sysinfo |
Node version, platform, process memory, CPU count and host CPU load | Server admins |
/diagnostics |
Database, Redis and GBX connectivity checked separately | Server admins |
Global panel admins, direct server Admins, and Admins of groups containing the
server can use the restricted commands. Probes and permission checks time out
after three seconds. Error details remain in service logs. /help <command>
describes each command when help is enabled. These native command names are
reserved and cannot be claimed by plugins.
Everything that talks to a dedicated server (connection errors, plugins, chat commands, match recording) is logged by the GBX service:
docker compose logs gbx-service
curl http://localhost:3100/health # Includes workers in cluster mode; 503 when degraded
curl http://localhost:3100/healthz # 200 when Redis is reachable and a worker heartbeat exists; otherwise 503- A container exits right after starting: a missing or too short (< 32 characters)
GBX_SERVICE_TOKENorWS_TICKET_SECRET, or an invalid value, is listed in its log. - Live pages stay empty or the servers show as offline: the browser can't reach
GBX_SERVICE_WS_URL, or the panel's origin is missing fromWS_ALLOWED_ORIGINS(the socket closes with code4403). Behind HTTPS the URL must start withwss://. - Everything is recorded or announced twice: check for an older controller, a service using another Redis, or overlapping services with
GBX_WORKERS=0. Cluster workers sharing Redis coordinate ownership through leases.
The release notes of every version are in CHANGELOG.md.
Admins of a server can install plugins from the marketplace on the Plugins page, or upload their own (with the plugins:upload permission). Plugins run sandboxed in the GBX service, and a plugin that misbehaves is turned off and its admins are notified.
MARKETPLACE_INDEX_URLon both containers selects the marketplace. The default is the official one; leave it empty to turn browsing off.- Plugin marketplace: how it works, running your own registry, withdrawing plugins, and the security model.
- Plugin SDK: writing, testing and publishing a plugin.
- First-party plugins: the first-party plugins published in the registry.
Contributions are welcome! If you have suggestions or improvements, please create a pull request or open an issue. Feel free to fork the repository and make changes as needed. See CONTRIBUTING.md for how to set up a local development environment.
This project is licensed under the MIT License - see the License file for details.