Uguu 1.9.9 Docker Compose 部署指南

用官方仓库自带 Dockerfile 自建 Uguu 1.9.9 镜像并以 Docker Compose 部署:源码获取与构建期网络适配、Compose 编排(数据双卷/配置挂载/端口子网规划)、上传下载闭环验证、数据备份与 cron 过期清理,含 vendor 缺失、/files/ 404 等排障实录,实测通过。

UguuUguuPHP文件传输文件分享自托管2026/11/01

Uguu 1.9.9 Docker Compose 部署指南

目标:在装有 Docker 的服务器上,用官方仓库自带的 Dockerfile 构建 Uguu 1.9.9 镜像,并以 Docker Compose 完成单机部署:覆盖源码获取、构建期网络适配、Compose 编排(数据持久化、配置挂载、端口与子网规划)、启动验证、上传下载闭环测试、数据备份与日常运维。已在 Ubuntu 24.04 LTS(x86_64)+ Docker 29.9.2 + Docker Compose v2 环境实测通过(2026-11-01)。

一、环境信息

  • 服务器:Ubuntu 24.04 LTS(x86_64),Docker 29.9.2,Docker Compose v2
  • 软件版本:Uguu 1.9.9(官方仓库 master,package.json 与 src/config.json 双渠道确认,2026-11-01 实查)
  • 镜像形态:Uguu 无官方预构建镜像(Docker Hub 无 nokonoko 官方仓库),官方仓库自带 Dockerfile(Alpine 3.20 底座 + Nginx 1.26.3 + PHP-FPM 8.3 + Bun 构建链,内置 SQLite 自动初始化与健康检查),本文按官方 Dockerfile 本地构建镜像 uguu:1.9.9
  • 端口规划:宿主机 8134 → 服务容器内 8080(镜像内 Nginx 监听 8080)
  • 网络规划:自定义 bridge 子网 10.89.56.0/24(显式指定,避开默认网段冲突)
  • 实测镜像体积:357MB(构建完成后 docker images 显示)

二、部署形态说明:为什么从源码构建

Uguu 与多数 Go 系文件分享组件(Plik/PicoShare/goploader 一个二进制即可跑)不同,它是构建型 PHP 项目:源码仓库里的 EJS 模板、JS、CSS 必须经 Bun 工具链编译进 dist/ 目录后才是可部署的站点,PHP 依赖需经 Composer 安装。官方仓库在 1.9.9 起自带 Dockerfile(发行注记「Added docker dev environment support」),把「Alpine 底座 + apk 装 PHP 8.3 全家桶 + Bun 编译 + Composer 装依赖 + Nginx/PHP-FPM 双进程启动 + SQLite 自动建库」整条链封装在镜像构建中,这是官方目前唯一的一键部署路径,也是本文采用的方案。

前置依赖(宿主机只需要 Docker,构建过程全部发生在构建容器内):

  • 网络可达:codeload.github.com(拉源码)、dl-cdn.alpinelinux.org(apk 依赖)、registry.npmjs.org(Bun 依赖)、getcomposer.org(Composer)、repo.packagist.org(PHP 依赖)。2026-11-01 实测以上站点直连均可用;⚠️ 网络说明:本环境 raw.githubusercontent.com 直连被阻断(TLS 握手无响应),而官方 Makefile 的 Composer 安装步骤恰要从该域名下载安装器,因此构建前需按第四章打网络适配补丁——补丁后全程仅依赖 getcomposer.org,实测可用。

三、获取源码并打网络适配补丁

mkdir -p /opt/uguu && cd /opt/uguu
curl -sL -o uguu-master.tar.gz https://codeload.github.com/nokonoko/Uguu/tar.gz/refs/heads/master
tar xzf uguu-master.tar.gz --strip-components=1
ls

实测回显(解压后的仓库根目录):

compress.sh  docker  Dockerfile  LICENSE  Makefile  package.json  php_cs.dist
pngcompression.sh  README.md  RELEASE_NOTE.md  src

编辑 Makefile,把 install 与 install-dev 两个 target 中「下载 composer-setup.php 安装器」的三行:

	cd $(DESTDIR)/ && $(CURL) -o composer-setup.php https://raw.githubusercontent.com/composer/getcomposer.org/main/web/installer
	cd $(DESTDIR)/ && $(PHP) composer-setup.php --quiet
	cd $(DESTDIR)/ && rm composer-setup.php

