PeerTube 8.3.2 Docker Compose 部署指南

用 PeerTube 官方 Compose 模板在 Ubuntu 服务器上从零部署 v8.3.2:编排与 .env 全量逐项说明、首启初始化与初始管理员接管、ffmpeg 自造素材上传与 HLS 转码端到端验证、数据持久化与等价 docker run、升级/卸载与六个实测踩坑(网段冲突、WEBSERVER 三件套一致性、videofile 字段、PUT /users/me 等)。

PeerTubePeerTube流媒体自托管Docker Compose2026/10/27

PeerTube 8.3.2 Docker Compose 部署指南

目标:在一台 Ubuntu 服务器上从零开始,用 PeerTube 官方 Docker Compose 模板完成 v8.3.2 的完整部署——环境准备、编排文件与 .env 编写、首次启动初始化、管理员口令接管、上传与转码验证、日常运维与卸载。已在 Ubuntu 24.04.5 LTS(x86_64)服务器上以本篇同款编排全量实测通过(2026-10-27),测试素材均由 ffmpeg 自造并已在正文中标注。

一、环境信息

本篇实测环境与版本对照如下:

  • 操作系统:Ubuntu 24.04.5 LTS(x86_64)
  • Docker:29.9.2;Docker Compose:v5.6.1(插件版,docker compose 子命令)
  • PeerTube 版本:v8.3.2(官方最新稳定版,2026-10-27 经 GitHub Releases 实查;许可 AGPL-3.0)
  • 数据库:postgres:17-alpine(官方 compose 指定版本)
  • 缓存/队列:redis:8-alpine(官方 compose 指定版本)
  • 转码工具:宿主机 ffmpeg 6.1.1-3ubuntu5(仅用于自造测试视频;PeerTube 服务端内置自己的 ffmpeg,不依赖宿主机)
  • 网络规划:专用 bridge 网络 10.89.64.0/24(自定义网段,避开宿主机上其他业务网段)
  • 对外端口:8131(宿主机)→ 9000(PeerTube HTTP);RTMP 直播端口本篇未启用(边界见 7.4)
  • 服务器地址:192.168.146.128(实验服务器局域网 IP,正文所有 URL 均以此为准)
  • 部署目录:/opt/peertube(正文演示路径;编排文件、.env、数据卷均在其下)

⚠️ 网络说明:chocobozzz/peertube:v8.3.2 镜像约 3GB(解压后),境外源拉取较慢;本机 Docker 守护进程已配置 HTTP 代理(192.168.1.62:7897),docker pull 自动经代理完成,拉取耗时约 2 分钟。若你的服务器未配代理且官方源拉取超时,可先配置镜像加速或代理后再执行第三章。

二、镜像与编排形态选型说明

2.1 官方 Compose 的两种形态

PeerTube 官方仓库在 support/docker/production/ 下提供的 docker-compose.yml(v8.3.2 版共 124 行)包含 7 个 service:

service镜像作用本篇是否启用
peertubechocobozzz/peertube:production主服务(Web/API/转码调度)✅ 启用(改为固定版本 tag)
postgrespostgres:17-alpine持久化数据库✅ 启用
redisredis:8-alpine缓存与转码队列✅ 启用
webserverchocobozzz/peertube-webserver:latestNginx 反代 + HTTPS 入口(80/443)❌ 本地边界:需真实域名与 80/443 端口
certbotcertbot/certbotLet's Encrypt 证书自动签发续期❌ 本地边界:依赖公网域名验证
webserver-reloaderalpine:latest定期 reload Nginx❌ 随 webserver 一并省略
postfixmwader/postfix-relay邮件外发中继❌ 本地边界:实验环境无外发邮件需求

官方文件对 webserver/certbot 两段有明确注释:You can comment this webserver section if you want to use another webserver/proxy or test PeerTube in local(如你使用其他 Web 服务器/反代,或在本地测试 PeerTube,可注释掉该段)。本篇采用"主服务三件套(peertube + postgres + redis)"的本地测试形态,并把 HTTP 端口直接映射出来;生产上公网域名 + HTTPS 的完整七件套形态在 2.2 给出边界说明。

