GameAP Docker Compose 部署指南

Docker Compose 部署 GameAP v4.5.8(PostgreSQL 17 + Redis 7)全链路实测:启动验证、管理员登录、节点 Daemon enrollment、游戏服务器创建与 healthcheck 假阳性等排障实录。

GameAPGameAPDocker ComposePostgreSQLRedis游戏服务器2026/11/03

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:latestmain 分支滚动构建尝鲜,不建议生产

💡 技术拓展:面板镜像的数据库形态并非只有一种——官方提供三套 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 形态在「常见问题」中给出对照。

三、前置条件

  1. 已安装 Docker Engine 与 compose 插件:
$ docker --version && docker compose version
Docker version 29.9.2, build a82e528
Docker Compose version v5.6.1
  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 并截断使用,属预期行为(详见配置篇)。

  1. 确认 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/gameapSQLite 库文件(simple 形态)、files/ 根(上传、ACME、传输会话)
gameap-pgdata/var/lib/postgresql/dataPostgreSQL 数据目录
gameap-redisdata/dataRedis 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_PORT0.0.0.0 / 8025同默认Web/API 监听
DATABASE_DRIVER无(必填)postgresmysql/postgres/sqlite/inmemory
DATABASE_URL无(必填)postgres://…?sslmode=disable连接串格式见配置篇
ENCRYPTION_KEY无(必填)32B hex敏感数据加密密钥
AUTH_SECRET取 ENCRYPTION_KEY32B hexPASETO/JWT 签名密钥,>32B 截断
CACHE_DRIVERmemoryredismemory/redis/postgres
CACHE_REDIS_ADDRlocalhost:6379gameap-redis:6379Redis 地址
FILES_DRIVERlocallocallocal/s3
FILES_LOCAL_BASE_PATH/var/www/gameap/storage/app/var/lib/gameap/files本地文件根,未设且目录不存在会 panic
LOGGER_LEVELinfoinfodebug/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 /metrics Prometheus 端点,本文未启用。

八、配置文件挂载

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,见「五、数据持久化说明」。

十二、参考链接

GameAP Docker Compose 部署指南 - Quzuo