替换为一行直接下载 Composer 官方 phar(install-dev target 中无 --quiet 变体同理替换):

	cd $(DESTDIR)/ && $(CURL) -fsSL -o composer.phar https://getcomposer.org/composer-stable.phar

⚠️ 排障实录 ①:替换行必须保留行首 TAB。Makefile 的 recipe 行以 TAB 开头;若替换时不小心把行首 TAB 丢掉,make 会把 cd $(DESTDIR)/ && $(CURL) ... composer.phar 整行解析成一串名为 cd、&&、composer.phar、https 的伪 target(构建日志出现成串 Makefile:124: warning: overriding recipe for target 'composer.phar'),后续 php composer.phar update 也随伪 target 一起被吞掉——构建照常「成功」,但 dist/vendor/autoload.php 不会生成,部署后所有上传请求 500(DEBUG 打开后显示 Undefined array key 之外的 autoload fatal)。实测中首次构建即踩中该坑,修 TAB 后重建解决。验证方法见第六章的 vendor 检查。

四、编写 Dockerfile 路径对齐与 Compose 编排

4.1 Compose 项目文件

创建 docker-compose.yml(项目名显式写为 uguu-1.9.9-stack,避免多项目同名互删):

name: uguu-1.9.9-stack

services:
  uguu:
    image: uguu:1.9.9
    container_name: uguu-1.9.9-web
    ports:
      - "8134:8080"
    volumes:
      - uguu-files:/var/www/files
      - uguu-db:/var/www/db
      - ./config/config.json:/var/www/uguu/dist/config.json:ro
    restart: unless-stopped

networks:
  default:
    name: uguu-1.9.9-net
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.56.0/24

volumes:
  uguu-files:
  uguu-db:

设计说明:

  • 数据双卷:上传文件(/var/www/files)与 SQLite 数据库(/var/www/db)各自独立命名卷,备份与迁移可以分开处理;镜像内 entrypoint 启动时会用 jq 读取 config.json 的 DB_PATH/FILES_ROOT,目录不存在则创建、库文件不存在则用官方 schema 自动初始化;
  • 配置挂载:config.json 以只读方式挂到 /var/www/uguu/dist/config.json(应用运行时唯一读取的配置位置,Classes 经 APCu 缓存键 UC 加载),改配置只需改宿主机文件并重启服务,无需重建镜像;
  • 端口/子网:8134 与 10.89.56.0/24 均为实测环境规划值,读者可按需替换,但 compose 的 name 必须保持 uguu-1.9.9-stack 形态(组件+版本+stack)以便识别。

4.2 构建期配置文件

创建 config/config.json(最小可用配置,完整参数逐项解释见《Uguu 1.9.9 配置参数详解》;注意 DOMAIN/FILE_DOMAIN 决定了 API 返回的下载 URL,请按实际访问地址填写):

{
  "dest": "dist",
  "pkgVersion": "1.9.9",
  "pages": ["index.ejs", "faq.ejs", "api.ejs", "404.ejs"],
  "DEBUG": false,
  "BENCHMARK_MODE": false,
  "max_upload_size": 128,
  "expireTime": 30,
  "expireTimeUnit": "minutes",
  "siteName": "Uguu Lab",
  "subTitle": "Temporary file hosting",
  "DOMAIN": "127.0.0.1:8134",
  "FILE_DOMAIN": "127.0.0.1:8134/files",
  "abuseContact": "abuse@example.com",
  "infoContact": "info@example.com",
  "ServerCountryLocation": "China",
  "SiteMetaInfo": "Uguu Lab is a temporary file hosting service!",
  "responseTime": "24 hours",
  "showGithub": true,
  "donationBanner": false,
  "paypalUrl": "",
  "bitcoinAddress": "",
  "ethereumAddress": "",
  "kofiUrl": "",
  "malwareBanner": false,
  "DB_MODE": "sqlite",
  "DB_PATH": "/var/www/db/uguu.sq3",
  "DB_USER": "NULL",
  "DB_PASS": "NULL",
  "LOG_IP": false,
  "ANTI_DUPE": true,
  "BLACKLIST_DB": false,
  "FILTER_MODE": true,
  "RATE_LIMIT": false,
  "RATE_LIMIT_TIMEOUT": 60,
  "RATE_LIMIT_FILES": 100,
  "FILES_ROOT": "/var/www/files/",
  "FILES_RETRIES": 15,
  "NAME_LENGTH": 8,
  "ID_CHARSET": "abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ",
  "DOUBLE_DOTS_EXTENSIONS": ["tar.bz2", "tar.gz", "min.css", "min.js", "conf.bak"],
  "FILTER_EXTENSIONS": ["exe", "scr", "com", "vbs", "bat", "cmd", "htm", "html", "jar", "msi", "apk", "phtml", "svg"],
  "FILTER_MIME": ["application/msword", "text/html", "application/x-dosexec", "application/java", "application/java-archive", "application/x-executable", "application/x-mach-binary", "image/svg+xml"],
  "GRILLS": ["2", "3", "4", "5"]
}