⚠️ 生产边界:公网生产部署时应启用 webserver + certbot + postfix 七件套形态(HTTPS 由内置 Nginx+Let's Encrypt 完成,官方模板已内置证书续期循环);本篇为无域名内网实测环境,如实采用三件套形态,HTTP 直连,联邦/嵌入等依赖 HTTPS 的功能会受限——这是形态差异带来的边界,不是软件缺陷。

2.2 镜像 tag 选型

官方 compose 中 peertube 服务默认写 chocobozzz/peertube:production(跟随最新稳定版的浮动 tag)。本篇固定版本 tag 为 chocobozzz/peertube:v8.3.2:版本可复现、升级节奏自主可控(浮动 tag 适合"永远最新"策略,固定 tag 适合"先测后升"的生产习惯,二选一,本篇取后者)。

三、前置条件

  1. Ubuntu 24.04 服务器一台,已安装 Docker 29+ 与 Compose 插件(docker compose version 可输出版本号);
  2. 服务器时间已同步(视频元数据、联邦签名对时间敏感,timedatectl 确认 NTP active);
  3. 规划好的对外端口(本篇取 8131)与自定义网段(本篇取 10.89.64.0/24),执行前先确认空闲:
# 确认 8131 端口未被占用(无输出即空闲)
ss -ltn | grep 8131

实测回显(空闲时无 grep 命中,退出码 1):

(无输出)
# 确认 10.89.64.0/24 网段未被其他 Docker 网络占用
docker network ls | wc -l
docker network inspect $(docker network ls -q) 2>/dev/null | grep -c '10.89.64'

实测回显(0 表示该网段空闲):

7
0
  1. 磁盘余量:镜像约 3GB + 数据卷(测试视频 + 数据库初始数据约 100MB),建议预留 20GB。

四、部署步骤(0→1 全流程)

4.1 建目录与数据卷目录

先建部署目录与四个数据卷挂载点,并把挂载点属主交给容器内运行用户(uid/gid 1000,PeerTube 官方镜像以非 root 的 peertube 用户运行):

mkdir -p /opt/peertube && cd /opt/peertube
mkdir -p docker-volume/data docker-volume/config docker-volume/db docker-volume/redis
chown -R 1000:1000 docker-volume

⚠️ 注意:docker-volume/data 与 config 是 bind 挂载进容器的,属主必须是 1000:1000。若漏掉这一步,PeerTube 启动时会因对 /data、/config 无写权限而循环报错(日志关键词 EACCES),这是官方镜像 bind 挂载部署最常见的首启失败原因。

4.2 编写 .env(初始化关键参数)

.env 供 compose 的 env_file 注入各 service,内容如下(本篇实测全量,可直接复用后改 IP 与端口):

# /opt/peertube/.env
# ---- 数据库 ----
POSTGRES_USER=peertube
POSTGRES_PASSWORD=q1w2e3r4
POSTGRES_DB=peertube
PEERTUBE_DB_USERNAME=peertube
PEERTUBE_DB_PASSWORD=q1w2e3r4
PEERTUBE_DB_SSL=false
PEERTUBE_DB_HOSTNAME=postgres

# ---- 实例网络与密钥 ----
# 对外访问的主机名/IP 与端口(必须与浏览器实际访问方式一致)
PEERTUBE_WEBSERVER_HOSTNAME=192.168.146.128
PEERTUBE_WEBSERVER_PORT=8131
PEERTUBE_WEBSERVER_HTTPS=false
# 反代/容器网络网段加入信任代理列表
PEERTUBE_TRUST_PROXY=["127.0.0.1", "loopback", "10.89.64.0/24"]
# openssl rand -hex 32 生成
PEERTUBE_SECRET=f3298ebd3872c906a33e6f0586ce44242e737d58795c6d1810583d8b7cdf9c74

# ---- 邮件(本实验未部署 postfix,仅保留必填管理员邮箱)----
PEERTUBE_SMTP_FROM=noreply@peertube.local
PEERTUBE_ADMIN_EMAIL=admin@peertube.local

# ---- 日志 ----
PEERTUBE_LOG_LEVEL=info

逐项说明:

变量取值与影响
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DBpostgres 容器的初始化三件套;必须与 PEERTUBE_DB_ 保持一致*,否则主服务连库失败
PEERTUBE_DB_HOSTNAME指向 compose 网络内的 postgres 服务名,不用 IP
PEERTUBE_WEBSERVER_HOSTNAME实例对外标识,写进视频 URL、Cookie、ActivityPub actor id;用 IP 就填 IP,用域名就填域名,与浏览器地址栏一致
PEERTUBE_WEBSERVER_PORT对外端口;本篇映射到宿主机 8131,故填 8131(不是容器内 9000)
PEERTUBE_WEBSERVER_HTTPS无 HTTPS 的内网实测填 false;生产经反代终止 TLS 时也填 false(TLS 在反代层),由 TRUST_PROXY 传递协议头
PEERTUBE_SECRET实例密钥,用于会话签名等;泄露等同于实例被接管,务必随机生成
PEERTUBE_TRUST_PROXY信任的代理网段;把 compose 网段加入后限流/日志才能取到真实客户端 IP
PEERTUBE_ADMIN_EMAIL管理员邮箱,实例配置页与通知使用

生成随机 PEERTUBE_SECRET(每次部署都应重新生成):

openssl rand -hex 32

实测回显:

f3298ebd3872c906a33e6f0586ce44242e737d58795c6d1810583d8b7cdf9c74

4.3 编写 docker-compose.yml

/opt/peertube/docker-compose.yml 全量内容如下(三件套形态,显式项目名与网段):

name: peertube-8.3.2-stack

services:
  peertube:
    image: chocobozzz/peertube:v8.3.2
    container_name: peertube-8.3.2-app
    env_file:
      - .env
    ports:
      - "8131:9000"
    volumes:
      - ./docker-volume/data:/data
      - ./docker-volume/config:/config
    depends_on:
      - postgres
      - redis
    restart: "always"
    networks:
      - peertube-net

  postgres:
    image: postgres:17-alpine
    container_name: peertube-8.3.2-postgres
    env_file:
      - .env
    volumes:
      - ./docker-volume/db:/var/lib/postgresql/data
    restart: "always"
    networks:
      - peertube-net

  redis:
    image: redis:8-alpine
    container_name: peertube-8.3.2-redis
    volumes:
      - ./docker-volume/redis:/data
    restart: "always"
    networks:
      - peertube-net

networks:
  peertube-net:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 10.89.64.0/24

要点逐项说明:

  • name: 必须显式:compose 项目名决定了网络与卷的前缀(本篇实测为 peertube-832-stack_peertube-net);不写 name 会以目录名兜底,多套部署共存时容易互相误删;
  • 固定版本 tag:chocobozzz/peertube:v8.3.2;
  • 只映射 8131:容器内 PeerTube 监听 9000,宿主机对外用 8131,.env 里 PEERTUBE_WEBSERVER_PORT=8131 与之呼应;
  • RTMP 端口(1935)未映射:官方 compose 中 "1935:1935" 服务直播推流,本篇关闭直播能力(7.4 边界),故不映射;
  • 不挂 assets 卷:官方 compose 中的 assets:/app/client/dist 命名卷是为 webserver(Nginx)静态直读准备的,本地测试形态(由 PeerTube 自身服务静态资源)官方注释明确可省略;
  • postgres 数据目录挂载点:postgres:17 挂 /var/lib/postgresql/data(官方注释明确:18+ 才改挂 /var/lib/postgresql)。

4.4 拉取镜像并启动

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

实测回显(pull 输出节选,实测首尾):

[+] Pulling 9/9
 ✔ peertube Pulled                                              118.2s
 ✔ postgres Pulled                                                3.4s
 ✔ redis Pulled                                                   2.7s

up -d 实测回显:

[+] Running 4/4
 ✔ Network peertube-832-stack_peertube-net  Created
 ✔ Container peertube-8.3.2-postgres        Started
 ✔ Container peertube-8.3.2-redis           Started
 ✔ Container peertube-8.3.2-app             Started

4.5 首次初始化与初始管理员口令

首次启动约 10~20 秒完成建库、生成 RSA 密钥对、创建 OAuth Client 与管理员。查看初始化日志:

docker logs peertube-8.3.2-app 2>&1 | head -25

实测回显(逐行照抄):

[192.168.146.128:8131] 2026-10-27 02:48:02.183 info: Using following configuration file hierarchy: /app/config/default.yaml -> /app/support/docker/production/config/production.yaml -> /app/support/docker/production/config/custom-environment-variables.yaml.
[192.168.146.128:8131] 2026-10-27 02:48:02.184 warn: SMTP is not configured so the contact form will not work.
[192.168.146.128:8131] 2026-10-27 02:48:02.239 info: i18n initialized with locales: ca-ES, en-US, eo, el-GR, ar, de-DE, eu-ES, cs-CZ, fa-IR, es-ES, zh-Hant-TW, tr-TR, zh-Hans-CN, vi-VN, uk-UA, sq, tok, sv-SE, sk-SK, th-TH, ru-RU, pt-BR, pl-PL, ro, pt-PT, ko-KR, nn, nl-NL, nb-NO, oc, kab, ka, it-IT, ja-JP, is, hr, hu-HU, gl-ES, gd, fr-FR, fi-FI
[192.168.146.128:8131] 2026-10-27 02:48:02.382 info: Database peertube is ready.
[192.168.146.128:8131] 2026-10-27 02:48:03.248 info: Init package.json in plugin directory
[2026-10-27 02:48:03.249 info: Creating a default OAuth Client.
[192.168.146.128:8131] 2026-10-27 02:48:03.254 info: Creating the administrator.
[192.168.146.128:8131] 2026-10-27 02:48:03.255 info: Generating a RSA key...
[192.168.146.128:8131] 2026-10-27 02:48:03.261 info: Client id: zwteext5xfaqgj33katpv068zwq5rt51
[192.168.146.128:8131] 2026-10-27 02:48:03.261 info: Client secret: OEL8vLaeziWhL0ayv0bVI1Blc1jI3Aq4
[192.168.146.128:8131] 2026-10-27 02:48:03.377 info: Username: root
[192.168.146.128:8131] 2026-10-27 02:48:03.377 info: User password: godoyezahayeqababuzu
[192.168.146.128:8131] 2026-10-27 02:48:03.615 info: HTTP server listening on 0.0.0.0:9000
[192.168.146.128:8131] 2026-10-27 02:48:03.615 info: Web server: http://192.168.146.128:8131

从日志中提取三个关键信息:

  1. 初始管理员:Username: root、User password: godoyezahayeqababuzu(每次部署随机生成,只在首次创建时打印一次);
  2. 配置文件层级:默认链为 default.yaml → 镜像内置 production.yaml → /config/production.yaml(你自己的覆盖层)→ 环境变量;
  3. SMTP 未配置 warn:本地形态无 postfix,联系表单不可用,属预期(生产七件套形态由 postfix 解决)。

验证服务可达:

curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://192.168.146.128:8131/
curl -s http://192.168.146.128:8131/api/v1/oauth-clients/local

实测回显:

HTTP 200
{"client_id":"zwteext5xfaqgj33katpv068zwq5rt51","client_secret":"OEL8vLaeziWhL0ayv0bVI1Blc1jI3Aq4"}

💡 说明:浏览器访问 http://192.168.146.128:8131 即见 PeerTube 首页;界面语言在右上角 Settings → Interface language 切换简体中文。

4.6 接管管理员口令(改为固定演示口令)

初始口令随机且仅打印一次,首次登录后立即改为固定演示口令 q1w2e3r4。先用初始口令取 OAuth 令牌,再以 PUT /api/v1/users/me 改密(v8 已从 PATCH 改为 PUT,用 PATCH 会得到无错误体的 400,见 9.4):

# 1) 用初始口令换访问令牌
curl -s -X POST http://192.168.146.128:8131/api/v1/users/token \
  -d 'client_id=zwteext5xfaqgj33katpv068zwq5rt51' \
  -d 'client_secret=OEL8vLaeziWhL0ayv0bVI1Blc1jI3Aq4' \
  -d 'grant_type=password&username=root&password=godoyezahayeqababuzu'

实测回显:

{"token_type":"Bearer","access_token":"1841429a3d289fb0057a7128181c49119b7c523c","refresh_token":"943ffbfb820a4257ec9d655239faf683f174d86d","expires_in":86399,"refresh_token_expires_in":2419199}
# 2) 携带 currentPassword 改密
AT=1841429a3d289fb0057a7128181c49119b7c523c
curl -s -X PUT -H "Authorization: Bearer $AT" -H 'Content-Type: application/json' \
  -d '{"currentPassword":"godoyezahayeqababuzu","password":"q1w2e3r4"}' \
  -w '\nHTTP %{http_code}\n' http://192.168.146.128:8131/api/v1/users/me

实测回显:

HTTP 204
# 3) 新口令回归验证
curl -s -X POST http://192.168.146.128:8131/api/v1/users/token \
  -d 'client_id=zwteext5xfaqgj33katpv068zwq5rt51' \
  -d 'client_secret=OEL8vLaeziWhL0ayv0bVI1Blc1jI3Aq4' \
  -d 'grant_type=password&username=root&password=q1w2e3r4' | head -c 120; echo

实测回显:

{"token_type":"Bearer","access_token":"224a6714f403e0222b7d0ebb2cc8616afc0a10cc","refresh_token":"d030bceb2dcb79f32542305fb61a44dbceef27c6"

本篇后续章节统一使用 root / q1w2e3r4 演示口令与上述 client 凭据。

4.7 上传一条视频做端到端验证

用宿主机 ffmpeg 自造一条 20 秒 720p 测试视频(画面叠加测试标注文字,正弦音轨;本素材为人工合成,非实拍):

ffmpeg -y -f lavfi -i testsrc2=size=1280x720:rate=25:duration=20 \
  -f lavfi -i sine=frequency=440:duration=20 \
  -vf "drawtext=text='PeerTube v8.3.2 Test Video A':fontsize=48:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2" \
  -c:v libx264 -preset veryfast -pix_fmt yuv420p -c:a aac -shortest peertube-test-a.mp4

经 REST API 上传(文件字段名在 v8 为 videofile,写 file 会报 MulterError: Unexpected file field,见 9.3):

AT=224a6714f403e0222b7d0ebb2cc8616afc0a10cc
curl -s -X POST -H "Authorization: Bearer $AT" http://192.168.146.128:8131/api/v1/videos/upload \
  -F "name=PeerTube v8.3.2 上传实测视频 A" -F "channelId=1" -F "category=15" -F "privacy=1" \
  -F "description=本视频由 ffmpeg 自造(testsrc2+440Hz 正弦音),用于 PeerTube v8.3.2 上传与转码实测" \
  -F "tags[]=peertube" -F "tags[]=selfhosted" \
  -F "videofile=@peertube-test-a.mp4;type=video/mp4"

实测回显:

{"video":{"id":1,"shortUUID":"b6ieXUA23uV8QHLvVt8ugP","uuid":"51b8bafe-5f89-4677-9ff9-65414027f5ad"}}

约 30 秒后查询视频详情确认转码与 HLS 已生成:

curl -s http://192.168.146.128:8131/api/v1/videos/b6ieXUA23uV8QHLvVt8ugP \
  | python3 -c "import json,sys;d=json.load(sys.stdin);print('state:',d['state']);[print('HLS',f['resolution']['id'],'p') for p in d['streamingPlaylists'] for f in p['files']]"

实测回显:

state: {'id': 1, 'label': 'Published'}
HLS 720 p

再验证 HLS 播放列表可拉取(内容节选):

curl -s http://192.168.146.128:8131/static/streaming-playlists/hls/51b8bafe-5f89-4677-9ff9-65414027f5ad/a413f0eb-e4f4-4ad1-a3c2-c1746f8f6197-master.m3u8

实测回显:

#EXTM3U
#EXT-X-VERSION:3

#EXT-X-STREAM-INF:BANDWIDTH=2508427,RESOLUTION=1280x720,FRAME-RATE=25,CODECS="avc1.64001f,mp4a.40.2"
ae319d8e-973e-47ef-8c86-ac0c06994a7d-720.m3u8

浏览器打开 http://192.168.146.128:8131/videos/watch/b6ieXUA23uV8QHLvVt8ugP 应能正常播放,播放器右下角有分辨率切换(当前仅 720p 原画质;多分辨率开启方法见《PeerTube 8.3.2 配置参数详解》)。

五、数据持久化说明

三件套形态下,全部有状态数据都落在 /opt/peertube/docker-volume/ 四个子目录:

目录容器内路径内容备份策略建议
docker-volume/data/data视频文件、HLS 分片、字幕、缩略图、头像、种子、原始文件核心资产,每日增量
docker-volume/config/config自定义 production.yaml(本篇未使用,见配置篇)纳入配置管理
docker-volume/db/var/lib/postgresql/dataPostgreSQL 全部库表核心资产,建议 pg_dump 逻辑备份 + 目录冷备
docker-volume/redis/data队列/缓存(可丢)无需备份

实测落盘验证(上传视频 A 后):

find /opt/peertube/docker-volume/data -maxdepth 1 -type d | sort

实测回显:

/opt/peertube/docker-volume/data
/opt/peertube/docker-volume/data/streaming-playlists
/opt/peertube/docker-volume/data/client-overrides
/opt/peertube/docker-volume/data/original-video-files
/opt/peertube/docker-volume/data/plugins
/opt/peertube/docker-volume/data/uploads
/opt/peertube/docker-volume/data/bin
/opt/peertube/docker-volume/data/previews
/opt/peertube/docker-volume/data/captions
/opt/peertube/docker-volume/data/avatars
/opt/peertube/docker-volume/data/storyboards
/opt/peertube/docker-volume/data/tmp
/opt/peertube/docker-volume/data/thumbnails
/opt/peertube/docker-volume/data/cache

持久化验证:docker compose down && docker compose up -d 后视频、账号、令牌全部保留(数据在 bind 目录中,容器重建不影响)。

六、环境变量表(.env 全量)

变量本篇取值说明与官方默认
POSTGRES_USERpeertubepostgres 初始化用户
POSTGRES_PASSWORDq1w2e3r4postgres 初始化密码(演示口令)
POSTGRES_DBpeertubepostgres 初始化库
PEERTUBE_DB_USERNAME / PASSWORD同上主服务连库凭据,必须与 POSTGRES_* 一致
PEERTUBE_DB_SSLfalse容器网络内不启用 TLS
PEERTUBE_DB_HOSTNAMEpostgrescompose 服务名解析
PEERTUBE_WEBSERVER_HOSTNAME192.168.146.128实例对外主机名/IP
PEERTUBE_WEBSERVER_PORT8131对外端口
PEERTUBE_WEBSERVER_HTTPSfalse是否按 HTTPS 对外
PEERTUBE_TRUST_PROXY["127.0.0.1","loopback","10.89.64.0/24"]信任的代理网段
PEERTUBE_SECRET(openssl 生成 64 位 hex)实例密钥
PEERTUBE_SMTP_FROMnoreply@peertube.local发件人地址(未配 SMTP 时不生效)
PEERTUBE_ADMIN_EMAILadmin@peertube.local管理员邮箱(必填)
PEERTUBE_LOG_LEVELinfo日志级别 debug/info/warn/error

完整的环境变量全集(含对象存储、导入代理、HTTP 代理池等)见官方 support/docker/production/config/custom-environment-variables.yaml(v8.3.2 版 137 行),《PeerTube 8.3.2 配置参数详解》有逐段解析与站内链接。

七、配置参数说明与挂载边界

7.1 配置加载层级(实测确认)

服务启动日志第一行即打印层级(见 4.5 回显):/app/config/default.yaml → /app/support/docker/production/config/production.yaml → /config/production.yaml → 环境变量。也就是说:

  1. .env 环境变量优先级最高,覆盖同名配置项(docker 形态的主配置入口);
  2. 在 docker-volume/config/(即容器 /config)放置 production.yaml 即可在环境变量之外追加任意配置项——本系列《PeerTube 8.3.2 配置参数详解》即以此方式实测(写入后日志层级会变为四段,出现 /config/production.yaml);
  3. 镜像内置的两层只读,不要改动。

7.2 HTTPS/域名形态的边界

公网生产形态把 80/443 交给官方 webserver + certbot(自动签发续期),peertube 服务本身仅在内网监听 9000,由 webserver 反代;此时 .env 改为 PEERTUBE_WEBSERVER_HOSTNAME=你的域名、PEERTUBE_WEBSERVER_PORT=443、PEERTUBE_WEBSERVER_HTTPS=true,并映射 1935 供直播推流。本篇内网实测不具备域名与 80/443 条件,如实采用 HTTP 直连形态——联邦握手、第三方嵌入播放等功能在无 HTTPS 的形态下会被浏览器/其他实例限制,属于形态边界而非故障。

7.3 直播(RTMP)边界

官方 compose 中 ports: - "1935:1935" 注释明确:Comment if you don't want to use the live feature(不用直播就注释掉)。本篇未映射 1935、管理面板直播开关保持关闭;启用直播需同时:映射 1935、管理面板开启直播、并评估 CPU 余量(官方文档对直播的资源开销有明确警示)。

7.4 邮件边界

本地三件套形态未部署 postfix,日志出现 SMTP is not configured so the contact form will not work(实测回显见 4.5),联系表单与邮件通知不可用;需要时把官方 postfix service 加回 compose 并配置 PEERTUBE_SMTP_* 即可。

八、等价 docker run(Compose 各 service 的等价命令)

便于理解 Compose 背后的等价操作(实验验证用,日常请继续用 Compose):

# 网络
docker network create --driver bridge --subnet 10.89.64.0/24 peertube-8.3.2-net

# postgres(等价于 compose 中 postgres service)
docker run -d --name peertube-8.3.2-postgres \
  --network peertube-8.3.2-net \
  -e POSTGRES_USER=peertube -e POSTGRES_PASSWORD=q1w2e3r4 -e POSTGRES_DB=peertube \
  -v /opt/peertube/docker-volume/db:/var/lib/postgresql/data \
  --restart always postgres:17-alpine

# redis(等价于 compose 中 redis service)
docker run -d --name peertube-8.3.2-redis \
  --network peertube-8.3.2-net \
  -v /opt/peertube/docker-volume/redis:/data \
  --restart always redis:8-alpine

# peertube(等价于 compose 中 peertube service)
docker run -d --name peertube-8.3.2-app \
  --network peertube-8.3.2-net \
  -p 8131:9000 \
  --env-file /opt/peertube/.env \
  -v /opt/peertube/docker-volume/data:/data \
  -v /opt/peertube/docker-volume/config:/config \
  --restart always chocobozzz/peertube:v8.3.2

九、常用运维命令

9.1 状态与日志

docker compose ps                     # 三容器状态
docker logs -f peertube-8.3.2-app     # 主服务日志跟随
docker compose restart peertube       # 仅重启主服务(改 .env 后必须重建而非 restart,见下)

实测 docker compose ps --format '{{.Name}} {{.Status}}' 回显:

peertube-8.3.2-app Up 30 seconds
peertube-8.3.2-postgres Up 30 seconds
peertube-8.3.2-redis Up 30 seconds

⚠️ 注意:修改 .env 后用 docker compose up -d peertube 让 Compose 检测环境差异并重建容器;restart 不会加载新环境变量(本篇实测曾因此误判配置未生效)。

9.2 升级

固定 tag 策略下的升级三步(以 v8.3.2 → 未来版本为例,官方文档另有 PostgreSQL 大版本升级专章,升级前必读):

cd /opt/peertube
# 1) 备份数据目录与数据库
tar czf peertube-data-$(date +%F).tgz docker-volume/data
docker exec peertube-8.3.2-postgres pg_dump -U peertube peertube > peertube-db-$(date +%F).sql
# 2) 改 compose 内镜像 tag 后重建
docker compose pull && docker compose up -d
# 3) 跟随日志确认迁移执行完毕
docker logs -f peertube-8.3.2-app

9.3 卸载与清理

cd /opt/peertube
docker compose down            # 停止并删除容器与网络(保留数据目录)
docker compose down -v         # 同时删除命名卷(本形态数据全在 bind 目录,-v 影响有限)
rm -rf /opt/peertube           # 彻底清理(含全部数据,慎用)
docker rmi chocobozzz/peertube:v8.3.2 postgres:17-alpine redis:8-alpine

十、常见问题(FAQ)

Q1:启动报 invalid pool request: Pool overlaps with other one on this address space,网络创建失败。 本篇实测遇到过:10.89.63.0/24 被服务器上其他编排占用。先盘点全部网段,换一个空闲网段写进 compose 的 ipam.config.subnet 与 .env 的 PEERTUBE_TRUST_PROXY:

for n in $(docker network ls --format '{{.Name}}'); do
  docker network inspect $n --format '{{.Name}} {{range .IPAM.Config}}{{.Subnet}}{{end}}'
done | grep 10.89

实测回显(冲突时刻):

audiobookshelf-2.37.2-net 10.89.60.0/24
simplex-704-stack_simplex-7.0.4-net 10.89.62.0/24
freeradius-net 10.89.56.0/24
nsupdate-info-net 10.89.59.0/24
simplex-net 10.89.61.0/24
openldap-net 10.89.63.0/24

改用 10.89.64.0/24 后启动成功(up -d 回显见 4.4)。

Q2:浏览器能打开首页,但登录后各种异常/视频 URL 域名不对。 检查三件套:PEERTUBE_WEBSERVER_HOSTNAME 必须与浏览器地址栏主机一致(用 IP 填 IP);PEERTUBE_WEBSERVER_PORT 必须与对外端口一致(本篇 8131,不是容器内 9000);改完 .env 必须 docker compose up -d peertube 重建容器(见 9.1 注意)。这三项是官方 .env 注释中 If you test PeerTube in local 段强调的对应关系。

Q3:API 上传报 {"type":"...Errors/MulterError","detail":"Unexpected file field","status":500,"code":"MulterError"}。 v8 上传表单的文件字段名是 videofile,不是 file(本篇实测踩坑,4.7 已用正确字段)。另注意 v8 上传除 legacy 多部分表单外还有 /videos/upload/resumable 断点续传端点,大文件推荐后者。

Q4:PATCH /api/v1/users/me 返回 400 且响应体为空。 v8 已把"更新我的资料/密码"路由从 PATCH 改为 PUT(本篇实测:PATCH 落到服务端兜底处理器,日志出现 API express handler not found: bad PeerTube request for PATCH - /api/v1/users/me)。改密须带 currentPassword 字段,完整流程见 4.6。

Q5:容器反复重启,日志报 /data 或 /config 权限错误。 bind 挂载目录属主不是 1000:1000(见 4.1 的 chown 步骤)。修复后 docker compose restart peertube。

Q6:首次启动日志没有打印初始口令? 初始口令只在首次创建管理员时打印一次(日志关键词 User password:)。错过可用运维脚本重置(node dist/scripts/reset-password.js --help 用法见《PeerTube 8.3.2 常用 CLI 命令详解》),或删库重建(首次部署阶段才可接受)。

十一、参考链接