Pterodactyl Docker Compose 部署指南

使用 Docker Compose 部署 Pterodactyl Panel 1.15.2(ghcr.io/pterodactyl/panel:v1.15.2 + MariaDB 11 + Redis),覆盖启动日志解读、APP_KEY 持久化、管理员创建、缓存/计划任务/队列验证与等价 docker run,已在 Ubuntu 22.04 + Docker 29.9.2 实测通过。

PterodactylPterodactylDocker部署MariaDBRedis缓存2026/11/03

Pterodactyl Docker Compose 部署指南

目标:使用 Docker Compose 一键部署 Pterodactyl Panel 1.15.2 游戏服务器管理面板(官方镜像 ghcr.io/pterodactyl/panel:v1.15.2 + MariaDB 11 + Redis),涵盖数据持久化、环境变量、启动日志解读、管理员创建与 Web 验证。本文档已在 Ubuntu 22.04(Docker 29.9.2 / Compose v5.6.1)环境按 /srv/pterodactyl 部署目录实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04 LTS(x86_64)
  • Docker 版本:Docker version 29.9.2, build a82e528;Docker Compose version v5.6.1
  • 面板镜像:ghcr.io/pterodactyl/panel:v1.15.2(Pterodactyl Panel 1.15.2,内置 PHP 8.3.36 + Laravel 12.64.0 + nginx + supervisor)
  • 数据库镜像:mariadb:11(实测解析为 11.8.9-MariaDB-ubu2404)
  • 缓存镜像:redis:alpine(实测解析为 redis_version:8.10.3)
  • 部署目录:/srv/pterodactyl(compose 文件与各 bind mount 数据目录)
  • Compose 项目名:pterodactyl-v1.15.2-stack;自定义网络:pterodactyl-v1152-net(子网 10.89.65.0/24)
  • 对外端口:宿主机 8138 → 面板 80(HTTP)
  • 演示账号:admin / q1w2e3r4(创建方式见「4.5 创建管理员账号」)

⚠️ 说明:本篇只部署面板侧(Panel)。Pterodactyl 采用「面板 + 节点守护进程」架构,真正跑游戏服务器的是节点侧 Wings(Go 编写、强依赖 Docker),Wings 需安装在独立的节点主机上,不在本篇范围内。面板本身不管理任何游戏服务器进程,部署完成后面板可正常登录与配置节点,但创建/启动游戏服务器需要先在面板中注册可达的 Wings 节点。

二、镜像选型说明

镜像用途版本策略
ghcr.io/pterodactyl/panel:v1.15.2面板本体(PHP/Laravel 应用)官方唯一发布渠道为 GitHub Container Registry(ghcr.io),生产环境用 v1.15.2 锁定版本,不要用 latest
ghcr.io/pterodactyl/panel:latest面板本体标签随上游漂移,升级不可控,不建议生产锁定
mariadb:11面板数据库官方支持 MySQL 5.7.22+/8.0 与 MariaDB 10.2+;本篇用 mariadb:11(实测 11.8.9)
redis:alpine缓存 / 会话 / 队列官方 quickstart 推荐 Redis;alpine 变体体积更小

💡 技术拓展:面板数据库不止 MariaDB 一种选择——

方案特点适用场景
MariaDB 10.x/11.x开源协议友好,官方 quickstart 默认示例即用 mariadb新建部署、无 Oracle 依赖顾虑
MySQL 5.7.22+/8.0官方同样支持,生态工具多已有 MySQL DBA 体系
外部托管数据库面板只要求网络可达与账号权限生产已有 RDS/PolarDB 类服务

本文按官方 quickstart 采用 mariadb:11。

三、前置条件

  • 已安装 Docker Engine 与 Compose 插件,可实测确认:
docker --version && docker compose version

实测回显:

