fix: something
This commit is contained in:
+129
-94
@@ -65,19 +65,21 @@ docker compose -f docker-compose.dev.yml up -d
|
||||
### 1.4 Database Setup
|
||||
|
||||
```bash
|
||||
# Generate migration files (if schema changed)
|
||||
pnpm db:generate
|
||||
|
||||
# Apply migrations to create all tables
|
||||
# Sync the schema from packages/database/src/schema, then apply the
|
||||
# hand-written data migrations in packages/database/drizzle/*.sql
|
||||
pnpm db:migrate
|
||||
|
||||
# Seed admin user and default games
|
||||
pnpm db:seed
|
||||
```
|
||||
|
||||
All three steps are idempotent, so re-running them after a `git pull` is the
|
||||
normal way to pick up schema and default-game changes.
|
||||
|
||||
After seeding, you'll have:
|
||||
- **Admin account**: `admin@gamepanel.local` / `admin123`
|
||||
- **Games**: Minecraft Java, CS2, Minecraft Bedrock, Terraria, Rust
|
||||
- **Games**: Minecraft Java & Bedrock, CS2, Terraria, Rust, Satisfactory,
|
||||
FiveM, ARK: Survival Evolved
|
||||
|
||||
### 1.5 Start Development Servers
|
||||
|
||||
@@ -129,123 +131,156 @@ cargo build --release # Production build
|
||||
|
||||
## 2. Docker Production Deployment
|
||||
|
||||
### 2.1 Prepare Environment
|
||||
The whole panel comes up with two commands. TLS and domain handling are
|
||||
deliberately **not** included — the panel serves plain HTTP and you put your own
|
||||
reverse proxy in front of it (see 2.6).
|
||||
|
||||
### 2.1 Install
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-org/source-gamepanel.git
|
||||
cd source-gamepanel
|
||||
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Edit `.env` with production values:
|
||||
|
||||
```env
|
||||
# REQUIRED — Generate unique secrets for each!
|
||||
JWT_SECRET=<generate-with-openssl-rand-hex-64>
|
||||
JWT_REFRESH_SECRET=<generate-another-secret>
|
||||
|
||||
# Database
|
||||
DB_USER=gamepanel
|
||||
DB_PASSWORD=<strong-random-password>
|
||||
DB_NAME=gamepanel
|
||||
|
||||
# Redis
|
||||
REDIS_PASSWORD=<strong-random-password>
|
||||
|
||||
# Networking
|
||||
CORS_ORIGIN=https://panel.yourdomain.com
|
||||
WEB_PORT=80
|
||||
API_PORT=3000
|
||||
|
||||
# Rate limiting
|
||||
RATE_LIMIT_MAX=100
|
||||
RATE_LIMIT_WINDOW_MS=60000
|
||||
```
|
||||
|
||||
### 2.2 Configure Daemon
|
||||
|
||||
Edit `daemon-config.yml`:
|
||||
|
||||
```yaml
|
||||
api_url: "http://api:3000"
|
||||
node_token: "<generate-a-secure-token>"
|
||||
grpc_port: 50051
|
||||
data_path: "/var/lib/gamepanel/servers"
|
||||
backup_path: "/var/lib/gamepanel/backups"
|
||||
docker:
|
||||
socket: "/var/run/docker.sock"
|
||||
network: "gamepanel_nw"
|
||||
network_subnet: "172.18.0.0/16"
|
||||
```
|
||||
|
||||
### 2.3 Build and Start
|
||||
|
||||
```bash
|
||||
# Build and start all services
|
||||
./scripts/install.sh
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
This starts 5 services:
|
||||
`scripts/install.sh` generates `.env` with fresh secrets, writes a
|
||||
`daemon-config.yml` with a matching node token, and creates the host data
|
||||
directories. It never overwrites files that already exist, so it is safe to
|
||||
re-run.
|
||||
|
||||
Then open `http://<server-ip>:80` and sign in with
|
||||
`admin@gamepanel.local` / `admin123` — change the password immediately.
|
||||
|
||||
### 2.2 What gets started
|
||||
|
||||
| Service | Port | Description |
|
||||
|---------|------|-------------|
|
||||
| `postgres` | 5432 | PostgreSQL database |
|
||||
| `redis` | 6379 | Rate limiting & cache |
|
||||
| `api` | 3000 | Fastify REST API |
|
||||
| `web` | 80 | nginx + React SPA |
|
||||
| `daemon` | 50051 | Rust gRPC daemon |
|
||||
| `postgres` | internal | PostgreSQL database |
|
||||
| `redis` | internal | Rate limiting & cache |
|
||||
| `migrate` | — | Applies the schema + seed, then exits |
|
||||
| `api` | internal | Fastify REST API |
|
||||
| `web` | `WEB_PORT` (80) | nginx + React SPA, proxies `/api` and `/socket.io` |
|
||||
| `daemon` | `DAEMON_GRPC_PORT` (50051) | Rust gRPC daemon |
|
||||
|
||||
### 2.4 Initialize Database
|
||||
Only `web` and `daemon` publish ports. Postgres, Redis and the API stay on the
|
||||
internal Compose network.
|
||||
|
||||
```bash
|
||||
# Run migrations
|
||||
docker compose exec api node -e "
|
||||
import('drizzle-kit').then(m => console.log('Use drizzle-kit migrate'))
|
||||
"
|
||||
The `migrate` service runs on every `docker compose up`; all three of its steps
|
||||
(`drizzle-kit push`, the data migrations, the seed) are idempotent.
|
||||
|
||||
# Or use the pnpm scripts with the container's DATABASE_URL
|
||||
docker compose exec api sh -c 'cd /app && node apps/api/dist/index.js'
|
||||
```
|
||||
### 2.3 Register the node
|
||||
|
||||
For the initial setup, the easiest approach is:
|
||||
In the panel, create a node with:
|
||||
|
||||
```bash
|
||||
# Run migrations from your host machine pointed at the Docker PostgreSQL
|
||||
DATABASE_URL=postgresql://gamepanel:<your-password>@localhost:5432/gamepanel pnpm db:migrate
|
||||
DATABASE_URL=postgresql://gamepanel:<your-password>@localhost:5432/gamepanel pnpm db:seed
|
||||
```
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| FQDN | `host.docker.internal` (or the host's IP/hostname) |
|
||||
| gRPC port | the `DAEMON_GRPC_PORT` from `.env` |
|
||||
| Daemon token | the `DAEMON_TOKEN` from `.env` |
|
||||
|
||||
### 2.4 Where game server files live
|
||||
|
||||
`DAEMON_DATA_PATH` in `.env` (default `/var/lib/gamepanel/servers`) is a **host**
|
||||
directory. The daemon runs in a container but creates game containers through
|
||||
the host's Docker socket, so their bind mounts are resolved by the host, not by
|
||||
the daemon container.
|
||||
|
||||
That is why the same path is passed twice — once as the daemon's own bind mount
|
||||
and once as `DAEMON_HOST_DATA_PATH`. If you change `DAEMON_DATA_PATH`, both
|
||||
follow automatically. Do not replace the bind mount with a named volume: the
|
||||
daemon and the game servers would then read and write two different
|
||||
directories, and files edited in the panel would never reach the game.
|
||||
|
||||
### 2.5 Verify
|
||||
|
||||
```bash
|
||||
# Check all services are healthy
|
||||
docker compose ps
|
||||
|
||||
# Test API health
|
||||
curl http://localhost:3000/api/health
|
||||
# {"status":"ok","timestamp":"2025-..."}
|
||||
|
||||
# Test web
|
||||
curl -s http://localhost | head -5
|
||||
# <!DOCTYPE html>...
|
||||
```
|
||||
|
||||
### 2.6 Monitoring
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
docker compose logs -f api
|
||||
docker compose logs -f daemon
|
||||
docker compose logs -f web
|
||||
|
||||
# Restart a service
|
||||
docker compose restart api
|
||||
curl -s http://localhost/api/health
|
||||
# {"status":"ok","timestamp":"..."}
|
||||
```
|
||||
|
||||
# Update to latest
|
||||
### 2.6 TLS, domain and reverse proxy
|
||||
|
||||
The panel intentionally ships without certificate handling. Terminate TLS in
|
||||
whatever proxy you already run and forward to `WEB_PORT`. WebSocket upgrades
|
||||
must be forwarded too, otherwise the live console will not connect.
|
||||
|
||||
Set `CORS_ORIGIN` in `.env` to the exact origin users open in the browser, then
|
||||
`docker compose up -d` to apply it.
|
||||
|
||||
Caddy (`Caddyfile`):
|
||||
|
||||
```
|
||||
panel.example.com {
|
||||
reverse_proxy 127.0.0.1:80
|
||||
}
|
||||
```
|
||||
|
||||
nginx:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name panel.example.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/panel.example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/panel.example.com/privkey.pem;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:80;
|
||||
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-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the proxy runs on the same host, bind the panel to loopback only by setting
|
||||
`WEB_PORT=127.0.0.1:8080` in `.env`.
|
||||
|
||||
### 2.7 Updating
|
||||
|
||||
```bash
|
||||
git pull
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The `migrate` service applies schema and seed changes on every start, so no
|
||||
extra step is needed.
|
||||
|
||||
### 2.8 Upgrading from a pre-`install.sh` deployment
|
||||
|
||||
Older `docker-compose.yml` versions stored the daemon's server directory in a
|
||||
named volume (`daemon_data`). That never matched what the game containers
|
||||
actually used: their bind mounts were resolved by the host, so the real game
|
||||
files ended up in `/var/lib/gamepanel/servers` on the host while the panel read
|
||||
and wrote the named volume. Editing a config in the panel appeared to work and
|
||||
then had no effect, and files could look like they reset themselves.
|
||||
|
||||
The compose file now bind-mounts the host directory directly, so after
|
||||
upgrading, the panel sees the same files the game servers do. Nothing needs to
|
||||
be moved — the game files were already on the host.
|
||||
|
||||
If you had put files into the old named volume through the panel and want them
|
||||
back, copy them out before removing it:
|
||||
|
||||
```bash
|
||||
docker run --rm -v gamepanel_daemon_data:/from -v /var/lib/gamepanel/servers:/to alpine sh -c 'cp -an /from/. /to/'
|
||||
docker volume rm gamepanel_daemon_data gamepanel_daemon_backups
|
||||
```
|
||||
|
||||
Also note that `postgres`, `redis` and `api` no longer publish host ports; only
|
||||
`web` and `daemon` do. If you were proxying straight to `API_PORT`, point your
|
||||
proxy at `WEB_PORT` instead — nginx forwards `/api` and `/socket.io`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Manual Production Setup (Ubuntu 22.04+)
|
||||
|
||||
Reference in New Issue
Block a user