PixelFed 0.15.2 Docker Compose 部署指南
官方编排形态从零部署 PixelFed v0.15.2 全流程实测:MariaDB 换型、自动迁移、管理员创建、功能验证与 8 类故障排障实录
PixelFed 0.15.2 Docker Compose 部署指南
目标:在一台 Ubuntu 22.04 服务器上,用官方编排形态从零部署 PixelFed v0.15.2(联邦图片分享平台),覆盖 .env 配置、数据库选型(含 MySQL 9 迁移失败的实测换型)、自动迁移、管理员创建、图片/故事功能验证与五大典型故障排查。已在 Ubuntu 22.04 x86_64 服务器(IP 192.168.146.128,端口 8135)实测通过,登录、发帖、故事发布全部验证成功。
一、环境信息
| 项目 | 实测值 |
|---|---|
| 操作系统 | Ubuntu 22.04(x86_64) |
| Docker | 29.9.2, build a82e528 |
| Docker Compose | v5.6.1 |
| PixelFed | v0.15.2(ghcr.io/pixelfed/pixelfed:v0.15.2,2.08GB) |
| 数据库 | MariaDB 11.8(458MB) |
| 缓存/队列 | Redis 8(redis:8-alpine,161MB) |
| 部署目录 | /opt/pixelfed |
| 服务端口 | 8135(HTTP) |
| 编排栈名 | pixelfed-0.15.2-stack(内部网络段 10.89.65.0/24) |
| 演示账号 | admin / q1w2e3r4(管理员) |
本方案为 5 角色完整形态:应用(Web/API)+ Horizon 队列工作器 + 定时任务调度 + MariaDB + Redis。
二、镜像选型说明
2.1 应用镜像来源
PixelFed 官方发布应用包于 GitHub Container Registry:ghcr.io/pixelfed/pixelfed:v0.15.2。官方仓库根目录同时提供 docker-compose.yml(该文件内以源码构建方式定义应用),对使用官方预构建发行包的部署,官方文档推荐直接引用 GHCR 上的版本号发行包。本文采用「官方预构建发行包 v0.15.2」,版本固定、可重复部署。
# 拉取官方发行包(预构建应用)
docker pull ghcr.io/pixelfed/pixelfed:v0.15.2
实测回显(首次拉取后再次执行验证,输出首尾节选):
v0.15.2: Pulling from pixelfed/pixelfed
Digest: sha256:f1237913ef0d392a5afef1dab8e3dd01234435ea90314a3a7221a2ea00932132
Status: Image is up to date for ghcr.io/pixelfed/pixelfed:v0.15.2
ghcr.io/pixelfed/pixelfed:v0.15.2
2.2 数据库选型:必须用 MariaDB 11.x,不要用 MySQL 9
官方编排文件开头注释为「## MariaDB and Redis (optional)」,但其 database 服务默认写的是 mysql:9。实测 v0.15.2 的 268 个迁移中,Laravel Pulse 迁移会创建 key_hash 生成列,MySQL 9 拒绝在生成列中使用 md5(),迁移直接失败(复现与解决见 2.3);MariaDB 11.8 执行同一建表语句正常。本方案将 database 服务改为 mariadb:11.8,全量迁移实测通过。
2.3 依赖组件版本对照(实测)
| 组件 | 镜像/版本 | 实测体积 | 角色 |
|---|---|---|---|
| 应用 | ghcr.io/pixelfed/pixelfed:v0.15.2 | 2.08GB | Web/API + 队列工作器 + 调度器(同一发行包三个服务) |
| 数据库 | mariadb:11.8 | 458MB | 全量数据存储 |
| 缓存 | redis:8-alpine | 161MB | 缓存/会话/队列 |
💡 技术拓展:关系型数据库选型 PixelFed 官方支持 MySQL 系与 PostgreSQL——
数据库 特点 适用场景 MariaDB 11.x 与 MySQL 协议兼容,生成列函数限制宽松 官方编排同源,实测 268 迁移全过(本文采用) MySQL 8.4 生成列函数校验同样收紧,需实测迁移 已有 MySQL 8.4 集群复用 MySQL 9.x 生成列禁用 md5(),Pulse 迁移失败(实测) 不推荐 PostgreSQL 16 官方支持,Pulse 用 uuid+md5 表达式 已有 PG 运维体系 本文因官方编排默认分支 + 实测结论采用 MariaDB 11.8;已有 PostgreSQL 运维体系的团队可改用 PG(.env 将 DB_CONNECTION 改为 pgsql)。
三、前置条件
- 服务器已安装 Docker 29.x 与 Docker Compose v2+(
docker --version、docker compose version可用); - 端口 8135 未被占用(可用
ss -ltn | grep 8135检查); - 磁盘空间 ≥ 10GB(应用发行包 2.08GB + 数据库与媒体数据增长);
- 内存 ≥ 2GB(应用 + Horizon 队列 + MariaDB 并存运行);
- 明确实例的对外访问地址:本文用
http://192.168.146.128:8135(生产带域名的场景,把下文所有192.168.146.128替换为你的域名,并在反向代理层做 TLS)。
四、部署步骤
4.1 目录与权限准备
本节创建部署目录,并预先解决「存储目录属主」问题(应用发行包内运行用户为 www-data,UID=33;存储目录若由 root 创建并挂载,应用启动会因无写权限失败,现象与解决见 11.1/11.2)。
# 创建部署目录与存储目录
mkdir -p /opt/pixelfed && cd /opt/pixelfed
mkdir -p storage
# 将存储目录属主对齐发行包内运行用户 www-data(UID/GID=33)
chown -R 33:33 /opt/pixelfed/storage
验证属主已生效:
ls -ld /opt/pixelfed/storage
实测回显:
drwxr-xr-x 2 33 33 4096 Oct 27 00:38 /opt/pixelfed/storage
4.2 编写 .env 配置文件
PixelFed 的全部行为由 .env 环境变量驱动。基于官方 .env.example(v0.15.2,88 行)修改,以下是本方案实测使用的完整 .env(数据库密码演示用 q1w2e3r4,生产请换强密码):
APP_NAME="Pixelfed"
APP_ENV="production"
APP_KEY=
APP_DEBUG="false"
APP_LOCALE="en-US"
# Instance Configuration
OPEN_REGISTRATION="false"
ENFORCE_EMAIL_VERIFICATION="false"
PF_MAX_USERS="1000"
PF_MIN_REGISTRATION_AGE="16"
OAUTH_ENABLED="true"
OAUTH_PAT_ENABLED="false"
ENABLE_CONFIG_CACHE="true"
INSTANCE_DISCOVER_PUBLIC="true"
STORIES_ENABLED="true"
# Media Configuration
IMAGE_DRIVER=vips # vips, gd, imagick
PF_OPTIMIZE_IMAGES="true"
IMAGE_QUALITY="80"
MAX_PHOTO_SIZE="15000"
MAX_CAPTION_LENGTH="500"
MAX_ALBUM_LENGTH="4"
# Instance URL Configuration
APP_URL="http://192.168.146.128:8135"
APP_DOMAIN="192.168.146.128"
ADMIN_DOMAIN="192.168.146.128"
SESSION_DOMAIN=null
TRUST_PROXIES="*"
FORCE_HTTPS_URLS="false"
SESSION_SECURE_COOKIE="false"
# Database Configuration
DB_CONNECTION="mysql"
DB_HOST="db"
DB_PORT="3306"
DB_DATABASE="pixelfed"
DB_USERNAME="pixelfed"
DB_PASSWORD="q1w2e3r4"
DB_ROOT_PASSWORD="q1w2e3r4"
# Redis Configuration
REDIS_CLIENT="predis"
REDIS_SCHEME="tcp"
REDIS_HOST="redis"
REDIS_PASSWORD="null"
REDIS_PORT="6379"
# Laravel Configuration
SESSION_DRIVER="database"
CACHE_STORE="redis"
QUEUE_DRIVER="redis"
BROADCAST_DRIVER="log"
LOG_CHANNEL="stack"
HORIZON_PREFIX="horizon-"
# ActivityPub Configuration
ACTIVITY_PUB="false"
AP_REMOTE_FOLLOW="false"
AP_INBOX="false"
AP_OUTBOX="false"
AP_SHAREDINBOX="false"
# Experimental Configuration
EXP_EMC="true"
## Mail Configuration (Post-Installer)
MAIL_DRIVER=log
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="pixelfed@example.com"
MAIL_FROM_NAME="Pixelfed"
MAIL_AUTO_TLS=true
## S3 Configuration (Post-Installer)
PF_ENABLE_CLOUD=false
FILESYSTEM_CLOUD=s3
关键项说明(全量 .env 变量的逐项实测说明见本专栏配置参数详解篇):
APP_URL/APP_DOMAIN/ADMIN_DOMAIN:三者必须与实际访问地址一致。PixelFed 按APP_DOMAIN做路由域名约束,不一致会整站 404(见 11.5 实测);FORCE_HTTPS_URLS:默认开启,强制生成 https 链接。纯 HTTP 内网部署必须显式置 false(见 11.4);SESSION_SECURE_COOKIE:默认 true,HTTP 部署时浏览器不会回传会话 Cookie,导致「登录永远失败」,必须置 false(见 11.4);DB_ROOT_PASSWORD:官方 .env.example 未含此变量,但编排健康检查引用它,缺失会导致数据库初始化失败,必须补上;STORIES_ENABLED:故事功能开关,默认关闭;注意它受「配置缓存」固化,改动后需清配置缓存(见 11.6)。
4.3 生成 APP_KEY
Laravel 应用必须有 APP_KEY(用于会话与加密)。用应用发行包内自带的 artisan 一次性生成并填入 .env:
docker run --rm ghcr.io/pixelfed/pixelfed:v0.15.2 php artisan key:generate --show
实测回显(每次生成不同,取自己那次输出的完整值):
base64:bm8hWRcRAgQ9LFRyvDgraqvX1J23z2mSht7dKIp3n70=
将输出填入 .env 的 APP_KEY= 后(本环境实测生成值为 base64:bm8hWRcRAgQ9LFRyvDgraqvX1J23z2mSht7dKIp3n70=,读者须使用自己环境生成的值,不可照抄)。
4.4 编写 docker-compose.yml 编排文件
在 /opt/pixelfed 下创建 docker-compose.yml(基于官方 v0.15.2 docker-compose.yml,改用 GHCR 发行包与 MariaDB 11.8,并修正两处官方编排与发行包不匹配的健康检查):
name: pixelfed-0.15.2-stack
services:
## MariaDB and Redis
db:
image: mariadb:11.8
restart: unless-stopped
env_file:
- .env
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- ./mariadb-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mariadb-admin", "ping", "-h", "127.0.0.1", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
networks:
- pixelfed-network
redis:
image: redis:8-alpine
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- ./redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
start_period: 10s
networks:
- pixelfed-network
## Pixelfed containers - App (Web/API), Horizon Queue, Scheduled task.
pixelfed:
image: ghcr.io/pixelfed/pixelfed:v0.15.2
restart: unless-stopped
ports:
- "8135:8080"
env_file:
- .env
environment:
HEALTHCHECK_PATH: "/up"
LOG_OUTPUT_LEVEL: "error"
SSL_MODE: "off"
PHP_POST_MAX_SIZE: "500M"
PHP_UPLOAD_MAX_FILE_SIZE: "500M"
PHP_OPCACHE_ENABLE: "1"
PHP_OPCACHE_VALIDATE_TIMESTAMPS: "0"
AUTORUN_ENABLED: "true"
AUTORUN_LARAVEL_MIGRATION: "true"
AUTORUN_LARAVEL_MIGRATION_ISOLATION: "true"
AUTORUN_LARAVEL_STORAGE_LINK: "true"
AUTORUN_LARAVEL_EVENT_CACHE: "true"
AUTORUN_LARAVEL_ROUTE_CACHE: "true"
AUTORUN_LARAVEL_VIEW_CACHE: "true"
AUTORUN_LARAVEL_CONFIG_CACHE: "true"
volumes:
- ./storage:/var/www/html/storage
depends_on:
- db
- redis
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:8080/api/v1/instance -o /dev/null"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
networks:
- pixelfed-network
horizon:
image: ghcr.io/pixelfed/pixelfed:v0.15.2
restart: unless-stopped
command: ["php", "artisan", "horizon"]
env_file:
- .env
environment:
PHP_POST_MAX_SIZE: "500M"
PHP_UPLOAD_MAX_FILE_SIZE: "500M"
PHP_OPCACHE_ENABLE: "1"
PHP_OPCACHE_VALIDATE_TIMESTAMPS: "0"
AUTORUN_ENABLED: "false"
AUTORUN_LARAVEL_MIGRATION: "false"
AUTORUN_LARAVEL_MIGRATION_ISOLATION: "false"
AUTORUN_LARAVEL_STORAGE_LINK: "true"
AUTORUN_LARAVEL_EVENT_CACHE: "false"
AUTORUN_LARAVEL_ROUTE_CACHE: "false"
AUTORUN_LARAVEL_VIEW_CACHE: "false"
AUTORUN_LARAVEL_CONFIG_CACHE: "true"
volumes:
- ./storage:/var/www/html/storage
depends_on:
- db
- redis
healthcheck:
test: ["CMD", "healthcheck-horizon"]
interval: 10s
timeout: 5s
retries: 3
networks:
- pixelfed-network
scheduler:
image: ghcr.io/pixelfed/pixelfed:v0.15.2
restart: unless-stopped
command: ["php", "artisan", "schedule:work"]
stop_signal: SIGTERM
env_file:
- .env
environment:
PHP_POST_MAX_SIZE: "500M"
PHP_UPLOAD_MAX_FILE_SIZE: "500M"
PHP_OPCACHE_ENABLE: "1"
PHP_OPCACHE_VALIDATE_TIMESTAMPS: "0"
AUTORUN_ENABLED: "false"
AUTORUN_LARAVEL_MIGRATION: "false"
AUTORUN_LARAVEL_MIGRATION_ISOLATION: "false"
AUTORUN_LARAVEL_STORAGE_LINK: "true"
AUTORUN_LARAVEL_EVENT_CACHE: "false"
AUTORUN_LARAVEL_ROUTE_CACHE: "false"
AUTORUN_LARAVEL_VIEW_CACHE: "false"
AUTORUN_LARAVEL_CONFIG_CACHE: "true"
volumes:
- ./storage:/var/www/html/storage
depends_on:
- db
- redis
healthcheck:
test: ["CMD", "healthcheck-schedule"]
interval: 10s
timeout: 5s
retries: 3
start_period: 10s
networks:
- pixelfed-network
networks:
pixelfed-network:
driver: bridge
ipam:
config:
- subnet: 10.89.65.0/24
⚠️ 两处与官方编排的差异(实测原因):
- database 服务由
mysql:9改为mariadb:11.8(MySQL 9 迁移失败,见 2.2/11.3);- 应用服务健康检查官方写法
healthcheck-frankenphp在 v0.15.2 发行包内不存在,改用 API 探活;数据库健康检查mysqladmin在 MariaDB 11.8 中改名为mariadb-admin(均见 11.7)。
4.5 启动与自动迁移
cd /opt/pixelfed
docker compose up -d
实测回显:
[+] Running 6/6
✔ Network pixelfed-0152-stack_pixelfed-network Created
✔ Container pixelfed-0.15.2-db Started
✔ Container pixelfed-0.15.2-redis Started
✔ Container pixelfed-0.15.2-app Started
✔ Container pixelfed-0.15.2-horizon Started
✔ Container pixelfed-0.15.2-scheduler Started
首次启动时,应用服务会自动执行初始化序列(AUTORUN):storage:link → 清缓存 → 数据库连接检查 → 全量迁移 → 优化缓存。观察启动日志:
docker compose logs pixelfed | grep -E 'storage|migration|migrat|optimize|cache|Server running' | head -20
实测回显(输出节选,实测首尾):
pixelfed-0.15.2-app | Starting container ...
pixelfed-0.15.2-app | Pixelfed auto-run
pixelfed-0.15.2-app | * Running in /var/www/html
pixelfed-0.15.2-app | * Setting Laravel storage permissions ... done!
pixelfed-0.15.2-app | * Clearing Laravel caches ... done!
pixelfed-0.15.2-app | * Attempting to establish a database connection ...
pixelfed-0.15.2-app | * Running Laravel migrations ...
pixelfed-0.15.2-app | INFO Running migrations.
pixelfed-0.15.2-app | 2014_10_12_000000_create_password_resets_tables ............ DONE
pixelfed-0.15.2-app | (……268 个迁移逐条输出,见 migrate:status 核对……)
pixelfed-0.15.2-app | * Caching Laravel config ... done!
pixelfed-0.15.2-app | * Caching Laravel routes ... done!
pixelfed-0.15.2-app | * Caching Laravel views ... done!
pixelfed-0.15.2-app | *** Pixelfed Auto-run completed successfully ***
等待全部服务健康(首次迁移约 1–2 分钟):
docker compose ps
实测回显:
NAME STATUS
pixelfed-0.15.2-app Up 9 minutes (healthy)
pixelfed-0.15.2-db Up 9 minutes (healthy)
pixelfed-0.15.2-horizon Up 9 minutes (healthy)
pixelfed-0.15.2-redis Up 9 minutes (healthy)
pixelfed-0.15.2-scheduler Up 9 minutes (healthy)
迁移核对(数量应为 268):
docker compose exec pixelfed php artisan migrate:status | grep -c 'Ran'
实测回显:
268
4.6 创建管理员与初始化命令
官方发行包不带默认账号,需用 artisan 命令创建。演示账号 admin / q1w2e3r4:
docker compose exec pixelfed php artisan user:create \
--name="admin" --username="admin" \
--email="admin@example.com" \
--password="q1w2e3r4" \
--is_admin=1 --confirm_email=1
实测回显:
Created user admin!
⚠️ 注意:
--is_admin=1仅在创建时给出标记,实测users.is_admin仍为 false,需再用user:admin授予管理权限(交互确认):
docker compose exec pixelfed php artisan user:admin admin
实测回显(交互输入 yes):
Add admin privileges to this user? (yes/no) [no]:
> yes
Successfully changed permissions!
继续两条官方推荐的初始化命令(城市数据用于地点/位置功能;实例 Actor 是实例自身的联邦身份记录):
# 1) 导入城市数据:发行包不含 cities.json,需先从源码仓库放入存储目录(见 11.8)
docker compose exec pixelfed php artisan import:cities
实测回显:
imported 128769 entries!
# 2) 创建实例 Actor
docker compose exec pixelfed php artisan instance:actor
实测回显:
Created instance actor!
4.7 部署验证
依次验证 API、登录页、管理后台三个入口:
# 1) 实例 API(用配置的 IP/域名访问,不要用 127.0.0.1,原因见 11.5)
curl -s http://192.168.146.128:8135/api/v1/instance -H 'Accept: application/json' | head -c 200
实测回显(输出节选):
{"domain":"192.168.146.128","title":"Pixelfed","version":"3.5.3 (compatible; Pixelfed 0.15.2)","description":...
# 2) 登录页
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.146.128:8135/login
实测回显:
200
用浏览器访问 http://192.168.146.128:8135/login,以 admin / q1w2e3r4 登录,应跳转至 Web 客户端;再以同一账号发布图片帖、创建故事,即可完成功能级验证(本环境实测:三图相册帖发布成功,故事发布成功并在个人主页故事栏展示)。
五、数据持久化说明
| 编排卷(相对 /opt/pixelfed) | 用途 | 重建栈后是否保留 |
|---|---|---|
| ./mariadb-data | 数据库全部数据(用户/帖子/关注/配置等 268 张表) | 是 |
| ./redis-data | 缓存/队列(AOF 持久化,appendonly yes) | 是 |
| ./storage | 用户上传媒体、缩略图、日志、OAuth 密钥(storage/oauth-*.key) | 是 |
⚠️ 注意:OAuth 公私钥(storage/oauth-public.key / oauth-private.key)存放在 storage 卷中。若换用空的存储卷重新部署,务必执行
php artisan passport:keys重新生成,否则已颁发的 OAuth 令牌全部失效。备份策略建议:每日mariadb-dump整库 + tar 打包 ./storage(日常维护命令详见本专栏命令详解篇)。
六、环境变量表
部署即用到的核心变量(完整全量逐项说明见配置详解篇):
| 变量 | 实测取值 | 说明 |
|---|---|---|
| APP_NAME | Pixelfed | 站点名称 |
| APP_ENV | production | 运行环境 |
| APP_KEY | base64:...(4.3 生成) | 加密密钥,必须唯一 |
| APP_URL | http://192.168.146.128:8135 | 对外访问地址 |
| APP_DOMAIN / ADMIN_DOMAIN | 192.168.146.128 | 路由域名约束 |
| FORCE_HTTPS_URLS | false | HTTP 部署必须关(默认 true) |
| SESSION_SECURE_COOKIE | false | HTTP 部署必须关(默认 true) |
| OPEN_REGISTRATION | false | 是否开放注册 |
| STORIES_ENABLED | true | 故事功能开关(默认 false) |
| DB_CONNECTION / DB_HOST | mysql / db | 数据库类型与编排内主机名 |
| DB_DATABASE / DB_USERNAME / DB_PASSWORD | pixelfed / pixelfed / q1w2e3r4 | 业务库凭据 |
| DB_ROOT_PASSWORD | q1w2e3r4 | 数据库 root 口令(健康检查引用) |
| REDIS_HOST / REDIS_PORT | redis / 6379 | Redis 地址 |
| IMAGE_DRIVER | vips | 图片处理驱动(vips/gd/imagick) |
| MAX_ALBUM_LENGTH | 4 | 单帖图片上限 |
| MAX_CAPTION_LENGTH | 500 | 文案上限(按 Unicode 字符计数) |
| ACTIVITY_PUB | false | 联邦总开关(开启后强制 https) |
七、配置参数说明
除 .env 外,应用服务还接受编排 environment: 注入的发行包级变量:
| 变量 | 实测取值 | 说明 |
|---|---|---|
| SSL_MODE | off | 发行包内 Web 服务(Caddy/FrankenPHP)的 TLS 模式;off=明文 HTTP |
| PHP_POST_MAX_SIZE / PHP_UPLOAD_MAX_FILE_SIZE | 500M | PHP 上传上限,需大于单图上限 MAX_PHOTO_SIZE |
| AUTORUN_ENABLED | true | 启动自动初始化总开关 |
| AUTORUN_LARAVEL_MIGRATION | true | 启动自动迁移(仅应用服务开启) |
| AUTORUN_LARAVEL_CONFIG_CACHE / ROUTE_CACHE / VIEW_CACHE / EVENT_CACHE | true | 启动时重建各类缓存 |
| LOG_OUTPUT_LEVEL | error | 发行包 JSON 日志级别 |
修改 .env 后的生效方式:docker compose up -d(重建服务,AUTORUN 会重建缓存)。特别注意:STORIES_ENABLED、OPEN_REGISTRATION 等实例级开关还会被「配置缓存」固化(DB + Redis 两级),仅改 .env 重建后可能仍读旧值,清法见 11.6。
八、配置文件挂载
| 挂载 | 说明 |
|---|---|
| ./storage:/var/www/html/storage | 全部持久化状态(媒体/日志/OAuth 密钥/缓存目录),必须 UID 33 属主 |
| ./mariadb-data:/var/lib/mysql | 数据库数据目录 |
| ./redis-data:/data | Redis AOF 数据 |
storage 目录内首次部署需具备发行包骨架(应用启动报 cache path 错误即缺失,见 11.2);由 AUTORUN 的「Setting Laravel storage permissions」步骤自动补齐,或在部署前手工创建:app/{backups,bouncer,nlp,remcache}、framework/{cache/data,sessions,testing,views}、logs、debugbar、purify。
九、等价 docker run(理解编排等价形态)
将本编排的应用服务单独跑起来的等价命令(用于理解映射关系,实际部署仍以 compose 为准):
# 数据库
docker run -d --name pixelfed-0.15.2-db \
-e MYSQL_DATABASE=pixelfed -e MYSQL_USER=pixelfed -e MYSQL_PASSWORD=q1w2e3r4 \
-e MYSQL_ROOT_PASSWORD=q1w2e3r4 \
-v /opt/pixelfed/mariadb-data:/var/lib/mysql mariadb:11.8
# 应用(含端口映射与存储挂载)
docker run -d --name pixelfed-0.15.2-app \
--env-file /opt/pixelfed/.env \
-p 8135:8080 \
-e AUTORUN_ENABLED=true -e AUTORUN_LARAVEL_MIGRATION=true \
-v /opt/pixelfed/storage:/var/www/html/storage \
ghcr.io/pixelfed/pixelfed:v0.15.2
# 队列工作器
docker run -d --name pixelfed-0.15.2-horizon \
--env-file /opt/pixelfed/.env \
-v /opt/pixelfed/storage:/var/www/html/storage \
ghcr.io/pixelfed/pixelfed:v0.15.2 php artisan horizon
# 定时任务调度器
docker run -d --name pixelfed-0.15.2-scheduler \
--env-file /opt/pixelfed/.env \
-v /opt/pixelfed/storage:/var/www/html/storage \
ghcr.io/pixelfed/pixelfed:v0.15.2 php artisan schedule:work
# 缓存
docker run -d --name pixelfed-0.15.2-redis \
-v /opt/pixelfed/redis-data:/data redis:8-alpine redis-server --appendonly yes
手动形态需自行创建内部网络并把五个实例接入同一网络、配好服务发现(编排已自动完成),故生产推荐使用 compose。
十、常用运维命令
# 状态总览
docker compose ps
# 应用日志(含 AUTORUN 初始化序列)
docker compose logs -f pixelfed
# 队列工作器日志(图片优化/联邦投递在此执行)
docker compose logs -f horizon
# 重启单个服务(.env 改动无效,见 11.6 注意事项)
docker compose restart pixelfed
# .env 修改后的正确生效方式:重建
docker compose up -d
# 进入应用执行 artisan(运维命令全集见命令详解篇)
docker compose exec pixelfed php artisan
# 版本升级:改 .env / compose 中的版本号后
docker compose pull && docker compose up -d
# 备份数据库
docker compose exec db sh -c 'mariadb-dump -uroot -p"$MYSQL_ROOT_PASSWORD" pixelfed' > pixelfed-$(date +%F).sql
升级说明:PixelFed 小版本升级(如 0.15.x 内)通常只需替换发行包版本号并 up -d,AUTORUN 会自动执行增量迁移;跨大版本(0.14 → 0.15)请先阅读官方 Release Notes 中的迁移说明并备份后再操作。
十一、常见问题(FAQ)
以下均为本环境实测遇到并解决的故障,按触发顺序排列。
Q1:应用启动后一直重启,日志报 storage/logs 权限拒绝
现象(日志实测):
file_put_contents(/var/www/html/storage/logs/laravel.log): Failed to open stream: Permission denied
原因:宿主 ./storage 由 root 创建,应用发行包内运行用户为 www-data(UID 33)无写权限。 解决:
chown -R 33:33 /opt/pixelfed/storage
docker compose up -d
Q2:权限修复后仍重启,报 Please provide a valid cache path
实测回显:
Please provide a valid cache path.
原因:storage 目录是空挂载,缺少 Laravel 必需的骨架子目录(framework/views 等)。 解决:补齐骨架目录并保持 33 属主(步骤见 4.1 与第八章骨架清单),或先启动一次让 AUTORUN 的权限步骤创建。
Q3:数据库迁移失败:Expression of generated column 'key_hash' contains a disallowed function: md5
实测报错(在 MySQL 9 上直接复现该建表语句):
ERROR 3763 (HY000) at line 1: Expression of generated column 'key_hash' contains a disallowed function: `md5`.
同一语句在 MariaDB 11.8 实测执行成功(建表返回 Query OK,表创建成功)。原因:MySQL 9 禁止生成列使用 md5(),而 Laravel Pulse 迁移定义了 key_hash char(16) ... AS (unhex(md5(\key`)))。 解决:database 服务改用 mariadb:11.8(本文方案),并删除 MySQL 9 产生的旧数据目录后重新 docker compose up -d`。改后全量迁移实测 268 个全部 Ran。
Q4:内网 HTTP 部署,登录表单提交后回到登录页,永远登不上
两个叠加原因,均有实测证据:
- 表单/链接被强制生成为 https(.env 未显式关 FORCE_HTTPS_URLS)。实测登录页表单 action:
关闭后变为 http。
<form method="POST" action="https://192.168.146.128:8135/login"> - 会话 Cookie 带 secure 标志(SESSION_SECURE_COOKIE 默认 true),HTTP 请求下浏览器不回传 Cookie。实测响应头:
set-cookie: pxfs=...; path=/; httponly; samesite=lax; secure
解决:.env 增加 FORCE_HTTPS_URLS="false" 与 SESSION_SECURE_COOKIE="false",然后 docker compose up -d 重建(restart 不会重新读取 .env,这是另一个易错点)。
Q5:全站 404,但 API 正常
现象:curl http://127.0.0.1:8135/login 返回 404,而 /api/v1/instance 正常返回 200。
原因:路由按 APP_DOMAIN 注册了域名约束,用 127.0.0.1/其他地址访问不匹配任何路由。
解决:始终用与 APP_URL/APP_DOMAIN 一致的地址访问(本文即 http://192.168.146.128:8135),实测该地址下 /login 返回 200。
Q6:改了 STORIES_ENABLED / OPEN_REGISTRATION 后行为不变
原因三层叠加(实测闭环):
docker compose restart不重读 .env,需up -d重建;- 实例级开关会被「配置缓存」固化在数据库 config_caches 表 + Redis(
config_cache:_v0-key:...键),首启时种入旧值; - 路由缓存编译时读的也是该缓存值(/register 路由按开关条件注册)。 解决:清对应键与库表行后重建缓存,实测闭环:OPEN_REGISTRATION=false → /register 404;置 true 并清缓存 → /register 200;还原后恢复 404。具体命令:
docker compose exec pixelfed php artisan tinker --execute='$r=\App\Models\ConfigCache::where("k","pixelfed.open_registration")->first(); if($r)$r->delete(); \Illuminate\Support\Facades\Cache::forget("config_cache:_v0-key:pixelfed.open_registration");'
docker compose exec pixelfed sh -c 'php artisan optimize:clear && php artisan optimize'
Q7:健康检查失败:healthcheck-frankenphp / mysqladmin 不存在
实测报错:
OCI runtime exec failed: exec: "healthcheck-frankenphp": executable file not found in $PATH: unknown
OCI runtime exec failed: exec: "mysqladmin": executable file not found in $PATH: unknown
原因:官方编排引用的健康检查脚本/命令与 v0.15.2 发行包不匹配(发行包内置的是 healthcheck-horizon/healthcheck-schedule/healthcheck-octane 等;MariaDB 11.8 管理命令为 mariadb-admin)。
解决:按第四章编排文件修正——应用用 API 探活(curl -fsS http://127.0.0.1:8080/api/v1/instance),数据库用 mariadb-admin ping。
Q8:import:cities 报 storage/app/cities.json 不存在
实测回显:
Error: The file storage/app/cities.json is missing. Run `git checkout storage/app/cities.json` to download it.
原因:发行包不含该数据文件(源码仓库才带)。 解决:从 GitHub 对应 tag 下载 cities.json 放入存储目录(实测 12977722 字节):
curl -fsSL -o /opt/pixelfed/storage/app/cities.json \
https://raw.githubusercontent.com/pixelfed/pixelfed/v0.15.2/storage/app/cities.json
chown 33:33 /opt/pixelfed/storage/app/cities.json
docker compose exec pixelfed php artisan import:cities
十二、参考链接
- 官方编排文件:https://github.com/pixelfed/pixelfed/blob/v0.15.2/docker-compose.yml
- 官方 .env.example:https://github.com/pixelfed/pixelfed/blob/v0.15.2/.env.example
- 官方文档(安装):https://docs.pixelfed.org/running-pixelfed/installation.html
- v0.15.2 发布说明:https://github.com/pixelfed/pixelfed/releases/tag/v0.15.2
- 本专栏相关文档:《PixelFed 0.15.2 介绍与选型指南》;配置逐项说明与命令速查见本专栏「配置参数详解」与「常用 CLI 命令详解」两篇。