motionEye 0.44.0 Docker Compose 部署指南
motionEye 0.44.0 Docker Compose 部署指南
目标:在一台 Ubuntu 22.04 服务器上用 Docker Compose 从零部署 motionEye 0.44.0 NVR,并在无真实摄像头环境下用 ffmpeg 生成的 MJPEG 模拟网络摄像头完成「接入 → 实时画面 → 运动侦测 → 录像 → 快照 → 时间轴」全链路实测。所有命令与回显均为部署实测过程的真实记录。
一、部署目标与方案设计
1.1 目标拓扑
本次部署共启动两个容器:motionEye 服务本体,以及一路 ffmpeg 模拟网络摄像头源。整体拓扑如下:
┌──────────────────────┐ ┌────────────────────────────────┐
│ motioneye-0.44.0-camsrc │ MJPEG │ motioneye-0.44.0-nvr │
│ ffmpeg testsrc 模拟源 │ ─────► │ motionEye 0.44.0 + motion 4.7.1 │
│ 容器内 8090 端口 │ 容器网 │ 容器内 8765 端口 │
└──────────┬───────────┘ └───────────────┬────────────────┘
│ 8151→8090(宿主验证用) │ 8150→8765
▼ ▼
宿主 8151 端口(可直连看流) 用户浏览器 http://<宿主IP>:8150
设计要点:motionEye 访问摄像头源走容器网络内网(motioneye-0.44.0-camsrc:8090),不绕行宿主端口;8151→8090 映射仅供部署者从宿主侧验证流是否正常,真实摄像头接入时此容器整体省略。
1.2 端口、目录与网络规划
| 项 | 取值 | 说明 |
|---|---|---|
| Web 端口 | 宿主 8150 → 容器 8765 | motionEye 官方镜像内固定监听 8765,宿主侧按需重映射 |
| 模拟源端口 | 宿主 8151 → 容器 8090 | ffmpeg mpjpeg 流,仅验证用 |
| 配置目录 | ./config → /etc/motioneye | motioneye.conf、motion.conf、camera-N.conf |
| 媒体目录 | ./media → /var/lib/motioneye | 录像/抓图落盘 |
| 容器网络 | motioneye-0.44.0-net(bridge,10.89.60.0/24) | 专用网络隔离摄像头源流量 |
1.3 硬件前置说明
⚠️ 硬件前置:motionEye 是纯软件 NVR,必须接入外部视频源才能工作。真实环境的三类常见接入(网络摄像机 RTSP、USB 摄像头 V4L2、远端 motionEye 互联)在部署层面与本文完全一致,唯一差别是添加摄像头时填写的流地址与协议。本文环境无真实摄像头,全程使用 ffmpeg testsrc 生成的 MJPEG 网络摄像头模拟——它输出的测试画面持续变化,恰好能稳定触发运动侦测,适合把整条链路验证完整;但画质(640x480)、编码(MJPEG 帧序列)与真实硬件(H.264/H.265)不同,测得的 CPU/带宽数据不能直接外推到真实摄像头。
二、环境准备
2.1 Docker 环境检查
docker --version && docker compose version
实测回显:
Docker version 27.5.1, build 9f9e405
Docker Compose version v2.38.2
2.2 目录规划
约定部署根目录为 motioneye/,其下三个子目录分工如下(config/ 与 media/ 由 bind mount 挂进容器,数据全部留在宿主):
mkdir -p motioneye/{compose,config,media} && find motioneye -maxdepth 1 -type d
实测回显:
motioneye
motioneye/compose
motioneye/config
motioneye/media
2.3 获取官方镜像
docker pull ghcr.io/motioneye-project/motioneye:0.44.0
实测回显(本地已有同版本镜像时为 up to date;首次拉取会逐层显示下载进度):
0.44.0: Pulling from motioneye-project/motioneye
Digest: sha256:7da31d62e6c46ee8b61280f872801e429ec6f3db81bb23aca11c83863939cade
Status: Image is up to date for ghcr.io/motioneye-project/motioneye:0.44.0
ghcr.io/motioneye-project/motioneye:0.44.0
💡 该官方镜像内已集成 motionEye 0.44.0、motion 4.7.1 与 ffmpeg 7.1.4,实测核验:
docker exec motioneye-0.44.0-nvr meyectl -v && docker exec motioneye-0.44.0-nvr motion -h | head -1 && docker exec motioneye-0.44.0-nvr ffmpeg -version | head -1
实测回显:
motionEye 0.44.0
motion Version 4.7.1, Copyright 2000-2024 Jeroen Vreeken/Folkert van Heusden/Kenneth Lavrsen/Motion-Project maintainers
ffmpeg version 7.1.4-0+deb13u1 Copyright (c) 2000-2026 the FFmpeg developers
三、编写 docker-compose.yml
3.1 完整文件
在 compose/ 目录下创建 docker-compose.yml(全文照抄即可,见 3.2 的逐段解说):
name: motioneye-0.44.0-stack
services:
motioneye:
image: ghcr.io/motioneye-project/motioneye:0.44.0
container_name: motioneye-0.44.0-nvr
restart: unless-stopped
ports:
- "8150:8765"
environment:
- TZ=Asia/Shanghai
volumes:
- ../config:/etc/motioneye
- ../media:/var/lib/motioneye
networks:
- motioneye-0.44.0-net
camsrc:
image: ghcr.io/motioneye-project/motioneye:0.44.0
container_name: motioneye-0.44.0-camsrc
restart: unless-stopped
entrypoint: ["/bin/sh", "-c"]
command:
- >
ffmpeg -hide_banner -re -f lavfi
-i "testsrc=size=640x480:rate=15"
-c:v mjpeg -q:v 6
-f mpjpeg -boundary_tag motioneye -listen 1 http://0.0.0.0:8090/cam-a
ports:
- "8151:8090"
networks:
- motioneye-0.44.0-net
networks:
motioneye-0.44.0-net:
name: motioneye-0.44.0-net
driver: bridge
ipam:
config:
- subnet: 10.89.60.0/24
3.2 逐段解说
name: motioneye-0.44.0-stack:固定 compose 项目名,避免多套部署互相干扰;container_name同理逐个固定,便于日志与命令定位。motioneye服务:即 NVR 本体。ports把容器内固定监听的 8765 重映射到宿主 8150(按宿主空闲端口自行调整);volumes两条 bind mount 把配置与媒体数据全部留在宿主目录,容器可随时重建。camsrc服务:复用 motionEye 官方镜像(省一份下载,且镜像内自带 ffmpeg),仅以 entrypoint 覆盖的方式跑一条 ffmpeg 命令充当摄像头源。-re让画面按真实时间节奏输出(模拟摄像头帧率);testsrc是 ffmpeg 内置测试画面(滚动的彩条与秒计数器);-f mpjpeg -boundary_tag motioneye -listen 1使 ffmpeg 作为 HTTP 服务器在 8090 端口提供 multipart MJPEG 流,流路径为/cam-a。networks:显式创建专用 bridge 网络,并以ipam固定子网段(本文为 10.89.60.0/24),多套监控栈共存时可按网段区分。真实摄像头环境直接删除整个camsrc服务即可,motionEye 容器访问局域网内 IPC 的 RTSP 地址不受影响。
3.3 关键参数速查
| 参数 | 位置 | 作用 |
|---|---|---|
8150:8765 | motioneye.ports | Web 界面入口,宿主侧访问 http://<宿主IP>:8150 |
TZ=Asia/Shanghai | motioneye.environment | 媒体目录按日期分组使用时区,不设则 UTC 分组 |
../config:/etc/motioneye | motioneye.volumes | 持久化全部配置文件 |
../media:/var/lib/motioneye | motioneye.volumes | 持久化录像/抓图媒体 |
restart: unless-stopped | 两个服务 | 容器异常退出自动拉起(模拟源靠它自愈,见 10.4) |
四、启动服务与初始化
4.1 启动并确认状态
cd compose && docker compose up -d
实测回显(首次创建为 Creating/Created + Starting/Started 序列;已存在时容器显示 Running):
Network motioneye-0.44.0-net Creating
Network motioneye-0.44.0-net Created
Container motioneye-0.44.0-nvr Creating
Container motioneye-0.44.0-camsrc Creating
Container motioneye-0.44.0-nvr Created
Container motioneye-0.44.0-camsrc Created
Container motioneye-0.44.0-camsrc Starting
Container motioneye-0.44.0-nvr Starting
Container motioneye-0.44.0-camsrc Started
Container motioneye-0.44.0-nvr Started
docker compose ps
实测回显:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
motioneye-0.44.0-camsrc ghcr.io/motioneye-project/motioneye:0.44.0 "/bin/sh -c 'ffmpeg …" camsrc Less than a second ago Up Less than a second 8765/tcp, 0.0.0.0:8151->8090/tcp, [::]:8151->8090/tcp
motioneye-0.44.0-nvr ghcr.io/motioneye-project/motioneye:0.44.0 "/entrypoint.sh" motioneye Less than a second ago Up Less than a second 0.0.0.0:8150->8765/tcp, [::]:8150->8765/tcp
4.2 服务日志检查
docker logs motioneye-0.44.0-nvr 2>&1 | head -6
实测回显:
configure_logging cmd motioneye: False
configure logging to file: None
INFO: hello! this is motionEye server 0.44.0
INFO: cleanup started
INFO: wsswitch started
INFO: tasks started
cleanup/wsswitch/tasks 三个后台任务就绪即代表服务启动完成。确认 Web 端口可访问:
curl -s -o /dev/null -w 'http_code=%{http_code}\n' http://127.0.0.1:8150/
实测回显:
http_code=200
4.3 首次登录与设置密码(实测实录)
motionEye 首次访问时 admin 用户无密码,此时未认证的登录探测返回 unauthorized:
curl -s http://127.0.0.1:8150/login/
实测回显:
{"error": "unauthorized", "prompt": true}
浏览器打开 http://<宿主IP>:8150 会弹出登录对话框。首次必须以空密码登录,服务端返回强制改密标记:
curl -s -c cookies.txt -X POST -d 'username=admin&password=' http://127.0.0.1:8150/login/
实测回显:
{"user": "admin", "force_password_change": true}
按界面提示分别设置管理员(admin)与普通用户(user)的密码后重新登录。本文演示统一使用 admin / q1w2e3r4。密码不落明文,以 argon2id 哈希写进宿主 config/motion.conf:
grep '^# @admin_password' config/motion.conf | cut -c1-60
实测回显:
# @admin_password $argon2id$v=19$m=65536,t=3,p=4$E3Xs/FuOAq5sh
⚠️ 注意:0.44.0 在「未设密码」状态下提交非空密码会直接 400(本节实测见排障实录 10.1),不要在首次登录框里预填新密码,先空密码进入再按向导设置。
4.4 验证会话与配置可读
用新密码重新登录并读取全局配置列表:
curl -s -c cookies.txt -X POST -d 'username=admin&password=q1w2e3r4' http://127.0.0.1:8150/login/ && echo && curl -s -b cookies.txt http://127.0.0.1:8150/config/list/
实测回显:
{"user": "admin"}
{"cameras": [{"name": "Camera1", "enabled": true, "id": 1, "proto": "mjpeg", "url": "http://motioneye-0.44.0-camsrc:8090/cam-a", "admin_only": false, "actions": []}, {"name": "Camera2", "enabled": true, "id": 2, "admin_only": false, "auto_brightness": false, "framerate": 2, "rotation": 0, ...
返回了已添加的两路摄像头摘要(Camera1 简单 MJPEG 形态带 proto/url;Camera2 为 motion 本地摄像头,带 framerate/rotation 等完整界面配置),会话与配置读取正常。
五、模拟网络摄像头源(无摄像头环境)
5.1 模拟源方案说明
真实摄像头接入 motionEye 的三种主流形态(RTSP/H.264、HTTP/MJPEG、V4L2)中,HTTP MJPEG 是「一条 ffmpeg 命令就能凭空造出一台摄像头」的最简形态:ffmpeg 的 lavfi 虚拟设备生成 testsrc 测试画面,转成 MJPEG 帧序列后以 mpjpeg(multipart JPEG over HTTP)格式对外提供。motion 的 netcam 模块原生消费这种流,motionEye 界面上它就是一台标准的「网络摄像头」。
5.2 容器内源进程核验
官方镜像内无 ps 工具,用 /proc 命令行核验 ffmpeg 源进程:
docker exec motioneye-0.44.0-camsrc sh -c 'for p in /proc/[0-9]*/cmdline; do tr "\0" " " < $p; echo; done' | grep ffmpeg | head -1
实测回显:
ffmpeg -hide_banner -re -f lavfi -i testsrc=size=640x480:rate=15 -c:v mjpeg -q:v 6 -f mpjpeg -boundary_tag motioneye -listen 1 http://0.0.0.0:8090/cam-a
5.3 从宿主验证流可用
curl -s -m 3 -D - http://127.0.0.1:8151/cam-a -o /dev/null
实测回显:
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Transfer-Encoding: chunked
抓取流前 120 字节确认 MJPEG 帧结构(--motioneye 边界 + image/jpeg 子段):
curl -s -m 2 http://127.0.0.1:8151/cam-a | head -c 120 | od -c | head -4
实测回显:
0000000 - - m o t i o n e y e \r \n C o n
0000020 t e n t - t y p e : i m a g e
0000040 / j p e g \r \n C o n t e n t - l
0000060 e n g t h : 1 6 8 7 7 \r \n \r \n
流结构正确,可以接入 motionEye。
六、添加摄像头(两种形态实测)
6.1 形态一:简单 MJPEG 摄像头(仅转发画面)
Web 界面添加对话框里选「简单 MJPEG 摄像头」并填 http://motioneye-0.44.0-camsrc:8090/cam-a(容器网络内直连,无认证)。命令行等价操作:
curl -s -b cookies.txt -H 'Content-Type: application/json' \
-d '{"proto":"mjpeg","scheme":"http","host":"motioneye-0.44.0-camsrc","port":8090,"path":"/cam-a"}' \
http://127.0.0.1:8150/config/add/ | head -c 120
实测回显:
{"name": "Camera1", "enabled": true, "id": 1, "admin_only": false, "auto_brightness": false, ...
注意这种形态 motionEye 不把画面交给 motion 引擎,仅在自身 Web 服务里转发 MJPEG,因此没有运动侦测/录像/抓图能力(实测差异见 7.1)。
6.2 形态二:网络摄像头(motion 引擎接入,全功能)
Web 界面添加对话框里选「网络摄像头」,协议选 http(源为 RTSP 时选 rtsp:// 并填 IPC 地址)。命令行等价操作:
curl -s -b cookies.txt -H 'Content-Type: application/json' \
-d '{"proto":"netcam","scheme":"http","host":"motioneye-0.44.0-camsrc","port":8090,"path":"/cam-a","username":"","password":""}' \
http://127.0.0.1:8150/config/add/ | head -c 120
实测回显:
{"name": "Camera2", "enabled": true, "id": 2, "admin_only": false, "auto_brightness": false, ...
添加成功后 motionEye 自动拉起 motion 守护进程(容器内精简镜像无 ps,读内核进程表核验),宿主 config/ 下同步生成 motion.conf 与 camera-2.conf:
docker exec motioneye-0.44.0-nvr sh -c 'for p in /proc/[0-9]*/cmdline; do tr "\0" " " < $p; echo; done' | grep '/usr/bin/motion' && ls config/
实测回显:
/usr/bin/motion -n -c /etc/motioneye/motion.conf -d 5
camera-1.conf
camera-2.conf
motion.conf
motioneye.conf
motion 日志确认摄像头线程加载(服务启动即重读配置文件并初始化 motion):
docker exec motioneye-0.44.0-nvr tail -5 /var/log/motioneye/motion.log
实测回显:
[0:motion] [NTC] [ALL] config_camera: Processing camera config file camera-2.conf
[0:motion] [NTC] [ALL] motion_startup: Logging to syslog
[0:motion] [NTC] [ALL] motion_startup: Motion 4.7.1 Started
[0:motion] [NTC] [ALL] motion_startup: Using default log type (ALL)
[0:motion] [NTC] [ALL] motion_startup: Using log type (ALL) log level (WRN)
6.3 两种形态对比
| 对比项 | 简单 MJPEG(Camera1) | 网络摄像头(Camera2) |
|---|---|---|
| 实时画面 | ✔(motionEye 转发) | ✔(motion 内置 MJPEG 流,默认端口 9082) |
当前帧接口 /picture/N/current/ | ✘(HTTP 400,见 7.1) | ✔ |
| 运动侦测 | ✘ | ✔ |
| 录像/抓图 | ✘ | ✔ |
| motion 线程 | 不占用 | 占用一路 camera 线程 |
七、功能逐项实测
7.1 实时画面
Camera2(motion 本地摄像头)当前帧接口实测——返回一张真实 JPEG:
curl -s -b cookies.txt -o frame2.jpg -w 'http_code=%{http_code} type=%{content_type} bytes=%{size_download}\n' http://127.0.0.1:8150/picture/2/current/ && file frame2.jpg | cut -c1-60
实测回显:
http_code=200 type=image/jpeg bytes=18664
frame2.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1
Camera1(简单 MJPEG)同接口实测返回 400(形态差异,非故障):
curl -s -b cookies.txt http://127.0.0.1:8150/picture/1/current/
实测回显:
{"error": "unknown operation"}
7.2 运动侦测
testsrc 画面持续变化,motion 侦测连续触发。当前帧接口的响应 Cookie 直接携带侦测状态:
curl -s -D - -o /dev/null -b cookies.txt http://127.0.0.1:8150/picture/2/current/ | grep -i motion_detected
实测回显:
Set-Cookie: motion_detected_2=true; Path=/
motion 自身的 HTTP 控制接口(webcontrol,容器内 7999 端口)也可核验侦测开关与阈值:
docker exec motioneye-0.44.0-nvr curl -s "http://127.0.0.1:7999/0/detection/status" && docker exec motioneye-0.44.0-nvr curl -s "http://127.0.0.1:7999/0/config/get?query=threshold"
实测回显:
Camera 1 Detection status ACTIVE
Camera 0
threshold = 1500
Done
💡 说明:webcontrol 编号从 0 起计(0 号即 motion.conf 主线程引述的第一路摄像头),与 motionEye 界面的摄像头 ID(从 1 起)编号不同。
threshold = 1500即帧差分判定阈值:一帧内变化像素超过 1500 判为运动。
7.3 录像
先在界面上把 Camera2 的「录像模式」设为运动触发、格式选 mp4(H.264 软编码),命令行验证配置落盘:
grep -E '^(movie_output|movie_codec|movie_format)' config/camera-2.conf
实测回显:
movie_output on
movie_codec libx264
movie_format mp4
侦测触发后媒体目录自动按「摄像头名/日期/时分秒」落盘录像:
find media -type f -name '*.mp4' -exec ls -la {} \;
实测回显:
-rw-r--r-- 1 1000 1000 786011 10月29日 20:49 media/Camera2/2026-10-29/20-49-29.mp4
用 ffmpeg 读取录像文件元数据,核验封装与编码:
ffmpeg -hide_banner -i media/Camera2/2026-10-29/20-49-29.mp4 2>&1 | grep -E 'Duration|Stream #'
实测回显:
Duration: 00:00:37.51, start: 0.000000, bitrate: 454 kb/s
Stream #0:0[0x1](und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(progressive), 640x480, 454 kb/s, 2.03 fps, 2 tbr, 16384 tbn (default)
7.4 快照
手动快照(Web 界面为摄像头画面右下角「抓拍」按钮):
curl -s -b cookies.txt -X POST http://127.0.0.1:8150/action/2/snapshot && sleep 4 && find media -type f -name '*.jpg' -exec ls -la {} \;
实测回显:
OK
-rw-r--r-- 1 1000 1000 26140 10月29日 20:50 media/Camera2/2026-10-29/20-50-05.jpg
-rw-r--r-- 1 1000 1000 25657 10月29日 20:50 media/Camera2/2026-10-29/20-50-31.jpg
另外两种快照来源同样有效:motion webcontrol 的 POST /0/action/snapshot(实测返回 200)与摄像头配置里的「间隔快照」。
7.5 时间轴媒体列表
motionEye 的时间轴页面按摄像头与日期聚合展示媒体,后端接口为媒体列表(图片)与录像列表两组:
curl -s -b cookies.txt "http://127.0.0.1:8150/picture/2/list/" | python3 -m json.tool | head -18
实测回显:
{
"mediaList": [
{
"path": "2026-10-29/20-50-31.jpg",
"momentStr": "2026-10-29 20:50",
"details": {
"sizeKb": 26,
"timestamp": 1769667031,
"frameTypes": "stream",
"width": 640,
"height": 480
},
"groupKey": "20:50",
"type": "picture"
},
...
curl -s -b cookies.txt "http://127.0.0.1:8150/movie/2/list/" | head -c 420
实测回显(两条录像,可见 mimeType/momentStr/sizeStr 等展示字段):
{"mediaList": [{"path": "/2026-10-29/20-50-36.mp4", "mimeType": "video/mp4", "momentStr": "29 October 2026, 21:01", "momentStrShort": "29 Oct, 21:01", "sizeStr": "35.5 MB", "timestamp": 1793278894.5664306}, {"path": "/2026-10-29/20-49-29.mp4", "mimeType": "video/mp4", "momentStr": "29 October 2026, 20:50", "momentStrShort": "29 Oct, 20:50", "sizeStr": "2.0 MB", "timestamp": 1793278219.424825}, {"path": "/2026-10-29/2...
时间轴页面上按 momentStr(时刻)分组平铺缩略图与录像卡片,点击可直接回放(/movie/2/playback/2026-10-29/20-49-29.mp4 返回视频流)。
八、数据持久化与备份
8.1 目录结构核验
两个 bind mount 卷的宿主侧内容(配置 + 媒体全部落宿主):
find config -type f | sort && echo '---' && find media -type f | sort
实测回显:
config/camera-1.conf
config/camera-2.conf
config/motion.conf
config/motioneye.conf
---
media/Camera2/2026-10-29/20-49-29.mp4
media/Camera2/2026-10-29/20-49-29.mp4.thumb
media/Camera2/2026-10-29/20-50-05.jpg
media/Camera2/2026-10-29/20-50-31.jpg
备份只需打包这两个宿主目录;此外 motionEye 自带配置备份接口(界面:设置 → 常规 → 保存/加载配置文件):
curl -s -b cookies.txt -o backup.tar.gz -w 'http_code=%{http_code} type=%{content_type} bytes=%{size_download}\n' http://127.0.0.1:8150/config/backup/ && tar tzf backup.tar.gz
实测回显:
http_code=200 type=application/x-compressed bytes=1528
motion.conf
camera-2.conf
camera-1.conf
恢复时在界面上传该 tar 包即可整体还原摄像头配置(对应接口 /config/restore/)。
8.2 媒体清理
motionEye 默认按「保留天数/磁盘占用百分比」自动清理媒体(设置 → 媒体 → 保留策略);也可在宿主侧用 find media -mtime +30 -delete 之类脚本自行清理,两者择一即可,避免叠加。
九、升级与卸载
9.1 升级流程
镜像 tag 即版本号,升级 = 改 tag → 拉取 → 重建(配置/媒体在宿主卷中不受影响):
docker compose pull motioneye && docker compose up -d motioneye
实测回显(当前已是最新版 0.44.0 时,拉取仅刷新元数据、容器无变化):
Image ghcr.io/motioneye-project/motioneye:0.44.0 Pulling
Image ghcr.io/motioneye-project/motioneye:0.44.0 Pulled
Container motioneye-0.44.0-nvr Running
升级后有新版本时,up -d 会显示 Recreate/Started 序列完成容器替换;配置与媒体在宿主卷中不受影响。升级后核对版本:
docker exec motioneye-0.44.0-nvr meyectl -v
实测回显:
motionEye 0.44.0
9.2 卸载与数据处置
docker compose down -v && cd .. && rm -rf config media compose
说明:down -v 移除容器与 compose 网络;最后一步删除宿主数据目录,执行前确认媒体不再需要。仅停用不删数据时用 docker compose down。
十、常见问题排障实录
10.1 首次登录提交非空密码返回 400
现象:首次登录框直接填入自定义密码提交:
curl -s -X POST -d 'username=admin&password=q1w2e3r4' http://127.0.0.1:8150/login/
实测回显:
{"error": "invalid credentials"}
原因:0.44.0 在 admin 无密码状态下只接受空密码认证,认证通过后返回 force_password_change 引导设置密码(见 4.3)。处置:先空密码登录,再按向导设置;已设密码后此现象不复现。
10.2 简单 MJPEG 摄像头没有当前帧接口
现象:Camera1 访问 /picture/1/current/ 返回 {"error": "unknown operation"}(见 7.1),服务日志:
[config] 20:51:24 ERROR: HTTP 400: Bad Request (unknown operation)
原因与处置:简单 MJPEG 形态仅做画面转发,实时画面由前端直连其 MJPEG 流。需要侦测/录像/抓图时,按 6.2 用「网络摄像头」形态重新添加。
10.3 修改摄像头配置返回错误
现象:只提交增量字段修改摄像头配置:
curl -s -b cookies.txt -H 'Content-Type: application/json' -d '{"still_images":true,"movies":true}' http://127.0.0.1:8150/config/2/set/
实测回显:
{"error": "internal server error"}
原因与处置:/config/<id>/set/ 不是增量合并语义,motionEye 按「整份 UI 配置」重建摄像头,缺字段的请求在服务端处理链上直接失败。正确做法是先 GET /config/2/get/ 取全量,在其 JSON 上改目标字段后整体提交:
curl -s -b cookies.txt http://127.0.0.1:8150/config/2/get/ > cam2.json \
&& python3 -c "import json;d=json.load(open('cam2.json'));d.update({'still_images':True,'movies':True,'movie_format':'mp4:libx264','capture_mode':'motion-triggered'});json.dump(d,open('cam2_set.json','w'))" \
&& curl -s -b cookies.txt -H 'Content-Type: application/json' --data @cam2_set.json http://127.0.0.1:8150/config/2/set/ | head -c 80
实测回显:
{"success": true}
⚠️ 浏览器操作不受影响(界面提交本就是全量配置),此坑仅影响直接调用 HTTP 接口的自动化脚本。
10.4 模拟源容器运行一段时间后自动重启
现象:docker compose ps 中 camsrc 容器 CREATED 24 minutes ago 但 STATUS Up 6 minutes——中间发生过重启。
原因:ffmpeg ... -listen 1 作为单次 HTTP 服务,部分客户端断开(如 curl 无参数超时截断)后会退出进程,容器随之停止;restart: unless-stopped 将其拉回。处置:保持 restart 策略即可(流会自动恢复,motionEye 侧表现为短暂「摄像头离线」后自动恢复);更稳的写法是在 command 外再包一层循环:
command:
- >
while true; do
ffmpeg -hide_banner -re -f lavfi
-i "testsrc=size=640x480:rate=15"
-c:v mjpeg -q:v 6
-f mpjpeg -boundary_tag motioneye -listen 1 http://0.0.0.0:8090/cam-a
|| sleep 1;
done
10.5 宿主端口 8765 冲突
现象:docker compose up -d 报端口绑定失败。原因:8765 是 motionEye 容器内固定端口,与其他监控软件(如 Home Assistant 默认 8123)无冲突,但若宿主已有进程占用重映射端口会失败。处置:先用 ss -ltn | grep <端口> 确认宿主端口空闲,再调整 compose 里的映射;容器内 8765 不需要改动。
十一、参考链接
- motionEye 官方仓库:https://github.com/motioneye-project/motioneye
- 官方 Docker 镜像说明:https://github.com/motioneye-project/motioneye/wiki(Deploy in Docker 一节)
- ffmpeg testsrc/mpjpeg 文档:https://ffmpeg.org/ffmpeg-filters.html(testsrc)、https://ffmpeg.org/ffmpeg-protocols.html(mpjpeg)
- motion 配置文档:https://motion-project.github.io/motion_config.html
- 本专栏入门篇:《motionEye 0.44.0 介绍与选型指南》
- 本专栏配置篇:《motionEye 0.44.0 配置参数详解》
- 本专栏命令篇:《motionEye 0.44.0 常用 CLI 命令与配置文件管理详解》