Docker version 29.9.2, build a82e528
Docker Compose version v5.6.1
  • 宿主机 8138 端口空闲(被占用则改 compose 中 ports 映射)
  • 已规划部署目录 /srv/pterodactyl 及数据子目录(见「五、数据持久化说明」)
  • 已确定数据库口令策略;本篇演示环境统一使用测试口令 q1w2e3r4(生产请替换为强口令,并通过 .env 文件或密钥管理注入)

四、部署步骤

4.1 创建部署目录

面板要求持久化 5 类数据(数据库文件、应用密钥目录、nginx 配置、证书、应用日志),先建好宿主目录:

sudo mkdir -p /srv/pterodactyl/database
sudo mkdir -p /srv/pterodactyl/var
sudo mkdir -p /srv/pterodactyl/nginx
sudo mkdir -p /srv/pterodactyl/certs
sudo mkdir -p /srv/pterodactyl/logs
cd /srv/pterodactyl

⚠️ 注意:var/ 目录存放面板自动生成的 APP_KEY 与 HASHIDS_SALT(见 4.4 启动日志与「五、数据持久化说明」),必须持久化;若丢失,数据库中加密的敏感字段(节点 token、用户 2FA 密钥等)将全部不可恢复。

4.2 编写 docker-compose.yml

将以下内容保存为 /srv/pterodactyl/docker-compose.yml(结构与官方 Docker quickstart 一致,锚点复用环境变量组):

name: pterodactyl-v1.15.2-stack
x-common:
  database:
    &db-environment
    MYSQL_PASSWORD: &db-password "q1w2e3r4"
    MYSQL_ROOT_PASSWORD: "q1w2e3r4"
  panel:
    &panel-environment
    APP_URL: "http://127.0.0.1:8138"
    APP_TIMEZONE: "Asia/Shanghai"
    APP_SERVICE_AUTHOR: "noreply@example.com"
  mail:
    &mail-environment
    MAIL_FROM: "noreply@example.com"
    MAIL_DRIVER: "log"
services:
  database:
    image: mariadb:11
    container_name: pterodactyl-v1152-database
    restart: unless-stopped
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - /srv/pterodactyl/database:/var/lib/mysql
    environment:
      <<: *db-environment
      MYSQL_DATABASE: "panel"
      MYSQL_USER: "pterodactyl"
  cache:
    image: redis:alpine
    container_name: pterodactyl-v1152-cache
    restart: unless-stopped
  panel:
    image: ghcr.io/pterodactyl/panel:v1.15.2
    container_name: pterodactyl-v1152-panel
    restart: unless-stopped
    ports:
      - "8138:80"
    links:
      - database
      - cache
    volumes:
      - /srv/pterodactyl/var/:/app/var/
      - /srv/pterodactyl/nginx/:/etc/nginx/http.d/
      - /srv/pterodactyl/certs/:/etc/letsencrypt/
      - /srv/pterodactyl/logs/:/app/storage/logs
    environment:
      <<: [*panel-environment, *mail-environment]
      DB_PASSWORD: *db-password
      DB_USERNAME: "pterodactyl"
      DB_DATABASE: "panel"
      APP_ENV: "production"
      APP_ENVIRONMENT_ONLY: "false"
      CACHE_DRIVER: "redis"
      SESSION_DRIVER: "redis"
      QUEUE_DRIVER: "redis"
      REDIS_HOST: "cache"
      DB_HOST: "database"
      DB_PORT: "3306"
      HASHIDS_LENGTH: 8
networks:
  default:
    name: pterodactyl-v1152-net
    ipam:
      config:
        - subnet: 10.89.65.0/24

