This bundle is ready for Debian/Ubuntu with systemd. It includes:
- Node.js backend (Express + Socket.IO)
- Swappable DB layer (SQLite or MySQL)
- Players module with Steam sync
- Fleet overview surfaces offline servers, stale data, and crowded queues without external services
- Sample systemd unit (backend)
- Sample nginx config (static frontend over HTTPS)
- scripts/install-linux.sh and scripts/uninstall-linux.sh
git clone https://github.com/demassimo/rust-control-panel.git
cd rust-control-panel
sudo bash scripts/install-linux.sh
# follow the prompts to configure the backend environmentPrefer containers? The bundled docker-compose.yml now launches three services: the Express API (rustadmin-backend), the Discord bot worker that keeps the Main Bot online (rustadmin-discord-bot), and a static nginx frontend (rustadmin-frontend). Bring them up together so saving Discord settings automatically boots the Main Bot:
docker compose up -d rustadmin-backend rustadmin-discord-bot rustadmin-frontendBoth backend services share the ./backend/data volume for SQLite storage and read the same environment variables, so the Discord worker can see new bot settings without extra steps. Inspect the worker logs with docker compose logs -f rustadmin-discord-bot whenever you need to confirm it connected to Discord.
The installer now provisions a self-signed TLS certificate for the hostname you provide in PANEL_PUBLIC_URL and configures nginx to listen on port 443. The certificate and key live at /etc/nginx/ssl/rustadmin.crt and /etc/nginx/ssl/rustadmin.key, and port 80 automatically redirects to HTTPS. When upgrading an existing install, the installer and update script generate a new certificate if they don't find one and will prompt for the hostname to embed in that cert when the current configuration doesn't specify one.
Browsers will show a warning until you trust the certificate or replace it with one from a public CA. To swap in a trusted certificate, update those files and reload nginx.
Need a tour of the codebase? Check out FILES.md for a high-level description of each file and directory.
Looking for a step-by-step walkthrough? The tutorial guides cover installation, OAuth setup, server connections, moderation, Discord tickets, announcements, maps/wipes, and backup/upgrade routines with non-technical explanations for backend settings.
The backend service reads its environment variables from /opt/rustadmin/backend/.env. Open this file with sudo nano /opt/rustadmin/backend/.env to adjust settings without uploading new files. If you deploy to a different base
directory, update your systemd service or deployment scripts so they point to the actual .env location before starting the
backend.
This project is released under the Rust Control Panel Personal Use License, which allows you to use, modify, and share the software for personal, educational, or internal business purposes. Commercial redistribution, resale, or rebranding for sale is not permitted. See LICENSE for the full terms.
# Safe uninstall (keeps data in /opt/rustadmin)
sudo bash scripts/uninstall-linux.sh
# Full purge (removes app dir and system user)
sudo bash scripts/uninstall-linux.sh --purgeIn /opt/rustadmin/backend/.env:
- SQLite (default)
DB_CLIENT=sqlite
SQLITE_FILE=./data/panel.sqlite
- MySQL
DB_CLIENT=mysql
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=rustadmin
MYSQL_PASSWORD=strongpass
MYSQL_DATABASE=rustadmin
Set STEAM_API_KEY=... for Steam enrichment.
Set RUSTMAPS_API_KEY=... to provide a fallback RustMaps key (optional). Each panel user can store their own key from Settings → Personal settings — required for the live map module (see https://api.rustmaps.com for keys).
Set PANEL_PUBLIC_URL=https://your-panel.example.com so ticket preview links shared over Discord resolve to the correct public hostname.
Set CHAT_TRANSLATE_TARGET_LANG=en (plus optional CHAT_TRANSLATE_URL / CHAT_TRANSLATE_API_KEY) to force Rust chat into a single language via LibreTranslate.
The dashboard now keeps an eye on every server without calling external AI models. Offline nodes, stale monitor data, near-capacity populations, and long queues are highlighted automatically in both the fleet overview and the per-server health card inside the workspace. Use the refresh buttons to re-poll /servers/status on demand—no additional environment variables required.
If your staff prefers to review chat logs in a single language, point the backend at a LibreTranslate instance and set the target locale:
CHAT_TRANSLATE_TARGET_LANG=en
CHAT_TRANSLATE_URL=https://libretranslate.example.com # optional, defaults to https://libretranslate.com
CHAT_TRANSLATE_API_KEY= # optional API key
CHAT_TRANSLATE_SOURCE_LANG=auto # optional override, defaults to auto-detect
When CHAT_TRANSLATE_TARGET_LANG is populated, every inbound Rust chat line is translated before it is stored or broadcast to clients, ensuring the UI displays consistent text. The raw/original message remains available for auditing through the raw payload and the database row.
The Linux installer will prompt for these values and can optionally pull a self-hosted LibreTranslate Docker container for you (default port 5000).
When the installer provisions LibreTranslate it now enables LT_UPDATE_MODELS=true and loads the full panel language set (LT_LOAD_ONLY=af,ar,az,bg,bn,ca,cs,da,de,el,en,eo,es,et,eu,fa,fi,fr,ga,gl,he,hi,hu,id,it,ja,ko,ky,lt,lv,ms,nb,nl,pl,pt,pt-BR,ro,ru,sk,sl,sq,sr,sv,th,tl,tr,uk,ur,vi,zh-Hans,zh-Hant) so Afrikaans and other less-common locales work out of the box.
The panel supports both TOTP codes and WebAuthn passkeys for MFA. To keep registration and sign-in working in all browsers:
- Point
PANEL_PUBLIC_URLat the URL users type into their browser (e.g.,https://panel.example.com). The installer now prompts for this value and writes it to the backend.envalongsidePASSKEY_ORIGIN. - Set
PASSKEY_RP_IDto the host portion of that URL (no scheme or port, e.g.,panel.example.com). When omitted, the backend falls back to the request host orlocalhostinstead of0.0.0.0. - Restart the backend after updating the
.envso new passkey settings take effect. - If you run behind a reverse proxy, keep
TRUST_PROXY=true(default) so the backend reads the forwarded host/protocol for passkey validation.
Admins can enroll MFA from Settings → Security in the UI. Enable TOTP by scanning the QR code with an authenticator app, or add a passkey using a supported browser platform authenticator.
Team authentication links now rely on OAuth flows for both Discord and Steam. Configure these backend environment variables so players can connect their accounts and receive the configured Discord role automatically:
DISCORD_OAUTH_CLIENT_IDandDISCORD_OAUTH_CLIENT_SECRET— credentials from your Discord application.DISCORD_OAUTH_REDIRECT_URI— the publicly reachable callback URL (defaults tohttps://<host>/api/auth/discord/callbackwhen omitted).STEAM_OPENID_RETURN_URL— the callback URL Steam should redirect to (defaults tohttps://<host>/api/auth/steam/callback).STEAM_OPENID_REALM— optional OpenID realm sent to Steam (defaults to the request origin).TEAM_AUTH_STATE_SECRET— secret used to sign OAuth state and session cookies (falls back toJWT_SECRET, but a dedicated value is recommended).
The bot credentials for Discord tickets (DISCORD_BOT_TOKEN, DISCORD_GUILD_ID, and DISCORD_TICKET_PANEL_CHANNEL_ID) also live in this file, but the ticket panel itself is created from the web UI—once the bot variables are set, publish the panel from Discord tickets → Create ticket panel.
With these values in place the /request.html flow prompts users to sign in with both providers before the panel links their Steam ID to their Discord account, assigns the configured team-auth role, and gives staff better visibility into potential alternate accounts.
See docs/team-auth-oauth.md for a full walkthrough that covers provider setup, required environment variables, and troubleshooting tips for the linking flow.
- Every change to the Main Bot (team scope) or a workspace Server Bot (per-server scope) now lands in the
audit_logstable. The Team panel includes an Audit log card, and each workspace’s Discord settings card shows the latest server-specific entries. - The installer and database bootstrap add this table automatically for both SQLite and MySQL. Updating the code and restarting the backend (or rerunning
scripts/install-linux.sh) applies the migration with no extra steps. - Each entry records who made the change, when it happened, and which parts of the configuration (token, guild/channel, ticketing, command roles, etc.) were touched, making it easier to understand Discord behaviour changes.
- On first boot the panel seeds an
admin / admin123account; sign in and change it immediately. - Team invites are not available in this build yet; create staff accounts manually from Users → New user and adjust their role after they sign in.
- To allow public self-registration set
ALLOW_REGISTRATION=truein the backend environment (defaults to disabled). - Set
JWT_SECRETto a long random value to secure issued session tokens.
-
The backend keeps a persistent WebSocket connection for every configured server and polls
statuson an interval. -
Adjust the cadence with
MONITOR_INTERVAL_MS(default60000ms) to balance responsiveness and RCON load. -
Real-time health information and player counts are surfaced in the dashboard and streamed over Socket.IO to connected clients.
-
The panel accepts custom map images up to 40 MB by default (see
MAX_MAP_IMAGE_BYTESinbackend/src/index.js). -
If you host the panel behind nginx, set
client_max_body_size 40M;(or higher) in your site config and reload nginx. -
For Caddy, configure
request_body { max_size 40MB }(or higher) on the site handling the panel. -
When reverse proxies enforce a lower cap you will see HTTP 413 errors during upload — raise the proxy limit first, then adjust
MAX_MAP_IMAGE_BYTESif you need to allow even larger files.