Jirafeau Docker Compose 部署指南
Jirafeau 4.7.2 官方镜像 Compose 部署实测:镜像选型取证、首启环境变量配置(数据目录与管理口令)、上传/一次性链接/下载口令/过期删除/管理端全链路验证、数据持久化与环境变量表。
Jirafeau Docker Compose 部署指南
目标:在 Linux 服务器上用 Docker Compose 部署官方镜像版 Jirafeau 4.7.2,完成首启配置(数据目录与管理口令)、上传/一次性链接/下载口令/过期删除/管理端全链路验证。以下全部命令与回显均在真实服务器实测通过(Ubuntu 宿主 + Docker 29.9.2,实测日期 2026-10-30)。
一、环境信息
- 宿主操作系统:Linux(x86_64)
- Docker:29.9.2(含 Compose v2 插件)
- Jirafeau 版本:4.7.2(官方镜像
registry.gitlab.com/jirafeau/jirafeau:4.7.2,镜像摘要sha256:77dc96d6ab0f7974d9a28bb639a82fd30b3c216e1a330ba73317decdc2909a8e,压缩后 35MB / 解压 129MB) - 服务端口:8150(宿主)→ 80(服务)
- 专用网络:
jirafeau-4.7.2-net,显式子网10.89.58.0/24 - 数据目录:
/opt/data/quzuo/tmp/jirafeau/jirafeau_data(挂载到服务内/data) - 管理口令(示例演示):
q1w2e3r4 - 架构组件:镜像内 lighttpd(Web 服务)+ PHP-FPM 8.3(应用运行时),无数据库
💡 说明:Jirafeau 官方镜像只暴露 80 端口(HTTP)与内部的 9000(PHP-FPM,仅容器网络内使用,无需映射)。镜像不提供 TLS,生产对外建议前置 Nginx/Caddy 反向代理并配证书。
二、镜像选型说明
Jirafeau 的镜像有"官方 registry"与"社区镜像"两个来源,实查结论如下(查询日期 2026-10-30):
| 来源 | 镜像 | 版本覆盖(实查) | 拉取量(实查) | 结论 |
|---|---|---|---|---|
| 官方 GitLab registry | registry.gitlab.com/jirafeau/jirafeau | 3.3.0 / 3.4.0 / 3.4.1 / 4.0.0 / 4.1.1 / 4.2.0 / 4.3.0 / 4.4.0 / 4.5.0 / 4.6.0-4.6.3 / 4.7.0 / 4.7.1 / 4.7.2 / latest,AMD64+ARM64 | —(registry 不公示 pulls) | 首选:与源码 tag 一一对应,4.7.2 在列 |
| Docker Hub(原作者名下) | mojo42/jirafeau | 最高 4.5.0(latest 与 4.5.0 同一镜像,停更) | 1,336,872 pulls | 历史社区镜像,版本落后两个 minor 线 |
| Docker Hub(社区) | evanhoucke/jirafeau | 仅 latest / 1.1 | 1,472,884 pulls | 版本过旧 |
| Docker Hub(社区) | jgeusebroek/jirafeau | 日期戳标签(最新 20221008) | 922,680 pulls | 版本过旧 |
选择 registry.gitlab.com/jirafeau/jirafeau:4.7.2 的理由:它是社区续作官方仓库 CI 构建的正牌镜像,版本与源码 tag 对齐且持续更新;Docker Hub 上的三个高拉取量社区镜像均停留在 4.5.0 及以前,不含 4.7.x 的安全修复(4.7.1 修复了 CVE-2022-30110 / CVE-2024-12326 / CVE-2025-7066 / CVE-2026-1466 一批预览类漏洞)。
拉取镜像:
docker pull registry.gitlab.com/jirafeau/jirafeau:4.7.2 # 拉取官方 4.7.2 镜像
实测回显(节选):
4.7.2: Pulling from jirafeau/jirafeau
Digest: sha256:77dc96d6ab0f7974d9a28bb639a82fd30b3c216e1a330ba73317decdc2909a8e
Status: Downloaded newer image for registry.gitlab.com/jirafeau/jirafeau:4.7.2
三、前置条件
- 端口空闲检查:宿主 8150 端口未被占用(部署前实测,8148/8149 已被其他业务占用故顺延取 8150):
ss -ltn | grep -E ':(815[0-9])' || echo "8150-8159 空闲" # 检查目标端口段
实测回显(部署前):
8150-8159 空闲
- 网络子网检查:
10.89.58.0/24未被既有网络占用(部署前实测,56/57 两个槽位已被其他业务占用):
docker network ls # 列出既有网络
实测回显(节选):
NETWORK ID NAME DRIVER SCOPE
bbe62be45f73 bridge bridge local
0d290fb2d329 mikochi-1.12.2-net bridge local
- 数据目录准备:在 compose 文件同目录建
jirafeau_data/(首启后属主会被自动调整为 UID 100 / GID 82,见第五节)。
四、部署步骤
4.1 编写 compose 文件
docker-compose.yml 全文如下(显式声明项目名、容器名、网络子网,避免与宿主上其他业务撞名撞网段):
name: jirafeau-4.7.2-stack
services:
web:
image: registry.gitlab.com/jirafeau/jirafeau:4.7.2
container_name: jirafeau-4.7.2-web
ports:
- "8150:80"
volumes:
- ./jirafeau_data:/data
environment:
ADMIN_PASSWORD: q1w2e3r4
restart: unless-stopped
networks:
jirafeau-4.7.2-net:
ipv4_address: 10.89.58.10
networks:
jirafeau-4.7.2-net:
driver: bridge
ipam:
config:
- subnet: 10.89.58.0/24
配置要点:
ADMIN_PASSWORD:管理界面(/admin.php)口令;不设置时首启会自动生成 20 位随机口令并打印到启动日志(官方 docker/README.md 声明),建议显式设定避免翻日志;./jirafeau_data:/data:全部上传数据(文件、链接元数据、异步中转)都落在/data,是唯一需要持久化的路径(配置文件除外,见第七节说明);- 网络子网
10.89.58.0/24为实测取用的空闲槽位,部署时请按宿主实际占用调整。
4.2 启动
docker compose up -d # 启动 jirafeau-4.7.2-stack 栈
实测回显:
Network jirafeau-472-stack_jirafeau-4.7.2-net Created
Container jirafeau-4.7.2-web Creating
Container jirafeau-4.7.2-web Created
Container jirafeau-4.7.2-web Starting
Container jirafeau-4.7.2-web Started
💡 说明:Compose 项目名中的
.会被归一化,jirafeau-4.7.2-stack落地为jirafeau-472-stack,网络名相应带上前缀,属正常现象。
确认运行状态:
docker ps --filter name=jirafeau-4.7.2-web --format '{{.Names}}\t{{.Status}}\t{{.Ports}}'
实测回显:
jirafeau-4.7.2-web Up 6 seconds 9000/tcp, 0.0.0.0:8150->80/tcp, [::]:8150->80/tcp
4.3 首启配置:数据目录与管理口令
官方镜像的"首启安装向导"由内置的首启脚本以环境变量方式完成——每次启动时按环境变量生成 lib/config.local.php(等效于源码部署时浏览器安装向导的三步:管理口令 → 数据目录 → 完成)。首启日志:
docker logs jirafeau-4.7.2-web # 查看首启配置过程
实测回显(完整):
[30-Oct-2026 08:05:51] NOTICE: fpm is running, pid 10
[30-Oct-2026 08:05:51] NOTICE: ready to handle connections
setting up admin password
setting var_root to '/data/'
warning: you may want to have set WEB_ROOT to your website URL (like 'jirafeau.mydomain.tld/')
setting title to ''
You can now connect to your Jirafeau instance
逐行解读:
setting up admin password:从ADMIN_PASSWORD环境变量取口令,计算 SHA256 后写入配置(实测生成的配置中admin_password值为13a5c202e320d0bf9bb2c6e2c7cf380a6f7de5d392509fee260b809c893ff2f9,即sha256("q1w2e3r4"),口令原文不落盘);setting var_root to '/data/':数据目录固定为挂载进来的/data;warning: ... WEB_ROOT ...:未设WEB_ROOT时的提醒,见十一节常见问题;You can now connect to your Jirafeau instance:配置完成,服务可用。
⚠️ 注意:实测发现官方 4.7.2 镜像内不含 install.php 安装向导页(镜像内
/www目录仅有 admin.php、f.php、index.php、script.php、tos.php 与 lib/media,docker exec ls 实查)。浏览器安装向导只存在于源码部署形态(git clone 后 PHP 直跑,向导三步:设置管理口令 → 设置数据目录 → 完成校验并写入配置)。容器化部署一律走上述环境变量首启路径,两者等效。
4.4 版本与容量自检
curl -sS "http://127.0.0.1:8150/script.php?get_version" # 查询服务版本
curl -sS "http://127.0.0.1:8150/script.php?get_capacity" # 查询单文件上限(字节,受 PHP 限制约束)
curl -sS "http://127.0.0.1:8150/script.php?get_maximal_upload_size" # 查询应用层大小限制(MB)
实测回显(依次三行):
4.7.2
1048576
0
get_capacity 返回 1048576 字节(1MB)来自镜像内置 php.ini 的 upload_max_filesize = 1M / post_max_size = 2M;get_maximal_upload_size 返回 0 表示应用层不限大小(MAXIMAL_UPLOAD_SIZE 未设)。两者取交集才是实际单请求上传上限,调大需同时改两者(见十一节)。
4.5 上传与下载验证
生成测试文件并通过脚本接口上传(有效期 month):
echo "jirafeau test file 2026-10-30" > upload_test.txt # 准备测试文件
curl -sS -X POST -F "file=@upload_test.txt" -F "time=month" http://127.0.0.1:8150/script.php
实测回显(两行:第 1 行下载链接名,第 2 行删除码):
0MUAUAsM
c841f
按返回链接下载并核对内容:
curl -sS "http://127.0.0.1:8150/f.php?h=0MUAUAsM&d=1" # d=1 直接下载
实测回显:
jirafeau test file 2026-10-30
浏览器访问 http://<服务器>:8150/ 即上传主页,访问 http://<服务器>:8150/f.php?h=0MUAUAsM 是标准下载页(页面标题 "Jirafeau, your web file repository",HTTP 200 实测)。
4.6 一次性链接验证
echo "one time only" > onetime.txt # 准备一次性文件
curl -sS -X POST -F "file=@onetime.txt" -F "time=day" -F "one_time_download=1" http://127.0.0.1:8150/script.php
实测回显:
2cPISNJJ
e9664
第一次下载成功返回原文;链接销毁后第二次下载返回"文件不存在"页:
curl -sS "http://127.0.0.1:8150/f.php?h=2cPISNJJ&d=1" # 第 1 次下载
curl -sS "http://127.0.0.1:8150/f.php?h=2cPISNJJ&d=1" # 第 2 次下载(链接已销毁)
实测回显(第 1 次):
one time only
实测回显(第 2 次,HTTP 200 错误页正文):
Sorry, the requested file is not found
4.7 下载口令验证
echo "secret content with password" > secret.txt # 准备口令保护文件
curl -sS -X POST -F "file=@secret.txt" -F "time=week" -F "key=q1w2e3r4" http://127.0.0.1:8150/script.php
实测回显:
1Ga0zOhX
cfafb
不带口令直接下载,返回的是口令输入页(HTTP 200,页面含 "Password protection" 表单与 Download/Preview 按钮);带口令 POST 才能取回内容:
curl -sS "http://127.0.0.1:8150/f.php?h=1Ga0zOhX&d=1" # 无口令 → 口令表单页
curl -sS -X POST -F "key=q1w2e3r4" "http://127.0.0.1:8150/f.php?h=1Ga0zOhX&d=1" # 带口令
实测回显(带口令):
secret content with password
4.8 过期与删除验证
上传一个 minute 档文件,等 65 秒后再取,验证到期自动失效:
echo "expire soon" > exp.txt # 准备过期测试文件
curl -sS -X POST -F "file=@exp.txt" -F "time=minute" http://127.0.0.1:8150/script.php
# 返回链接名 0njphHoH,等待 65 秒
curl -sS "http://127.0.0.1:8150/script.php?h=0njphHoH&d=1"
实测回显(过期后):
Error 9
主动删除验证——用上传时返回的删除码(第 2 行)拼删除请求:
curl -sS "http://127.0.0.1:8150/script.php?h=0MUAUAsM&d=c841f" # 删除码来自 4.5 节上传回显
实测回显:
Ok
4.9 管理界面验证
登录管理端(口令即 ADMIN_PASSWORD):
curl -sS -c admin_cookies.txt -o admin_login.html -X POST -F "admin_password=q1w2e3r4" http://127.0.0.1:8150/admin.php
登录成功页的页面标题为 "Admin interface (version 4.7.2)",动作菜单包含:Clean expired files / Clean old unfinished transfers / List all files / Data size / Search for files by name / Search for files by file hash / Search a specific link / Reporting an issue。
⚠️ 注意:管理端每个动作 POST 都必须携带登录页下发的隐藏字段
admin_csrf(64 位十六进制),否则服务端会话校验失败、永远弹回登录页——脚本化管理时先从登录响应中提取它:
CSRF=$(grep -o "admin_csrf' value='[0-9a-f]*'" admin_login.html | head -1 | grep -o '[0-9a-f]\{64\}')
curl -sS -b admin_cookies.txt -X POST -F "action=size" -F "admin_csrf=${CSRF}" http://127.0.0.1:8150/admin.php
实测回显(action=size,存储清点):
Data size: 226B
实测回显(action=clean,清理过期文件):
Number of cleaned files : 0
实测回显(action=list,文件清单节选,含下载统计):
secret.txt Type: text/plain Size: 29B Expire: 2026-11-06 08:06 (GMT) One-time: No Encrypted: No Upload date: 2026-10-30 08:06 (GMT) Origin: 10.89.58.1 Downloads: 1 Last download: 2026-10-30 08:06 (GMT) Downloaded from: 10.89.58.1
删除指定链接(action=delete_link + link 参数)实测返回管理菜单页,对应链接随即失效。管理端功能与脚本化操作在《Jirafeau 4.7.2 常用 CLI 命令与工具详解》中逐条展开。
4.10 内置定时清理
官方镜像自带清理循环(每日执行一次):启动时先等 10 秒,随后循环执行"清理过期文件 + 清理超时未完成传输"并休眠 24 小时(官方 docker/cleanup.sh 源码逻辑)。其等效的手工执行方式为:
php /www/admin.php clean_expired # 清理过期文件
php /www/admin.php clean_async # 清理超时未完成的分块传输
实测回显(依次两行):
0 expired files deleted.
0 old unfinished transfers deleted.
五、数据持久化说明
5.1 目录结构
挂载的 /data 下生成三个子目录(实测 ls):
drwxrwx--- 5 100 82 4096 Oct 30 16:05 .
drwxrwx--- 2 100 82 4096 Oct 30 16:05 async
drwxrwx--- 3 100 82 4096 Oct 30 16:10 files
drwxrwx--- 3 100 82 4096 Oct 30 16:10 links
files/:文件内容按内容哈希分层存放(实测路径形态files/fec2ab10/aea6b090/4ad54eb7/3e027314/fec2ab10aea6b0904ad54eb73e027314),同哈希文件只存一份,旁边有<哈希>_count引用计数文件——文件级去重开启(FILE_HASH=md5)时同内容上传直接命中;links/:每个链接名一个同名元数据文件(实测links/0MUAUAsM/0MUAUAsM),记录哈希、过期时间、口令哈希、一次性标记、来源 IP、下载次数;async/:HTML5 分块上传中转。
删除链接时引用计数递减,归零即物理删除文件——实测把测试链接全部删除后 files/ 自动清空。
5.2 属主与备份
数据目录属主被首启过程调整为 UID 100 / GID 82(镜像内 lighttpd/www-data 用户组,可用环境变量 USER_ID/GROUP_ID 覆盖)。宿主侧备份即打包该目录:
tar czf jirafeau_data_$(date +%F).tar.gz jirafeau_data/ # 冷备:先停服务再打包更稳妥
⚠️ 注意:配置文件
lib/config.local.php不在/data内(官方 docker/README.md 明确 "Note that configuration is not stored in /data")。但它由环境变量在每次启动时重建,因此只要保留 compose 文件中的环境变量即可完整恢复,无需单独备份配置。
六、环境变量表
官方镜像通过环境变量完成全部首启配置(来源:官方 docker/README.md 与镜像内首启脚本实读,键名为大写化的配置项):
| 环境变量 | 默认 | 说明 |
|---|---|---|
| ADMIN_PASSWORD | 未设则随机生成 20 位 | 管理界面口令(自动转 SHA256 存储) |
| ADMIN_IP | 空 | 可访问管理界面的 IP 白名单(逗号分隔,CIDR) |
| LANG | auto | 界面语言(auto 跟随浏览器) |
| AVAILABILITIES | 九档 JSON | 可选有效期档位(JSON 布尔数组,见下方示例) |
| WEB_ROOT | 空 | 生成链接用的对外域名(如 jirafeau.example.com/) |
| VAR_ROOT | /data/ | 数据目录 |
| FILE_HASH | random | 文件哈希方式:md5(去重)/ md5_outside / random |
| PREVIEW | 1 | 是否提供浏览器预览 |
| TITLE | 空 | 站点标题 |
| ORGANISATION | ACME | 服务条款页组织名 |
| CONTACTPERSON | 空 | 条款页联系人 |
| STYLE | courgette | 亮色主题 |
| DARK_STYLE | dark-courgette | 暗色主题 |
| AVAILABILITY_DEFAULT | month | 默认有效期档位 |
| ONE_TIME_DOWNLOAD | 1 | 是否允许一次性下载选项 |
| ONE_TIME_DOWNLOAD_PRESELECTED | 0 | 一次性下载是否默认勾选 |
| ENABLE_CRYPT | 0 | 服务端加密(与去重互斥) |
| DEBUG | 0 | 调试输出(生产禁用) |
| MAXIMAL_UPLOAD_SIZE | 0(不限) | 应用层单文件上限(MB) |
| UPLOAD_PASSWORD | 空 | 上传口令(逗号分隔多个) |
| UPLOAD_IP | 空 | 允许上传的 IP 白名单 |
| UPLOAD_IP_NO_PASSWORD | 空 | 免口令上传 IP 白名单 |
| PROXY_IP | 空 | 反向代理来源 IP(改从 X-Forwarded-For 取访客 IP) |
| STORE_UPLOADER_IP | 1 | 是否记录上传者 IP |
| DOWNLOAD_PASSWORD_REQUIREMENT | optional | 下载口令策略:optional / required / generated |
| DOWNLOAD_PASSWORD_GEN_LEN | 10 | 自动生成口令长度 |
| DOWNLOAD_PASSWORD_GEN_CHARS | 见配置模板 | 自动生成口令字符集 |
| DOWNLOAD_PASSWORD_POLICY | none | 口令复杂度:none / regex |
| DOWNLOAD_PASSWORD_POLICY_REGEX | /.*/ | regex 模式下的校验表达式 |
| USER_ID / GROUP_ID | 100 / 82 | 数据目录属主 UID/GID |
多值环境变量示例(AVAILABILITIES 的 JSON 写法,官方 compose 示例同款):
environment:
AVAILABILITIES: |
{
"minute": true,
"hour": true,
"day": true,
"week": true,
"fortnight": true,
"month": true,
"quarter": false,
"year": false,
"none": false
}
⚠️ 注意:镜像路径下环境变量优先级最高——每次启动都会按环境变量重写服务内的
lib/config.local.php。实测:手工把配置中title改为MY-TITLE后重启服务,该字段被还原为默认值false(改动丢失)。因此持久化配置只有两条正路:改环境变量,或挂载自备配置并接受启动重写行为(见第七节)。
七、配置文件挂载
配置项的完整语义(约 30 项)在《Jirafeau 4.7.2 配置参数详解》逐项拆解,这里只讲挂载方式:
- 配置文件挂载:把自备的
config.local.php挂到服务内配置路径:
volumes:
- ./jirafeau_data:/data
- ./config.local.php:/www/lib/config.local.php
⚠️ 注意:由于首启脚本每次启动都会按环境变量重写该文件,挂载自备配置时请同时确保环境变量与之一致(或仅保留
ADMIN_PASSWORD等必需项),否则重启后挂载文件内容会被环境变量生成的版本覆盖。
- 主题挂载(官方 docker/README.md 四步法):先把镜像内主题目录拷出来,再挂回并指定主题名:
docker compose cp web:/www/media jirafeau_media # 第 1 步:拷出主题目录
volumes:
- ./jirafeau_media/your_theme:/www/media/your_theme # 第 2 步:挂载自定义主题
environment:
STYLE: 'your_theme' # 第 3 步:指定亮色主题
DARK_STYLE: 'your_theme' # 指定暗色主题
之后 docker compose up -d 重建生效(第 4 步)。
八、等价 docker run
与第四节 compose 等价的单命令启动方式:
docker run -d --name jirafeau-4.7.2-web \
-p 8150:80 \
-v /opt/data/quzuo/tmp/jirafeau/jirafeau_data:/data \
-e ADMIN_PASSWORD=q1w2e3r4 \
--restart unless-stopped \
registry.gitlab.com/jirafeau/jirafeau:4.7.2
生产环境建议仍用 compose:网络子网、卷、环境变量的声明式管理便于复现与升级。
九、常用运维命令
docker compose ps # 栈内服务状态
docker logs -f jirafeau-4.7.2-web # 跟踪服务日志(含每日清理动作)
docker compose restart # 重启(注意:会按环境变量重写配置文件)
docker compose down # 停止并移除栈(数据在 ./jirafeau_data 不受影响)
docker compose up -d # 重新拉起
升级路径(官方 CHANGELOG 的 in-place upgrade 原则):备份 jirafeau_data/ → 改 compose 中镜像 tag 到新版本 → docker compose up -d → 首启脚本自动检测数据目录并完成迁移 → 对照 CHANGELOG 检查新增配置项并补齐环境变量。特别地,从 4.7.0 升级需在配置中显式补 max_upload_chunk_size_bytes = 5000000(官方 CHANGELOG 4.7.1 明确要求)。
十、常见问题(FAQ)
Q1:上传大文件失败 / get_capacity 只有 1MB?
镜像内置 php.ini 限制 upload_max_filesize = 1M、post_max_size = 2M(实测 get_capacity 返回 1048576)。浏览器分块上传可绕过单请求限制,但脚本接口单请求上传受它约束。解决:挂载自定义 php.ini 或调整 MAXIMAL_UPLOAD_SIZE(应用层,单位 MB)与 PHP 限制两层。
Q2:为什么生成出来的 Bash 客户端脚本里 url 是空的?
因为未设置 WEB_ROOT。首启日志中的 warning: you may want to have set WEB_ROOT ... 就是这个原因——WEB_ROOT 决定自动生成客户端脚本里预填的服务地址。实测未设时脚本头部为 url='',需手工 export JIRAFEAU_URL 补上;设置 WEB_ROOT: 'jirafeau.example.com/' 后生成即预填。
Q3:访问首页报 "Installation file not found / The file directory is not writable"? 两种可能:一是数据目录属主不对(需 UID 100 / GID 82 可写,或保持默认让首启脚本自建);二是用镜像却想走浏览器安装向导——官方 4.7.2 镜像不含 install.php(实测),容器化部署只支持环境变量首启配置,向导路径属源码部署形态。
Q4:改了服务内配置文件重启后又变回去了?
正常行为:首启脚本每次启动都按环境变量重写 lib/config.local.php(第六节实测)。持久化配置请改 compose 环境变量。
Q5:管理界面登录后点任何动作都弹回登录页?
动作 POST 缺少 admin_csrf 字段(4.9 节)。该字段在登录成功页的隐藏域中,脚本化操作需先提取再随动作提交。
十一、参考链接
- 官方仓库:https://gitlab.com/jirafeau/Jirafeau
- 官方镜像说明(docker/README.md):https://gitlab.com/jirafeau/Jirafeau/-/blob/master/docker/README.md
- 官方 compose 示例:https://gitlab.com/jirafeau/Jirafeau/-/blob/master/docker-compose.yaml
- 本系列认知篇:《Jirafeau 介绍与选型指南》
- 本系列配置篇:《Jirafeau 4.7.2 配置参数详解》
- 本系列操作篇:《Jirafeau 4.7.2 常用 CLI 命令与工具详解》