Signature PDF 1.11.0 配置参数详解
逐项实测讲解 Signature PDF 1.11.0 的全部配置面:Docker 环境变量层、config.ini 的 [globals] 键与 [signature] retention 段、NSS3 数字签名与管理页授权,含重启覆写、路由遮蔽等踩坑实录与生产配置模板。
Signature PDF 1.11.0 配置参数详解
目标:把 Signature PDF 1.11.0 的全部配置面——Docker 环境变量层、config.ini 的
[globals]键与[signature]retention 段、数字签名 NSS3 证书、管理页授权——逐项讲清「默认值、改法、生效机制、实测行为」,并沉淀重启覆写、路由遮蔽、错误段等踩坑实录。已在 Ubuntu 26.04.1 LTS(x86_64,Docker 29.9.2 / Compose v5.6.1)运行中的 signaturepdf-1.11.0-stack 环境逐项实测(2026-11-02),源码结论以 v1.11.0 tag 实拉核对。
一、环境信息
- 操作系统:Ubuntu 26.04.1 LTS(x86_64,内核 7.0.0-38-generic)
- 应用版本:Signature PDF v1.11.0,官方镜像
xgaia/signaturepdf:1.11.0(镜像 IDe4e417983384,基础镜像php:8.2-apache) - 运行栈:《Signature PDF 1.11.0 Docker Compose 部署指南》 所建 Compose 栈——服务名
signaturepdf、容器signaturepdf-1.11.0-web、端口8140:80、网络10.89.60.0/24(网关10.89.60.1)、数据目录./data:/data - 本部署注入的环境变量:
SERVERNAME=localhost:8140、UPLOAD_MAX_FILESIZE=48M、POST_MAX_SIZE=48M、MAX_FILE_UPLOADS=401、PDF_STORAGE_PATH=/data、DEFAULT_LANGUAGE=en_US.UTF-8(其余未设置,取模板默认) - 应用内关键路径:配置文件
/usr/local/signaturepdf/config/config.ini、PHP 限额/usr/local/etc/php/conf.d/uploads.ini、Apache 虚拟主机/etc/apache2/sites-available/signaturepdf.conf、共享存储/data - 取证方式:宿主侧
curl http://localhost:8140/...观察行为,docker exec读写配置;源码结论来自 v1.11.0 源码包(Config.class.php、MainController.class.php、entrypoint.sh、config/config.ini.example) - 测试素材:
contract-test.pdf(2 页 A4、1061 字节)、overlay-b.svg(签名图层)、hello.png(位图转矢量输入)
💡 说明:本篇与部署篇共用同一运行栈,所有「实测」都是对活服务的观察实验——改一个键、发一个请求、看一次回显。数字签名(NSS3)与 OCR 两条能力因官方镜像未预装对应组件,本篇只给出源码级配置方法与缺件证据,完整 API 面实测见 《Signature PDF 1.11.0 API 使用详解》。
二、前置条件
- 栈已按部署篇拉起且可访问:
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8140/signature
实测回显:
200
- 具备进入应用容器的权限(改配置、看渲染产物都要用):
docker exec signaturepdf-1.11.0-web id
实测回显:
uid=0(root) gid=0(root) groups=0(root)
- 备好测试 PDF 与 SVG 图层(用于观察配置对处理行为的影响):
cd /opt/data/quzuo/tmp/signature-pdf
ls -la contract-test.pdf overlay-b.svg e2e/g3_hello.png
实测回显:
-rw-r--r-- 1 root root 1061 Nov 2 08:25 contract-test.pdf
-rw-r--r-- 1 root root 448 Nov 2 11:40 overlay-b.svg
-rw-r--r-- 1 root root 309 Nov 2 13:00 e2e/g3_hello.png
三、参数查看与修改方式
3.1 两层配置模型
Signature PDF 的配置分两层,改法与生效时机完全不同:
第 1 层:Docker 环境变量(compose environment:)
└─ 启动瞬间由 entrypoint.sh 用 envsubst 渲染进 3 个产物:
apache.conf → /etc/apache2/sites-available/signaturepdf.conf
php.ini → /usr/local/etc/php/conf.d/uploads.ini
config.ini.tpl → /usr/local/signaturepdf/config/config.ini(只渲染 4 个键)
第 2 层:config.ini 本体(Fat-Free $f3->config() 加载)
└─ 除模板 4 键外,ADMIN_AUTHORIZED_IP、PDF_LOCAL_PATH、METADATA_DEFAULT_FIELDS、
REVERSE_PROXY_URL、NSS3_*、[signature] retention 等键只能直接编辑该文件
⚠️ 注意:第 1 层只覆盖 4 个键(
PDF_STORAGE_PATH、DISABLE_ORGANIZATION、PDF_DEMO_LINK、PDF_STORAGE_ENCRYPTION),其余键环境变量不认——设了也不会进 config.ini。想持久化第 2 层配置,必须挂载定制config.ini.tpl或做派生镜像(见 9.2 与常见问题 Q1)。
3.2 查看当前生效值
三个渲染产物逐一实查(宿主侧执行):
docker exec signaturepdf-1.11.0-web cat /usr/local/signaturepdf/config/config.ini
实测回显(本部署启动后原样):
[globals]
; Path to which stored pdf to activate the mode of sharing a signature to several.
; To deactivate this mode, simply do not configure it or leave it empty
PDF_STORAGE_PATH=/data
; Disable organization tab and routes
DISABLE_ORGANIZATION=false
; Manage demo link pdf : true (by default, show), false (hide), or custom link
PDF_DEMO_LINK=
; Encryption activation (default activation if GPG is installed)
PDF_STORAGE_ENCRYPTION=false
docker exec signaturepdf-1.11.0-web cat /usr/local/etc/php/conf.d/uploads.ini
实测回显:
upload_max_filesize = 48M
post_max_size = 48M
max_file_uploads = 401
docker exec signaturepdf-1.11.0-web grep ServerName /etc/apache2/sites-available/signaturepdf.conf
实测回显:
ServerName localhost:8140
PHP 限额不必进机器查 php.ini,页面内嵌 JS 直接暴露实际生效值:
curl -s http://localhost:8140/signature | grep -oE 'maxSize = [0-9]+|maxPage = [0-9]+'
实测回显:
maxSize = 48000000
maxPage = 400
3.3 内置配置查看面板 /administration
应用自带一个「Administration panel」配置总览页,汇总外部工具版本与关键路径。默认授权名单只有 localhost、127.0.0.1、::1 三个来源 IP(源码 Config.class.php 硬编码合并进 ADMIN_AUTHORIZED_IP),经宿主端口映射访问时来源是 Docker 网关 10.89.60.1,因此直接访问被拒:
curl -s http://localhost:8140/administration; echo; curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost:8140/administration
实测回显:
You (10.89.60.1) are not allowed to access this file. Check MainController.class.php for more information.
HTTP 200
💡 说明:这里有两个反直觉点。其一,拒绝响应是 HTTP 200 + 纯文本而不是 403——源码
MainController::administration用的是 PHPdie('You ('.$_SERVER['REMOTE_ADDR'].') are not allowed...'),die()直接输出正文、不改状态码;用监控脚本判断该页可用性时不能只看状态码。其二,提示文案里点名的MainController.class.php就是改授权的地方(准确说是 config.ini 的ADMIN_AUTHORIZED_IP键,见 6.1)。
把网关 IP 加进授权名单后(改法见 3.4):
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost:8140/administration
curl -s http://localhost:8140/administration | grep -oE '<title>[^<]+</title>'
实测回显:
HTTP 200
<title>Administration panel</title>
面板正文(纯文本化节选)把工具链版本、缺件状态、存储路径与授权名单一次列全:
Configuration
PHP version 8.2.35
rsvg-convert version 2.60.0
pdftk port to java 3.3.3
ImageMagick 7.1.1-43
potrace 1.16
Ghostscript version 10.05.1
gpg (GnuPG) 2.4.7
CertUtil (Package libnss3-tools missing)
Pdfsig (Package poppler-utils missing)
File Configuration
PDF_STORAGE_PATH /data/
UPLOADS /tmp/
List of authorized IP : localhost 127.0.0.1 ::1 10.89.60.1
CertUtil/Pdfsig 两行 missing 即官方镜像未预装数字签名组件的直接证据(NSS 配置见 6.5)。
3.4 修改方式与生效时机
| 改法 | 适用键 | 生效时机 | 重启后 |
|---|---|---|---|
改 compose environment: 后 docker compose up -d 重建 | 第 1 层 9 个环境变量 | 重建即生效 | 保留(源头就是它) |
docker exec ... vi /usr/local/signaturepdf/config/config.ini 直接编辑 | 第 2 层全部键 | 下一个请求即生效,无需重启 | 丢失(被模板重渲染覆写) |
挂载定制 config.ini.tpl 或派生镜像 | 两层全部 | 重建/重发布即生效 | 保留 |
「直接编辑即时生效」的机制:Fat-Free 在每个请求初始化 Config 时都执行 $this->f3->config(ROOT.'/config/config.ini') 重新读文件。实测佐证——向 config.ini 追加 PDF_LOCAL_PATH=/data 后不做任何重启,紧接着的请求行为立刻改变:
docker exec signaturepdf-1.11.0-web sh -c "printf '\nPDF_LOCAL_PATH=/data\n' >> /usr/local/signaturepdf/config/config.ini"
curl -s -o /dev/null -w 'HTTP %{http_code}\n' 'http://localhost:8140/api/file/get?path=probe.pdf'
实测回显:
HTTP 200
(追加前同一请求返回 403,见 6.2。)
「重启覆写」实测:对容器执行 docker restart 后,上一段追加的键整段消失,文件恢复为模板渲染的 4 键:
docker restart signaturepdf-1.11.0-web && sleep 6
docker exec signaturepdf-1.11.0-web grep -c 'PDF_LOCAL_PATH' /usr/local/signaturepdf/config/config.ini
实测回显:
0
四、参数总览
全部可配项、默认值与来源一览(官方默认取自 installation.md 与 config.ini.example,2026-11-02 实查):
| 层 | 键 | 默认值 | 作用 | 详解小节 |
|---|---|---|---|---|
| 环境变量 | SERVERNAME | localhost | Apache ServerName(部署 URL) | 5.1 |
| 环境变量 | UPLOAD_MAX_FILESIZE | 24M | 单上传文件大小上限 | 5.2 |
| 环境变量 | POST_MAX_SIZE | 24M | 整个 POST 请求体上限 | 5.2 |
| 环境变量 | MAX_FILE_UPLOADS | 201 | 单次请求文件数上限(=页数+1) | 5.2 |
| 环境变量 | PDF_STORAGE_PATH | /data | 共享存储目录;留空关闭共享模式 | 5.3 |
| 环境变量 | DISABLE_ORGANIZATION | false | 关闭页面整理入口 | 5.4 |
| 环境变量 | PDF_DEMO_LINK | true | 演示 PDF 链接:true/false/自定义 URL | 5.5 |
| 环境变量 | DEFAULT_LANGUAGE | fr_FR.UTF-8 | 界面默认语言(决定 locale-gen) | 5.6 |
| 环境变量 | PDF_STORAGE_ENCRYPTION | false | 共享存储 GPG 加密开关 | 5.7 |
| 环境变量 | DEBUG | 未设 | 保留临时文件不清理(非官方文档项,源码实查) | 5.8 |
| config.ini | ADMIN_AUTHORIZED_IP | 空(硬编码并入 localhost/127.0.0.1/::1) | /administration 授权 IP,空格分隔 | 6.1 |
| config.ini | PDF_LOCAL_PATH | 未设 | 本地文件 API 根目录 | 6.2 |
| config.ini | METADATA_DEFAULT_FIELDS[key].type | 未设 | 元数据页预置字段 | 6.3 |
| config.ini | REVERSE_PROXY_URL | '' | 反代改写下沉时的前缀 | 6.4 |
| config.ini | NSS3_DIRECTORY/NSS3_PASSWORD/NSS3_NICK | 未设 | 数字签名 NSS 证书库 | 6.5 |
| config.ini [signature] | retention[+N unit]="文案" | 6 档默认(1hour~1year) | 覆盖共享保留期选项 | 七 |
五、Docker 环境变量层详解
5.1 SERVERNAME
渲染进 Apache 虚拟主机的 ServerName(3.2 已见回显 ServerName localhost:8140)。生产填实际域名;不填时 Apache 启动日志出现 AH00558: Could not reliably determine the server's fully qualified domain name 告警,功能不受影响(部署篇 4.1 实测)。它同时决定 Web::send 回显文件名之外的站点自识别 URL 基座(/api/share/new 返回的 url 字段用 $_SERVER['SERVER_NAME']+端口拼接,见 API 篇)。
5.2 三个上传限额
UPLOAD_MAX_FILESIZE/POST_MAX_SIZE/MAX_FILE_UPLOADS 渲染进 uploads.ini(3.2 回显 48M/48M/401)。约束关系:单文件 ≤ UPLOAD_MAX_FILESIZE,整个请求体 ≤ POST_MAX_SIZE(整理多份 PDF 时是「所有文件之和」,最先撞),文件数 ≤ MAX_FILE_UPLOADS - 1(页数上限)。页面 JS 里的 maxSize 取两者较小值、按 1000 进制折算(48M→48000000,源码 Config::convertPHPSizeToBytes 逐级 ×1000,与 1024 进制 MiB 不同——按 MiB 预期请填 50M)。超限文件在落盘前被 PHP 拒收,前端表现为上传直接失败。
5.3 PDF_STORAGE_PATH:留空即关共享
设为空值后共享模式整体关闭——签名页不再出现「分享」表单,前端共享开关归零:
# 实验:把模板渲染出的 PDF_STORAGE_PATH=/data 改为空并即时生效(无需重启)
docker exec signaturepdf-1.11.0-web sh -c "sed -i 's|^PDF_STORAGE_PATH=/data|PDF_STORAGE_PATH=|' /usr/local/signaturepdf/config/config.ini"
curl -s http://localhost:8140/signature | grep -c 'form_sharing'
curl -s http://localhost:8140/signature | grep -o 'var sharingMode = [01]'
实测回显:
0
var sharingMode = 0
改回 /data 后 form_sharing 命中恢复、sharingMode = 1。源码路径:MainController::signature 中 if(!$f3->get('PDF_STORAGE_PATH')) { $f3->set('noSharingMode', true); };此外 Config.class.php 会给不带尾斜杠的值自动补 /(管理面板显示 /data/ 即此行为)。
5.4 DISABLE_ORGANIZATION:只关首页入口,不封路由
设为 true 后首页直接重定向到签名页:
curl -s -o /dev/null -w 'GET / -> HTTP %{http_code} redirect=%{redirect_url}\n' http://localhost:8140/
实测回显:
GET / -> HTTP 302 redirect=http://localhost:8140/signature
⚠️ 注意:
/organization路由本身仍然放行——直接访问依旧返回 200 并渲染整理页(实测GET /organization -> HTTP 200)。源码MainController::index只做首页 reroute,未对 organization 路由加拦截;installation.md 所谓 "Disable the Organize route" 实际只是「隐藏入口」。需要硬关路由时要在前置反代上屏蔽/organization。
5.5 PDF_DEMO_LINK:三态取值
控制签名页「试试示例 PDF」链接。三种取值实测:
- 空/true(默认):渲染出指向仓库示例文档的链接——
curl -s http://localhost:8140/signature | grep -o 'document\.pdf' | sort -u
实测回显:
document.pdf
(源码缺省值为 https://raw.githubusercontent.com/24eme/signaturepdf/master/tests/files/document.pdf,阿拉伯语界面自动切换 document_ar.pdf。)
- false:链接整体消失——实测页面 grep demo 链接命中
0; - 自定义 URL:链接指向所填地址,实测回显
href="#https://example.org/demo.pdf"——注意模板在值前拼了#(前端 JS 拦截该链接代为拉取),填相对路径亦可。
5.6 DEFAULT_LANGUAGE:locale 生成 + 界面缺省语言
启动时入口脚本 sed 取消 /etc/locale.gen 中所填 locale 的注释并 locale-gen,再 export LANG/LANGUAGE/LC_ALL。启动日志可见生成过程(部署篇 4.3 回显 en_US.UTF-8... done)。界面实际语言优先级:?lang= 参数 > LANGUAGE Cookie > 该缺省值。实测带 ?lang=fr 访问返回法文页并种一年期 Cookie:
curl -s -D - -o /dev/null 'http://localhost:8140/signature?lang=fr' | grep -E 'HTTP|Set-Cookie: LANGUAGE'
实测回显(节选):
HTTP/1.1 200 OK
Set-Cookie: LANGUAGE=fr; expires=Tue, 02 Nov 2027 05:02:26 GMT; Max-Age=31536000; path=/; SameSite=Strict
响应页面 <title>Signature PDF - Signer un PDF en ligne</title>(法文)。支持值共 15 种(ar/de/en/es/eu/fr/it/gl/kab/nl/oc/pl/ro/ta/tr,源码 SUPPORTED_LANGUAGES),中文不在列;?lang=zh 会被 selectLanguage 忽略、回落缺省语言。
5.7 PDF_STORAGE_ENCRYPTION:加密开关与 GPG 依赖
设为 true 后,签名页共享表单出现默认勾选的加密选项:
docker exec signaturepdf-1.11.0-web sh -c "sed -i 's|^PDF_STORAGE_ENCRYPTION=false|PDF_STORAGE_ENCRYPTION=true|' /usr/local/signaturepdf/config/config.ini"
curl -s http://localhost:8140/signature | grep -o 'checkbox_encryption[^/]*/'
实测回显:
checkbox_encryption" name="encryption" value="true" checked="checked" form='form_sharing'/
源码约束(Config.class.php):开关为真但 GPG 未安装时强制回落 false——官方镜像已含 /usr/bin/gpg(GnuPG 2.4.7,管理面板可见),故本实验生效。开启后共享目录内全部文件带 .gpg 后缀、服务端不可读明文(密钥只在浏览器 Cookie 与链接 # 片段),共享目录形态实测见部署篇第五章与 API 篇生命周期实验。
5.8 DEBUG:源码级隐藏项
Config.class.php 读 getenv("DEBUG"),为真时各处理路由(sign/share/image2svg/compress)跳过临时文件清理、PDFSignature 跳过中间产物归并,便于排查合成问题。该变量不在 installation.md 配置表内,属调试用途,生产勿开(临时文件会持续占盘)。本篇结论为源码实查(v1.11.0 MainController.class.php 多处 if($f3->get('DEBUG')) return;),未做运行态实验。
六、config.ini [globals] 键详解
以下键均不在 envsubst 模板内,只能按 3.4 方式直接编辑 config.ini(即时生效、重启丢失)。
6.1 ADMIN_AUTHORIZED_IP
控制谁能打开 /administration 面板。值按空格分隔的 IP 列表解析,源码再硬编码并入 localhost 127.0.0.1 ::1:
$this->f3->set('ADMIN_AUTHORIZED_IP', array_merge(["localhost", "127.0.0.1", "::1"],
explode(' ', $this->f3->get('ADMIN_AUTHORIZED_IP') . '')));
$this->f3->set('IS_ADMIN', in_array(@$_SERVER["REMOTE_ADDR"], $this->f3->get('ADMIN_AUTHORIZED_IP')));
实测(3.3 已演示拒绝态):追加 ADMIN_AUTHORIZED_IP=10.89.60.1 后面板打开,且面板授权名单行显示 localhost 127.0.0.1 ::1 10.89.60.1——合并逻辑的直接可视化。经宿主端口映射访问时来源 IP 是 Docker 网关而非 127.0.0.1,这是「本地 curl 能开、浏览器打不开」的根因;裸机 Apache 直连则无此问题。
⚠️ 注意:该键必须落在
[globals]段。实测把同样的行写到[signature]段下(文件尾新起一段),面板依旧被拒——Fat-Free 按段取键,$f3->get('ADMIN_AUTHORIZED_IP')只认[globals]下的同名键。排障实录见 Q5。
6.2 PDF_LOCAL_PATH:本地文件 API 根目录
设定后 /api/file/get 端点才工作(未设时一律 403)。三重路径校验(源码 Config::getApiLocalFilePath):拒绝含 .. 的路径、realpath 必须落在根目录内、文件必须存在;扩展名只放行 pdf/png/jpg/jpeg。四组实测:
# 未设 PDF_LOCAL_PATH
curl -s -o body.txt -w 'HTTP %{http_code}\n' 'http://localhost:8140/api/file/get?path=contract-test.pdf'
# 设定后:合法路径
curl -s -o ok.pdf -w 'HTTP %{http_code}\n' 'http://localhost:8140/api/file/get?path=probe.pdf'
# 设定后:穿越攻击
curl -s -o trav.txt -w 'HTTP %{http_code}\n' 'http://localhost:8140/api/file/get?path=../../etc/passwd'
# 设定后:不存在 / 非法扩展名
curl -s -o miss.txt -w 'HTTP %{http_code}\n' 'http://localhost:8140/api/file/get?path=nothere.pdf'
curl -s -o ext.txt -w 'HTTP %{http_code}\n' 'http://localhost:8140/api/file/get?path=local-sample.txt'
实测回显:
HTTP 403
HTTP 200
HTTP 403
HTTP 403
HTTP 403
未设时的 403 响应体(Fat-Free 默认错误页,节选):
<h1>Forbidden</h1>
<p>HTTP 403 (GET /api/file/get?path=contract-test.pdf)</p>
⚠️ 注意(重要实测发现):合法路径的 200 响应 Content-Length 为 0,且目标文件被截成 0 字节——实测
probe.pdf由 1061 字节变 0:-rw-r--r-- 1 www-data www-data 1061 Nov 2 00:25 /data/probe.pdf # 请求前 -rw-r--r-- 1 www-data www-data 0 Nov 2 06:42 /data/probe.pdf # 请求后根因是 v1.11.0 源码
app.php把GET /api/file/get注册了两次:ApiController->fileGet(读)之后又注册了ApiController->fileSave(写),后者遮蔽前者;fileSave把请求体原样写入目标文件,GET 无请求体即写空。带请求体时该端点表现为「写入本地文件」:实测以--data-binary @contract-test.pdf再发一次 GET,probe.pdf恢复为 1061 字节。结论:该端点的「读」能力在当前版本不可用,「写」可用但语义危险(路径即写入目标),配置PDF_LOCAL_PATH前务必确认调用方行为,详见 《Signature PDF 1.11.0 API 使用详解》 的逐请求实测。
6.3 METADATA_DEFAULT_FIELDS:元数据页预置字段
按 METADATA_DEFAULT_FIELDS[字段名].type="输入类型" 逐行声明,元数据编辑页会把它们渲染成默认表单字段(模板 metadata.html.php 输出 var defaultFields = <?php echo json_encode($METADATA_DEFAULT_FIELDS) ?>)。实测追加四行:
docker exec signaturepdf-1.11.0-web sh -c "printf 'METADATA_DEFAULT_FIELDS[title].type=\"text\"\nMETADATA_DEFAULT_FIELDS[author].type=\"text\"\nMETADATA_DEFAULT_FIELDS[creationDate].type=\"date\"\nMETADATA_DEFAULT_FIELDS[subject].type=\"email\"\n' >> /usr/local/signaturepdf/config/config.ini"
curl -s http://localhost:8140/metadata | grep -oE 'var defaultFields = [^;]+'
实测回显:
var defaultFields = {"title":{"type":"text"},"author":{"type":"text"},"creationDate":{"type":"date"},"subject":{"type":"email"}}
type 对应 HTML 输入类型(config.ini.example 注明 text/date/number/email 等),字段名即 PDF 信息字典键(Title/Author/CreationDate/Subject 等)。
6.4 REVERSE_PROXY_URL:改写不下沉时的前缀兜底
官方场景:前置反代无法把路径重写透传到应用时,在 config.ini 声明本站公网前缀,模板中所有 href/action/静态资源 URL 与 reroute 目标都会拼上它。实测设 REVERSE_PROXY_URL=http://127.0.0.1:8140 后签名页表单动作变为绝对地址:
curl -s http://localhost:8140/signature | grep -o 'action="http://127.0.0.1:8140/share"'
实测回显:
action="http://127.0.0.1:8140/share"
缺省为空串(Config.class.php 对不存在该键的情况 set('REVERSE_PROXY_URL','')),此时全部相对路径。子路径部署(如 https://host/sign/)优先在反代层做 rewrite,确实做不了才用该键。
6.5 NSS3_DIRECTORY / NSS3_PASSWORD / NSS3_NICK:数字签名证书
三键必须同时存在才启用数字签名路径(源码逐键 exists 判断后初始化 NSSCryptography):
NSS3_DIRECTORY=/path/to/nss3
NSS3_PASSWORD="my secret password"
NSS3_NICK="certificate nick"
配置后每次压印自动调 pdfsig 附加 PKCS#7 签名("Signed with SignaturePDF")。官方镜像缺件实测——容器内 command -v pdfsig certutil 均无输出(ABSENT),管理面板同样显示 CertUtil (Package libnss3-tools missing)、Pdfsig (Package poppler-utils missing):在该镜像里配好三键也不会生效,需派生镜像补装(FROM xgaia/signaturepdf:1.11.0 + RUN apt-get update && apt-get install -y poppler-utils libnss3-tools)。证书库生成用仓库自带 tools/create_nss_certs.sh(官方 installation.md 原文用法):
bash tools/create_nss_certs.sh NSS_DIR PASSWORD NICK URL
生成后 chown www-data NSS 目录,否则 Apache 用户读不到证书库。
七、[signature] retention:自定义共享保留期
共享 PDF 的保留期下拉默认 6 档(1 hour/1 day/1 week/1 month/6 months/1 year,config.ini.example 注释列明)。在 config.ini 新开 [signature] 段、按 retention[+N unit]="文案" 声明即可整体覆盖默认档位。实测追加:
[signature]
retention[+30 minutes]="for 30 minutes"
retention[+2 days]="for two days"
签名页共享表单的下拉随即只剩这两档(源码 MainController::signature 读 signature.retention 注入模板):
<select name='duration' form='form_sharing'>
<option value='+30 minutes'>for 30 minutes</option>
<option value='+2 days'>for two days</option>
</select>
保留期语义实测(发起共享选 +30 minutes):
- 响应
HTTP 302,Location 指向分享链接; - 存储目录旁出现
<hash>.expire(11 字节),文件内容就是保留期字符串:
+30 minutes
- 其 mtime = 发起时刻 + 30 分钟(实测发起于 05:12:28 UTC,mtime 显示
2026-11-02 05:42:28 +0000);追加签名会按当前档位续期; - 到期后由
GET /cron清理(部署篇第十章)。
右侧文案会过 gettext 翻译(example 注释 "Text on the right of the colon will be translated according to the .po files"),界面语言为法语时 "for 30 minutes" 自动译出。
八、生产配置模板
场景假设:协会/小团队内网接力签署站,单台 4C8G、50GB SSD、Ubuntu 26.04,前置 Nginx 反代已配好路径透传(无需 REVERSE_PROXY_URL),共享保留期收紧为 30 分钟与 2 天两档,管理面板仅放行运维跳板与 Docker 网关。
Compose 层(/opt/signaturepdf/docker-compose.yml 增量):
environment:
SERVERNAME: "pdf.example.org"
UPLOAD_MAX_FILESIZE: "48M"
POST_MAX_SIZE: "48M"
MAX_FILE_UPLOADS: "401"
PDF_STORAGE_PATH: "/data"
DEFAULT_LANGUAGE: "en_US.UTF-8"
PDF_STORAGE_ENCRYPTION: "true"
volumes:
- ./data:/data
- ./config.ini.tpl:/usr/local/signaturepdf/config/config.ini.tpl:ro
挂载的定制模板 config.ini.tpl(在官方 4 键基础上追加第 2 层键,重启不再丢):
[globals]
PDF_STORAGE_PATH=${PDF_STORAGE_PATH}
DISABLE_ORGANIZATION=${DISABLE_ORGANIZATION}
PDF_DEMO_LINK=${PDF_DEMO_LINK}
PDF_STORAGE_ENCRYPTION=${PDF_STORAGE_ENCRYPTION}
; 管理面板授权:跳板机 + Docker 网关
ADMIN_AUTHORIZED_IP=10.89.60.1 10.0.0.50
[signature]
retention[+30 minutes]="for 30 minutes"
retention[+2 days]="for two days"
要点核对(均可按本篇对应小节复测):PDF_DEMO_LINK 建议置 false 或换内网示例,避免用户浏览器被引向 raw.githubusercontent.com(5.5);加密开关需镜像含 gpg,官方镜像满足(5.7);ADMIN_AUTHORIZED_IP 务必留在 [globals] 段(6.1/Q5);不建议开 PDF_LOCAL_PATH——当前版本该端点读不可用、写有截断风险(6.2)。
九、常见问题
Q1:改好的 config.ini 一重启全没了?
设计如此:entrypoint.sh 每次启动都用 envsubst < config.ini.tpl > config.ini 重刷目标文件(3.4 实测 grep -c 归 0)。持久化只有两条正路——挂载定制模板(第八章)或派生镜像 RUN sed -i '$a ADMIN_AUTHORIZED_IP=...' /usr/local/signaturepdf/config/config.ini.tpl。直接把 config.ini bind mount 进去也会被同一命令覆写,无效。
Q2:/administration 返回 200 却打不开面板?
200 + 纯文本 You (x.x.x.x) are not allowed... 是 die() 的拒绝响应(3.3),把来源 IP 加进 ADMIN_AUTHORIZED_IP 即可;经 Docker 端口映射访问时来源是网关地址(本环境 10.89.60.1),不是 127.0.0.1。
Q3:DISABLE_ORGANIZATION=true 后整理页还能直接访问?
是。该开关只让首页 302 到 /signature,/organization 路由未封(5.4 实测 200)。要硬关在反代上屏蔽路径。
Q4:配了 PDF_LOCAL_PATH 后,/api/file/get 下载回来是空文件,服务器上的文件还被清空了?
v1.11.0 路由双注册缺陷:fileSave 遮蔽 fileGet,GET 空请求体即把目标文件写成 0 字节(6.2 实测)。在修复前不要依赖该端点读取文件;需要程序化取回共享 PDF 用 /api/share/get/<hash>/<symmkey>(API 篇实测可用)。
Q5:retention 或 ADMIN_AUTHORIZED_IP 写了没反应?
先查段归属:ADMIN_AUTHORIZED_IP 等键必须在 [globals],retention[...] 必须在 [signature]。实测把 ADMIN_AUTHORIZED_IP 写进 [signature] 段后面板依旧被拒(6.1 踩坑实录);写对段后无需重启、下一请求即生效(3.4)。
Q6:NSS3 三键配了,签名 PDF 里没有数字签名?
官方镜像未装 pdfsig/certutil(6.5 ABSENT 实测),需派生镜像补 poppler-utils libnss3-tools;再核对 NSS 目录属主为 www-data、三键值完全一致(缺一键即整体不启用)。
Q7:PDF_STORAGE_ENCRYPTION=true 但共享页没有加密选项? 镜像缺 GPG 时源码强制回落 false(5.7)。官方镜像自带 gpg 2.4.7 不会触发;自构建精简镜像注意保留。
十、参考链接
- 官方仓库:https://github.com/24eme/signaturepdf (installation.md 配置表、config/config.ini.example,2026-11-02 实查)
- 源码实查文件:
app.php(路由双注册)、lib/Config.class.php(键加载/授权合并/演示链接缺省)、lib/MainController.class.php(die() 拒绝、retention 注入、noSharingMode)、entrypoint.sh(envsubst 渲染链) - 本专栏姊妹篇:《Signature PDF 1.11.0 介绍与选型指南》、《Signature PDF 1.11.0 Docker Compose 部署指南》、《Signature PDF 1.11.0 API 使用详解》