URL-to-PNG Docker Compose 部署指南
在 Ubuntu 22.04 用 Docker Compose 从零部署 URL-to-PNG v2.1.4:镜像选型、持久化、环境变量全表、等价 docker run、升级回滚与六个实测常见问题。
URL-to-PNG Docker Compose 部署指南
目标:在 Ubuntu 22.04 服务器上用 Docker Compose 从零部署 URL-to-PNG v2.1.4 截图服务,包含镜像选型、数据持久化、环境变量全表、等价单命令与日常运维操作。全文命令与回显均在 Ubuntu 22.04 实测通过,服务部署后监听 8136 端口。
一、环境信息
- 操作系统:Ubuntu 22.04 LTS(x86_64)
- Docker:24.x(含 compose v2 插件,
docker compose version可验证) - 截图服务:URL-to-PNG v2.1.4(2026-10-31 实查为官方最新稳定版)
- 对外端口:
8136(服务内默认监听 3089,经端口映射对外提供 8136) - 部署目录:
/opt/url-to-png/(compose 文件与缓存数据所在) - 缓存目录:
/opt/url-to-png/data/images/(映射到服务内/app/images)
二、镜像选型说明
官方发布两条镜像通道,版本号一致(2026-10-31 实查):
| 通道 | 引用 | 说明 |
|---|---|---|
| GitHub Container Registry | ghcr.io/jasonraimondi/url-to-png | 官方 getting-started 默认引用 |
| Docker Hub | jasonraimondi/url-to-png | 国内拉取通常更快,本文实测采用 |
版本标签选择建议:
- 固定小版本(如
:v2.1.4,本文采用):升级节奏自己掌控,生产推荐; :latest:跟随上游,适合测试环境。
⚠️ 不要使用 v2.0.2 及更早版本:v2.0.3 修复了
file://协议任意文件读取安全问题,生产环境务必不低于 v2.0.3(版本演进细节见《URL-to-PNG 介绍与选型指南》第二章)。
⚠️ 网络说明:实测环境中 Docker Hub 直连超时,docker pull 需经代理完成(本环境代理为 192.168.1.62:7897,配置于 Docker 守护进程代理设置);无代理环境可改用国内镜像加速通道。
三、前置条件
- 服务器已安装 Docker 与 compose 插件:
docker --version
# Docker version 24.0.7, build afdd53b
docker compose version
# Docker Compose version v2.24.5
- 对外端口未被占用(本文用 8136):
ss -ltn | grep 8136 || echo "8136 可用"
# 8136 可用
- 目标网页可达:服务在渲染时会从服务器侧发起对目标 URL 的访问,请确认服务器出网策略允许。
四、部署步骤
4.1 创建部署目录与 compose 文件
mkdir -p /opt/url-to-png/data/images
vim /opt/url-to-png/docker-compose.yml
/opt/url-to-png/docker-compose.yml 全文(本文实测所用配置):
name: url-to-png
services:
urltopng:
image: jasonraimondi/url-to-png:v2.1.4
container_name: urltopng-web
restart: unless-stopped
ports:
- "8136:3089"
environment:
LOG_LEVEL: info
NODE_ENV: production
METRICS: "true"
STORAGE_PROVIDER: filesystem
IMAGE_STORAGE_PATH: /app/images
CACHE_CONTROL: "public, max-age=86400, immutable"
volumes:
- ./data/images:/app/images
逐项说明:
image:固定 v2.1.4 版本标签,生产环境不追浮动标签;ports:宿主 8136 → 服务 3089(3089 为 v2.0.0 起的默认端口);METRICS: "true":开启/metrics连接池指标,容量观测需要;STORAGE_PROVIDER: filesystem+IMAGE_STORAGE_PATH: /app/images:渲染结果缓存到本地磁盘;volumes:把宿主./data/images(即/opt/url-to-png/data/images)挂为缓存目录,服务重启缓存不丢;restart: unless-stopped:异常退出自动拉起。
4.2 拉取镜像并启动
cd /opt/url-to-png
docker compose pull
# [+] Pulling 1/1
# ✔ urltopng Pulled 8.9s
docker compose up -d
# [+] Running 2/2
# ✔ Network url-to-png_default Created 0.1s
# ✔ Container urltopng-web Started 0.6s
4.3 验证服务就绪
docker compose ps
# NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
# urltopng-web jasonraimondi/url-to-png:v2.1.4 "docker-entrypoint.s…" urltopng 5 seconds ago Up 4 seconds 0.0.0.0:8136->3089/tcp, [::]:8136->3089/tcp
curl -s http://localhost:8136/ping
# "pong"
再发第一张真实截图(默认 250x250):
curl -s 'http://localhost:8136/?url=https://example.com&forceReload=true' -o first.png
file first.png
# first.png: PNG image data, 250 x 250, 8-bit/color RGB, non-interlaced
能看到 PNG 尺寸即部署完成。首次启动后可顺手确认缓存目录已开始工作:
ls /opt/url-to-png/data/images/
# 10-31-2026.httpsexamplecom_forcereload-true.png
💡 缓存文件名即 imageId:
日期.URL与参数的 slug 化串.png,参数一变文件名就变(机制详见 D5 篇)。
五、数据持久化说明
URL-to-PNG 的"数据"只有一类:渲染结果缓存。本文配置下全部落在宿主 /opt/url-to-png/data/images/:
- 重启不丢:缓存文件落在宿主 bind mount 目录,服务重启后同参数请求依然毫秒级命中(实测重启后首请求 0.014s 返回同尺寸缓存图);
- 可以整目录备份:
tar czf urltopng-cache-$(date +%F).tgz -C /opt/url-to-png/data images; - 可以整目录清理:删光目录内文件即可释放空间,服务无需重启,下一请求自动重建缓存;
- 容量增长注意:每种「URL+参数」组合各存一个文件且无自动清理,长期运行建议按月巡检
du -sh(见 8.2 节)。
若改用 s3 后端(STORAGE_PROVIDER=s3 + AWS_* 环境变量),本地目录不再是数据权威副本,多实例可共享同一缓存。
六、环境变量表
官方支持的环境变量全项(官方文档 Configuration 页 + v2.1.4 实测核对):
| 环境变量 | 默认值 | 说明 |
|---|---|---|
LOG_LEVEL | debug | 日志级别:debug / info / warn / error |
NODE_ENV | development | Node 运行环境,生产建议 production |
PORT | 3089 | 服务监听端口(改了需同步改 ports 映射) |
CACHE_CONTROL | public, max-age=86400, immutable | 截图响应的 Cache-Control 头 |
ALLOW_LIST | 空(全放行) | 白名单,逗号分隔 host,精确匹配 |
BLOCK_LIST | 空(全放行) | 黑名单,逗号分隔 host,精确匹配 |
BROWSER_TIMEOUT | 10000 | 渲染超时(毫秒),超时返回 500 |
BROWSER_WAIT_UNTIL | domcontentloaded | 页面加载等待事件:load / domcontentloaded / networkidle |
POOL_IDLE_TIMEOUT_MS | 15000 | 浏览器实例空闲回收时间(毫秒) |
POOL_MAX | 10 | 浏览器池上限 |
POOL_MAX_WAITING_CLIENTS | 50 | 等待队列上限 |
POOL_MIN | 2 | 浏览器池常驻下限 |
DEFAULT_WIDTH / DEFAULT_HEIGHT | 250 | 默认输出宽高 |
DEFAULT_VIEWPORT_WIDTH / DEFAULT_VIEWPORT_HEIGHT | 1080 | 默认渲染视口 |
DEFAULT_IS_MOBILE / DEFAULT_IS_FULL_PAGE / DEFAULT_IS_DARK_MODE | false | 默认布尔渲染开关 |
DEFAULT_DEVICE_SCALE_FACTOR | 1 | 默认 DPR |
METRICS | false | 是否开启 /metrics |
CRYPTO_KEY | 空 | AES-GCM 256 加密密钥(JWK JSON 串),配置后只收加密请求 |
STORAGE_PROVIDER | stub | 存储后端:stub / filesystem / s3 / couchdb |
IMAGE_STORAGE_PATH | — | filesystem 后端的存储目录 |
AWS_BUCKET / AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_DEFAULT_REGION / AWS_FORCE_PATH_STYLE / AWS_ENDPOINT_URL_S3 | — | s3 后端参数 |
COUCH_DB_PROTOCOL / COUCH_DB_USER / COUCH_DB_PASS / COUCH_DB_HOST / COUCH_DB_PORT / COUCHDB_DATABASE | — | couchdb 后端参数 |
各变量分类详解、名单匹配与超时实测见《URL-to-PNG 2.1.4 配置参数详解》。
七、配置文件挂载与配置调整
URL-to-PNG 没有配置文件,全部配置走环境变量(上表),因此无需挂载任何 conf/yaml:
- 改配置 = 改 compose 的
environment:段 →docker compose up -d重建生效; - 服务内唯一有状态目录是缓存目录
/app/images(已挂出); - 验证环境变量生效的实测方法——以
METRICS为例,改后重建并探测:
curl -s http://localhost:8136/metrics
# {"poolMetrics":{"spareResourceCapacity":8,"size":2,"available":2,"borrowed":0,"pending":0,"max":10,"min":2}}
min: 2 / max: 10 即 POOL_MIN/POOL_MAX 的生效值;若把 METRICS 关掉,该端点返回 404。
八、常用运维命令
以下命令均在 /opt/url-to-png 目录执行。
8.1 状态与日志
docker compose ps
# NAME IMAGE ... STATUS PORTS
# urltopng-web jasonraimondi/url-to-png:v2.1.4 ... Up 2 hours 0.0.0.0:8136->3089/tcp
docker compose logs --tail 5 urltopng
# {"level":30,"time":1793408061674,"pid":1,"hostname":"...","name":"url-to-png","msg":"Allowed Domains: (none)"}
# {"level":30,"time":1793408061674,"pid":1,"hostname":"...","name":"url-to-png","msg":"Server is running on port http://localhost:3089/ping"}
日志为 JSON 行(pino 格式),level 30=info、40=warn、50=error;被名单拦截的请求会输出 Blocked request to ... 警告行。
8.2 缓存巡检与清理
du -sh /opt/url-to-png/data/images/
# 1.8M /opt/url-to-png/data/images/
ls /opt/url-to-png/data/images/ | wc -l
# 18
# 全量清空(服务不停)
rm -f /opt/url-to-png/data/images/*.png
8.3 升级版本
# 1. 改 compose 中 image 标签为新版本号
sed -i 's|jasonraimondi/url-to-png:v2.1.4|jasonraimondi/url-to-png:<新版本>|' docker-compose.yml
# 2. 拉新镜像并重建(缓存目录不受影响)
docker compose pull && docker compose up -d
# 3. 回归验证
curl -s http://localhost:8136/ping ; echo
curl -s 'http://localhost:8136/?url=https://example.com&forceReload=true' -o /dev/null -w '%{http_code}\n'
# 200
升级回滚:把 image 标签改回旧版本号,重复第 2、3 步即可;缓存文件与版本无关,无需清理。
8.4 停止与卸载
docker compose down # 停止并移除服务网络(缓存数据保留在宿主目录)
# 完全卸载:docker compose down 后 rm -rf /opt/url-to-png
九、等价 docker run
不使用 Compose 时的等价单命令(与 4.1 compose 语义一致):
docker run -d \
--name urltopng-web \
--restart unless-stopped \
-p 8136:3089 \
-e LOG_LEVEL=info \
-e NODE_ENV=production \
-e METRICS=true \
-e STORAGE_PROVIDER=filesystem \
-e IMAGE_STORAGE_PATH=/app/images \
-e CACHE_CONTROL="public, max-age=86400, immutable" \
-v /opt/url-to-png/data/images:/app/images \
jasonraimondi/url-to-png:v2.1.4
启动后同样以 curl -s http://localhost:8136/ping 验证(实测返回 "pong")。多实例或长期维护仍建议用 Compose(声明式、可复制)。
十、常见问题
Q1:截图请求返回 500,日志里是 page.goto: Timeout ... exceeded?
渲染耗时超过 BROWSER_TIMEOUT(默认 10 秒)。实测把 BROWSER_TIMEOUT 压到 2000 后请求 example.com,可稳定复现:
{"message":"page.goto: Timeout 2000ms exceeded.\nCall log:\n - navigating to \"https://example.com/\", waiting until \"domcontentloaded\"\n"}
解决:按目标站点最慢耗时放宽 BROWSER_TIMEOUT;或接受失败让调用方重试。
Q2:目标域名渲染失败,日志报 ERR_NAME_NOT_RESOLVED?
服务器侧解析不了目标域名(实测对不存在域名返回):
{"message":"page.goto: net::ERR_NAME_NOT_RESOLVED at https://nonexistent.invalid/\nCall log:\n - navigating to \"https://nonexistent.invalid/\", waiting until \"domcontentloaded\"\n"}
排查服务器 DNS 与出网策略,而非截图服务本身。
Q3:请求被 403 拒绝:{"message":"Access to this URL is forbidden"}?
命中了 ALLOW_LIST/BLOCK_LIST。注意名单是 host 精确匹配:白名单 example.com 不会放行 www.example.com(实测两者回显一致)。把需要的全部 host 逐个列入,或清空名单恢复全放行。
Q4:首次请求比缓存命中慢很多(约 1-5 秒)?
正常现象:缓存未命中需真实渲染(含浏览器取页面、等资源、截图、缩放全链路);命中后毫秒级返回(实测 0.0015s)。含慢资源的页面首图耗时约等于最慢资源耗时(实测 5 秒慢图页返回耗时 5.1 秒),完整实验数据见《URL-to-PNG 2.1.4 API 使用详解》。
Q5:缓存目录写入失败?
镜像内服务以非 root 运行账号(pwuser)写 /app/images。若 bind mount 的宿主目录权限过窄会出现 EACCES,实测正常启动时宿主目录属主会被调整为该运行账号;也可手动 chown -R 1000:1000 /opt/url-to-png/data/images 兜底。
Q6:8136 端口被其他服务占用?
ss -ltn | grep 8136 找到占用方;要么换 compose ports 左侧端口(如 "8200:3089"),要么停掉占用服务后重新 up -d。
十一、参考链接
- 官方 getting-started:https://jasonraimondi.github.io/url-to-png/docs/getting-started
- 官方配置文档:https://jasonraimondi.github.io/url-to-png/docs/config
- GitHub 仓库:https://github.com/jasonraimondi/url-to-png
- Docker Hub:https://hub.docker.com/r/jasonraimondi/url-to-png
- 本专栏配套篇目:《URL-to-PNG 介绍与选型指南》、《URL-to-PNG 2.1.4 配置参数详解》、《URL-to-PNG 2.1.4 API 使用详解》