GameAP Docker Compose 部署指南
Docker Compose 部署 GameAP v4.5.8(PostgreSQL 17 + Redis 7)全链路实测:启动验证、管理员登录、节点 Daemon enrollment、游戏服务器创建与 healthcheck 假阳性等排障实录。
GameAP Docker Compose 部署指南
目标:用 Docker Compose 从零部署 GameAP v4.5.8 生产形态(PostgreSQL 17 + Redis 7),完成面板启动、管理员登录、节点 Daemon 注册、游戏服务器创建的全链路验证。本文全部命令与回显均在真实 Linux 服务器上实测,环境为 Ubuntu 24.04.5 LTS(x86_64)、Docker 29.9.2、Docker Compose v5.6.1。
一、环境信息
- 服务器:Ubuntu 24.04.5 LTS,x86_64,内核态 systemd
- Docker Engine 29.9.2(build a82e528)、Docker Compose v5.6.1
- GameAP 面板 v4.5.8(Build date: 2026-10-18T17:08:49+00:00)
- GameAP Daemon v4.1.5(Build Date: 2026-09-20T02:09:14+00:00)
- 依赖服务:PostgreSQL 17、Redis 7(Alpine)
- 端口规划:面板 Web
8025、面板 gRPC(Daemon 接入)31718、Daemon 监听31717 - 网络:自定义 bridge 网络,示例网段
10.89.56.0/24(请按你的环境改为空闲网段) - 演示管理账号:
admin/q1w2e3r4(由 ADMIN_* 环境变量种子)
二、镜像选型说明
GameAP 官方镜像发布于 Docker Hub gameap/gameap,CI/CD 规则(官方 DOCKER.md,查询日期 2026-11-02):push 到 main 自动构建 latest;打版本 tag(如 v4.5.8)自动构建同号 tag;多平台构建 linux/amd64 与 linux/arm64。镜像内运行用户为 gameap(UID 1000)。
| 镜像 tag | 含义 | 适用 |
|---|---|---|
gameap/gameap:v4.5.8 | 锁定稳定版(2026-10-18 发布) | 生产,推荐 |
gameap/gameap:latest | main 分支滚动构建 | 尝鲜,不建议生产 |
💡 技术拓展:面板镜像的数据库形态并非只有一种——官方提供三套 compose 变体:默认(PostgreSQL 17 + Redis 7,生产推荐)、MySQL 变体(
docker-compose.mysql.yml,MySQL 8.4 + Redis 7)、Simple 变体(docker-compose.simple.yml,SQLite + memory 缓存,零外部依赖)。本文主线采用官方推荐的 PostgreSQL + Redis 生产形态;Simple 形态在「常见问题」中给出对照。
三、前置条件
- 已安装 Docker Engine 与 compose 插件:
$ docker --version && docker compose version
Docker version 29.9.2, build a82e528
Docker Compose version v5.6.1
- 生成两个 32 字节密钥(
ENCRYPTION_KEY与AUTH_SECRET为生产必改项,官方安全清单要求):
$ openssl rand -hex 32
63911321e9de171f1c38e22218440f8f5c8095a728bcd360bf9d693f00e28d2b
$ openssl rand -hex 32
3369429fe4f21bebb6a324f19be774dfa320807ca4883ded191b7916d8c54d84
⚠️ 注意:
AUTH_SECRET若给到 64 个十六进制字符(32 字节 hex 文本 = 64 字节),面板启动会打印WARN Auth secret key is longer than 32 bytes, trimming the key to 32 bytes length=64并截断使用,属预期行为(详见配置篇)。
- 确认 8025/31718 端口空闲、选定空闲网段(
docker network ls与ip route核对,避免与其他自定义网络冲突)。
四、部署步骤
4.1 编写 compose 文件
创建 gameap/docker-compose.yml(显式 name: 固定项目名,避免目录重命名导致卷/网络归属漂移):
name: gameap-stack
services:
gameap:
image: gameap/gameap:v4.5.8
container_name: gameap-panel
ports:
- "8025:8025"
environment:
HTTP_HOST: 0.0.0.0
HTTP_PORT: 8025
DATABASE_DRIVER: postgres
DATABASE_URL: postgres://gameap:gameap_pg_2026@gameap-postgres:5432/gameap?sslmode=disable
ENCRYPTION_KEY: 63911321e9de171f1c38e22218440f8f5c8095a728bcd360bf9d693f00e28d2b
AUTH_SECRET: 3369429fe4f21bebb6a324f19be774dfa320807ca4883ded191b7916d8c54d84
CACHE_DRIVER: redis
CACHE_REDIS_ADDR: gameap-redis:6379
FILES_DRIVER: local
FILES_LOCAL_BASE_PATH: /var/lib/gameap/files
LOGGER_LEVEL: info
ADMIN_LOGIN: admin
ADMIN_EMAIL: admin@example.com
ADMIN_PASSWORD: q1w2e3r4
volumes:
- gameap-storage:/var/lib/gameap
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- gameap-net
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8025/api/health"]
interval: 30s
timeout: 3s
start_period: 10s
retries: 3
postgres:
image: postgres:17
container_name: gameap-postgres
environment:
POSTGRES_USER: gameap
POSTGRES_PASSWORD: gameap_pg_2026
POSTGRES_DB: gameap
volumes:
- gameap-pgdata:/var/lib/postgresql/data
networks:
- gameap-net
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gameap -d gameap"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: gameap-redis
command: redis-server --appendonly yes
volumes:
- gameap-redisdata:/data
networks:
- gameap-net
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
volumes:
gameap-storage:
driver: local
gameap-pgdata:
driver: local
gameap-redisdata:
driver: local
networks:
gameap-net:
driver: bridge
ipam:
config:
- subnet: 10.89.56.0/24
逐项说明:
DATABASE_URL:PostgreSQL 连接串,sslmode=disable因数据库与应用同网互通;跨主机请改require;CACHE_DRIVER=redis:多实例部署与 ACME 分布式锁的前提;单机也可用默认memory;FILES_LOCAL_BASE_PATH=/var/lib/gameap/files:面板本地文件根(上传、ACME 材料、传输会话都落在这里),必须显式设置并持久化,缺省值会指向/var/www/gameap/storage/app导致启动 panic(见常见问题 11.6);ADMIN_LOGIN/ADMIN_EMAIL/ADMIN_PASSWORD:首次启动种子管理员。实测:8 位的q1w2e3r4在种子路径可以通过(种子不校验密码策略),但之后经 API 改密会被 min 12 策略拒绝(见 11.4);- healthcheck 用
wget -qO-(GET)而非官方 DOCKER.md 的wget --spider(HEAD)——原因与实测证据见常见问题 11.1。
4.2 启动栈
$ docker compose up -d
[+] Running 5/5
✔ Network gameap-stack_gameap-net Created
✔ Container gameap-postgres Healthy
✔ Container gameap-redis Healthy
✔ Container gameap-panel Started
depends_on.condition: service_healthy 生效:面板在 postgres/redis 双双 Healthy 后才启动。确认状态:
$ docker compose ps
NAME IMAGE COMMAND SERVICE STATUS PORTS
gameap-panel gameap/gameap:v4.5.8 "/usr/bin/gameap" gameap Up (healthy) 0.0.0.0:8025->8025/tcp, :::8025->8025/tcp
gameap-postgres postgres:17 "docker-entrypoint.s…" postgres Up (healthy) 5432/tcp
gameap-redis redis:7-alpine "docker-entrypoint.s…" redis Up (healthy) 6379/tcp
4.3 启动日志核验
$ docker compose logs gameap | head -40
关键行(实测逐行照抄):
INFO Password blocklist loaded entries=46146 source=embedded
INFO password hashing configured bcrypt_cost=13
INFO Applied migration path=001_create_gameap_tables.sql version=1 result="OK up ... (22.37ms)"
INFO Client certificate seeded successfully fingerprint=9dd43c17...
INFO Games and mods seeded successfully
INFO Roles seeded successfully
INFO Admin user seeded successfully login=admin email=admin@example.com
INFO GameAP started version=v4.5.8 build_date=2026-10-18T17:08:49+00:00
WARN plugin permission enforcement is disabled: ... set PLUGINS_PERMISSIONS_ENFORCE=true
INFO Starting pub-sub listener driver=memory
INFO gRPC TLS server certificate loaded common_name="GameAP API Server" dns_names=[localhost] ip_addresses="[10.89.56.4 127.0.0.1]" mtls_required=false
INFO Starting gRPC server address=0.0.0.0:31718 tls_enabled=true mtls_required=false reflection_enabled=false max_recv_mb=10 max_send_mb=10
解读:共 23 条迁移全部 OK;游戏库、角色、管理员自动种子;gRPC 服务在 31718 监听且默认开启 TLS(自签证书,SAN 仅 localhost + 面板自身 IP)、mTLS 默认关闭。WARN plugin permission enforcement is disabled 为 v4.5.8 默认行为(PLUGINS_PERMISSIONS_ENFORCE 未来将默认 true),可暂时忽略。
4.4 健康检查与登录验证
$ curl -s http://127.0.0.1:8025/api/health
{"status":"ok"}
$ curl -s -X POST http://127.0.0.1:8025/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"login":"admin","password":"q1w2e3r4"}'
实测返回 200,节选:
{"token":"v4.local.……","expires_in":86400,"token_type":"Bearer",
"user":{"login":"admin","email":"admin@example.com","name":"Admin"},
"mfa_nudge":{"required":true,"days_remaining":30}}
要点:请求体字段名是 login(也接受 email),写成 username 会得到 422 login or email fields are required;mfa_nudge 提示管理员 30 天宽限期内需启用二次认证。后续 API 调用统一用该 token:
$ TOKEN=$(curl -s -X POST http://127.0.0.1:8025/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"login":"admin","password":"q1w2e3r4"}' | jq -r .token)
4.5 节点注册(Daemon enrollment)
GameAP 的节点不能在面板侧手工创建——实测 POST /api/nodes 返回 405,GET /api/nodes 初始为 []。节点由 Daemon 侧凭 setup-key 主动 enrollment 注册。
第一步,面板签发 setup-key:
$ curl -s -X POST http://127.0.0.1:8025/api/nodes/setup-key \
-H "Authorization: Bearer $TOKEN"
{"setup_key":"gxaGOpNKUWxYUml41z0R3vTbgbmzKZYy"}
第二步,在游戏节点服务器(与面板同网,本例 10.89.56.5)安装 GameAP Daemon 二进制(官方 release gameap-daemon-v4.1.5-linux-amd64.tar.gz)并注册:
$ ./gameap-daemon enroll --connect grpc://gameap-panel:31718/gxaGOpNKUWxYUml41z0R3vTbgbmzKZYy
实测失败回显(重要,见常见问题 11.2):
x509: certificate is valid for localhost, not gameap-panel
面板自签 gRPC 证书的 SAN 只含 localhost 与面板自身 IP,用主机名连接必然校验失败。改用面板 IP 后成功:
$ ./gameap-daemon enroll --connect grpc://10.89.56.4:31718/gxaGOpNKUWxYUml41z0R3vTbgbmzKZYy
Successfully registered with panel
注册同时生成了 /etc/gameap-daemon/gameap-daemon.yaml(节选,密钥与证书路径按你的 --config-path/--certs-dir 而定):
ds_id: 1
api_key: <enroll 生成的 64 位随机密钥>
ca_certificate_file: /etc/gameap-daemon/certs/ca.crt
certificate_chain_file: /etc/gameap-daemon/certs/server.crt
private_key_file: /etc/gameap-daemon/certs/server.key
work_path: /srv/gameap
steamcmd_path: /srv/gameap/steamcmd
grpc:
address: 10.89.56.4:31718
第三步,回面板验证节点已入网:
$ curl -s http://127.0.0.1:8025/api/nodes -H "Authorization: Bearer $TOKEN"
[{"id":1,"enabled":true,"name":"10.89.56.5","os":"linux","ip":["10.89.56.5"]}]
GET /api/nodes/1 全量可见 work_path=/srv/gameap、gdaemon_host/port=31717、client_certificate_id 等字段。
4.6 创建第一个游戏服务器
$ curl -s http://127.0.0.1:8025/api/games -H "Authorization: Bearer $TOKEN" | jq length
43
$ curl -s http://127.0.0.1:8025/api/games/cs15/mods -H "Authorization: Bearer $TOKEN"
[{"id":7,"name":"Default"}]
种子库含 43 个游戏(7d2d、ark、arma3、cs15…)。创建服务器:
$ curl -s -X POST http://127.0.0.1:8025/api/servers \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"test-cs","ds_id":1,"game_id":"cs15","game_mod_id":7,"server_ip":"10.89.56.5","server_port":27015}'
{"message":"success","result":{"taskId":0,"serverId":1}}
两个实测 422 前置错误供排障:缺 game_mod_id → game_mod_id is required;mod 与游戏不匹配 → game mod does not belong to the specified game。创建成功后列表可见引擎信息:
$ curl -s http://127.0.0.1:8025/api/servers -H "Authorization: Bearer $TOKEN" | jq '.[0].game'
"Counter-Strike 1.5"
版本接口核验部署完整性:
$ curl -s http://127.0.0.1:8025/api/version -H "Authorization: Bearer $TOKEN"
实测节选:panel current=v4.5.8、latest_stable=4.5.8、latest_beta=4.6.0-dev.1;daemon latest_stable=4.1.5。
五、数据持久化说明
| 卷 | 挂载点 | 内容 |
|---|---|---|
gameap-storage | /var/lib/gameap | SQLite 库文件(simple 形态)、files/ 根(上传、ACME、传输会话) |
gameap-pgdata | /var/lib/postgresql/data | PostgreSQL 数据目录 |
gameap-redisdata | /data | Redis AOF(appendonly yes) |
⚠️ 注意:面板进程运行用户为
gameap(UID 1000)。若改用宿主机目录 bind 挂载替代 named volume,必须chown -R 1000:1000 <挂载目录>,否则文件上传与 ACME 写入会报权限错误(官方 DOCKER.md「Permission errors」节)。
六、环境变量表
本文用到的核心变量(全量 150+ 变量分类详解见 《GameAP 4.5.8 配置参数详解》):
| 变量 | 默认值 | 本文取值 | 说明 |
|---|---|---|---|
HTTP_HOST / HTTP_PORT | 0.0.0.0 / 8025 | 同默认 | Web/API 监听 |
DATABASE_DRIVER | 无(必填) | postgres | mysql/postgres/sqlite/inmemory |
DATABASE_URL | 无(必填) | postgres://…?sslmode=disable | 连接串格式见配置篇 |
ENCRYPTION_KEY | 无(必填) | 32B hex | 敏感数据加密密钥 |
AUTH_SECRET | 取 ENCRYPTION_KEY | 32B hex | PASETO/JWT 签名密钥,>32B 截断 |
CACHE_DRIVER | memory | redis | memory/redis/postgres |
CACHE_REDIS_ADDR | localhost:6379 | gameap-redis:6379 | Redis 地址 |
FILES_DRIVER | local | local | local/s3 |
FILES_LOCAL_BASE_PATH | /var/www/gameap/storage/app | /var/lib/gameap/files | 本地文件根,未设且目录不存在会 panic |
LOGGER_LEVEL | info | info | debug/info/warn/error |
ADMIN_LOGIN/ADMIN_EMAIL/ADMIN_PASSWORD | — | admin/admin@example.com/演示口令 | 首次启动种子管理员 |
七、配置参数说明
- 面板配置只有环境变量一个来源:二进制接受
-env <path>指向 env 文件,或从进程环境读取;没有独立 YAML/TOML。 - gRPC 监听端口由
GRPC_ADDR族变量控制(默认0.0.0.0:31718),日志行Starting gRPC server address=0.0.0.0:31718 tls_enabled=true即最终生效值。 - 密码策略:长度 min 12 / max 128、弱口令黑名单 46146 条(
source=embedded)、bcrypt cost 13;AUTH_ALLOW_WEAK_PASSWORDS=true可关黑名单(启动会打警告),长度校验不可关。 METRICS_TOKEN非空时才注册GET /metricsPrometheus 端点,本文未启用。
八、配置文件挂载
compose 内联 environment: 之外,官方推荐用 .env 文件与 compose 同目录存放密钥(compose 自动注入 ${ENCRYPTION_KEY} 插值),样例(官方 DOCKER.md「Example .env File」):
# Security (CHANGE THESE IN PRODUCTION!)
ENCRYPTION_KEY=your-random-32-char-encryption-key-here
AUTH_SECRET=your-random-32-char-auth-secret-here
POSTGRES_PASSWORD=secure-database-password
LOGGER_LEVEL=info
若希望配置完全脱离 compose,可把 env 文件 bind 进面板并在 command 里引用 -env:
gameap:
volumes:
- ./config.env:/etc/gameap/config.env:ro
command: ["/usr/bin/gameap", "-env", "/etc/gameap/config.env"]
九、等价 docker run
官方 README 给出的最小单机形态(SQLite + 本地文件,无 PG/Redis):
docker run -d -p 8025:8025 \
-e DATABASE_DRIVER=sqlite \
-e DATABASE_URL=file:/var/lib/gameap/db.sqlite?_busy_timeout=5000\&_journal_mode=WAL\&cache=shared \
-e ENCRYPTION_KEY=your-secret-key \
-e AUTH_SECRET=your-auth-secret \
-v gameap-data:/var/lib/gameap \
gameap/gameap:latest
💡 技术拓展:
DATABASE_URL的 SQLite 参数_busy_timeout=5000&_journal_mode=WAL&cache=shared是官方推荐的生产参数组合——WAL 提升并发读写、busy_timeout 缓解写锁竞争;对比 MySQL 格式user:pass@tcp(host:port)/db?parseTime=true与 PostgreSQL 格式postgres://user:pass@host:port/db?sslmode=disable,三者不可混用。
十、常用运维命令
# 跟踪面板日志
docker compose logs -f gameap
# 重启面板(不影响数据库)
docker compose restart gameap
# 升级:改 image tag 后
docker compose pull gameap && docker compose up -d gameap
# 备份数据库
docker exec gameap-postgres pg_dump -U gameap gameap > backup.sql
# 恢复数据库
docker exec -i gameap-postgres psql -U gameap gameap < backup.sql
# 备份文件存储卷
docker run --rm -v gameap-stack_gameap-storage:/data -v $(pwd):/backup \
alpine tar czf /backup/gameap-storage.tar.gz /data
# 彻底重置(连数据一起删,慎用)
docker compose down -v
十一、常见问题
11.1 面板一切正常但状态恒为 (unhealthy)
现象:docker compose ps 显示 gameap-panel ... Up (unhealthy),但宿主机 curl http://127.0.0.1:8025/api/health 返回 {"status":"ok"}。
定位(实测):
$ curl -s -o /dev/null -w "%{http_code}\n" -I http://127.0.0.1:8025/api/health
405
$ curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8025/api/health
200
$ docker exec gameap-panel wget --no-verbose --tries=1 --spider http://localhost:8025/api/health
http://localhost:8025/api/health:
Remote file does not exist -- broken link!!!
根因:官方 DOCKER.md 的 healthcheck 用 wget --spider,它以 HEAD 探测,而 /api/health 只允许 GET(HEAD 返回 405),于是健康检查永远失败——属探测方法与端点方法不匹配的假阳性。
解决:healthcheck 改用 GET 探测(本文 4.1 已采用):
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8025/api/health"]
改后 docker compose ps 状态变为 Up (healthy)。
11.2 enroll 报 x509: certificate is valid for localhost
见 4.5 实录:面板自签 gRPC 证书 SAN 仅 localhost + 面板 IP(日志行 dns_names=[localhost] ip_addresses="[10.89.56.4 127.0.0.1]")。解决三选一:① --connect 直接用面板 IP(本文做法);② 为面板配置带域名 SAN 的证书;③ 节点侧信任 CA 并用匹配域名。注意面板 IP 重建后可能变化,生产建议固定 ipv4_address。
11.3 登录 422:login or email fields are required
请求体字段写成 username 所致,GameAP 登录字段为 login(或 email),见 4.4。
11.4 改密码 400:password must be at least 12 characters long
实测 PUT /api/users/1 提交 8 位口令 q1w2e3r4 被拒:invalid input: password must be at least 12 characters long;换 12 位以上强口令返回 200。另注意该接口不带 email 字段会先报 email is required。种子路径(ADMIN_PASSWORD)不校验策略,所以初装口令可以短,上线前务必经 API/UI 改成 ≥12 位。
11.5 POST /api/nodes 返回 405
节点创建不是 REST 资源操作,只能走 Daemon enrollment(见 4.5),这是 GameAP 与 Pterodactyl(面板手工建节点)的工作流差异。
11.6 启动 panic:failed to open root directory
裸跑二进制(未走本文 compose、未设 FILES_LOCAL_BASE_PATH)实测 panic:
panic: failed to open root directory: open /var/www/gameap/storage/app: no such file or directory
根因:FILES_LOCAL_BASE_PATH 缺省值 /var/www/gameap/storage/app 不存在。解决:显式设置该变量(compose 已设)或预建目录。
11.7 bind 挂载后上传报权限错误
面板进程 UID 1000(gameap 用户),宿主机目录需 chown -R 1000:1000,见「五、数据持久化说明」。
十二、参考链接
- 官方部署文档 DOCKER.md:https://github.com/gameap/gameap/blob/main/DOCKER.md (查询日期 2026-11-02)
- 官方 README(Quick Start / Configuration):https://github.com/gameap/gameap
- 节点代理发布页:https://github.com/gameap/daemon/releases
- 站内相关:《GameAP 介绍与选型指南》、《GameAP 4.5.8 配置参数详解》、《GameAP 4.5.8 常用 CLI 命令与工具详解》