关键项逐项说明:

  • name: pterodactyl-v1.15.2-stack:Compose 项目名,docker compose ps/logs 按项目聚合。
  • x-common + YAML 锚点(&db-environment / *db-environment):把数据库口令定义为锚点 &db-password,面板侧 DB_PASSWORD: *db-password 引用同一值,避免两处改密码不同步。
  • APP_URL: "http://127.0.0.1:8138":面板对外访问地址,必须与最终浏览器访问 URL 一致,否则生成的资源链接/回调会指向错误地址。
  • command: --default-authentication-plugin=mysql_native_password:MariaDB 11 默认认证插件与面板 PDO 连接兼容性处理,官方 quickstart 保留项。
  • links + DB_HOST: database / REDIS_HOST: cache:面板通过 compose 服务名解析数据库与缓存地址(同网络内 DNS 即服务名)。
  • APP_ENVIRONMENT_ONLY: "false":允许通过 Web 设置页修改部分配置(默认 true 时仅允许环境变量配置)。
  • CACHE_DRIVER/SESSION_DRIVER/QUEUE_DRIVER: redis:三类后端全部走 Redis;若 Redis 不可用,面板队列与会话将失效。
  • HASHIDS_LENGTH: 8:服务器/用户短 ID 的长度,创建后不可更改(改了会导致既有 URL 全部失效)。

4.3 启动栈

cd /srv/pterodactyl
docker compose up -d

启动后确认三个服务均为 Up:

docker compose ps

实测回显:

NAME                         IMAGE                               COMMAND                  SERVICE    CREATED       STATUS       PORTS
pterodactyl-v1152-cache      redis:alpine                        "docker-entrypoint.s…"   cache      7 hours ago   Up 7 hours   6379/tcp
pterodactyl-v1152-database   mariadb:11                          "docker-entrypoint.s…"   database   7 hours ago   Up 7 hours   3306/tcp
pterodactyl-v1152-panel      ghcr.io/pterodactyl/panel:v1.15.2   "/bin/ash .github/do…"   panel      7 hours ago   Up 7 hours   443/tcp, 9000/tcp, 0.0.0.0:8138->80/tcp, [::8138->80/tcp]

4.4 查看面板启动日志(理解初始化行为)

面板镜像的入口脚本在首次启动时自动完成:生成应用密钥 → 选择 nginx 配置 → 等待数据库 → 建表与种子数据。实测 docker logs pterodactyl-v1152-panel 输出节选(实测首尾):