4.3 Nginx 文件下载链路修复补丁(必做)

⚠️ 排障实录 ②(上游缺陷):官方 docker/nginx.conf 的静态资源正则 location 会抢占 /files/ 前缀 location,导致图片类上传文件按 URL 访问 404。

官方 docker/nginx.conf 中同时存在两处相关 location:

location ~* \.(?:js|css|png|jpg|jpeg|gif|ico|svg|avif)$ {
    expires 30d;
    access_log off;
}
location /files/ {
    alias /var/www/files/;
    autoindex on;
    access_log off;
}

Nginx 的匹配规则是:先记下最长前缀匹配,再按顺序查正则,命中正则即直接采用(除非前缀带 ^~)。因此 .png 结尾的请求会落到静态资源 location,用 root /var/www/uguu/dist/public 拼路径找 dist/public/files/xxx.png——实测该文件不存在,返回 404(nginx error.log 实锤:open() "/var/www/uguu/dist/public/files/bkBnnvRE.png" failed (2: No such file or directory));而 .txt 不在正则里,走 /files/ 别名返回 200。实测取证(修复前):

GET /files/wnBwPUJr.txt  → 200
GET /files/bkBnnvRE.png  → 404

修复:编辑 docker/nginx.conf,给 /files/ 加 ^~ 前缀(跳过正则检查):

location ^~ /files/ {
    alias /var/www/files/;
    autoindex on;
    access_log off;
}

五、构建镜像并启动

5.1 构建

docker build -t uguu:1.9.9 .

构建过程要点(实测日志节选,构建总耗时约 1 分钟,其中 Bun 依赖 2035 个包安装 7.9s、make 编译约 2s、Composer 依赖安装约 30s):

#6 [ 2/14] RUN apk add --no-cache ... nginx php83 php83-fpm ... composer ...
#6 DONE ...
#11 [ 7/14] RUN bun install --ignore-scripts && make development && make install-dev ...
#11 0.158 bun install v1.4.4
#11 7.999 Resolved, downloaded and extracted [2035]
#11 8.052 556 packages installed [7.89s]
#11 DONE 10.3s
#19 naming to docker.io/library/uguu:1.9.9 done

构建完成后核对产物完整性(vendor 目录即排障实录 ① 的验证点):

docker run --rm --entrypoint sh uguu:1.9.9 -c \
  'test -f /var/www/uguu/dist/vendor/autoload.php && echo "vendor OK"; \
   ls /var/www/uguu/dist/'

实测回显:

vendor OK
classes  composer.json  composer.lock  composer.phar  config.json  vendor  ...
public  checkExpire.php  upload.php

5.2 启动与状态确认

docker compose up -d
docker compose ps

实测回显:

 Container uguu-1.9.9-web  Created
 Container uguu-1.9.9-web  Starting
 Container uguu-1.9.9-web  Started
NAME              IMAGE        STATUS
uguu-1.9.9-web    uguu:1.9.9   Up 4 seconds (health: starting)

