SentryShot v0.3.11 Docker Compose 部署指南
在 Linux 服务器上用 Docker Compose 部署 SentryShot v0.3.11 的完整实测流程:首启配置生成、auth_none 引导建号、接入 RTSP 摄像头并完成录像与回放验证。
SentryShot v0.3.11 Docker Compose 部署指南
本文给出在 Linux 服务器上用 Docker Compose 部署 SentryShot v0.3.11 的完整流程:首次启动的配置文件生成、创建管理员账号、接入摄像头并用 ffmpeg 合成的测试流完成取流与录像验证。全程命令均在 Debian 12 服务器实测通过(2026-10-30)。
前置阅读:《SentryShot 介绍与选型指南》(含摄像头硬件前置要求)。
一、环境信息
- 操作系统:Debian 12(宿主机),Docker Engine 27+ 与 Docker Compose v2(
docker compose version可用)。 - SentryShot 版本:v0.3.11(2026-04-27 发布),软件包来源
codeberg.org/sentryshot/sentryshot:v0.3.11(Apache-2.0,主仓库在 Codeberg)。 - 测试流组件:mediamtx 1.21.3(
bluenviron/mediamtx:1.21.3-ffmpeg,自带 ffmpeg)。 - 端口规划:SentryShot 服务端固定监听 2020,本文映射宿主机 8247;mediamtx 监听 8554,映射宿主机 8148。宿主端口需未被占用(
ss -ltn | grep -E '8247|8148'检查;本文实测时 8147 被宿主上其他进程占用,改用 8247,读者按空闲端口自行调整)。 - 数据目录:
/opt/sentryshot/stack/(配置与录像均在此目录下持久化)。 - 真实摄像头场景只需第 1、3、4 步 + 第 5 步里把流地址换成摄像头 RTSP 地址;模拟流服务(mediamtx + ffmpeg 推流)可在验证完成后移除。
二、目录与文件准备
创建工作目录并写入三个文件:
mkdir -p /opt/sentryshot/stack/configs
mkdir -p /opt/sentryshot/stack/storage
cd /opt/sentryshot/stack
docker-compose.yml(栈内三个服务:SentryShot 本体、mediamtx 流媒体服务、ffmpeg 测试流推流服务):
name: sentryshot-0.3.11-stack
services:
sentryshot:
image: codeberg.org/sentryshot/sentryshot:v0.3.11
container_name: sentryshot-0.3.11-web
restart: unless-stopped
ports:
- "8247:2020"
environment:
- TZ=Asia/Shanghai
volumes:
- ./configs:/app/configs
- ./storage:/app/storage
mediamtx:
image: bluenviron/mediamtx:1.21.3-ffmpeg
container_name: sentryshot-0.3.11-mediamtx
restart: unless-stopped
ports:
- "8148:8554"
volumes:
- ./mediamtx.yml:/mediamtx.yml
camera:
image: bluenviron/mediamtx:1.21.3-ffmpeg
container_name: sentryshot-0.3.11-camera
restart: unless-stopped
volumes:
- /usr/share/fonts/truetype/dejavu:/fonts:ro
entrypoint: >-
ffmpeg -re -f lavfi -i testsrc2=size=1280x720:rate=25
-vf "drawtext=fontfile=/fonts/DejaVuSansMono-Bold.ttf:text='CAM1 %{localtime}':x=16:y=16:fontsize=40:fontcolor=white:box=1:boxcolor=black@0.5"
-c:v libx264 -preset veryfast -tune zerolatency -g 50 -pix_fmt yuv420p
-f rtsp -rtsp_transport tcp rtsp://mediamtx:8554/cam1
networks:
default:
name: sentryshot-0.3.11-net
ipam:
config:
- subnet: 10.89.67.0/24
说明:
camera服务用 ffmpeg 的testsrc2源合成带时间戳的 720p 测试画面并推到 mediamtx 的cam1路径,充当一台"模拟摄像头";drawtext需要字体文件,故只读挂载了宿主机的 DejaVu 字体目录(若路径不同先find /usr/share/fonts -name '*.ttf'确认)。真实摄像头接入时把sourcertsp.mainStream换成摄像头地址即可,camera与mediamtx两个服务可删除。
mediamtx.yml(接收推流的最小配置):
logLevel: info
paths:
cam1:
三、首次启动与配置文件生成
SentryShot 首次启动有一个必须知道的行为:检测不到配置文件时,生成默认 sentryshot.toml 后立即退出,随后因为默认配置里两个认证插件都未启用而继续退出,需要手工编辑后再启动。完整过程如下。
第一次 docker compose up -d:
cd /opt/sentryshot/stack
docker compose up -d
实测回显:
Network sentryshot-0.3.11-net Creating
Network sentryshot-0.3.11-net Created
Container sentryshot-0.3.11-web Creating
Container sentryshot-0.3.11-mediamtx Creating
Container sentryshot-0.3.11-camera Creating
Container sentryshot-0.3.11-web Created
Container sentryshot-0.3.11-mediamtx Created
Container sentryshot-0.3.11-camera Created
Container sentryshot-0.3.11-camera Starting
Container sentryshot-0.3.11-web Starting
Container sentryshot-0.3.11-mediamtx Starting
Container sentryshot-0.3.11-camera Started
Container sentryshot-0.3.11-web Started
Container sentryshot-0.3.11-mediamtx Started
查看 SentryShot 服务日志,会看到它生成默认配置后退出:
docker logs sentryshot-0.3.11-web 2>&1 | head -3
Generating '/app/configs/sentryshot.toml' and exiting..
此时 configs/sentryshot.toml 已自动生成。由于默认配置中 auth_basic 与 auth_none 都是 enable = false,进程重启后会再次退出并提示启用认证插件(restart: unless-stopped 会不断重试):
docker logs sentryshot-0.3.11-web 2>&1 | tail -1
Please enable one of the authentication plugins in the generated sentryshot.toml file. See docs for more info
按官方安装文档指引,编辑 configs/sentryshot.toml,临时启用 auth_none(免认证,仅用于创建首个账号,创建后切回):
# No authentication.
[[plugin]]
name = "auth_none"
enable = true
再次启动并确认三个服务都在运行:
docker compose up -d
docker compose ps --format 'table {{.Name}}\t{{.Status}}\t{{.Ports}}'
NAME STATUS PORTS
sentryshot-0.3.11-camera Up 4 minutes
sentryshot-0.3.11-mediamtx Up 4 minutes 0.0.0.0:8148->8554/tcp, [::]:8148->8554/tcp
sentryshot-0.3.11-web Up 49 seconds 0.0.0.0:8247->2020/tcp, [::]:8247->2020/tcp
docker logs sentryshot-0.3.11-web --since 1m 2>&1 | head -5
[INFO] App: loading plugin auth_basic
[INFO] App: loading plugin motion
[INFO] App: loading plugin thumb_scale
[DEBUG] App: TZ=Asia/Shanghai
[INFO] App: Serving app on port 2020
看到 Serving app on port 2020 即服务就绪。configs/accounts.json 此时尚不存在,会在创建第一个账号时生成。
四、创建管理员账号(首次必做)
auth_none 已启用,此时无需认证即可调用建号接口。写请求(PUT)需要携带 CSRF token,token 从 GET /api/account/my-token 获取:
TOKEN=$(curl -s http://127.0.0.1:8247/api/account/my-token)
echo $TOKEN
btIFh54xNQF64esB071BAe452EgjOPBR
创建管理员账号(用户名 admin、密码 q1w2e3r4;账号 ID 为 16 位字符串,字符集为小写字母与数字 2-9,不含 0/1/i/l/o):
curl -s -w '\nHTTP %{http_code}\n' -X PUT http://127.0.0.1:8247/api/account \
-H "Content-Type: application/json" \
-H "X-CSRF-TOKEN: $TOKEN" \
-d '{"id":"a2b3c4d5e6f7g8h9","username":"admin","isAdmin":true,"plainPassword":"q1w2e3r4"}'
HTTP 201
PUT 成功返回 201、响应体为空。用列表接口确认账号已存在:
curl -s http://127.0.0.1:8247/api/accounts
{"a2b3c4d5e6f7g8h9":{"id":"a2b3c4d5e6f7g8h9","username":"admin","isAdmin":true}}
同时 configs/accounts.json 落盘,密码以 argon2id 哈希保存:
{
"a2b3c4d5e6f7g8h9": {
"id": "a2b3c4d5e6f7g8h9",
"username": "admin",
"password": "$argon2id$v=19$m=19456,t=2,p=1$yd8y1jQGF76oIp+7PP7Reg$p67eVK09hd2P4mNm5IBDmq11LBEiHFFLrS0DcMmzxFo",
"isAdmin": true
}
}
三类常见错误实测(便于排障对照):
# ID 长度不足 16 位
curl -s -w '\nHTTP %{http_code}\n' -X PUT http://127.0.0.1:8247/api/account \
-H "Content-Type: application/json" -H "X-CSRF-TOKEN: $TOKEN" \
-d '{"id":"zzzz","username":"x","isAdmin":true,"plainPassword":"q1w2e3r4"}'
Failed to deserialize the JSON body into the target type: id: expected length 16, got 4 at line 1 column 12
HTTP 422
# ID 含字符集之外的字符('1' 不在允许字符集内)
curl -s -w '\nHTTP %{http_code}\n' -X PUT http://127.0.0.1:8247/api/account \
-H "Content-Type: application/json" -H "X-CSRF-TOKEN: $TOKEN" \
-d '{"id":"a1b2c3d4e5f60718","username":"t","isAdmin":false,"plainPassword":"q1w2e3r4"}'
Failed to deserialize the JSON body into the target type: id: invalid character: '1' at line 1 column 24
HTTP 422
# Basic 认证开启后,写请求缺 X-CSRF-TOKEN 请求头
curl -s -w '\nHTTP %{http_code}\n' -u admin:q1w2e3r4 -X PUT http://127.0.0.1:8247/api/account \
-H "Content-Type: application/json" \
-d '{"id":"b2c3d4f5g6h7j8k9","username":"temp1","isAdmin":false,"plainPassword":"q1w2e3r4"}'
Invalid CSRF-token
HTTP 401
切回 Basic 认证:编辑 configs/sentryshot.toml,把 auth_none 的 enable 改回 false、auth_basic 改为 true,再次启动。验证未认证被拒、认证通过:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8247/live
curl -s -o /dev/null -w '%{http_code}\n' -u admin:q1w2e3r4 http://127.0.0.1:8247/live
401
200
浏览器访问 http://服务器IP:8247/live 弹出登录框,输入 admin/q1w2e3r4 即可进入直播页。
五、接入摄像头
模拟摄像头(本栈演练)
先确认测试流已在推流(在 camera 服务里用 ffprobe 探测 mediamtx):
docker compose exec camera ffprobe -v error -rtsp_transport tcp \
-i rtsp://mediamtx:8554/cam1 \
-show_entries stream=codec_name,width,height,avg_frame_rate -of default=noprint_wrappers=1
codec_name=h264
width=1280
height=720
avg_frame_rate=25/1
添加到 SentryShot
通过 API 添加名为 cam2 的摄像头,开启持续录像(接口细节见 《SentryShot v0.3.11 HTTP API 使用详解》):
TOKEN=$(curl -s -u admin:q1w2e3r4 http://127.0.0.1:8247/api/account/my-token)
curl -s -w '\nHTTP %{http_code}\n' -u admin:q1w2e3r4 -X PUT http://127.0.0.1:8247/api/monitor \
-H "Content-Type: application/json" \
-H "X-CSRF-TOKEN: $TOKEN" \
-d '{"id":"cam2","name":"cam2","enable":true,"alwaysRecord":true,"videoLength":1,"source":"rtsp","sourcertsp":{"protocol":"tcp","mainStream":"rtsp://mediamtx:8554/cam1"}}'
HTTP 200
说明:PUT 同一 ID 时是全量覆盖(upsert),返回 201(新建)或 200(更新)都属正常。请求体里未携带的字段(如
motion移动侦测段)会被清空,需要时应在请求体中一并给出。
真实摄像头把 mainStream 换成如 rtsp://用户名:密码@192.168.1.64:554/stream1 即可;协议建议 tcp。
服务端日志出现取流成功标志:
[DEBUG] cam2: Monitor: (main) rtsp source: using h264 video stream
[INFO] cam2: Monitor: recorder: starting recording: 2026-10-30_01-26-03_cam2
六、验证录像与回放
等 1~2 分钟(videoLength: 1 表示按 1 分钟粒度入库,参数语义见 《SentryShot v0.3.11 配置参数详解》),检查存储目录与录像查询:
ls /opt/sentryshot/stack/storage/recordings/2026/10/30/cam2/ | head -8
输出节选(实测首尾,共 115 个文件):
2026-10-30_00-26-08_cam2.jpeg
2026-10-30_00-26-08_cam2.json
2026-10-30_00-26-08_cam2.mdat
2026-10-30_00-26-08_cam2.meta
2026-10-30_00-33-12_cam2.jpeg
2026-10-30_00-33-12_cam2.json
2026-10-30_00-33-12_cam2.mdat
2026-10-30_00-33-12_cam2.meta
每个录像段落四个文件:.mdat 视频数据、.meta 元数据、.json 时间信息、.jpeg 缩略图。
查询录像段落(recording-id 传一个"未来"的时间串表示从头查,include-data 必传):
curl -s -u admin:q1w2e3r4 \
"http://127.0.0.1:8247/api/recording/query?recording-id=2099-01-01_00-00-00_x&limit=3&reverse=false&include-data=true"
[{"state":"active","id":"2026-10-30_01-08-23_cam2","data":{"start":1793322503575455555,"end":1793322514575455555,"events":[]}},{"state":"finalized","id":"2026-10-30_01-07-21_cam2","data":{"start":1793322441575455555,"end":1793322503575455555,"events":[]}},{"state":"finalized","id":"2026-10-30_01-06-19_cam2","data":{"start":1793322379575455555,"end":1793322441575455555,"events":[]}}]
回放验证(下载一段完整录像 MP4,/api/recording/video/<录像ID>):
curl -s -u admin:q1w2e3r4 -o /dev/null -w '%{http_code} %{size_download}\n' \
"http://127.0.0.1:8247/api/recording/video/2026-10-30_00-41-06_cam2"
200 32354736
缩略图接口同样可用:
curl -s -u admin:q1w2e3r4 -o /dev/null -w '%{http_code} %{size_download}\n' \
"http://127.0.0.1:8247/api/recording/thumbnail/2026-10-30_00-41-06_cam2"
200 52694
浏览器侧:/live 页可看到摄像头实时画面,/recordings 页按日期浏览录像段落并在线播放。至此部署闭环完成。
七、常用运维命令
cd /opt/sentryshot/stack
docker compose ps # 查看三个服务状态
docker logs sentryshot-0.3.11-web --since 10m # 最近 10 分钟服务日志
docker compose restart sentryshot # 修改 toml 配置后重启生效
docker compose down # 停止并移除编排(configs/ 与 storage/ 数据保留)
docker compose up -d # 重新拉起
八、排障实录
| 现象 | 原因与处理 |
|---|---|
首次 up 后服务反复重启 | 首次启动生成默认配置即退出;默认配置两个认证插件均为 enable = false,按第三章手工启用 auth_none(或 auth_basic)后再启动 |
PUT /api/account 返回 401,响应体 Invalid CSRF-token | 建号、改配置类写请求必须带 X-CSRF-TOKEN 请求头,token 从 GET /api/account/my-token 获取 |
| 建号返回 422 | 账号 ID 必须 16 位、字符集为小写字母与数字 2-9(0/1/i/l/o 不可用);报错原文见第四章负样本 |
| 摄像头添加后无画面 | 服务端日志无 using h264 video stream 行时,检查摄像头是否输出 H.264、地址端口是否可达;SentryShot 仅接受 H.264 视频轨 |
| 修改摄像头配置后不生效 | PUT /api/monitor 保存后需调用 POST /api/monitor/restart?id=<id>(同样带 CSRF token)才会按新配置重建取流与录制 |
| 修改摄像头配置后移动侦测丢失 | PUT /api/monitor 是全量覆盖,请求体漏掉 motion 段会把已有移动侦测配置清空,需要原样带回 |
ffmpeg drawtext 启动失败 | 字体路径不存在,确认宿主机字体文件并保持只读挂载路径一致 |
| 宿主端口映射后无法访问 | 检查宿主端口是否被其他进程占用(`ss -ltnp |
九、延伸阅读
- 《SentryShot v0.3.11 配置参数详解》:
sentryshot.toml、账号文件与摄像头字段逐项说明。 - 《SentryShot v0.3.11 HTTP API 使用详解》:账号/摄像头/录像/直播全部接口实测。