ln: /var/log/panel/logs: File exists
external vars don't exist.
Generating key.
Generated app key: Xxlo1pXG2rakzCEU1bFlwEuTcBZjepTk
Generating hashids salt.
Generated hashids salt: (@aWpiAA<6GK(OgU*>?e
Checking if https is required.
Checking if letsencrypt email is set.
No letsencrypt email is set using http config.
Removing the default nginx config
Checking log folder permissions.
Fixing log folder permissions.
Checking database status.
Waiting for database connection...
Waiting for database connection...
Waiting for database connection...
Waiting for database connection...
database (10.89.65.3:3306) open
Migrating and Seeding D.B

   INFO  Preparing database.  

  Creating migration table ....................................... 4.71ms DONE

   INFO  Running migrations.  

  2024_07_13_091852_clear_unused_allocation_notes ................ 0.55ms DONE

   INFO  Seeding database.  

  Database\Seeders\NestSeeder ........................................ RUNNING  
  Database\Seeders\NestSeeder ..................................... 12 ms DONE  

  Database\Seeders\EggSeeder ......................................... RUNNING  
...
Created Sponge (SpongeVanilla)
Created Paper
Created Bungeecord
Created Forge Minecraft
Created Vanilla Minecraft
...
  Database\Seeders\EggSeeder ..................................... 112 ms DONE  

Starting cron jobs.
Starting supervisord.
2026-11-02 19:06:57,917 CRIT Server 'unix_http_server' running without any HTTP authentication checking

逐段解读:

  1. 密钥生成:/app/var/.env 不存在时,入口脚本随机生成 APP_KEY 与 HASHIDS_SALT 写入该文件——这就是 4.1 中 var/ 目录必须挂载持久化的原因。
  2. nginx 配置选择:未设置 LE_EMAIL(Let's Encrypt 邮箱)时使用 HTTP 配置,把镜像内 default.conf 复制为 /etc/nginx/http.d/panel.conf(该目录已挂载到宿主 nginx/,配置因此持久化)。
  3. 等待数据库:Waiting for database connection... 会循环直到 MariaDB 3306 可达;首次初始化 MariaDB 数据目录需要若干秒,属正常现象。
  4. 建表与种子数据:自动执行 php artisan migrate --seed --force,种子数据即游戏服务模板体系——实测种出 4 个 Nest(Minecraft、Source Engine、Voice Servers、Rust)共 14 个 Egg。
  5. 常驻进程:入口脚本最后启动 crond(每分钟跑 php artisan schedule:run)与 supervisord(拉起 php-fpm、nginx、queue-worker 三个进程)。

数据库侧就绪日志(docker logs pterodactyl-v1152-database 尾部实测):

2026-11-02 19:06:55 0 [Note] Server socket created on IP: '::', port: '3306'.
2026-11-02 19:06:55 0 [Note] mariadbd: Event Scheduler: Loaded 0 events
2026-11-02 19:06:55 0 [Note] mariadbd: ready for connections.
Version: '11.8.9-MariaDB-ubu2404'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution

4.5 创建管理员账号

官方面板镜像不会自动创建管理员(启动日志里没有建用户步骤),需手动执行 p:user:make。创建一个超级管理员(--admin=1):

docker exec pterodactyl-v1152-panel php artisan p:user:make \
  --username=webadmin \
  --email=webadmin@pterodactyl.local \
  --name-first=Web --name-last=Admin \
  --password=q1w2e3r4 \
  --admin=1

实测回显:

+----------+--------------------------------------+
| Field    | Value                                |
+----------+--------------------------------------+
| UUID     | a3ea25f0-e776-4aa7-adda-1d697963a4de |
| Email    | webadmin@pterodactyl.local           |
| Username | webadmin                             |
| Name     | Web Admin                            |
| Admin    | Yes                                  |
+----------+--------------------------------------+

💡 说明:--admin=1 写入 users.root_admin=1,对应后台 /admin 全部权限;普通用户传 --admin=0。创建后密码以 bcrypt 哈希入库,可用 php artisan tinker --execute="var_dump(Hash::check('q1w2e3r4', \Pterodactyl\Models\User::where('username','webadmin')->value('password')));" 验证(实测返回 bool(true))。

4.6 Web 访问验证

curl -sI http://127.0.0.1:8138/

实测回显:

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=utf-8
Connection: keep-alive
X-Powered-By: PHP/8.3.36
Cache-Control: no-cache, private
Date: Tue, 03 Nov 2026 02:00:13 GMT
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: no-referrer-when-downgrade
curl -s http://127.0.0.1:8138/ -o /dev/null -w '%{http_code} %{redirect_url}\n'
curl -sL http://127.0.0.1:8138/ | grep -oE '<title>[^<]*</title>'
curl -sL http://127.0.0.1:8138/auth/login | grep -oE '<title>[^<]*</title>'

实测回显:

200 
<title>Pterodactyl</title>
<title>Pterodactyl</title>

浏览器打开 http://127.0.0.1:8138/auth/login,用 4.5 创建的账号登录即可进入面板。

4.7 缓存预热与产物检查

面板是 Laravel 应用,生产部署惯例是把配置/路由/视图编译缓存。逐条实测:

docker exec pterodactyl-v1152-panel php artisan config:cache
   INFO  Configuration cached successfully.  
docker exec pterodactyl-v1152-panel php artisan route:cache
   INFO  Routes cached successfully.  
docker exec pterodactyl-v1152-panel php artisan view:cache
   INFO  Blade templates cached successfully.  
docker exec pterodactyl-v1152-panel php artisan optimize:clear
   INFO  Clearing cached bootstrap files.  

  config ......................................................... 1.04ms DONE
  cache .......................................................... 3.18ms DONE
  compiled ....................................................... 0.51ms DONE
  events ......................................................... 0.33ms DONE
  routes ......................................................... 0.43ms DONE
  views .......................................................... 3.08ms DONE

⚠️ 注意:optimize:clear 会把刚做的编译缓存全部清掉(用于排障或改配置后重建)。改完 .env 或 compose 环境变量后,正确顺序是先 optimize:clear 再重新 config:cache/route:cache。

docker exec pterodactyl-v1152-panel php artisan storage:link
   ERROR  The [public/storage] link already exists.  

回显 already exists 是正常现象:官方镜像构建时已建好 public/storage 软链,无需重复执行(见 FAQ Q2)。

4.8 计划任务与队列验证

面板的自动化依赖两个常驻机制:cron 每分钟触发 schedule:run,supervisor 常驻 queue:work。手动跑一轮验证:

docker exec pterodactyl-v1152-panel php artisan schedule:run

实测回显:

  2026-11-03 10:00:16 Running ['artisan' cache:prune-stale-tags]  136.30ms DONE
  ⇂ '/usr/local/bin/php' 'artisan' cache:prune-stale-tags > '/dev/null' 2>&1  
  2026-11-03 10:00:17 Running ['artisan' p:schedule:process] ... 128.73ms DONE
  ⇂ Process schedules in the database and determine which are ready to run  
  2026-11-03 10:00:17 Running ['artisan' p:maintenance:prune-backups]  124.67ms DONE
  ⇂ Marks all backups older than "n" minutes that have not yet completed as being failed  

exit=0
docker exec pterodactyl-v1152-panel php artisan queue:work --stop-when-empty
exit=0
docker exec pterodactyl-v1152-panel php artisan schedule:list

实测回显(节选):

  0    * * * *  php artisan cache:prune-stale-tags  Next Due: 59 minutes from now
  *    * * * *  php artisan p:schedule:process . Next Due: 39 seconds from now
  0    0 * * *  php artisan p:maintenance:clean-service-backups  Next Due: 13 hours from now
  */30 * * * *  php artisan p:maintenance:prune-backups  Next Due: 29 minutes from now
  0    0 * * *  php artisan model:prune --model='Pterodactyl\Models\ActivityLog'  Next Due: 13 hours from now
  7    5 * * *  Collect Telemetry ................ Next Due: 19 hours from now

💡 说明:官方面板镜像已内置 crontab 行 * * * * * /usr/local/bin/php /app/artisan schedule:run >> /dev/null 2>&1 与 supervisor 的 [program:queue-worker](queue:work --queue=high,standard,low --sleep=3 --tries=3),Compose 部署无需再自建 cron/worker;若你改用裸机安装(非镜像),这两项必须手动配置,否则面板的备份、清理、任务调度全部停摆。

五、数据持久化说明

宿主目录挂载点内容丢失后果
/srv/pterodactyl/database/var/lib/mysqlMariaDB 数据目录面板全部业务数据(用户/节点/服务器/活动日志)清零
/srv/pterodactyl/var/app/var.env(APP_KEY、HASHIDS_SALT)不可逆:加密字段无法解密、会话与短 ID 全部失效
/srv/pterodactyl/nginx/etc/nginx/http.dnginx 站点配置 panel.conf回退镜像默认配置,自定义 HTTPS 配置丢失
/srv/pterodactyl/certs/etc/letsencryptLet's Encrypt 证书证书重签(有速率限制)
/srv/pterodactyl/logs/app/storage/logsLaravel 应用日志(按日切分)历史日志丢失,排障无据

实测验证 var/.env 持久化与软链机制:

ls -la /app/.env /app/var/.env
lrwxrwxrwx    1 root     root            13 Nov  2 19:06 /app/.env -> /app/var/.env
-rw-r--r--    1 root     root            75 Nov  2 19:06 /app/var/.env
cat /app/var/.env
APP_KEY=Xxlo1pXG2rakzCEU1bFlwEuTcBZjepTk
HASHIDS_SALT=(@aWpiAA<6GK(OgU*>?e

⚠️ 注意:入口脚本的逻辑是「/app/var/.env 存在则软链复用;不存在则新生成一组密钥写入」。也就是说只要 var/ 挂载在,重建面板服务不会换密钥;一旦 var/ 丢失,面板会静默生成新密钥,旧密文(节点 token、2FA 等)从此解不开。建议把 var/.env 纳入备份清单。

六、环境变量表

面板服务通过 compose environment 注入配置(实测 env | sort 中面板相关变量节选):

APP_ENVIRONMENT_ONLY=false
APP_ENV=production
APP_SERVICE_AUTHOR=noreply@example.com
APP_TIMEZONE=Asia/Shanghai
APP_URL=http://127.0.0.1:8138
CACHE_DRIVER=redis
DB_DATABASE=panel
DB_HOST=database
DB_PASSWORD=q1w2e3r4
DB_PORT=3306
DB_USERNAME=pterodactyl
HASHIDS_LENGTH=8
MAIL_DRIVER=log
MAIL_FROM=noreply@example.com
QUEUE_DRIVER=redis
REDIS_HOST=cache
SESSION_DRIVER=redis
变量本篇取值作用
APP_URLhttp://127.0.0.1:8138面板对外 URL,影响所有生成链接
APP_ENVproductionLaravel 运行环境;production 下部分 artisan 命令需 --force
APP_TIMEZONEAsia/Shanghai面板显示时区
APP_SERVICE_AUTHORnoreply@example.com系统邮件默认发件人
APP_ENVIRONMENT_ONLYfalse是否禁止 Web 设置页改配置(true 为仅环境变量)
DB_HOST / DB_PORTdatabase / 3306数据库地址(compose 服务名解析)
DB_DATABASE / DB_USERNAME / DB_PASSWORDpanel / pterodactyl / q1w2e3r4库名与账号(与 database 服务的 MYSQL_DATABASE/MYSQL_USER/MYSQL_PASSWORD 对应)
REDIS_HOSTcacheRedis 地址(compose 服务名)
CACHE_DRIVER / SESSION_DRIVER / QUEUE_DRIVERredis缓存/会话/队列后端;可选值见「七、配置参数说明」
HASHIDS_LENGTH8短 ID 长度,创建后不可更改
MAIL_DRIVER / MAIL_FROMlog / noreply@example.com邮件通道;log 表示只写日志不真发信(演示环境用)
LE_EMAIL(未设置)设置后面板侧走 Let's Encrypt 签发 HTTPS
APP_KEY / HASHIDS_SALT(未显式设置)不注入时入口脚本自动生成并持久化到 var/.env

七、配置参数说明

面板的配置分三层,实测各层现状:

  1. 环境变量层(compose environment):优先级最高,见第六章。
  2. .env 文件层:容器内 /app/.env 实测只有两行(其余全走环境变量):
docker exec pterodactyl-v1152-panel cat /app/.env
APP_KEY=Xxlo1pXG2rakzCEU1bFlwEuTcBZjepTk
HASHIDS_SALT=(@aWpiAA<6GK(OgU*>?e
  1. 镜像模板层:/app/.env.example 列出全部可配键(44 行),关键默认值:DB_CONNECTION=mysql、LOG_CHANNEL=daily、QUEUE_CONNECTION=redis、MAIL_MAILER=smtp、MAIL_ENCRYPTION=tls、HASHIDS_LENGTH=8。

用 p:info 一次性核对三层合成后的生效配置(实测回显节选):

docker exec pterodactyl-v1152-panel php artisan p:info
Version Information
===================

Panel Version     1.15.2              
Latest Version    1.15.2              
Up-to-Date        Yes                 

Application Configuration
=========================

Environment            <1>production         
Debug Mode             <1>No                 
Installation URL       http://127.0.0.1:8138 
Timezone               Asia/Shanghai         
Cache Driver           redis                 
Queue Driver           redis                 
Session Driver         redis                 

Database Configuration
======================

Driver   mysql       
Host     database    
Port     3306        
Database panel       
Username pterodactyl 

💡 技术拓展:CACHE_DRIVER/SESSION_DRIVER/QUEUE_DRIVER 的可选后端不止 Redis——

驱动特点适用
file落盘 /app/storage,零依赖单机试装、无 Redis 时兜底
redis内存级性能,会话/队列共享一致官方推荐,生产标配
database存面板数据库会话量小、不想多起服务
array进程内存,重启即失仅测试,禁止生产

本文按官方 quickstart 三者统一取 redis;队列驱动必须与 worker 进程共享同一后端,故 QUEUE_DRIVER 不建议用 file/array。

八、配置文件挂载

面板镜像的 nginx 站点配置持久化在 /srv/pterodactyl/nginx/panel.conf(首次启动由入口脚本从镜像默认模板复制生成),实测内容:

server {
    listen 80;
    server_name _;

    root /app/public;
    index index.html index.htm index.php;
    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    access_log off;
    error_log  /var/log/nginx/pterodactyl.app-error.log error;

    # allow larger file uploads and longer script runtimes
    client_max_body_size 100m;
    client_body_timeout 120s;
    sendfile off;

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_read_timeout 300;
    }
}

要点:root /app/public 是 Laravel 标准入口;client_max_body_size 100m 与 PHP 侧 upload_max_filesize=100M 对齐,决定面板上传(如备份恢复、服务器文件)的上限;要上 HTTPS,把 listen 80 段替换为 443 + ssl_certificate 指向 /etc/letsencrypt/(即宿主 certs/ 目录),或设置 LE_EMAIL 让入口脚本自动签发。改完配置执行 docker compose restart panel 生效。

九、等价 docker run

不依赖 Compose 时,三个服务可用等价 docker run 拉起(先建网络与目录):

sudo mkdir -p /srv/pterodactyl/{database,var,nginx,certs,logs}
docker network create --subnet 10.89.65.0/24 pterodactyl-v1152-net

docker run -d --name pterodactyl-v1152-database \
  --network pterodactyl-v1152-net --restart unless-stopped \
  -v /srv/pterodactyl/database:/var/lib/mysql \
  -e MYSQL_PASSWORD=q1w2e3r4 -e MYSQL_ROOT_PASSWORD=q1w2e3r4 \
  -e MYSQL_DATABASE=panel -e MYSQL_USER=pterodactyl \
  mariadb:11 --default-authentication-plugin=mysql_native_password

docker run -d --name pterodactyl-v1152-cache \
  --network pterodactyl-v1152-net --restart unless-stopped \
  redis:alpine

docker run -d --name pterodactyl-v1152-panel \
  --network pterodactyl-v1152-net --restart unless-stopped \
  -p 8138:80 \
  -v /srv/pterodactyl/var/:/app/var/ \
  -v /srv/pterodactyl/nginx/:/etc/nginx/http.d/ \
  -v /srv/pterodactyl/certs/:/etc/letsencrypt/ \
  -v /srv/pterodactyl/logs/:/app/storage/logs \
  -e APP_URL=http://127.0.0.1:8138 \
  -e APP_TIMEZONE=Asia/Shanghai \
  -e APP_SERVICE_AUTHOR=noreply@example.com \
  -e MAIL_FROM=noreply@example.com -e MAIL_DRIVER=log \
  -e DB_PASSWORD=q1w2e3r4 -e DB_USERNAME=pterodactyl -e DB_DATABASE=panel \
  -e DB_HOST=pterodactyl-v1152-database -e DB_PORT=3306 \
  -e REDIS_HOST=pterodactyl-v1152-cache \
  -e APP_ENV=production -e APP_ENVIRONMENT_ONLY=false \
  -e CACHE_DRIVER=redis -e SESSION_DRIVER=redis -e QUEUE_DRIVER=redis \
  -e HASHIDS_LENGTH=8 \
  ghcr.io/pterodactyl/panel:v1.15.2

💡 说明:单容器方式里 DB_HOST/REDIS_HOST 用容器名(自定义 bridge 网络内按容器名解析),与 Compose 里用服务名等价。两种方式的初始化行为完全相同(同一入口脚本)。

十、常用运维命令

cd /srv/pterodactyl

# 查看栈内服务状态
docker compose ps

# 跟踪面板日志
docker compose logs -f panel

# 重启面板(配置/环境变量变更后)
docker compose restart panel

# 升级面板:改 compose 中镜像 tag 后重建
docker compose pull panel
docker compose up -d panel

# 进入面板 artisan 环境
docker exec -it pterodactyl-v1152-panel php artisan --version

# 停止整栈(保留数据)
docker compose down

# 停止并删除命名卷(本部署数据在 bind mount,不受 -v 影响)
docker compose down -v

数据库与缓存连通性抽查(实测):

docker exec pterodactyl-v1152-database mariadb -uroot -pq1w2e3r4 -e 'use panel; select id,email,username,name_first,root_admin from users;'
id	email	username	name_first	root_admin
1	admin@pterodactyl.local	admin	Admin	1
2	demo@example.com	demo	Demo	0
docker exec pterodactyl-v1152-cache redis-cli dbsize
1

十一、常见问题(FAQ)

Q1:手动执行 php artisan migrate 提示 APPLICATION IN PRODUCTION 后直接取消?

实测复现:

$ docker exec pterodactyl-v1152-panel php artisan migrate

                                                                                
                           APPLICATION IN PRODUCTION.                           
                                                                                

   WARN  Command cancelled.  

原因:APP_ENV=production 下 Laravel 对破坏性命令要求交互确认,docker exec 无 TTY 时直接取消。解决:加 --force(面板入口脚本自动迁移时用的正是 migrate --seed --force):

docker exec pterodactyl-v1152-panel php artisan migrate --force

Q2:storage:link 报 The [public/storage] link already exists.?

官方镜像构建时已创建软链,该报错可安全忽略;php artisan about 中 Storage 段显示 public/storage ... LINKED 即为正常(实测如此)。

Q3:面板反复打印 Waiting for database connection...?

入口脚本会每 1 秒探测 DB_HOST:DB_PORT 直到通。常见原因:① 首次启动 MariaDB 初始化数据目录慢(实测等待约 4 轮后 database (10.89.65.3:3306) open,属正常);② DB_HOST 与实际服务名不符;③ 数据库口令与 MYSQL_PASSWORD 不一致导致面板连不上。用 docker compose ps 与 docker logs pterodactyl-v1152-database 定位。

Q4:p:user:make 报 The email has already been taken / The username has already been taken?

实测复现:

In Model.php line 50:
                                                                               
  Could not save Pterodactyl\Models\User[]: failed to validate data: {"email"  
  :["The email has already been taken."],"username":["The username has alread  
  y been taken."]}                                                                             
                                                                               

邮箱与用户名各自全局唯一,换其一即可;重复校验是数据完整性保护,不是故障。

Q5:p:user:delete 传邮箱位置参数报错?

实测复现:

$ docker exec pterodactyl-v1152-panel php artisan p:user:delete demo@example.com

                                                                              
  No arguments expected for "p:user:delete" command, got "demo@example.com".  
                                                                              

exit=1

该命令只接受选项:--user=<邮箱>,随后交互输入用户 ID 与 yes 二次确认(详见 CLI 命令篇)。

Q6:重建面板后所有用户登录态/2FA 异常?

检查 /srv/pterodactyl/var/.env 是否还在——若 var/ 未挂载或目录被删,入口脚本会生成全新 APP_KEY,旧密文无法解密,只能重置。备份该文件即可避免。

十二、参考链接

Pterodactyl Docker Compose 部署指南 - Quzuo