Uguu 1.9.9 配置参数详解
逐项详解 Uguu 1.9.9 config.json 全部参数:站点信息与编译期烧录、max_upload_size 三层真相(前端 only)、过期/存储/数据库/黑白名单/限速/隐私调试参数与实测行为、APCu 缓存生效机制与参数速查表,实测通过。
Uguu 1.9.9 配置参数详解
目标:逐项讲解 Uguu 1.9.9 的
config.json全部 40 余个参数——位置、加载机制、分组语义、默认值与实测行为(含官方文档未写清的坑:max_upload_size只管前端、站点文案编译期烧录、配置被 APCu 缓存需重启生效),并给出与 Nginx/PHP 三层上传限制的配合关系。本文所有实测均在 Ubuntu 24.04 LTS(x86_64)+ Nginx 1.26.3 + PHP 8.3.15 + SQLite 3.45.3 环境完成(2026-11-01,Uguu 1.9.9)。
一、环境信息
- 操作系统:Ubuntu 24.04 LTS(x86_64)
- 软件版本:Uguu 1.9.9(官方仓库 master;
package.json与src/config.json双渠道确认) - 组件版本:Nginx 1.26.3、PHP-FPM 8.3.15、SQLite 3.45.3(
nginx -v、php -v、sqlite3 --version实测) - 服务实例:Web 端口 8134(部署形态见《Uguu 1.9.9 Docker Compose 部署指南》)
- 运行时配置位置:
/var/www/uguu/dist/config.json - 源码引用:
src/Classes/Upload.php、src/Classes/expireChecker.php、src/Classes/Database.php(1.9.9 源码)
二、配置文件的位置与加载机制
Uguu 的配置有两份、一进一出:
| 文件 | 角色 | 说明 |
|---|---|---|
src/config.json | 编译输入 | 仓库源码里的模板配置,EJS 编译时烧进静态页面(站点名/副标题/上限提示文案),Makefile 也从这里读 DOMAIN、max_upload_size、expireTime 等变量 |
dist/config.json | 运行时唯一读取点 | 编译产物目录下的同名文件,PHP 类运行时加载;部署后改它即可改后端行为 |
加载机制有三个必须理解的细节(均有源码与实测依据):
- APCu 缓存:
Connector::loadConfig()与expireChecker::loadConfig()优先从 APCu 取配置(缓存键UC),只有 APCu 未启用或未命中才读文件。因此改完dist/config.json必须重载 PHP-FPM(裸机systemctl reload php8.3-fpm,Compose 部署docker compose restart uguu),否则改了也白改——本系列实测中每一轮配置变更均以重启后行为变化确认了这一点; - 运行时与编译期分离:
siteName、subTitle、max_upload_size的页面展示文案等在make编译期就固定进了dist/public/*.html。实测把运行时config.json的siteName改成 "Uguu Lab"、expireTime改成 30 minutes 后,首页<title>仍是编译期的Uguu · Temporary file hosting、提示仍是Max upload size is 128 MiB & files expire after 8 hours.,但后端过期判断已按 30 分钟执行——要改页面文案必须改src/config.json重新构建; - JSON 健壮性:
loadConfig()对 JSON 解析失败直接报Invalid JSON in config file.(HTTP 500),手改文件后建议先jq . config.json静默校验。
三、站点信息与编译期参数
| 参数 | 类型 | 默认值 | 作用与实测说明 |
|---|---|---|---|
dest | string | dist | 编译输出目录名,Makefile 的 DESTDIR 来源;保持默认即可 |
pkgVersion | string | 1.9.9 | 包版本号,make dist 打包命名用(uguu-1.9.9.tar.xz);与 package.json 的 version 保持一致 |
pages | array | ["index.ejs","faq.ejs","api.ejs","404.ejs"] | 要编译的 EJS 模板列表;新增自定义页面在此登记后 make 生成 |
siteName | string | Uguu | 站点名称,浏览器标题与多处页面文案;编译期烧录 |
subTitle | string | Temporary file hosting | 副标题,与站点名一起出现在 <title>;编译期烧录 |
DOMAIN | string | dev.uguu.se | 主站域名(FAQ 页展示、页面内链生成);实测填 127.0.0.1:8134 后编译页面内链指向本地 |
FILE_DOMAIN | string | files.dev.uguu.se | 下载文件域名,API 返回的 url 由它拼出:https://FILE_DOMAIN/filename。不用独立子域时按官方要求填 主域/路径 形态(如 example.com/files,注意末尾不加斜杠) |
abuseContact | string | abuse@email.com | 滥用投诉邮箱,展示在 FAQ 页;官方提醒必须为可收信邮箱,否则可能被主机商处理 |
infoContact | string | info@email.com | 一般联系邮箱,展示在 FAQ 页 |
ServerCountryLocation | string | Sweden | 服务器所在国家,DMCA/滥用处置依当地法律的声明项 |
SiteMetaInfo | string | Uguu is a temporary file hosting service! | 站点 meta description,搜索引擎展示 |
responseTime | string | 24 hours | FAQ 页展示的「投诉响应时间」承诺文案 |
showGithub | bool | true | 导航栏是否显示 GitHub 仓库链接 |
donationBanner | bool | false | 是否编译捐赠横幅(配合下面四个收款渠道参数) |
paypalUrl / bitcoinAddress / ethereumAddress / kofiUrl | string | 空 | PayPal/比特币/以太坊/Ko-Fi 四种捐赠渠道,仅在 donationBanner: true 时被编译进页面 |
malwareBanner | bool | false | 是否编译「恶意软件警示」横幅(公共实例用于提示文件安全风险) |
GRILLS | array | 2~20 的字符串数组 | 页脚看板娘随机立绘的编号池,文件来自 dist/public/img/grills/;按部署需要增删编号 |
四、上传限制参数:max_upload_size 的三层真相
| 参数 | 类型 | 默认值 | 作用 |
|---|---|---|---|
max_upload_size | number | 128 | 仅用于前端展示与浏览器端预校验:编译进首页 lead 文案(Max upload size is 128 MiB)与上传表单的 data-max-size 属性(128MiB),JS 据此在浏览器侧拦截超限文件 |
这是 Uguu 官方文档里最容易被误解的参数:它在后端代码中没有任何执行点(1.9.9 源码中仅 src/templates/partials/upload_form.ejs 与 lead.ejs 两处模板引用)。服务端真正的硬限由另外两层把守:
| 层 | 参数 | 默认(官方 Wiki/镜像) | 超限行为 |
|---|---|---|---|
| Nginx | client_max_body_size | 官方 docker 配置 128m;裸机 Wiki 要求改 nginx.conf 与上限一致 | 413 Request Entity Too Large |
| PHP | upload_max_filesize / post_max_size | 镜像内置 128M/128M;裸机 Wiki 建议 128M/256M | POST 被截断,$_FILES['files'] 为空 → API 返回 400 No input file(s) |
实测证据:把 config.json 的 max_upload_size 改成 1(页面上会显示 1 MiB,但该值不重编译不生效)并重启后,直接用 curl 传一个 2MB 文件——成功:
curl -s -F "files[]=@big2m.bin" http://127.0.0.1:8134/upload.php
{
"success": true,
"files": [
{
"filename": "yGNjTZlU.bin",
"size": 2097152,
"dupe": false
}
]
}
结论:要收紧 API 侧上限,必须同时调小 Nginx client_max_body_size 与 PHP upload_max_filesize/post_max_size;config.json 只改前端体验。三层保持「PHP ≥ Nginx = config 提示值」的比例(PHP 的 post_max_size 需容纳表单开销,官方建议设为文件上限的 2 倍)。
五、过期与存储参数
| 参数 | 类型 | 默认值 | 作用与实测说明 |
|---|---|---|---|
expireTime | number | 8 | 过期时长数值。必须为整数:expireChecker::checkDB() 有 is_int 判断,非整数则整个过期检查直接跳过(返回 false,静默不清理) |
expireTimeUnit | string | hours | 时间单位,七选一:seconds/minutes/hours/days/weeks/months/years。源码会把单位转大写后做白名单校验,非法值回退 HOURS |
FILES_ROOT | string | /var/www/files/ | 上传文件落盘目录。entrypoint 会按它自动建目录并授权;末尾斜杠是拼接约定的一部分(源码直接 FILES_ROOT . filename),不要去掉 |
FILES_RETRIES | number | 15 | 随机文件名撞名时的重试次数(8 位随机名 + 52 字符表空间极大,撞名概率可忽略) |
NAME_LENGTH | number | 8 | 随机文件名长度。官方提醒:调小会提高被穷举枚举的风险,不建议低于默认值 |
ID_CHARSET | string | 52 个大小写字母 | 随机名字符表。注意默认表里没有易混淆的 I 和 O(ABCDEFGHJKLMNOPQRSTUVWXYZ),官方已做防混淆处理 |
DOUBLE_DOTS_EXTENSIONS | array | ["tar.bz2","tar.gz","min.css","min.js","conf.bak"] | 双点扩展名识别表:扩展名提取逻辑对两个点的文件名先按此表匹配(archive.tar.gz 的扩展名是 tar.gz 而非 gz),黑/白名单按匹配结果过滤 |
过期机制与 expireTime 的实测闭环(1 分钟过期档):
# 到期前库里有 8 条记录、files 目录 8 个文件
php /var/www/uguu/dist/checkExpire.php
# (过期文件存在时脚本静默删除,无任何输出)
sqlite3 /var/www/db/uguu.sq3 "SELECT id, filename FROM files;"
# (空)——files 表记录与物理文件全部删除
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8134/files/HEJAifkR.txt
# 404
完整实测与 cron 配置见《Uguu 1.9.9 常用命令详解》。
六、数据库参数
| 参数 | 类型 | 默认值 | 作用 |
|---|---|---|---|
DB_MODE | string | sqlite | 数据库类型:sqlite/mysql/pgsql 三选一,PDO DSN 前缀 |
DB_PATH | string | /var/www/db/uguu.sq3 | 三种库的路径语义不同:SQLite=库文件绝对路径;MySQL=unix_socket=/var/run/mysqld/mysqld.sock;dbname=uguu;PostgreSQL=host=DBHOST;port=5432;dbname=uguu |
DB_USER / DB_PASS | string | NULL | SQLite 保持字面量 NULL(代码按字面量处理);MySQL/PostgreSQL 填真实凭据 |
建库方式:SQLite 用官方 schema 一次性初始化(sqlite3 $DB_PATH -init src/static/dbSchemas/sqlite_schema.sql "");镜像部署由 entrypoint 检测 DB_PATH 不存在时自动执行。库内四张表实测结构(PRAGMA table_info(files) 原样回显):
0|id|INTEGER|1||1
1|hash|char(40)|0|NULL|0
2|originalname|varchar(255)|0|NULL|0
3|filename|varchar(30)|0|NULL|0
4|size|INTEGER|0|NULL|0
5|date|INTEGER|0|NULL|0
6|ip|char(15)|0|NULL|0
其余三张表:ratelimit(限速记账:iphash/files/time)、blacklist(哈希黑名单)、accounts(管理面板 Moe Panel 使用的账号表,核心功能不依赖)。
七、内容管控参数
7.1 FILTER_MODE / FILTER_EXTENSIONS / FILTER_MIME
| 参数 | 类型 | 默认值 | 作用 |
|---|---|---|---|
FILTER_MODE | bool | true | 过滤模式开关:true=黑名单模式,false=白名单模式。官方 Wiki 该条目两句都写「if set to true」属笔误,源码 Upload::uploadFile() 的分支一目了然:FILTER_MODE 为 true 走 checkMimeBlacklist()/checkExtensionBlacklist()(在名单内→415 拒收),为 false 走 checkMimeWhitelist()/checkExtensionWhitelist()(不在名单内→415 拒收) |
FILTER_EXTENSIONS | array | 13 项:exe/scr/com/vbs/bat/cmd/htm/html/jar/msi/apk/phtml/svg | 黑名单模式下=禁止上传的扩展名;白名单模式下=仅允许上传的扩展名。官方建议保留默认集(恶意软件常用投递格式) |
FILTER_MIME | array | 8 项:application/msword、text/html、application/x-dosexec、application/java、application/java-archive、application/x-executable、application/x-mach-binary、image/svg+xml | MIME 过滤表,语义同上按模式切换。MIME 由 finfo 按文件内容探测(改后缀不绕过),官方建议与扩展名表对齐 |
两个方向的实测(同一份 PNG,扩展名 png 不在默认表内):
- 黑名单模式(
FILTER_MODE: true,默认):上传成功——png不在黑名单; - 白名单模式(
FILTER_MODE: false):上传被拒——
{
"success": false,
"errorcode": 415,
"description": "Filetype not allowed"
}
黑名单模式的拦截实测(setup.exe):
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json; charset=UTF-8
{
"success": false,
"errorcode": 415,
"description": "Filetype not allowed"
}
💡 技术拓展:文件上传过滤的「扩展名 vs MIME」之争——扩展名是文件名的自我声明,MIME(libmagic/finfo)是内容的指纹判断,两者都可能被构造绕过(把脚本伪装成 image/jpeg 内容)。Uguu 的做法是双表联动 + 建议两表对齐,属于实用的纵深防御第一层;要做到更强的内容安全,可在 Nginx 层加病毒扫描(如 ClamAV 模块)或配合
BLACKLIST_DB沉淀已知恶意哈希。
7.2 BLACKLIST_DB 与 ANTI_DUPE
| 参数 | 类型 | 默认值 | 作用与实测说明 |
|---|---|---|---|
BLACKLIST_DB | bool | false | 开启后每个上传文件先按 xxh3 内容哈希查 blacklist 表,命中即 415。表数据由管理面板(Moe Panel)或手工 SQL 沉淀,实测默认空表:SELECT * FROM blacklist; 无行 |
ANTI_DUPE | bool | false | 开启后按 xxh3 哈希查 files 表,已有同内容文件则不再落盘,直接返回既有文件名,响应带 "dupe": true。实测同一文件二次上传:filename 与首次完全一致(wnBwPUJr.txt),dupe 翻转为 true |
八、限速参数
| 参数 | 类型 | 默认值 | 作用与实测说明 |
|---|---|---|---|
RATE_LIMIT | bool | false | 上传限速总开关 |
RATE_LIMIT_TIMEOUT | number | 60 | 限速窗口(秒) |
RATE_LIMIT_FILES | number | 100 | 窗口内允许上传的文件份数 |
限速的记账对象不是裸 IP,而是「IP + User-Agent」的 xxh3 指纹(源码 fingerPrint():hash('xxh3', CLIENT_IP . USER_AGENT)),写入 ratelimit 表;LOG_IP=false 时表里只有指纹哈希、无明文 IP。实测 RATE_LIMIT_FILES: 2 + TIMEOUT: 60:同指纹连续第 1、2 次上传成功,第 3 次被拒:
HTTP/1.1 500 Internal Server Error
{
"success": false,
"errorcode": 500,
"description": "Rate limit, please wait 60 seconds before uploading again."
}
ratelimit 表实测内容(第 3 次被拒后):1|a9e2bf4eb803d333|1793507088|2(id|iphash|time|files)。过期记录(24 小时前)由 checkExpire.php 每次顺带清理(cleanRateLimitDB())。
九、隐私与调试参数
| 参数 | 类型 | 默认值 | 作用与实测说明 |
|---|---|---|---|
LOG_IP | bool | false | 是否在 files.ip 落明文上传者 IP。默认 false(隐私优先设计),实测 SELECT id, filename, ip FROM files; 的 ip 列为空;开启后新上传记录 ip 列写入客户端地址。指纹用途的 ip_hash(xxh3)不受此开关影响,始终计算但不落库 |
DEBUG | bool | false | 错误详情开关。false 时所有 500 统一返回 Server error.;true 时返回根因文本。实测定位 CSV 输出缺陷就靠它:DEBUG 开启后 ?output=csv 的 500 显示 Server error: Undefined array key "name"(1.9.9 上游缺陷:响应负载已不含 name 字段而 CSV 格式化器仍读取)。生产必须 false——错误详情可能泄露路径与配置信息 |
BENCHMARK_MODE | bool | false | 基准测试模式:true 时跳过 move_uploaded_file 落盘与真实入库(仅走流程计时),文件不会被保存。官方明确要求非压测场景必须 false |
十、参数速查:改了谁要动哪里
| 想做的事 | 改哪里 | 生效方式 |
|---|---|---|
| 改过期时长/单位、存储路径、过滤名单、限速、防重复、DEBUG | dist/config.json(挂载卷/裸机 /var/www/uguu/dist/config.json) | 重载 PHP-FPM(清 APCu) |
| 改站点名、副标题、页面提示文案、上传上限的展示值 | src/config.json 后重新 make(或重建镜像) | 重新构建部署 |
| 收紧真实上传上限 | Nginx client_max_body_size + PHP upload_max_filesize/post_max_size,与 config 提示值对齐 | 重载 Nginx 与 PHP-FPM |
| 切换 MySQL/PostgreSQL | DB_MODE/DB_PATH/DB_USER/DB_PASS + 对应 schema 建库 | 重载 PHP-FPM |
十一、参考链接
- 官方配置 Wiki(参数定义出处):https://github.com/nokonoko/Uguu/wiki/Uguu-Configuration-%26-Installation
- 默认配置文件(1.9.9 源码):https://github.com/nokonoko/Uguu/blob/master/src/config.json
- 本系列选型篇:《Uguu 1.9.9 介绍与选型指南》
- 本系列部署篇:《Uguu 1.9.9 Docker Compose 部署指南》
- 本系列命令篇:《Uguu 1.9.9 常用命令详解》