Pinepods Docker Compose 部署指南
基于 Pinepods 0.9.0 实测:三服务 Compose 编排、数据持久化与重启验证、初始化向导建管理员、添加真实播客 RSS 端到端验证与排障实录。
Pinepods Docker Compose 部署指南
目标:在一台 Linux 服务器上用 Docker Compose 完成自托管播客服务器 Pinepods 0.9.0 的整套部署,覆盖镜像选型、三服务编排(应用 + 数据库 + 缓存)、数据持久化、初始化向导建管理员、添加一档真实播客 RSS 的端到端验证,并沉淀部署过程实测排障记录。本文所有命令与回显均在真实部署环境执行验证。
一、环境信息
| 项目 | 值 | 说明 |
|---|---|---|
| 宿主系统 | Ubuntu(x86_64) | Docker 环境由宿主提供 |
| Docker 版本 | 29.9.2 | docker --version 实测 |
| Compose 版本 | v5.6.1 | docker compose version 实测 |
| 应用服务 | madeofpendletonwool/pinepods:0.9.0 | 官方镜像,tag 固定版本 |
| 数据库服务 | postgres:18 | 本文实测后端;官方默认编排用 mariadb:12 |
| 缓存服务 | valkey/valkey:8-alpine | 官方编排指定 |
| 应用端口 | 宿主 8140 → 服务 8040(Web/API),服务内 8042(gPodder 同步) | docker port 实测 |
| 数据目录 | /opt/pinepods/{pgdata,downloads,backups,local-media} | bind mount 持久化 |
| 网络 | 自定义 bridge,独立子网 10.89.64.0/24 | compose 自动创建 |
二、镜像选型说明
2.1 应用镜像
选型结论:使用官方镜像 madeofpendletonwool/pinepods,tag 固定为 0.9.0,不使用 latest——Pinepods 仍在 0.x 快速迭代期,固定 tag 可避免升级带来的行为变化。
实测镜像元数据(docker image inspect 输出节选):
{
"Id": "sha256:ebc258bb0c62cdb69e5fb726b247c885dac19b50d06fed68fa8d37197b88ace4",
"Created": "2026-06-26T14:35:06.86597788Z",
"Architecture": "amd64",
"Config": {
"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TZ=UTC", "APP_ROOT=/pinepods"],
"ExposedPorts": { "8040/tcp": {}, "8042/tcp": {} },
"Healthcheck": {
"Test": ["CMD-SHELL", "curl -fsS http://localhost:8040/api/health || exit 1"],
"Interval": 30000000000, "Timeout": 5000000000,
"StartPeriod": 30000000000, "Retries": 3
}
}
}
三点解读:镜像构建日期与 0.9.0 发布日期(2026-06-26)同日,是版本正式构建;APP_ROOT=/pinepods 是应用在服务内的工作根目录;内置健康检查每 30 秒探测一次 /api/health,启动宽限期 30 秒,失败重试 3 次。
2.2 数据库与缓存镜像
- 数据库:官方同时支持 MariaDB/MySQL 与 PostgreSQL(
DB_TYPE切换)。官方文档默认编排用mariadb:12;本文实测环境选择postgres:18,两种后端功能面一致。若选 MariaDB,把数据库服务替换为 mariadb 并改用MYSQL_*环境变量(差异对照见第六节)。 - 缓存:
valkey/valkey:8-alpine为官方编排指定,应用通过 Redis 协议访问它,无需任何密码配置(仅内网通信)。
三、前置条件
- 一台 Linux 服务器(x86_64,建议 2 核 2GB 内存起步),已安装 Docker 与 Docker Compose 插件。
- 规划好数据根目录,本文统一用
/opt/pinepods/,先建好四个子目录并放行应用运行身份(服务内以 911:911 非 root 身份运行):
mkdir -p /opt/pinepods/{pgdata,downloads,backups,local-media}
ls /opt/pinepods
实测回显(目录创建后核对):
backups downloads local-media pgdata
- 防火墙放行对外端口(本文映射到宿主 8140,按需调整)。
四、部署步骤
4.1 编写 compose 文件
在 /opt/pinepods/ 下创建 docker-compose.yml(官方默认编排为 MariaDB,下面是本文实测的 PostgreSQL 版本,数据库差异仅在这一段):
name: pinepods-stack
services:
db:
container_name: pinepods-db
image: postgres:18
environment:
POSTGRES_DB: pinepods_database
POSTGRES_USER: postgres
POSTGRES_PASSWORD: myS3curepass
PGDATA: /var/lib/pgdata/pgdata
volumes:
- /opt/pinepods/pgdata:/var/lib/pgdata
restart: unless-stopped
valkey:
container_name: pinepods-valkey
image: valkey/valkey:8-alpine
restart: unless-stopped
pinepods:
container_name: pinepods-web
image: madeofpendletonwool/pinepods:0.9.0
ports:
- "8140:8040"
environment:
SEARCH_API_URL: "https://search.pinepods.online/api/search"
PEOPLE_API_URL: "https://people.pinepods.online"
HOSTNAME: "http://<服务器IP或域名>:8140"
DB_TYPE: postgresql
DB_HOST: db
DB_PORT: 5432
DB_USER: postgres
DB_PASSWORD: myS3curepass
DB_NAME: pinepods_database
VALKEY_HOST: valkey
VALKEY_PORT: 6379
DEBUG_MODE: false
PUID: 911
PGID: 911
TZ: "Asia/Shanghai"
DEFAULT_LANGUAGE: "en"
volumes:
- /opt/pinepods/downloads:/opt/pinepods/downloads
- /opt/pinepods/backups:/opt/pinepods/backups
- /opt/pinepods/local-media:/opt/pinepods/local-media
depends_on:
- db
- valkey
逐段说明:db 服务把数据目录 bind mount 到宿主实现持久化;valkey 无需端口映射(仅编排网络内通信);pinepods 服务只对外映射 8040 一个端口,HOSTNAME 必须写成外部实际访问地址(分享链接、同步地址都会以它为准);PUID/PGID=911 是服务内运行身份,保持官方默认即可。
4.2 启动服务
cd /opt/pinepods && docker compose up -d
docker compose ps
实测回显(三服务全部就绪后的状态):
NAME IMAGE STATUS PORTS
pinepods-0-9-0-db postgres:18 Up 7 hours 5432/tcp
pinepods-0-9-0-valkey valkey/valkey:8-alpine Up 7 hours 6379/tcp
pinepods-0-9-0-web madeofpendletonwool/pinepods:0.9.0 Up 43 seconds (healthy) 8042/tcp, 0.0.0.0:8140->8040/tcp, [::]:8140->8040/tcp
应用状态带 (healthy) 即通过内置健康检查;数据库与缓存不对外暴露端口是预期行为。
4.3 首次启动日志解读
docker compose logs pinepods | head -40 关键行实测(首次启动时序):
PinePods 0.9.0
https://pinepods.online
Setting timezone to Asia/Shanghai
Using mounted timezone file from host
Creating required directories...
Using postgresql database
2026-10-30 01:40:29,214 - INFO - Starting PinePods database setup...
2026-10-30 01:40:29,307 - WARNING - Connection attempt 1/30 failed: connection failed: connection to server at "10.89.64.2", port 5432 failed: Connection refused
2026-10-30 01:40:30,318 - INFO - PostgreSQL is ready after 2 attempts
2026-10-30 01:40:30,333 - INFO - Database pinepods_database already exists.
2026-10-30 01:40:30,373 - INFO - Registered migration 001: create_core_tables
2026-10-30 01:40:30,396 - INFO - Found 57 pending migrations
2026-10-30 01:40:30,625 - INFO - Database setup completed successfully!
Starting Horust in production mode (logs to files)...
Configuring non-root execution as 911:911...
Starting services as 911:911 with Horust...
PinePods startup complete, running Horust in foreground...
时序解读:应用先等数据库就绪(最多重试 30 次,首次启动数据库尚未监听时会出现 1 次 Connection refused 警告,属正常重试)→ 自动执行 57 个数据库迁移建表 → 用 Horust 进程管理器以 911:911 非 root 身份拉起各组件。出现最后一行即启动完成。
4.4 初始化向导:创建管理员
浏览器打开 http://<服务器IP>:8140,服务检测到无管理员账号时自动进入初始化向导。本文实测填入:用户名 admin、全名 Pinepods Admin、邮箱 admin@pinepods.local、密码 q1w2e3r4,提交后用该账号登录进入主界面。
向导是否已完成的接口验证回显(first_admin_created: true 即完成):
$ curl -s http://127.0.0.1:8140/api/data/admin_self_service_status -H "Api-Key: <你的API密钥>"
{"first_admin_created":true,"status":false}
登录后进入用户设置页创建一个 API 密钥(认证头 Api-Key 用),后续验证与运维接口都依赖它。
4.5 添加一档播客验证端到端链路
用 Web 界面搜索或直接用 API 添加一档真实公开播客。先查重(exists: false 表示可添加):
$ curl -s "http://127.0.0.1:8140/api/data/check_podcast?user_id=2&podcast_name=The%20Daily&podcast_url=https%3A%2F%2Ffeeds.simplecast.com%2F54nAGcIl" -H "Api-Key: <你的API密钥>"
{"exists":false}
再通过 RSS 添加(服务端会自动拉取封面、作者、剧集列表):
$ curl -s -X POST "http://127.0.0.1:8140/api/data/add_custom_podcast" -H "Api-Key: <你的API密钥>" -H "Content-Type: application/json" -d '{"feed_url":"https://feeds.simplecast.com/54nAGcIl","user_id":2}'
{"data":{"artworkurl":"https://image.simplecastcdn.com/images/7f2f4c05-9c2f-4deb-82b7-b538062bc22d/73549bf1-94b3-40ff-8aeb-b4054848ec1b/3000x3000/the-daily-album-art-original.jpg?aid=rss_feed","author":"The New York Times","autodownload":false,"categories":{},"description":"This is what the news should sound like. ...","episodecount":3021,"explicit":false,"feedcutoffdays":30,"feedurl":"https://feeds.simplecast.com/54nAGcIl","isyoutubechannel":false,"notificationsenabled":false,"password":null,"playbackspeed":1.0,"playbackspeedcustomized":false,"podcastid":3,"podcastindexid":0,"podcastname":"The Daily","startskip":0,"userid":2,"username":null,"websiteurl":"https://feeds.simplecast.com/54nAGcIl"}}
回显要点:podcastid=3 是服务端分配的订阅 ID,episodecount=3021 说明服务端已完整解析该 RSS 的剧集列表。此时浏览器刷新订阅页即可看到《The Daily》并可播放。API 的完整用法见《Pinepods 0.9.0 API 使用详解》。
五、数据持久化说明
| 挂载点(服务内) | 宿主目录 | 内容 |
|---|---|---|
| /var/lib/pgdata | /opt/pinepods/pgdata | 数据库全部数据(用户/订阅/进度/队列) |
| /opt/pinepods/downloads | /opt/pinepods/downloads | 下载的剧集音频/视频文件 |
| /opt/pinepods/backups | /opt/pinepods/backups | 备份产物 |
| /opt/pinepods/local-media | /opt/pinepods/local-media | 本地媒体库(可选功能) |
重启持久化实测:重启应用服务后健康检查通过、订阅数据完好:
$ docker compose restart pinepods
Container pinepods-0-9-0-web Restarting
Container pinepods-0-9-0-web Started
$ curl -s http://127.0.0.1:8140/api/health
{"status":"healthy","database":true,"redis":true,"timestamp":"2026-10-30T00:21:10.885665443Z"}
同时用数据库侧复核订阅数(3 档:默认新闻播客 + 2 档测试添加的播客):
$ docker exec pinepods-0-9-0-db psql -U postgres -d pinepods_database -t -c 'select count(*) from "Podcasts";'
3
两点注意:pgdata 是唯一不可丢失的目录,备份策略围绕它制定(服务自带备份能力见《Pinepods 0.9.0 配置参数详解》);downloads/backups/local-media 属于「可再生成/可选」数据,按磁盘预算决定是否保留。
六、环境变量表
6.1 应用服务(pinepods)
| 变量 | 实测值 | 说明 |
|---|---|---|
| DB_TYPE | postgresql | 数据库类型,postgresql 或 mariadb,决定连接驱动与迁移方言 |
| DB_HOST | db | 数据库地址(编排内服务名) |
| DB_PORT | 5432 | 数据库端口,PostgreSQL 5432 / MariaDB 3306 |
| DB_USER | postgres | 数据库用户 |
| DB_PASSWORD | myS3curepass | 数据库密码 |
| DB_NAME | pinepods_database | 数据库名 |
| VALKEY_HOST | valkey | 缓存地址 |
| VALKEY_PORT | 6379 | 缓存端口 |
| HOSTNAME | http://<服务器IP或域名>:8140 | 对外访问地址,分享/同步链接以它为准 |
| SEARCH_API_URL | https://search.pinepods.online/api/search | 官方托管搜索 API;自建可换自托管搜索服务 |
| PEOPLE_API_URL | https://people.pinepods.online | 主持人信息库(PodPeopleDB)地址 |
| DEBUG_MODE | false | 调试日志开关 |
| PUID / PGID | 911 / 911 | 服务内运行身份(非 root) |
| TZ | Asia/Shanghai | 时区;启动日志会回显「Setting timezone to Asia/Shanghai」 |
| DEFAULT_LANGUAGE | en | 界面默认语言 |
| PINEPODS_AI_URL | 未设置(可选) | AI 转写侧车地址,需另起 pinepods-ai 服务才启用 |
6.2 数据库服务(PostgreSQL 与 MariaDB 对照)
| 用途 | PostgreSQL(本文实测) | MariaDB(官方默认) |
|---|---|---|
| 镜像 | postgres:18 | mariadb:12 |
| 库名变量 | POSTGRES_DB: pinepods_database | MYSQL_DATABASE: pinepods_database |
| 管理员密码变量 | POSTGRES_PASSWORD: myS3curepass | MYSQL_ROOT_PASSWORD: myS3curepass |
| 端口 | 5432(DB_PORT 同步改) | 3306(官方另设 MYSQL_TCP_PORT: 3306) |
| 数据目录 | PGDATA: /var/lib/pgdata/pgdata | /var/lib/mysql |
| 附加参数 | 无 | command: --wait_timeout=1800、MYSQL_INIT_CONNECT 放大 max_allowed_packet 至 64MB(官方编排为导入大剧集元数据设置) |
切换要点:两种后端除数据库段环境变量外,只需把应用的 DB_TYPE/DB_PORT 与之对齐,功能面一致;官方 MariaDB 编排的字符集用 utf8mb4/utf8mb4_unicode_ci,中文播客名实测(本文环境「声东击西」)在两种后端下均正常存取。
七、配置文件挂载
Pinepods 应用本体零配置文件:全部配置通过环境变量注入,运行期设置存数据库并从 Web 界面管理,因此不需要挂载任何配置文件。需要挂载的只有三类路径:
- 数据卷(见第五节表格):downloads / backups / local-media 三个功能目录 + 数据库数据目录。
- 时区文件(可选):官方默认编排挂载
/etc/localtime与/etc/timezone(只读)让服务时区与宿主一致;未挂载时用TZ环境变量亦可(实测两种方式取其一即可,启动日志「Using mounted timezone file from host」表示挂载方式生效)。 - 不要挂载应用目录:
APP_ROOT=/pinepods内是程序本体,挂载覆盖会破坏启动。
八、等价 docker run 命令
不用 Compose 时,以下三条命令等价于上面的编排(逐条执行,注意先后顺序):
docker network create pinepods-net
docker run -d --name pinepods-db --network pinepods-net \
-e POSTGRES_DB=pinepods_database \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=myS3curepass \
-e PGDATA=/var/lib/pgdata/pgdata \
-v /opt/pinepods/pgdata:/var/lib/pgdata \
--restart unless-stopped \
postgres:18
docker run -d --name pinepods-valkey --network pinepods-net \
--restart unless-stopped \
valkey/valkey:8-alpine
docker run -d --name pinepods-web --network pinepods-net \
-p 8140:8040 \
-e SEARCH_API_URL="https://search.pinepods.online/api/search" \
-e PEOPLE_API_URL="https://people.pinepods.online" \
-e HOSTNAME="http://<服务器IP或域名>:8140" \
-e DB_TYPE=postgresql \
-e DB_HOST=pinepods-db \
-e DB_PORT=5432 \
-e DB_USER=postgres \
-e DB_PASSWORD=myS3curepass \
-e DB_NAME=pinepods_database \
-e VALKEY_HOST=pinepods-valkey \
-e VALKEY_PORT=6379 \
-e DEBUG_MODE=false \
-e PUID=911 -e PGID=911 \
-e TZ="Asia/Shanghai" \
-e DEFAULT_LANGUAGE="en" \
-v /opt/pinepods/downloads:/opt/pinepods/downloads \
-v /opt/pinepods/backups:/opt/pinepods/backups \
-v /opt/pinepods/local-media:/opt/pinepods/local-media \
--restart unless-stopped \
madeofpendletonwool/pinepods:0.9.0
与 Compose 版的差异只有两处:服务名换成容器名(DB_HOST=pinepods-db、VALKEY_HOST=pinepods-valkey),网络需先手工创建。生产环境建议仍用 Compose,便于一键升级与回滚。
九、常用运维命令
docker compose ps # 三服务状态(应用应带 healthy)
docker compose logs -f pinepods # 跟踪应用日志
docker compose restart pinepods # 重启应用(不动数据库)
docker compose stop # 停止全部服务(保留数据)
docker compose up -d # 启动/应用配置变更
升级到新版本的标准流程:改 compose 中应用镜像 tag 为新版本号 → docker compose pull pinepods → docker compose up -d。启动时迁移机制会自动把数据库结构迁到新版本(首次部署实测执行 57 个迁移即此机制);回滚则把 tag 改回旧版本重新 up -d,但需注意新版本迁移不可自动逆转,回滚前先备份 /opt/pinepods/pgdata。
十、常见问题(排障实录)
Q1:应用启动日志出现 Connection attempt 1/30 failed: ... Connection refused。
实测结论:这是首次启动时数据库还未完成初始化监听,应用会自动重试(上限 30 次),实测第 2 次尝试即成功(「PostgreSQL is ready after 2 attempts」)。若持续 30 次失败,检查 DB_HOST 是否与数据库服务名一致、数据库服务是否处于 Up 状态(docker compose ps)。
Q2:应用容器状态一直 starting,不出现 healthy。
排查顺序:先 docker compose logs pinepods 看是否卡在数据库连接(对应 Q1);再看 /api/health 手工返回什么——实测健康检查同时报告数据库与缓存两层({"status":"healthy","database":true,"redis":true,...}),哪一层为 false 就查哪一层;本文实测一次重启后 30 秒内即恢复 healthy(镜像健康检查宽限期 30 秒)。
Q3:宿主端口 8140 被占用。
把 compose 中 ports 改为其他宿主端口(如 "9140:8040"),同时同步修改 HOSTNAME 环境变量(它必须与外部访问地址一致,否则分享链接与同步地址不可用)。
Q4:添加播客时返回 HTTP 400 Feed request failed: HTTP 404 Not Found。
实测复现:feed 地址失效时服务端原样返回该错误(实测用已失效的 RSS 地址添加得到 {"error":"Bad request","message":"Bad request: Feed request failed: HTTP 404 Not Found","status_code":400})。先在浏览器打开 RSS 地址确认可达,再重新添加。
Q5:中文播客名乱码或存库失败。 MariaDB 后端确认字符集变量为 utf8mb4(官方默认编排已带);PostgreSQL 后端默认 UTF8 无需处理。本文实测中文播客「声东击西」订阅、播放、删除全程正常。
十一、参考链接
- 官方安装文档:https://docs.pinepods.online
- 官方 Compose 编排文件仓库目录:https://github.com/madeofpendletonwool/Pinepods/tree/main/deployment/docker
- Docker Hub 镜像页:https://hub.docker.com/r/madeofpendletonwool/pinepods
- 0.9.0 发布说明:https://github.com/madeofpendletonwool/Pinepods/releases/tag/0.9.0
- 本专栏配套文档:《Pinepods 介绍与选型指南》、《Pinepods 0.9.0 配置参数详解》、《Pinepods 0.9.0 API 使用详解》