![CubeAdmin-logo](https://git.azuze.fr/kawa/CubeAdmin/raw/branch/main/cubeadmin-logo-dark.png) 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](https://bun.sh) | | Framework | [Next.js 16](https://nextjs.org) (App Router) | | Database | SQLite via `bun:sqlite` + [Drizzle ORM](https://orm.drizzle.team) | | Auth | [Better Auth v1.5](https://better-auth.com) | | UI | [shadcn/ui v4](https://ui.shadcn.com) + [Base UI](https://base-ui.com) + Tailwind CSS v4 | | Real-time | [Socket.io](https://socket.io) | | Email | [Nodemailer](https://nodemailer.com) (any SMTP server) | --- ## Quick Start (Development) ### Prerequisites - [Bun](https://bun.sh) ≥ 1.1 - A Minecraft server with RCON enabled (or use the provided `docker-compose.dev.yml`) ### 1. Clone and install ```bash git clone https://github.com/your-org/cubeadmin.git cd cubeadmin bun install ``` ### 2. Configure environment ```bash cp .env.example .env.local ``` Edit `.env.local` — at minimum you need: ```env 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) ```bash 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 ```bash bun dev ``` Open [http://localhost:3000](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 ```bash cp .env.example .env ``` Fill in all required values (see [Environment Variables](#environment-variables) below). #### 2. Start the stack ```bash 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 `Upgrade` header. Nginx snippet: ```nginx 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 ```bash bun install bun run build ``` #### 2. Run ```bash 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 ```ini # /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 ``` ```bash 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`: ```bash bun run db:generate ``` > **Note:** `bun run db:migrate` (drizzle-kit) does not work with Bun's native `bun:sqlite` driver. Always apply migrations through the app startup migrator or manually with `bun:sqlite` scripts. To open the Drizzle Studio database browser: ```bash 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. | ### Email (SMTP) CubeAdmin sends email via any standard SMTP server — Gmail, Mailgun, Postfix, Brevo, Amazon SES, or your own self-hosted relay. Email is only used for team invitations and magic-link sign-in. The app starts without email configured; invitations will fail gracefully with a logged error. | Variable | Required | Default | Description | |---|---|---|---| | `SMTP_HOST` | No* | — | SMTP server hostname (e.g. `smtp.gmail.com`, `smtp.mailgun.org`, `localhost`). Required for any email to be sent. | | `SMTP_PORT` | No | `587` | SMTP server port. Common values: `587` (STARTTLS), `465` (TLS/SSL), `25` (plain, relay), `1025` (local dev). | | `SMTP_SECURE` | No | `false` | Set to `true` to use implicit TLS (port 465). Leave `false` for STARTTLS (port 587) or plain. | | `SMTP_USER` | No | — | SMTP authentication username. Leave unset for unauthenticated relay (e.g. local Postfix). | | `SMTP_PASS` | No | — | SMTP authentication password or app-specific password. | | `EMAIL_FROM` | No | `CubeAdmin ` | The `From` address on outgoing emails. Must be authorised by your SMTP provider to avoid spam filtering. | #### Common SMTP configurations **Gmail** (app password required — enable 2FA first): ```env SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_SECURE=false SMTP_USER=you@gmail.com SMTP_PASS=your-app-password EMAIL_FROM=CubeAdmin ``` **Mailgun**: ```env SMTP_HOST=smtp.mailgun.org SMTP_PORT=587 SMTP_SECURE=false SMTP_USER=postmaster@mg.yourdomain.com SMTP_PASS=your-mailgun-smtp-password EMAIL_FROM=CubeAdmin ``` **Amazon SES**: ```env SMTP_HOST=email-smtp.us-east-1.amazonaws.com SMTP_PORT=587 SMTP_SECURE=false SMTP_USER=your-ses-access-key-id SMTP_PASS=your-ses-smtp-secret EMAIL_FROM=CubeAdmin ``` **Local dev with Mailpit** (catches all emails, no real sending): ```env SMTP_HOST=localhost SMTP_PORT=1025 SMTP_SECURE=false # no SMTP_USER / SMTP_PASS needed ``` Run Mailpit with `docker run -p 1025:1025 -p 8025:8025 axllent/mailpit` and view emails at [http://localhost:8025](http://localhost:8025). ### 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/ # Nodemailer SMTP client + email templates │ ├── 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`: ```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_SECRET`** before 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 `Secure` in 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.