Files

631 lines
28 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 使用 Docker / Podman 部署
在生产环境中自托管 BentoPDF 的最简单方式。
> [!IMPORTANT]
> **Office 文件转换所需的响应头**
>
> 基于 LibreOffice 的工具(Word、Excel、PowerPoint 转换)需要以下 HTTP 响应头来支持 `SharedArrayBuffer`:
>
> - `Cross-Origin-Opener-Policy: same-origin`
> - `Cross-Origin-Embedder-Policy: require-corp`
>
> 页面还必须通过安全上下文提供。`http://localhost` 可用于本地测试,但 `http://192.168.x.x` 等局域网 IP 通常不符合要求,因此即使响应头存在,通过纯 HTTP 进行 Office 转换也会失败。
>
> 官方容器镜像已包含这些响应头。如果使用反向代理(Traefik、Caddy 等),请确保保留或添加这些响应头,并对非环回访问使用 HTTPS。
> [!TIP]
> **Podman 用户:** 将 `docker` 替换为 `podman`、将 `docker-compose` 替换为 `podman-compose`,所有 `docker` 命令都同样适用于 Podman。
## 快速开始
> [!TIP]
> BentoPDF 提供两种构建版本:
>
> - **自托管版本**:`ghcr.io/alam00000/bentopdf-simple:latest`。包含所有 PDF 工具,但**不含**营销页面元素(没有首页横幅、FAQ、用户评价和页脚)。适用于内部/团队/组织部署。它**不是**功能精简的 "lite" 版本。
> - **商业版本**:`ghcr.io/alam00000/bentopdf:latest`。完整的营销站点,由 bentopdf.com 自身使用,也供持有商业许可、运行面向公众部署的用户使用。
>
> 如果拿不准,请拉取自托管版本。
```bash
# Docker
docker run -d \
--name bentopdf \
-p 3000:8080 \
--restart unless-stopped \
ghcr.io/alam00000/bentopdf-simple:latest
# Podman
podman run -d \
--name bentopdf \
-p 3000:8080 \
ghcr.io/alam00000/bentopdf-simple:latest
```
## Docker Compose / Podman Compose
创建 `docker-compose.yml`:
```yaml
services:
bentopdf:
image: ghcr.io/alam00000/bentopdf-simple:latest
container_name: bentopdf
ports:
- '3000:8080'
restart: unless-stopped
healthcheck:
test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:8080']
interval: 30s
timeout: 10s
retries: 3
```
运行:
```bash
# Docker Compose
docker compose up -d
# Podman Compose
podman-compose up -d
```
## 构建您自己的镜像
```dockerfile
# Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
ENV HUSKY=0
COPY package*.json ./
COPY vendor ./vendor
RUN npm ci
COPY . .
RUN npm run build
FROM nginxinc/nginx-unprivileged:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY --from=builder /app/security-headers.conf /etc/nginx/security-headers.conf
COPY --from=builder /app/security-headers-docs.conf /etc/nginx/security-headers-docs.conf
COPY nginx.conf /etc/nginx/nginx.conf
RUN mkdir -p /etc/nginx/tmp
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]
```
构建并运行:
```bash
docker build -t bentopdf:custom .
docker run -d -p 3000:8080 bentopdf:custom
```
## 环境变量
| 变量 | 说明 | 默认值 |
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| `SIMPLE_MODE` | 构建自托管变体(隐藏 bentopdf.com 的营销页面元素:首页横幅、FAQ、用户评价、页脚)。所有 PDF 工具均保留。 | `false` |
| `BASE_URL` | 部署到子目录 | `/` |
| `VITE_WASM_PYMUPDF_URL` | PyMuPDF WASM 模块 URL | `https://cdn.jsdelivr.net/npm/@bentopdf/[email protected]/` |
| `VITE_WASM_GS_URL` | Ghostscript WASM 模块 URL | `https://cdn.jsdelivr.net/npm/@bentopdf/[email protected]/assets/` |
| `VITE_WASM_CPDF_URL` | CoherentPDF WASM 模块 URL | `https://cdn.jsdelivr.net/npm/[email protected]/dist/` |
| `VITE_TESSERACT_WORKER_URL` | OCR worker 脚本 URL | _(空;使用 Tesseract.js 默认 CDN)_ |
| `VITE_TESSERACT_CORE_URL` | OCR 核心运行时目录 | _(空;使用 Tesseract.js 默认 CDN)_ |
| `VITE_TESSERACT_LANG_URL` | OCR traineddata 目录 | _(空;使用 Tesseract.js 默认 CDN)_ |
| `VITE_TESSERACT_AVAILABLE_LANGUAGES` | 在界面中提供的 OCR 语言,以逗号分隔 | _(空;显示完整列表)_ |
| `VITE_OCR_FONT_BASE_URL` | OCR 文本层字体目录 | _(空;使用远程 Noto 字体 URL)_ |
| `VITE_DEFAULT_LANGUAGE` | 默认界面语言 | `en` |
| `VITE_BRAND_NAME` | 自定义品牌名称 | `BentoPDF` |
| `VITE_BRAND_LOGO` | 相对于 `public/` 的 Logo 路径 | `images/favicon-no-bg.svg` |
| `VITE_FOOTER_TEXT` | 自定义页脚/版权文本 | `© 2026 BentoPDF. All rights reserved.` |
| `DISABLE_TOOLS` | 要隐藏的工具 ID,以逗号分隔 | _(空;启用所有工具)_ |
| `DISABLE_GITHUB_STARS` | 页面加载时跳过获取 GitHub star 数量,并从 CSP 中移除 `api.github.com`。Simple Mode 构建始终会跳过。 | `false` |
| `SITE_URL` | 写入 canonical、hreflang 和站点地图链接的公开 URL。除非您希望搜索引擎将您的部署视为独立站点,否则请保持默认值。 | `https://www.bentopdf.com` |
| `ALLOW_INDEXING` | 使用自定义 `SITE_URL` 时,每个页面都会被标记为 `noindex`,以免您的副本在搜索结果中与 bentopdf.com 竞争。设为 `true` 可允许搜索引擎索引。 | `false` |
| `COMPRESSION_MODE` | 要保存的预压缩副本:`o` 不保存,`g` `.gz`(由镜像内的 nginx 提供),`b` `.br`,`all` 两者都保存。镜像内的 nginx 无法提供 `.br`。 | `o` |
WASM 模块 URL 已预先配置了 CDN 默认值,所有高级功能开箱即用。对于离线隔离或自托管部署,请覆盖这些值。
### 搜索引擎
默认情况下,每个页面都会让搜索引擎将 bentopdf.com 视为原始来源,因此您的部署不会作为重复内容出现。对于私有或内部实例,您无需做任何更改。
- **让您的实例完全不出现在搜索结果中:** 使用 `-e ROBOTS_NOINDEX=true` 运行容器。这只需要重启,无需重新构建。
- **让您的实例在搜索结果中成为独立站点:** 使用 `--build-arg SITE_URL=https://your-domain.example --build-arg ALLOW_INDEXING=true` 构建。如果没有 `ALLOW_INDEXING=true`,自定义的 `SITE_URL` 会将每个页面标记为 `noindex`。
### Content-Security-Policy
nginx 镜像自带强制执行的 `Content-Security-Policy` 响应头。CSP 的 `script-src`、`connect-src` 和 `font-src` 指令会在**构建时**根据上述 `VITE_*` URL 变量生成,您通过 `--build-arg` 传入的任何主机都会自动加入策略。
因此:
- 如果在构建时覆盖 `VITE_CORS_PROXY_URL` 或 `VITE_WASM_*_URL`,CSP 会自动允许这些来源,无需额外配置。
- 对于 `cdn.jsdelivr.net` 上的 URL,`script-src` 只允许精确到版本的包文件夹,例如 `https://cdn.jsdelivr.net/npm/@bentopdf/[email protected]/`,而不是整个 CDN。jsDelivr 提供任何公开的 npm 包或 GitHub 仓库,允许整个主机会让其中任何内容都能在您的实例上运行。其他主机上的 URL 则按来源允许。
- 如果您在*运行时*通过应用内的高级设置页面配置自定义 WASM URL,这些来源**不在** CSP 中,浏览器会阻止对它们的请求。对于 `cdn.jsdelivr.net` 上同一个包的不同版本也是如此,因为只允许构建时设置的版本。运行时配置仅用于试验;要永久使用自定义 URL,请设置对应的 `VITE_*` 构建参数。
- 覆盖全部三个 `VITE_WASM_*_URL` 值的离线隔离部署,也会从 CSP 中移除这些 `cdn.jsdelivr.net` 包文件夹(每个默认值都会被替换,而不是追加)。`cdn.jsdelivr.net` 上的 Tesseract OCR 默认值会保留在策略中,直到您同时设置三个 `VITE_TESSERACT_*` 值。同样,设置 `VITE_CORS_PROXY_URL` 会替换公共的 `bentopdf-cors-proxy.bentopdf.workers.dev` 默认值。
CSP 的 `script-src` 中包含 `'unsafe-eval'`,因为 LibreOffice WASM 运行时(用于 Word/Excel/PowerPoint 转换工具)和 wasm-vips 图像库(用于 PDF 转 TIFF)会在内部动态编译调度代码(通过 `new Function()`)。移除它会导致这些工具无法使用。如果您以 `SIMPLE_MODE`(不含 LibreOffice)构建,且不需要 PDF 转 TIFF,可以手动编辑生成的 `security-headers.conf` 去掉 `'unsafe-eval'`,以获得更严格的策略。
对于 OCR,将 `VITE_TESSERACT_*` 变量留空即可使用默认的在线资源,或者三个一起设置以用于自托管/离线 OCR。部分覆盖会被拒绝,因为 worker、核心运行时和 traineddata 目录必须相互匹配。要完全离线输出可搜索 PDF,还需设置 `VITE_OCR_FONT_BASE_URL`,让 OCR 文本层字体从您的内部服务器加载,而不是公共的 Noto 字体 URL。
`VITE_DEFAULT_LANGUAGE` 设置首次访问者的界面语言。支持的值:`en`、`ar`、`be`、`fr`、`de`、`es`、`zh`、`zh-TW`、`vi`、`tr`、`id`、`it`、`pt`、`nl`、`da`。用户仍可切换语言,这只会更改默认值。
示例:
```bash
# Build with French as the default language
docker build --build-arg VITE_DEFAULT_LANGUAGE=fr -t bentopdf .
docker run -d -p 3000:8080 bentopdf
```
### 自定义品牌
将默认的 BentoPDF 标志、名称和页脚文本替换为您自己的。将您的 Logo 文件放入 `public/` 文件夹(或使用现有图片),然后在构建时传入品牌变量:
```bash
docker build \
--build-arg VITE_BRAND_NAME="AcmePDF" \
--build-arg VITE_BRAND_LOGO="images/acme-logo.svg" \
--build-arg VITE_FOOTER_TEXT="© 2026 Acme Corp. Internal use only." \
-t acmepdf .
```
品牌定制在完整模式和 Simple Mode 下都可使用,并且可以与所有其他构建时选项组合。
### 禁用特定工具
出于合规或安全要求,可以在界面中隐藏工具。被禁用的工具会从主页、搜索结果、键盘快捷键和工作流构建器中移除。直接通过 URL 访问会显示"工具不可用"页面。
工具 ID 是去掉 `.html` 的页面 URL。例如,如果工具位于 `bentopdf.com/edit-pdf.html`,则 ID 为 `edit-pdf`。
#### 查找工具 ID
最简单的方法:在 BentoPDF 中打开任意工具并查看 URL。路径的最后一部分(去掉 `.html`)就是工具 ID。
<details>
<summary>完整的工具 ID 列表</summary>
**编辑与批注:** `edit-pdf`, `bookmark`, `table-of-contents`, `page-numbers`, `add-page-labels`, `bates-numbering`, `add-watermark`, `header-footer`, `invert-colors`, `scanner-effect`, `adjust-colors`, `background-color`, `text-color`, `sign-pdf`, `add-stamps`, `remove-annotations`, `crop-pdf`, `form-filler`, `form-creator`, `remove-blank-pages`
**转换为 PDF:** `image-to-pdf`, `jpg-to-pdf`, `png-to-pdf`, `webp-to-pdf`, `svg-to-pdf`, `bmp-to-pdf`, `heic-to-pdf`, `tiff-to-pdf`, `txt-to-pdf`, `markdown-to-pdf`, `json-to-pdf`, `csv-to-pdf`, `rtf-to-pdf`, `odt-to-pdf`, `word-to-pdf`, `excel-to-pdf`, `powerpoint-to-pdf`, `xps-to-pdf`, `mobi-to-pdf`, `epub-to-pdf`, `fb2-to-pdf`, `cbz-to-pdf`, `wpd-to-pdf`, `wps-to-pdf`, `xml-to-pdf`, `pages-to-pdf`, `odg-to-pdf`, `ods-to-pdf`, `odp-to-pdf`, `pub-to-pdf`, `vsd-to-pdf`, `psd-to-pdf`, `email-to-pdf`
**从 PDF 转换:** `pdf-to-jpg`, `pdf-to-png`, `pdf-to-webp`, `pdf-to-bmp`, `pdf-to-tiff`, `pdf-to-cbz`, `pdf-to-svg`, `pdf-to-csv`, `pdf-to-excel`, `pdf-to-greyscale`, `pdf-to-json`, `pdf-to-docx`, `extract-images`, `pdf-to-markdown`, `prepare-pdf-for-ai`, `pdf-to-text`
**整理与管理:** `ocr-pdf`, `merge-pdf`, `alternate-merge`, `organize-pdf`, `add-attachments`, `extract-attachments`, `edit-attachments`, `pdf-multi-tool`, `pdf-layers`, `extract-tables`, `split-pdf`, `divide-pages`, `extract-pages`, `delete-pages`, `add-blank-page`, `reverse-pages`, `rotate-pdf`, `rotate-custom`, `n-up-pdf`, `pdf-booklet`, `combine-single-page`, `view-metadata`, `edit-metadata`, `pdf-to-zip`, `compare-pdfs`, `posterize-pdf`, `page-dimensions`
**优化与修复:** `compress-pdf`, `pdf-to-pdfa`, `fix-page-size`, `linearize-pdf`, `remove-restrictions`, `repair-pdf`, `rasterize-pdf`, `deskew-pdf`, `font-to-outline`
**安全:** `encrypt-pdf`, `sanitize-pdf`, `decrypt-pdf`, `flatten-pdf`, `remove-metadata`, `change-permissions`, `digital-sign-pdf`, `validate-signature-pdf`, `timestamp-pdf`
</details>
#### 方式 1:构建时(Docker 构建参数)
```bash
docker build \
--build-arg DISABLE_TOOLS="edit-pdf,sign-pdf,encrypt-pdf" \
-t bentopdf .
```
这会将禁用列表写入 JavaScript 包中。更改时需要重新构建。
#### 方式 2:运行时(config.json)
将 `config.json` 文件挂载到提供服务的目录中,无需重新构建:
```json
{
"disabledTools": ["edit-pdf", "sign-pdf", "encrypt-pdf"]
}
```
```bash
docker run -d \
-p 3000:8080 \
-v ./config.json:/usr/share/nginx/html/config.json:ro \
ghcr.io/alam00000/bentopdf-simple:latest
```
或者使用 Docker Compose:
```yaml
services:
bentopdf:
image: ghcr.io/alam00000/bentopdf-simple:latest
ports:
- '3000:8080'
volumes:
- ./config.json:/usr/share/nginx/html/config.json:ro
```
两种方式可以同时使用,列表会被合并。只要工具出现在任一列表中,就会被禁用。
#### 禁用编辑器功能
您还可以禁用 PDF 编辑器中的特定功能(例如涂黑、批注、表单),而无需禁用整个编辑器工具。在 `config.json` 中添加 `editorDisabledCategories`:
```json
{
"editorDisabledCategories": ["redaction", "annotation-stamp"]
}
```
<details>
<summary>完整的编辑器类别列表</summary>
**缩放:** `zoom`, `zoom-in`, `zoom-out`, `zoom-fit-page`, `zoom-fit-width`, `zoom-marquee`, `zoom-level`
**批注:** `annotation`, `annotation-markup`, `annotation-highlight`, `annotation-underline`, `annotation-strikeout`, `annotation-squiggly`, `annotation-ink`, `annotation-text`, `annotation-stamp`
**形状:** `annotation-shape`, `annotation-rectangle`, `annotation-circle`, `annotation-line`, `annotation-arrow`, `annotation-polygon`, `annotation-polyline`
**测量:** `annotation-measurement`, `mode-measure`, `annotation-distance`, `annotation-perimeter`, `annotation-area`
**表单:** `form`, `form-textfield`, `form-checkbox`, `form-radio`, `form-select`, `form-listbox`, `form-fill-mode`
**涂黑:** `redaction`, `redaction-area`, `redaction-text`, `redaction-apply`, `redaction-clear`
**文档:** `document`, `document-open`, `document-close`, `document-print`, `document-capture`, `document-export`, `document-fullscreen`, `document-protect`
**页面:** `page`, `spread`, `rotate`, `scroll`, `navigation`
**面板:** `panel`, `panel-sidebar`, `panel-search`, `panel-comment`
**工具:** `tools`, `pan`, `pointer`, `capture`, `organize`
**选择:** `selection`, `selection-copy`
**历史记录:** `history`, `history-undo`, `history-redo`
</details>
类别是分层级的:禁用父级(例如 `annotation`)会同时禁用它的所有子级。
### 禁用 GitHub Star 计数器
导航栏会显示实时的 GitHub star 数量,页面加载时从 `api.github.com` 获取。这是唯一一个不用于 PDF 功能的外部请求。可以在构建时禁用它,从包中移除获取代码,并从 Content-Security-Policy 中移除 `api.github.com`:
```bash
docker build --build-arg DISABLE_GITHUB_STARS=true -t bentopdf .
```
Simple Mode 构建(`bentopdf-simple`)始终会跳过 star 计数器,此参数只在商业版本或自定义的完整构建中需要。
### 自定义 WASM URL(离线隔离 / 自托管)
> [!IMPORTANT]
> WASM URL 会在**构建时**写入 JavaScript。WASM 文件由**用户的浏览器**在运行时下载,Docker 在构建期间不会下载它们。对于离线隔离网络,您必须将 WASM 文件托管在浏览器可以访问的内部服务器上。
**完整的离线隔离工作流程:**
```bash
# 1. On a machine WITH internet — download WASM packages
bash scripts/prepare-airgap.sh --list-ocr-languages
bash scripts/prepare-airgap.sh --search-ocr-language german
# 2. Download WASM/OCR packages
npm pack @bentopdf/[email protected]
npm pack @bentopdf/gs-wasm
npm pack coherentpdf
npm pack [email protected]
npm pack [email protected]
mkdir -p tesseract-langdata
curl -fsSL https://cdn.jsdelivr.net/npm/@tesseract.js-data/eng/4.0.0_best_int/eng.traineddata.gz -o tesseract-langdata/eng.traineddata.gz
mkdir -p ocr-fonts
curl -fsSL https://raw.githack.com/googlefonts/noto-fonts/main/hinted/ttf/NotoSans/NotoSans-Regular.ttf -o ocr-fonts/NotoSans-Regular.ttf
# 3. Build the image with your internal server URLs
docker build \
--build-arg VITE_WASM_PYMUPDF_URL=https://internal-server.example.com/wasm/pymupdf/ \
--build-arg VITE_WASM_GS_URL=https://internal-server.example.com/wasm/gs/ \
--build-arg VITE_WASM_CPDF_URL=https://internal-server.example.com/wasm/cpdf/ \
--build-arg VITE_TESSERACT_WORKER_URL=https://internal-server.example.com/wasm/ocr/worker.min.js \
--build-arg VITE_TESSERACT_CORE_URL=https://internal-server.example.com/wasm/ocr/core \
--build-arg VITE_TESSERACT_LANG_URL=https://internal-server.example.com/wasm/ocr/lang-data \
--build-arg VITE_TESSERACT_AVAILABLE_LANGUAGES=eng,deu \
--build-arg VITE_OCR_FONT_BASE_URL=https://internal-server.example.com/wasm/ocr/fonts \
-t bentopdf .
# 4. Export the image
docker save bentopdf -o bentopdf.tar
# 5. Transfer bentopdf.tar + the .tgz packages + tesseract-langdata/ + ocr-fonts/ into the air-gapped network
# 6. Inside the air-gapped network — load and run
docker load -i bentopdf.tar
# Extract WASM packages to your internal web server
mkdir -p /var/www/wasm/pymupdf /var/www/wasm/gs /var/www/wasm/cpdf /var/www/wasm/ocr/core /var/www/wasm/ocr/lang-data /var/www/wasm/ocr/fonts
tar xzf bentopdf-pymupdf-wasm-0.11.14.tgz -C /var/www/wasm/pymupdf --strip-components=1
tar xzf bentopdf-gs-wasm-*.tgz -C /var/www/wasm/gs --strip-components=1
tar xzf coherentpdf-*.tgz -C /var/www/wasm/cpdf --strip-components=1
TEMP_TESS=$(mktemp -d)
tar xzf tesseract.js-7.0.0.tgz -C "$TEMP_TESS"
cp "$TEMP_TESS/package/dist/worker.min.js" /var/www/wasm/ocr/worker.min.js
rm -rf "$TEMP_TESS"
tar xzf tesseract.js-core-7.0.0.tgz -C /var/www/wasm/ocr/core --strip-components=1
cp ./tesseract-langdata/*.traineddata.gz /var/www/wasm/ocr/lang-data/
cp ./ocr-fonts/* /var/www/wasm/ocr/fonts/
# Run BentoPDF
docker run -d -p 3000:8080 --restart unless-stopped bentopdf
```
对于 `--ocr-languages`,请使用 `bash scripts/prepare-airgap.sh --list-ocr-languages` 打印出的代码,或使用 `bash scripts/prepare-airgap.sh --search-ocr-language <term>` 按名称搜索。当您使用受限的 OCR 子集构建时,请将相同的代码传给 `VITE_TESSERACT_AVAILABLE_LANGUAGES`,这样应用只会显示已打包的语言。要获得完整的离线 OCR 输出,还需托管随附的 `ocr-fonts/` 目录,并将 `VITE_OCR_FONT_BASE_URL` 指向它。
将变量设为空字符串即可禁用对应模块(用户必须通过高级设置手动配置)。
## 自定义端口
默认情况下,BentoPDF 在容器内监听 `8080` 端口。要更改此设置,请在运行时设置 `PORT` 环境变量:
```bash
docker run -p 3000:9090 -e PORT=9090 ghcr.io/alam00000/bentopdf-simple:latest
```
| 变量 | 说明 | 默认值 |
| ------ | --------------------- | ------ |
| `PORT` | 容器内 Nginx 监听端口 | `8080` |
标准 Dockerfile 和 nonroot Dockerfile 都支持此设置。
## 自定义用户 ID(PUID/PGID)
对于需要以特定非 root 用户运行的环境(NAS 设备、带安全上下文的 Kubernetes、组织策略),BentoPDF 提供了一个单独的 Dockerfile,支持 LSIO 风格的 PUID/PGID。
### 构建并运行
```bash
# Build the non-root image
docker build -f Dockerfile.nonroot -t bentopdf-nonroot .
# Run with custom UID/GID
docker run -d \
--name bentopdf \
-p 3000:8080 \
-e PUID=1000 \
-e PGID=1000 \
--restart unless-stopped \
bentopdf-nonroot
```
### 环境变量
| 变量 | 说明 | 默认值 |
| -------------- | ------------------- | ------- |
| `PUID` | 运行时使用的用户 ID | `1000` |
| `PGID` | 运行时使用的组 ID | `1000` |
| `PORT` | Nginx 监听端口 | `8080` |
| `DISABLE_IPV6` | 禁用 IPv6 监听 | `false` |
### Docker Compose
```yaml
services:
bentopdf:
build:
context: .
dockerfile: Dockerfile.nonroot
container_name: bentopdf
ports:
- '3000:8080'
environment:
- PUID=1000
- PGID=1000
restart: unless-stopped
```
### 工作原理
容器以 root 身份启动,使用指定的 PUID/PGID 创建用户,调整所有可写目录的所有权,然后通过 `su-exec` 降低权限。nginx 进程完全以您指定的用户身份运行。
> [!NOTE]
> 标准 `Dockerfile` 使用 `nginx-unprivileged`(UID 101),推荐用于大多数部署。仅在需要特定 UID/GID 时才使用 `Dockerfile.nonroot`。
> [!WARNING]
> PUID/PGID 不能为 `0`(root)。入口脚本会验证输入,遇到无效值时会报错退出。
## 配合 Traefik(反向代理)
```yaml
services:
traefik:
image: traefik:v2.10
command:
- '--providers.docker=true'
- '--entrypoints.web.address=:80'
- '--entrypoints.websecure.address=:443'
- '[email protected]'
- '--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web'
ports:
- '80:80'
- '443:443'
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
bentopdf:
image: ghcr.io/alam00000/bentopdf-simple:latest
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.bentopdf.rule=Host(`pdf.example.com`)'
- 'traefik.http.routers.bentopdf.entrypoints=websecure'
- 'traefik.http.routers.bentopdf.tls.certresolver=letsencrypt'
- 'traefik.http.services.bentopdf.loadbalancer.server.port=8080'
# Required headers for SharedArrayBuffer (LibreOffice WASM)
- 'traefik.http.routers.bentopdf.middlewares=bentopdf-headers'
- 'traefik.http.middlewares.bentopdf-headers.headers.customresponseheaders.Cross-Origin-Opener-Policy=same-origin'
- 'traefik.http.middlewares.bentopdf-headers.headers.customresponseheaders.Cross-Origin-Embedder-Policy=require-corp'
restart: unless-stopped
```
## 配合 Caddy(反向代理)
```yaml
services:
caddy:
image: caddy:2
ports:
- '80:80'
- '443:443'
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
bentopdf:
image: ghcr.io/alam00000/bentopdf-simple:latest
restart: unless-stopped
volumes:
caddy_data:
```
Caddyfile:
```
pdf.example.com {
reverse_proxy bentopdf:8080
header Cross-Origin-Opener-Policy "same-origin"
header Cross-Origin-Embedder-Policy "require-corp"
}
```
## 资源限制
```yaml
services:
bentopdf:
image: ghcr.io/alam00000/bentopdf-simple:latest
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
```
## Podman Quadlet(Systemd 集成)
[Quadlet](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html) 允许您将 Podman 容器作为 systemd 服务运行。这非常适合 Linux 系统上的生产部署。
### 基本 Quadlet 设置
在 `~/.config/containers/systemd/bentopdf.container`(用户级)或 `/etc/containers/systemd/bentopdf.container`(系统级)创建容器单元文件:
```ini
[Unit]
Description=BentoPDF - Privacy-first PDF toolkit
After=network-online.target
Wants=network-online.target
[Container]
Image=ghcr.io/alam00000/bentopdf-simple:latest
ContainerName=bentopdf
PublishPort=3000:8080
AutoUpdate=registry
[Service]
Restart=always
TimeoutStartSec=300
[Install]
WantedBy=default.target
```
### 启用并启动
```bash
# Reload systemd to detect new unit
systemctl --user daemon-reload
# Start the service
systemctl --user start bentopdf
# Enable on boot
systemctl --user enable bentopdf
# Check status
systemctl --user status bentopdf
# View logs
journalctl --user -u bentopdf -f
```
> [!TIP]
> 对于系统级部署,请使用不带 `--user` 参数的 `systemctl`,并将文件放在 `/etc/containers/systemd/` 中。
### 带健康检查的 Quadlet
```ini
[Unit]
Description=BentoPDF with health monitoring
After=network-online.target
Wants=network-online.target
[Container]
Image=ghcr.io/alam00000/bentopdf-simple:latest
ContainerName=bentopdf
PublishPort=3000:8080
AutoUpdate=registry
HealthCmd=wget --spider -q http://localhost:8080 || exit 1
HealthInterval=30s
HealthTimeout=10s
HealthRetries=3
[Service]
Restart=always
TimeoutStartSec=300
[Install]
WantedBy=default.target
```
### 使用 Quadlet 自动更新
Podman 可以在有新镜像时自动更新容器:
```bash
# Enable auto-update timer
systemctl --user enable --now podman-auto-update.timer
# Check for updates manually
podman auto-update
# Dry run (check without updating)
podman auto-update --dry-run
```
### Quadlet 网络配置
如需自定义网络配置,请创建网络文件 `bentopdf.network`:
```ini
[Network]
Subnet=10.89.0.0/24
Gateway=10.89.0.1
```
然后在您的容器文件中引用它:
```ini
[Container]
Image=ghcr.io/alam00000/bentopdf-simple:latest
ContainerName=bentopdf
PublishPort=3000:8080
Network=bentopdf.network
```
## 更新
```bash
# Pull latest image
docker compose pull
# Recreate container
docker compose up -d
```