Stirling-PDF 自建 PDF 工具箱实战:合并压缩转换 OCR 与加解密,中文乱码与上传 413 排查全流程

个人站长为什么离不开 PDF 处理

做一个内容站或工具站,你迟早会遇到一堆和 PDF 打交道的事:给访客提供一份下载资料,需要合并、压缩、加水印;把合同或者发票打上页码归档;把扫描件里的文字提取出来;把一堆图片拼成一个 PDF;给文档加密设个打开密码;把 PDF 拆页或者旋转方向不对的页面转正。

这些操作如果去找在线网站,问题有三个:一是隐私——你的合同、发票、身份材料全都上传到了别人的服务器上;二是有文件大小和次数限制,稍微大一点就要付费;三是那些站点广告满天飞,还经常挂掉。装个桌面版 Adobe Acrobat 又是几百上千块,对只是偶尔用一下的个人站长来说不值。

Stirling-PDF 就是为解决这个问题而生的:一个完全开源的、可以自托管的 PDF 工具箱,把所有常用的 PDF 操作做成网页界面,跑在你自己的服务器上。它底层用 Java + PDFBox 和 LibreOffice 做处理,功能覆盖合并、拆分、压缩、转换、OCR、签名、水印、加密等几十项。本文把它部署起来,并讲清楚几个关键配置和容易踩的坑。

先看它能干什么:先确认它合不合适

Stirling-PDF 的功能可以分成几大类,先扫一眼,确认覆盖你的需求:

  • 页面操作:合并、拆分、提取页面、删除页面、旋转、调整页面顺序、裁剪、多页合一。
  • 格式转换:图片转 PDF、PDF 转图片、Office 文档(Word/Excel/PPT)转 PDF、HTML 转 PDF、PDF 转文本、Markdown 转 PDF。
  • 优化:压缩减小体积、修复损坏的 PDF、去除元数据。
  • 安全:加密加密码、移除密码、给文件打水印、数字签名验签、涂黑敏感信息(redact)。
  • 识别与处理:对扫描件做 OCR 提取文字、自动识别并纠正歪斜的扫描页。

它跟前面我们写过的 Paperless-ngx 定位不同:Paperless-ngx 是一个文档管理系统,重点是「归档 + 全文检索 + 自动分类」,你上传的文档它替你长期管着;Stirling-PDF 是一个手动的工具箱,你上传一个文件、做一步处理、下载回来,重点是「处理」而不是「管理」。两个可以配合用。

Docker 部署:一个命令的事

Stirling-PDF 官方镜像叫 stirlingtools/stirling-pdf。最简部署:

mkdir -p /opt/stirling/{configs,trainingData,logs,extraConfigs}
cd /opt/stirling

写 docker-compose.yml:

services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest
    container_name: stirling-pdf
    environment:
      - DOCKER_ENABLE_SECURITY=false
      - LANGS=zh_CN
      - TZ=Asia/Shanghai
    volumes:
      - ./configs:/configs
      - ./logs:/logs
      - ./extraConfigs:/configs/custom
    ports:
      - "127.0.0.1:8080:8080"
    restart: unless-stopped

几个配置点的含义:

  • LANGS=zh_CN 是为了启用中文界面。默认镜像为了控制体积只带英文,指定这个环境变量后镜像会加载中文语言包。
  • DOCKER_ENABLE_SECURITY=false 表示先不开登录认证。因为端口已经绑在 127.0.0.1 上,外人访问不到,认证交给 Nginx 那一层。如果你想在容器内就启用登录,把它改成 true 并配置用户名密码。
  • 挂载 /configs 是为了让配置持久化,重启不丢。

启动:

docker compose up -d
docker compose logs -f stirling-pdf

第一次启动会慢一些,因为它要初始化 Java 环境和一些依赖,日志里出现 Started Application 之类才算就绪。之后浏览器访问 http://127.0.0.1:8080 就能看到界面。用 SSH 隧道临时看一眼:

ssh -L 8080:127.0.0.1:8080 root@你的服务器IP

Office 转 PDF 与 OCR:两个最容易翻车的功能

Stirling-PDF 大部分功能开箱即用,但有两个功能对依赖特别敏感,必须先配好,否则要么报错要么出乱码。

第一,Office 文档转 PDF。 把 Word/Excel/PPT 转成 PDF 靠的是 LibreOffice。官方镜像里已经内置了它,但中文字体是个常见的坑——如果容器里没有安装中文字体,转换出来的 PDF 里中文会变成一排方块或者问号,而英文正常,很容易误判成「功能坏了」。

解决办法是在启动时安装字体,或者用一个挂了字体目录的镜像。最省事的做法是建一个自定义 Dockerfile:

