Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ CORS_ORIGIN="https://minepanel.xyz" # required in production; exact frontend or
# Compose defaults to `latest` for the future stable channel; no stable release is published yet.
# For current pre-stable deployments, set this explicitly to the `edge` image.
MINEPANEL_IMAGE=ghcr.io/minepanelproject/minepanel-backend:latest
# Required managed-Minecraft image identity. The digest is a verified amd64/arm64 manifest.
MINECRAFT_IMAGE=itzg/minecraft-server:2026.8.2@sha256:efa878ddb49cf5251b2e5f2ad71b08fd2f7236c1f7907433f6697258b31d2ce4

# ─── Database ─────────────────────────────────────────────────────────────────
POSTGRES_PASSWORD=your-secure-password-here
Expand All @@ -24,8 +26,6 @@ ENCRYPTION_KEY=
SETUP_TOKEN=

REQUIRE_ADMIN_APPROVAL=true # true = new users start as PENDING, admin must approve
LOGIN_THROTTLE_LIMIT=5 # max login attempts per window
LOGIN_THROTTLE_TTL_MS=10000 # window duration in ms (default: 10s)
# Optional. Enables Google ID-token login; use the trusted frontend OAuth client ID.
# The backend derives its frontend origin from CORS_ORIGIN and never accepts an origin from requests.
GOOGLE_CLIENT_ID=
Expand Down Expand Up @@ -65,6 +65,8 @@ MC_PORT_MAX=25665
MIN_FREE_DISK_MB=2048
MAX_MEMORY_RATIO=0.90
STOP_WARN_SECONDS=30 # seconds to warn players before graceful shutdown (0-300, default 30)
MC_CPU_NANO_CPUS=2000000000 # global per-container quota; 2 CPUs
MC_PIDS_LIMIT=512 # finite per-container process limit

# ─── Volume / network names (overridable for disposable tests) ───────────────
POSTGRES_VOLUME_NAME=minepanel-postgres-data
Expand Down
51 changes: 50 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,59 @@ jobs:
severity: HIGH
ignore-unfixed: true

trusted-lifecycle:
runs-on: ubuntu-latest
timeout-minutes: 20
needs: [test, migration, e2e, image]
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: minepanel
POSTGRES_PASSWORD: minepanel
POSTGRES_DB: minepanel
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U minepanel"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
DATABASE_URL: postgresql://minepanel:minepanel@localhost:5432/minepanel
JWT_SECRET: trusted-lifecycle-jwt-secret-long-enough
JWT_EXPIRES_IN: 15m
JWT_REFRESH_EXPIRES_IN: 7d
ENCRYPTION_KEY: '0000000000000000000000000000000000000000000000000000000000000000'
CORS_ORIGIN: http://127.0.0.1:3000
DOCKER_SOCKET: /var/run/docker.sock
MINECRAFT_IMAGE: itzg/minecraft-server:2026.8.2@sha256:efa878ddb49cf5251b2e5f2ad71b08fd2f7236c1f7907433f6697258b31d2ce4
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Install Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.14

- name: Install dependencies (frozen lockfile)
run: bun install --frozen-lockfile

- name: Apply migrations
run: bun run db:migrate

- name: Build production application
run: bun run build

- name: Run trusted real-Docker lifecycle
run: bun run docker:lifecycle

publish:
runs-on: ubuntu-latest
timeout-minutes: 25
needs: [test, migration, e2e, image]
needs: [test, migration, e2e, image, trusted-lifecycle]
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))
permissions:
contents: read
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ docker compose pull && docker compose up -d
│ │ │
│ /var/run/docker.sock (root, local) │
│ ▼ │
│ mc-{id} (itzg/minecraft-server) │
│ on dedicated managed-MC bridge │
mc-{id} (itzg/minecraft-server pinned image) │
on managed bridge (CPU/PIDs capped) │
└──────────────────────────────────────────────┘
```

Expand Down Expand Up @@ -153,6 +153,7 @@ See [`.env.example`](./.env.example) for the full list. Key variables:
| `DOMAIN` | Public domain - used by Caddy for HTTPS | required in prod |
| `CORS_ORIGIN` | Allowed frontend origin - never derived from `DOMAIN` | required in prod |
| `MINEPANEL_IMAGE` | Backend image used by Compose | `ghcr.io/minepanelproject/minepanel-backend:latest` |
| `MINECRAFT_IMAGE` | Required image identity shared by prefetch and managed containers | pinned multi-arch digest in `.env.example` |
| `DATABASE_URL` | PostgreSQL connection string | required |
| `JWT_SECRET` | Secret for JWT signing | required |
| `ENCRYPTION_KEY` | 32 random bytes encoded as 64 hexadecimal characters; generate with `openssl rand -hex 32` | required |
Expand All @@ -163,6 +164,8 @@ See [`.env.example`](./.env.example) for the full list. Key variables:
| `MC_DATA_PATH` | Base path inside the backend; Compose fixes it to `/mc-data` (direct backend execution only) | `/mc-data` |
| `MIN_FREE_DISK_MB` | Minimum free disk to allow server creation | `2048` |
| `MAX_MEMORY_RATIO` | Max fraction of host RAM allocatable to MC servers | `0.90` |
| `MC_CPU_NANO_CPUS` | Per-container CPU quota in NanoCPU units | `2000000000` |
| `MC_PIDS_LIMIT` | Per-container process limit | `512` |

---

Expand Down
Loading