镜像自带健康检查(curl -fsS http://127.0.0.1:8080/,30s 间隔),半分钟后 STATUS 转为 Up (healthy)。

六、部署验证

6.1 Web 首页

curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8134/
curl -s http://127.0.0.1:8134/ | grep -oE "<title>[^<]*"

实测回显:

200
<title>Uguu &middot; Temporary file hosting

⚠️ 注意:页面 <title> 与「Max upload size is …」提示文案来自构建期编译的静态 HTML(构建时用的是仓库默认 src/config.json:上限 128 MiB、过期 8 hours),运行时挂载的 config.json 只影响后端行为。改站点文案需改 src/config.json 后重新构建,详见配置篇排障实录。

6.2 上传-下载闭环(含二进制校验)

printf 'hello uguu' > hello.txt
curl -s -F "files[]=@hello.txt" http://127.0.0.1:8134/upload.php

实测回显:

{
    "success": true,
    "files": [
        {
            "hash": "47272535fb3d837e",
            "filename": "wnBwPUJr.txt",
            "url": "https:\/\/127.0.0.1:8134\/files\/wnBwPUJr.txt",
            "size": 22,
            "dupe": false
        }
    ]
}

⚠️ 排障实录 ③:响应里的 url 是硬编码 https:// 前缀拼 FILE_DOMAIN(源码 Upload::uploadFile() 固定写死)。本地 HTTP 实测时把 https:// 手动改成 http:// 即可下载;生产环境给站点配 TLS 后此问题自然消失。

按返回的 filename 下载并做二进制校验(换用一张真实 PNG,源文件与下载文件 md5 应一致):

curl -s http://127.0.0.1:8134/files/bkBnnvRE.png -o downloaded.png
md5sum photo.png downloaded.png

实测回显(location ^~ 补丁后):

93ca32a536da1698ea979f183679af29  photo.png
93ca32a536da1698ea979f183679af29  downloaded.png

6.3 数据库与文件落位确认

docker exec uguu-1.9.9-web sqlite3 /var/www/db/uguu.sq3 ".tables"
docker exec uguu-1.9.9-web sqlite3 /var/www/db/uguu.sq3 \
  "SELECT id, hash, originalname, filename, size, date FROM files ORDER BY id;"
docker exec uguu-1.9.9-web ls -la /var/www/files/

实测回显:

accounts   blacklist  files      ratelimit
1|47272535fb3d837e|hello.txt|wnBwPUJr.txt|22|1793506876
2|32962fc36316ee0c|photo.png|bkBnnvRE.png|67|1793506876
-rw-r--r-- 1 nginx nginx   22 Nov  1 04:21 wnBwPUJr.txt
-rw-r--r-- 1 nginx nginx   67 Nov  1 04:21 bkBnnvRE.png

四张表(accounts/blacklist/files/ratelimit)由官方 schema 自动建好;文件属主为 nginx(镜像内 Nginx/PHP-FPM 运行用户),权限 0644。

七、数据持久化、备份与到期清理

  • 备份对象:命名卷 uguu-1.9.9-stack_uguu-db(SQLite 单文件 uguu.sq3)与 uguu-1.9.9-stack_uguu-files(上传文件目录)。SQLite 库建议用 sqlite3 /var/www/db/uguu.sq3 ".backup '/var/www/db/backup.sq3'" 做一致性快照后再拷贝,避免直接 cp 正在写入的库文件;
  • 到期清理:容器内没有 cron,必须由外部定时任务触发 checkExpire.php。官方裸机方案是 root crontab 每分钟执行;在 Compose 部署下,在宿主机 crontab 里加一条即可:
* * * * * docker exec uguu-1.9.9-web php /var/www/uguu/dist/checkExpire.php

实测该脚本行为:无过期文件时输出 No file(s) expired, nothing to do.;有过期文件时静默删除(物理文件 + files 表记录一并清掉,同时清理 24 小时前的 ratelimit 记录)。完整实测过程见《Uguu 1.9.9 常用命令详解》。

八、日常运维命令

# 查看服务日志(Nginx access/error + PHP-FPM 汇总到容器 stdout/stderr)
docker compose logs -f --tail 100 uguu

# 修改 config.json 后使其生效(APCu 缓存了配置,必须重启 PHP-FPM 所在容器)
docker compose restart uguu

# 重建镜像(升级版本:改 tag 与 compose 中 image 后重复第三章~第五章)
docker compose down && docker build -t uguu:1.9.10 . && docker compose up -d

# 彻底清理(含数据卷,谨慎)
docker compose down -v

九、参考链接