Jirafeau Docker Compose 部署指南

Jirafeau 4.7.2 官方镜像 Compose 部署实测:镜像选型取证、首启环境变量配置(数据目录与管理口令)、上传/一次性链接/下载口令/过期删除/管理端全链路验证、数据持久化与环境变量表。

JirafeauJirafeauDocker Compose自托管2026/10/30

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 registryregistry.gitlab.com/jirafeau/jirafeau3.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.11,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

三、前置条件

  1. 端口空闲检查:宿主 8150 端口未被占用(部署前实测,8148/8149 已被其他业务占用故顺延取 8150):
ss -ltn | grep -E ':(815[0-9])' || echo "8150-8159 空闲"   # 检查目标端口段

实测回显(部署前):

8150-8159 空闲
  1. 网络子网检查: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
  1. 数据目录准备:在 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)
LANGauto界面语言(auto 跟随浏览器)
AVAILABILITIES九档 JSON可选有效期档位(JSON 布尔数组,见下方示例)
WEB_ROOT空生成链接用的对外域名(如 jirafeau.example.com/)
VAR_ROOT/data/数据目录
FILE_HASHrandom文件哈希方式:md5(去重)/ md5_outside / random
PREVIEW1是否提供浏览器预览
TITLE空站点标题
ORGANISATIONACME服务条款页组织名
CONTACTPERSON空条款页联系人
STYLEcourgette亮色主题
DARK_STYLEdark-courgette暗色主题
AVAILABILITY_DEFAULTmonth默认有效期档位
ONE_TIME_DOWNLOAD1是否允许一次性下载选项
ONE_TIME_DOWNLOAD_PRESELECTED0一次性下载是否默认勾选
ENABLE_CRYPT0服务端加密(与去重互斥)
DEBUG0调试输出(生产禁用)
MAXIMAL_UPLOAD_SIZE0(不限)应用层单文件上限(MB)
UPLOAD_PASSWORD空上传口令(逗号分隔多个)
UPLOAD_IP空允许上传的 IP 白名单
UPLOAD_IP_NO_PASSWORD空免口令上传 IP 白名单
PROXY_IP空反向代理来源 IP(改从 X-Forwarded-For 取访客 IP)
STORE_UPLOADER_IP1是否记录上传者 IP
DOWNLOAD_PASSWORD_REQUIREMENToptional下载口令策略:optional / required / generated
DOWNLOAD_PASSWORD_GEN_LEN10自动生成口令长度
DOWNLOAD_PASSWORD_GEN_CHARS见配置模板自动生成口令字符集
DOWNLOAD_PASSWORD_POLICYnone口令复杂度:none / regex
DOWNLOAD_PASSWORD_POLICY_REGEX/.*/regex 模式下的校验表达式
USER_ID / GROUP_ID100 / 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 配置参数详解》逐项拆解,这里只讲挂载方式:

  1. 配置文件挂载:把自备的 config.local.php 挂到服务内配置路径:
    volumes:
      - ./jirafeau_data:/data
      - ./config.local.php:/www/lib/config.local.php

⚠️ 注意:由于首启脚本每次启动都会按环境变量重写该文件,挂载自备配置时请同时确保环境变量与之一致(或仅保留 ADMIN_PASSWORD 等必需项),否则重启后挂载文件内容会被环境变量生成的版本覆盖。

  1. 主题挂载(官方 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 节)。该字段在登录成功页的隐藏域中,脚本化操作需先提取再随动作提交。

十一、参考链接