FROM stirlingtools/stirling-pdf:latest
USER root
RUN apt-get update && apt-get install -y fonts-noto-cjk && rm -rf /var/lib/apt/lists/*

然后 docker build -t stirling-pdf-cn .,compose 里的 image 改成 stirling-pdf-cn。这样中文转换就不会出方块了。

第二,扫描件 OCR。 OCR 依赖 Tesseract,中文识别需要单独安装 tesseract-ocr-chi-sim 语言包。默认镜像往往只带英文。如果对一张中文扫描件做 OCR,出来的结果全是英文垃圾字符,就是这个原因。同样用上面的自定义 Dockerfile 加上 tesseract-ocr-chi-sim 即可。注意 Tesseract 的中文包命名是 chi_sim(简体)和 chi_tra(繁体),不是 ISO 语言码 zh-CN,这是很多人第一次配置时找不到包的原因。

Nginx 反向代理:别忘了放大上传体积

PDF 文件通常都不小,几十兆很常见,扫描件合集上百兆也有。Nginx 默认 client_max_body_size 只有 1M,超过就直接返回 413,页面提示「文件太大」,你会以为是 Stirling-PDF 的问题,其实是 Nginx 拦在了前面。

server {
    listen 443 ssl http2;
    server_name pdf.example.com;

    ssl_certificate     /etc/letsencrypt/live/pdf.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pdf.example.com/privkey.pem;

    # 放大上传体积,建议 200M 起
    client_max_body_size 200M;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 处理大文件时可能耗时较长,拉长超时
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}

两处关键:client_max_body_size 200M 解决上传被拒;proxy_read_timeout 300s 解决大文件处理时连接被 Nginx 提前掐断。OCR 和 Office 转换都是耗时操作,几十秒很正常,超时太短会让你以为卡死了。

加一层访问控制:别把它直接对着公网

Stirling-PDF 能处理你的合同、发票、身份材料,绝不能让任何人访问到。除了端口绑回环,对外那一层要么用 HTTP Basic 认证,要么用更强的认证网关。

最轻量的做法是用 htpasswd:

htpasswd -c /etc/nginx/.htpasswd myuser

然后在 server 块里加:

location / {
    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
    proxy_pass http://127.0.0.1:8080;
    # ... 其余反代头
}

如果站点本身已经有认证网关(比如 Authelia),用 forward auth 更优雅,一次登录全站通行。无论哪种方式,原则都是:这类「能碰你敏感文件」的服务永远要有认证,而且优先考虑干脆只在内网/VPN 里访问,不暴露公网。

把它做成一个命令行的 PDF 处理入口

Stirling-PDF 除了网页界面,也暴露了 REST API,可以写进脚本里批量处理。比如批量压缩一个目录下的 PDF:

#!/bin/bash
# 需要先在网页界面生成一个 API Key,或使用认证
API=https://pdf.example.com
KEY=你的APIKey
for f in /data/pdfs/*.pdf; do
    curl -s -X POST "$API/api/v1/misc/compress-pdf" \
      -H "X-API-KEY: $KEY" \
      -F "fileInput=@$f" \
      -F "optimizeLevel=2" \
      -o "${f%.pdf}_compressed.pdf"
done

API 路径会随版本变化,具体以你部署版本的 /swagger-ui(自带接口文档)为准。这个能力很适合把它接进你的内容流水线——比如访客上传照片生成 PDF 资料、或者定时把站点的某个报表转成 PDF 分发。

资源占用与性能取舍

Stirling-PDF 是 Java 应用,对内存有一定要求。Java 堆默认可能吃几百 MB 到 1G,如果你的服务器内存只有 1G,会和 MySQL、PHP 抢内存。可以在 compose 里限制:

    deploy:
      resources:
        limits:
          memory: 1g

另外注意,OCR 和 Office 转 PDF 是 CPU 密集操作,并发几个人同时用会把 CPU 打满。个人站一般不会有高并发,但如果对公网开放,最好限一下并发数,避免被人当成免费的 PDF 处理服务刷爆你的机器。可以在 Nginx 里加 limit_req 对上传接口做限速。

备份与升级:升级前一定要做的事

Stirling-PDF 本身是无状态的——它不像数据库那样存着你的业务数据,处理的文件都是「即用即走」,处理完就删。所以它没有「数据备份」的强需求,真正需要备份的只有两样:/configs 里的配置文件(比如你设的认证、界面偏好、API Key),以及你自定义的 Dockerfile 和字体安装脚本。

把这两样东西放进 Git 或者用 restic/rsync 定期同步到异地,就足够应付绝大多数意外了。真正要小心的是升级:Stirling-PDF 迭代很快,新版本偶尔会改动 API 路径、界面结构甚至配置项名称。升级前先把 compose 里的镜像 tag 从 latest 固定成一个具体版本号(比如 0.x.x),并记录当前能正常工作的版本。这样一旦新版有问题,改回旧 tag 就能立刻回滚,不用去猜「到底哪个版本是好的」。

升级动作本身就是:

cd /opt/stirling
docker compose pull
docker compose up -d

因为用了固定 tag,pull 只会在你主动改了 tag 之后才拉到新版本,日常不会因为官方发了新版就意外变动,这对生产环境很重要。

六个常见坑

  1. 上传大文件报 413:99% 是 Nginx client_max_body_size 默认 1M 太小,不是 Stirling-PDF 的问题。
  2. Office 转出来的中文是方块:容器里没装中文字体(fonts-noto-cjk),英文正常中文乱码是典型特征。
  3. OCR 中文识别出英文垃圾:没装 tesseract-ocr-chi-sim 语言包,且要注意语言码不是 zh-CN。
  4. 处理大文件时页面一直转圈最后失败:Nginx 的 proxy_read_timeout 太短,OCR/转换耗时几十秒被提前切断。
  5. 端口暴露到公网且没认证:等于把「处理你敏感文件」的工具交给全世界,务必绑回环 + 加认证。
  6. 容器重启后配置丢失:忘了挂载 /configs 卷,或者自定义的字体/Dockerfile 没固化进镜像,重建后又变回默认状态。

小结

Stirling-PDF 补上了自托管工具链里一块很实用的拼图:把日常那些零散的 PDF 操作从「上传到陌生网站」变成「跑在自己机器上」。部署不复杂——Docker 起容器、绑回环、Nginx 反代加认证、按需装中文字体和中英文 OCR 包就能正常干活。

几个要点再强调一次:client_max_body_size 一定要放大,中文场景要装 fonts-noto-cjk 和 tesseract-ocr-chi-sim,反代超时拉到 300 秒,访问控制绝不能省。把这几点做到位,你会得到一个既省心又保隐私的私人 PDF 工作站。

Last modification:October 16th, 2026 at 12:25 pm

Leave a Comment