CubeAdmin
A production-ready Minecraft server administration panel built with Next.js, Bun, and SQLite.
Features
- Real-time console — stream server output and send commands via Socket.io
- Server control — start, stop, and restart your Minecraft server from the dashboard
- Player management — view online/offline players, ban/unban, manage the whitelist
- Plugin management — list, enable/disable, and upload plugins
- File explorer — browse, upload, download, and delete server files
- Backup system — create and restore backups on demand or on a schedule
- Team management — invite team members by email with role-based access control
- World map — embedded BlueMap 3D map integration
- Server version management — switch between Vanilla, Paper, and Fabric versions
- Monitoring — live CPU and memory charts
- Task scheduler — run RCON commands on a cron schedule
- Audit log — full record of all administrative actions
- Dark/light theme — persisted per user
Tech Stack
| Layer | Technology |
|---|---|
| Runtime | Bun |
| Framework | Next.js 16 (App Router) |
| Database | SQLite via bun:sqlite + Drizzle ORM |
| Auth | Better Auth v1.5 |
| UI | shadcn/ui v4 + Base UI + Tailwind CSS v4 |
| Real-time | Socket.io |
| Resend |
Quick Start (Development)
Prerequisites
- Bun ≥ 1.1
- A Minecraft server with RCON enabled (or use the provided
docker-compose.dev.yml)
1. Clone and install
git clone https://github.com/your-org/cubeadmin.git
cd cubeadmin
bun install
2. Configure environment
cp .env.example .env.local
Edit .env.local — at minimum you need:
BETTER_AUTH_SECRET=your-32-char-secret-here
MC_SERVER_PATH=/path/to/your/minecraft/server
MC_RCON_PASSWORD=your-rcon-password
3. Spin up a local Minecraft server (optional)
docker compose -f docker-compose.dev.yml up -d
This starts a Paper Minecraft server with RCON exposed on port 25575.
4. Run the development server
bun dev
Open http://localhost:3000. The first account you register automatically becomes the administrator.
Deployment
Option A — Docker Compose (recommended)
This is the easiest way to run CubeAdmin and a Minecraft server together on a single host.
1. Create your environment file
cp .env.example .env
Fill in all required values (see Environment Variables below).
2. Start the stack
docker compose up -d
This starts three services:
| Service | Description | Port |
|---|---|---|
cubeadmin |
The admin panel | 3000 |
minecraft |
Paper Minecraft server | 25565 |
bluemap |
3D world map (optional) | 8100 |
3. Reverse proxy (recommended)
Put Nginx or Caddy in front of CubeAdmin on port 3000. Example Caddyfile:
cubeadmin.example.com {
reverse_proxy localhost:3000
}
Important: Socket.io requires WebSocket support. Ensure your proxy forwards the
Upgradeheader.
Nginx snippet:
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
4. First login
Navigate to https://your-domain.com and register the first account — it is automatically granted the superadmin role.
Option B — Bare Metal (Bun)
1. Build
bun install
bun run build
2. Run
NODE_ENV=production bun --bun run server.ts
The server binds to 0.0.0.0:3000 by default. Use PORT and HOSTNAME env vars to change this.
3. Run as a systemd service
# /etc/systemd/system/cubeadmin.service
[Unit]
Description=CubeAdmin
After=network.target
[Service]
Type=simple
User=cubeadmin
WorkingDirectory=/opt/cubeadmin
ExecStart=/usr/local/bin/bun --bun run server.ts
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production
EnvironmentFile=/opt/cubeadmin/.env
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now cubeadmin
Database Migrations
CubeAdmin uses Drizzle ORM with a SQLite database. Migrations are applied automatically at startup via lib/db/migrate.ts.
To generate a new migration after changing lib/db/schema.ts:
bun run db:generate
Note:
bun run db:migrate(drizzle-kit) does not work with Bun's nativebun:sqlitedriver. Always apply migrations through the app startup migrator or manually withbun:sqlitescripts.
To open the Drizzle Studio database browser:
bun run db:studio
Environment Variables
Authentication
| Variable | Required | Default | Description |
|---|---|---|---|
BETTER_AUTH_SECRET |
Yes | — | Secret key used to sign sessions and tokens. Must be at least 32 characters. Generate one with openssl rand -base64 32. |
BETTER_AUTH_URL |
No | http://localhost:3000 |
The public base URL of the CubeAdmin app. Used by Better Auth to construct callback URLs. |
NEXT_PUBLIC_BETTER_AUTH_URL |
No | (inferred from browser) | Browser-side auth URL. Only needed if the public URL differs from what the browser can infer (e.g. behind a proxy). |
BETTER_AUTH_TRUSTED_ORIGINS |
No | http://localhost:3000 |
Comma-separated list of allowed origins for CORS and CSRF protection. Add your public domain in production. |
| Variable | Required | Default | Description |
|---|---|---|---|
RESEND_API_KEY |
No* | — | API key for Resend. Required for team invitation emails to work. The app starts without it, but invitations will fail silently. |
EMAIL_FROM |
No | CubeAdmin <noreply@example.com> |
The sender address used for outgoing emails. Must be a verified address in your Resend account. |
Minecraft Server
| Variable | Required | Default | Description |
|---|---|---|---|
MC_SERVER_PATH |
No | /opt/minecraft/server |
Absolute path to the Minecraft server directory on the host. CubeAdmin reads/writes files here and spawns the server process from this directory. |
MC_RCON_HOST |
No | 127.0.0.1 |
Hostname or IP where the Minecraft RCON interface is listening. Use minecraft when running the Docker Compose stack. |
MC_RCON_PORT |
No | 25575 |
TCP port for the Minecraft RCON interface. Must match rcon.port in server.properties. |
MC_RCON_PASSWORD |
Yes* | — | Password for the Minecraft RCON interface. Must match rcon.password in server.properties. Required for player management, whitelist, and scheduler features. |
*Only truly required if you want RCON-based features (player commands, scheduler). The app will start without it.
Database
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_PATH |
No | ./data/cubeadmin.db |
Path to the SQLite database file. The directory must exist and be writable. In Docker, this is mapped to a named volume. |
Server
| Variable | Required | Default | Description |
|---|---|---|---|
PORT |
No | 3000 |
TCP port the HTTP server listens on. |
HOSTNAME |
No | 0.0.0.0 |
Hostname the HTTP server binds to. |
NODE_ENV |
No | development |
Set to production for production deployments. Affects CSP headers, error verbosity, and Hot Module Replacement. |
Optional / Advanced
| Variable | Required | Default | Description |
|---|---|---|---|
BLUEMAP_URL |
No | — | URL where BlueMap is accessible from the browser (e.g. http://localhost:8100). Enables the Map page. Configurable from the Server Settings UI as well. |
RATE_LIMIT_RPM |
No | 100 |
Maximum number of API requests per minute per IP address. Applied to all /api/* routes by the middleware. |
Role System
CubeAdmin has three roles:
| Role | Description |
|---|---|
superadmin |
Full access — server control, settings, team management, everything. Automatically granted to the first registered user. |
admin |
Can manage players, plugins, files, backups, and the scheduler. Cannot change server settings or manage team roles. |
moderator |
Read-only access to most sections. Can send console commands and manage players. |
Roles are assigned when inviting team members. The initial superadmin can promote/demote others from the Team page.
Project Structure
.
├── app/
│ ├── (auth)/ # Login, register, accept-invite pages
│ ├── (dashboard)/ # All protected dashboard pages
│ │ ├── dashboard/ # Overview page (/)
│ │ ├── console/ # Real-time server console
│ │ ├── players/ # Player management
│ │ ├── plugins/ # Plugin management
│ │ ├── files/ # File explorer
│ │ ├── backups/ # Backup manager
│ │ ├── monitoring/ # CPU/RAM charts
│ │ ├── scheduler/ # Cron task scheduler
│ │ ├── team/ # Team & invitations
│ │ ├── audit/ # Audit log
│ │ ├── map/ # BlueMap integration
│ │ ├── server/ # Server settings
│ │ ├── updates/ # Version management
│ │ └── settings/ # Account settings
│ └── api/ # API routes
├── components/
│ ├── layout/ # Sidebar, Topbar
│ └── ui/ # shadcn/ui components
├── lib/
│ ├── auth/ # Better Auth config + client
│ ├── backup/ # Backup manager
│ ├── db/ # Drizzle schema + migrations
│ ├── email/ # Resend email client
│ ├── minecraft/ # Process manager, RCON, version fetcher
│ ├── security/ # Rate limiting
│ └── socket/ # Socket.io server setup
├── data/ # SQLite database (gitignored)
├── server.ts # Bun entry point (HTTP + Socket.io)
├── proxy.ts # Next.js middleware (auth guard + CSP)
├── docker-compose.yml # Production stack
└── docker-compose.dev.yml # Dev Minecraft server only
Enabling RCON on Your Minecraft Server
Add these lines to your server.properties:
enable-rcon=true
rcon.port=25575
rcon.password=your-strong-password
broadcast-rcon-to-ops=false
Restart the Minecraft server after editing server.properties.
Security Notes
- Change the default
BETTER_AUTH_SECRETbefore going to production. A leaked secret allows anyone to forge session tokens. - Use a strong RCON password. RCON has full server control — never expose RCON port 25575 to the public internet.
- HTTPS in production. Better Auth cookies are
Securein production; the app will not authenticate over plain HTTP. BETTER_AUTH_TRUSTED_ORIGINS— add your production domain to prevent CSRF attacks from other origins.- The middleware (
proxy.ts) enforces a strict Content Security Policy with per-request nonces. No inline scripts are permitted. - All API routes are rate-limited to 100 requests/minute per IP by default.