| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <title>帮助手册 - 车牌识别系统</title>
- <style>
- *{box-sizing:border-box;margin:0;padding:0}
- body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:#f0f2f5;color:#333}
- .navbar{background:#1a1a2e;color:#fff;padding:12px 20px;display:flex;align-items:center;gap:20px;box-shadow:0 2px 8px rgba(0,0,0,0.15)}
- .navbar a{color:#ccc;text-decoration:none;padding:6px 12px;border-radius:4px;font-size:14px}
- .navbar a:hover,.navbar a.active{background:rgba(255,255,255,0.15);color:#fff}
- .navbar .brand{font-size:16px;font-weight:bold;color:#4fc3f7;margin-right:10px}
- .container{max-width:960px;margin:20px auto;padding:0 16px}
- .card{background:#fff;border-radius:8px;margin-bottom:16px;box-shadow:0 1px 4px rgba(0,0,0,0.08);overflow:hidden}
- .card-title{background:#263238;color:#fff;padding:10px 16px;font-size:14px;font-weight:600;display:flex;align-items:center;justify-content:space-between;cursor:pointer;user-select:none}
- .card-title:hover{background:#37474f}
- .card-title .arrow{transition:transform 0.2s;font-size:12px}
- .card-title.collapsed .arrow{transform:rotate(-90deg)}
- .card-body{padding:16px 20px;line-height:1.8;font-size:14px}
- .card-body.hidden{display:none}
- h3{color:#1a1a2e;margin:16px 0 8px;font-size:15px;border-left:3px solid #667eea;padding-left:10px}
- h4{color:#333;margin:12px 0 6px;font-size:14px}
- table{width:100%;border-collapse:collapse;margin:8px 0 16px;font-size:13px}
- th{background:#f5f5f5;padding:8px 10px;text-align:left;font-weight:600;border-bottom:2px solid #e0e0e0;white-space:nowrap}
- td{padding:8px 10px;border-bottom:1px solid #f0f0f0;vertical-align:top}
- td:first-child{font-family:monospace;color:#d32f2f;white-space:nowrap;font-size:12px}
- code{background:#f5f5f5;padding:2px 6px;border-radius:3px;font-size:12px;color:#d32f2f;font-family:monospace}
- pre{background:#1e1e2e;color:#cdd6f4;padding:14px 18px;border-radius:6px;font-size:12px;overflow-x:auto;margin:8px 0 16px;line-height:1.6}
- pre code{background:none;color:#cdd6f4;padding:0;font-size:12px}
- .tip{background:#e8f5e9;border-left:4px solid #4caf50;padding:10px 14px;margin:8px 0;border-radius:0 4px 4px 0;font-size:13px}
- .warn{background:#fff3e0;border-left:4px solid #ff9800;padding:10px 14px;margin:8px 0;border-radius:0 4px 4px 0;font-size:13px}
- .note{background:#e3f2fd;border-left:4px solid #2196f3;padding:10px 14px;margin:8px 0;border-radius:0 4px 4px 0;font-size:13px}
- ul{padding-left:20px;margin:6px 0}
- li{margin:4px 0;font-size:13px;line-height:1.7}
- .toc{background:#fff;border-radius:8px;padding:16px 24px;margin-bottom:16px;box-shadow:0 1px 4px rgba(0,0,0,0.08)}
- .toc h2{font-size:16px;color:#1a1a2e;margin-bottom:10px;border-bottom:2px solid #667eea;padding-bottom:6px}
- .toc ol{padding-left:20px;columns:2;column-gap:30px}
- .toc li{margin:4px 0;font-size:13px;break-inside:avoid}
- .toc a{color:#667eea;text-decoration:none}
- .toc a:hover{text-decoration:underline}
- @media(max-width:768px){
- .navbar{flex-wrap:wrap;gap:8px;padding:10px 14px}
- .navbar .brand{font-size:14px;width:100%}
- .navbar a{font-size:12px;padding:4px 8px}
- .container{padding:0 10px;margin:10px auto}
- .toc ol{columns:1}
- table{font-size:12px;display:block;overflow-x:auto}
- th,td{padding:6px 8px}
- td:first-child{font-size:11px}
- }
- @media(max-width:480px){
- .navbar .brand{font-size:13px}
- .navbar a{font-size:11px;padding:3px 6px}
- .card-body{padding:12px 14px}
- }
- </style>
- </head>
- <body>
- <nav class="navbar">
- <span class="brand">🚛 车牌识别系统</span>
- <a href="/">监控首页</a>
- <a href="/video">视频预览</a>
- <a href="/locks">锁定管理</a>
- <a href="/help" class="active">帮助手册</a>
- </nav>
- <div class="container">
- <div class="toc">
- <h2>📋 目录</h2>
- <ol>
- <li><a href="#sec1">系统概述</a></li>
- <li><a href="#sec2">快速部署指南</a></li>
- <li><a href="#sec3">config.ini 完整配置说明</a></li>
- <li><a href="#sec4">RTSP 摄像头配置</a></li>
- <li><a href="#sec5">车牌识别上传流程</a></li>
- <li><a href="#sec6">MQTT 数据上报配置</a></li>
- <li><a href="#sec7">称重系统对接</a></li>
- <li><a href="#sec8">ROI 区域识别配置</a></li>
- <li><a href="#sec9">交替锁定机制</a></li>
- <li><a href="#sec10">登录认证与权限</a></li>
- <li><a href="#sec11">frpc.toml 内网穿透配置详解</a></li>
- <li><a href="#sec12">Nginx 反向代理配置详解</a></li>
- <li><a href="#sec13">SSL/HTTPS 证书配置</a></li>
- <li><a href="#sec14">系统监控与日志</a></li>
- <li><a href="#sec15">Web 管理功能</a></li>
- <li><a href="#sec16">数据库与备份</a></li>
- <li><a href="#sec17">常见问题 FAQ</a></li>
- </ol>
- </div>
- <!-- 1. 系统概述 -->
- <div class="card" id="sec1">
- <div class="card-title" onclick="toggleCard(this)">1. 系统概述 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>系统简介</h3>
- <p>车牌识别系统(PlateRecApp)是一款基于 HyperLPR3 的实时车牌识别应用,运行在树莓派 5 (aarch64) 上,支持:</p>
- <ul>
- <li>多路 RTSP 摄像头实时抓拍识别(进场/出场/侧面进/侧面出)</li>
- <li>车牌识别结果自动上传至云端 API</li>
- <li>称重系统对接(TCP 协议),自动关联车牌与称重数据</li>
- <li>MQTT 协议实时推送识别结果</li>
- <li>飞书群消息通知(异常报警)</li>
- <li>Web 管理界面(监控首页、视频预览、系统配置、锁定管理等)</li>
- <li>frpc 内网穿透管理 + Nginx stream + ssl_preread 协议分流(HTTP 自动跳 HTTPS)</li>
- <li>登录认证与角色权限控制</li>
- <li>SD 卡写入寿命保护(内存缓冲 + 每日定时写盘)</li>
- </ul>
- <h3>运行环境</h3>
- <table>
- <tr><th>项目</th><th>要求</th></tr>
- <tr><td>硬件</td><td>树莓派 5 8GB(推荐)</td></tr>
- <tr><td>系统</td><td>Debian 13 (trixie) / Ubuntu 24.04 aarch64</td></tr>
- <tr><td>依赖</td><td>HyperLPR3 SDK、FFmpeg、libcurl、OpenSSL、cJSON、Mosquitto、Nginx</td></tr>
- <tr><td>内网穿透</td><td>frpc(通过 systemctl 管理)</td></tr>
- <tr><td>协议分流</td><td>Nginx stream + ssl_preread(TCP 层 HTTP/HTTPS 自动检测分流)</td></tr>
- </table>
- <h3>网络架构总览(v2 — nginx stream + ssl_preread 方案)</h3>
- <pre>外网客户端 frps 服务器 本机(树莓派5)
- ───────── ───────── ─────────────
- ┌─ TLS → nginx stream → C++ HTTPS:8080 (透传)
- https://mqtt.zhonjin.com:40963/ ─TCP─→ discover.zhonjin.com:9443 ─TCP─→ frpc ─→ nginx:40963 (stream+ssl_preread)
- http://mqtt.zhonjin.com:40963/ ─TCP─→ ↑ ─TCP─→ frpc ─→└─ HTTP → nginx:8081 (301→HTTPS)
- https://mqtt.zhonjin.com:40964/ ─TCP─→ ↑ ─TCP─→ frpc ─→ nginx:8082 (HTTPS代理) → ttyd:7681</pre>
- <div class="tip"><strong>v2 方案优势:</strong>公网只需一个端口 40963,nginx stream 在 TCP 层自动检测协议类型并分流。HTTP 自动跳 HTTPS,HTTPS 透传到 C++ 应用处理。用户只需记住一个地址。</div>
- <h3>目录结构</h3>
- <table>
- <tr><th>路径</th><th>说明</th></tr>
- <tr><td>PlateRecApp</td><td>主程序二进制</td></tr>
- <tr><td>config.ini</td><td>主配置文件</td></tr>
- <tr><td>config.txt</td><td>MD5 校验配置</td></tr>
- <tr><td>hyperlpr3/</td><td>HyperLPR3 SDK 模型文件</td></tr>
- <tr><td>assets/web/</td><td>Web 页面文件(HTML/CSS/JS)</td></tr>
- <tr><td>data/</td><td>数据库目录(auth.db、upload_records.db、system_metrics.db)</td></tr>
- <tr><td>photos/</td><td>抓拍图片存储目录</td></tr>
- <tr><td>scripts/</td><td>运维脚本(sudoers 配置、密码重置等)</td></tr>
- </table>
- </div>
- </div>
- <!-- 2. 快速部署指南 -->
- <div class="card" id="sec2">
- <div class="card-title" onclick="toggleCard(this)">2. 快速部署指南 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>编译部署</h3>
- <ol>
- <li>解压代码包:<code>tar xzf fix24_vXX.tar.gz</code></li>
- <li>编译:<code>cd fix24/build && cmake .. && make -j4</code></li>
- <li>部署文件到安装目录(如 <code>/opt/openAI/project/003.PlateRecAPP/</code>)</li>
- <li>复制 HTML 文件:<code>cp -r assets/web/ /安装目录/assets/web/</code></li>
- <li>配置 sudoers(frpc 管理需要):<code>sudo bash scripts/setup_frpc_sudoers.sh</code></li>
- <li>安装 nginx stream 模块:<code>sudo apt install libnginx-mod-stream</code></li>
- <li>部署 nginx stream 配置文件(详见第 12 章)</li>
- <li>部署 SSL 证书(C++ 应用自管理,详见第 13 章)</li>
- <li>修改 <code>config.ini</code> 配置(参考下文各节)</li>
- <li>启动服务:<code>sudo systemctl restart nginx && sudo systemctl restart PlateRecApp</code></li>
- </ol>
- <h3>systemd 服务配置</h3>
- <p>PlateRecApp 服务文件路径:<code>/etc/systemd/system/PlateRecApp.service</code></p>
- <pre>Unit]
- Description=PlateRecApp License Plate Recognition System
- After=network.target frpc.service
- [Service]
- User=stevenroc
- Group=stevenroc
- WorkingDirectory=/opt/openAI/project/003.PlateRecAPP
- ExecStartPre=/bin/sleep 10
- ExecStart=/opt/openAI/project/003.PlateRecAPP/PlateRecApp
- TimeoutStartSec=30
- TimeoutStopSec=10
- Restart=on-failure
- RestartSec=5
- StandardOutput=append:/opt/openAI/project/003.PlateRecAPP/PlateRecApp.log
- LimitNOFILE=1048576
- [Install]
- WantedBy=multi-user.target</pre>
- <div class="tip">PlateRecApp 以非 root 用户运行(stevenroc),frpc 管理通过 sudoers 授权。日志输出由 v36 内存缓冲系统接管,systemd 的 StandardOutput 仅作备份。</div>
- <h3>密码重置</h3>
- <p>如忘记管理员密码,运行:<code>python3 reset_passwords.py</code></p>
- <h3>Nginx 服务配置(v2 — stream 方案)</h3>
- <p>安装 stream 模块并部署配置:</p>
- <pre># 安装 stream 模块(必须)
- sudo apt install -y libnginx-mod-stream
- # 验证模块
- nginx -V 2>&1 | grep stream
- # 替换 nginx.conf(详见第 12 章)
- sudo cp nginx-stream.conf /etc/nginx/nginx.conf
- # 验证配置
- sudo nginx -t
- # 启动/重载
- sudo systemctl enable nginx
- sudo systemctl restart nginx</pre>
- </div>
- </div>
- <!-- 3. config.ini 完整配置 -->
- <div class="card" id="sec3">
- <div class="card-title" onclick="toggleCard(this)">3. config.ini 完整配置说明 <span class="arrow">▼</span></div>
- <div class="card-body">
- <p>配置文件路径:<code><安装目录>/config.ini</code>,ini 格式,section 和 key 均不区分大小写。</p>
- <h3>[config] 核心识别配置</h3>
- <table>
- <tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
- <tr><td>project_name</td><td>string</td><td>-</td><td>项目名称</td></tr>
- <tr><td>point_number</td><td>string</td><td>-</td><td>站点编号</td></tr>
- <tr><td>throughway</td><td>string</td><td>-</td><td>通道名称</td></tr>
- <tr><td>rtsp_url_front_in</td><td>string</td><td>-</td><td>前侧进场摄像头 RTSP 地址</td></tr>
- <tr><td>rtsp_url_front_out</td><td>string</td><td>-</td><td>前侧出场摄像头 RTSP 地址</td></tr>
- <tr><td>rtsp_url_side_in</td><td>string</td><td>-</td><td>侧面进场摄像头 RTSP 地址</td></tr>
- <tr><td>rtsp_url_side_out</td><td>string</td><td>-</td><td>侧面出场摄像头 RTSP 地址</td></tr>
- <tr><td>app_api</td><td>string</td><td>-</td><td>云端上传 API 地址</td></tr>
- <tr><td>app_key</td><td>string</td><td>-</td><td>API 认证 Key</td></tr>
- <tr><td>app_secret</td><td>string</td><td>-</td><td>API 认证 Secret</td></tr>
- <tr><td>DEBUG_LOG</td><td>int</td><td>0</td><td>调试日志开关(0=关闭,1=开启)</td></tr>
- <tr><td>TestFlag</td><td>int</td><td>0</td><td>测试模式开关</td></tr>
- <tr><td>wType</td><td>int</td><td>0</td><td>称重类型(0=禁用,1=启用)</td></tr>
- <tr><td>TIME_WINDOW</td><td>int</td><td>5</td><td>识别时间窗口(分钟),同一车牌在窗口内不重复上传</td></tr>
- <tr><td>MAX_PHOTO_GROUPS</td><td>int</td><td>100</td><td>最大照片组数缓存</td></tr>
- <tr><td>in_out_interval</td><td>int</td><td>5</td><td>⚠️ 单位是<strong>分钟</strong>!交替锁定间隔(同一车牌进出最短时间),内部转为秒存储</td></tr>
- <tr><td>PLATE_CONFIDENCE_THRESHOLD</td><td>float</td><td>0.7</td><td>车牌识别置信度阈值(0~1),低于此值不上传</td></tr>
- <tr><td>PLATE_LOG_THRESHOLD</td><td>float</td><td>0.5</td><td>日志记录置信度阈值</td></tr>
- <tr><td>AlternatingMerge</td><td>int</td><td>0</td><td>交替合并开关(0=关闭,1=开启)</td></tr>
- <tr><td>hw_decode_mode</td><td>string</td><td>auto</td><td>硬件解码模式:auto/soft/drm</td></tr>
- <tr><td>hw_decode_device</td><td>string</td><td>/dev/dri/renderD128</td><td>硬件解码设备路径</td></tr>
- <tr><td>rtsp_transport</td><td>string</td><td>tcp</td><td>RTSP 传输协议:tcp/udp</td></tr>
- <tr><td>PhotoMaxCapacityMB</td><td>int</td><td>1024</td><td>照片目录最大容量(MB),超限自动清理旧照片</td></tr>
- <tr><td>LogRetentionDays</td><td>int</td><td>30</td><td>日志保留天数</td></tr>
- </table>
- <h3>[server] Web 服务配置</h3>
- <table>
- <tr><th>参数</th><th>说明</th></tr>
- <tr><td>ip</td><td>Web 服务监听地址(含端口),如 <code>0.0.0.0:8080</code>。v2 方案下 PlateRecApp 提供 HTTPS 服务(SSL 自管理),nginx stream 透传 TLS 流量到此处</td></tr>
- </table>
- <h3>[mqtt] MQTT 上报配置</h3>
- <table>
- <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
- <tr><td>MQTT_HOST</td><td>-</td><td>MQTT Broker 地址(填写后自动启用 MQTT)</td></tr>
- <tr><td>MQTT_PORT</td><td>1883</td><td>MQTT Broker 端口</td></tr>
- <tr><td>MQTT_USER</td><td>-</td><td>MQTT 用户名</td></tr>
- <tr><td>MQTT_PASS</td><td>-</td><td>MQTT 密码</td></tr>
- <tr><td>MQTT_TOPIC</td><td>-</td><td>推送主题</td></tr>
- <tr><td>MQTT_CLIENT_ID</td><td>-</td><td>客户端 ID</td></tr>
- </table>
- <h3>[auth] 登录认证配置</h3>
- <table>
- <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
- <tr><td>enabled</td><td>1</td><td>认证开关(0=关闭,1=开启)</td></tr>
- <tr><td>db_path</td><td>data/auth.db</td><td>认证数据库路径</td></tr>
- <tr><td>session_idle_timeout</td><td>1800</td><td>Session 空闲超时(秒)</td></tr>
- <tr><td>session_max_timeout</td><td>28800</td><td>Session 最大超时(秒)</td></tr>
- <tr><td>session_remember_timeout</td><td>604800</td><td>记住登录超时(秒)</td></tr>
- <tr><td>max_failed_attempts</td><td>5</td><td>最大登录失败次数</td></tr>
- <tr><td>lockout_duration</td><td>900</td><td>锁定时长(秒)</td></tr>
- </table>
- <h3>[ssl] HTTPS 配置(v2 — C++ 应用自管理)</h3>
- <table>
- <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
- <tr><td>enabled</td><td>1</td><td>HTTPS 开关。v2 方案下必须设为 1(C++ 应用直接处理 TLS)</td></tr>
- <tr><td>cert_path</td><td>ssl/plate_fullchain.pem</td><td>SSL 证书路径(相对于安装目录)</td></tr>
- <tr><td>key_path</td><td>ssl/plate_privkey.pem</td><td>SSL 私钥路径(相对于安装目录)</td></tr>
- </table>
- <div class="note">v2 方案变更:nginx stream 只做 TCP 分流,不解密 TLS。SSL 证书由 C++ 应用自己管理,<code>enabled</code> 必须为 1。</div>
- <h3>[system] 系统监控配置(v38 内存缓冲)</h3>
- <table>
- <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
- <tr><td>monitor_interval</td><td>2</td><td>监控采集间隔(秒),delta 法计算 CPU 使用率</td></tr>
- <tr><td>temp_alert_threshold</td><td>70</td><td>温度告警阈值(°C)</td></tr>
- <tr><td>cpu_alert_threshold</td><td>90</td><td>CPU 告警阈值(%)</td></tr>
- <tr><td>db_path</td><td>data/system_metrics.db</td><td>监控数据库路径</td></tr>
- <tr><td>history_retention_days</td><td>7</td><td>原始数据保留天数</td></tr>
- <tr><td>aggregation_retention_days</td><td>365</td><td>聚合数据保留天数</td></tr>
- <tr><td>flush_time</td><td>23:20</td><td>每日定时刷盘时间(HH:MM)</td></tr>
- </table>
- <h3>[frpc] 内网穿透配置</h3>
- <table>
- <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
- <tr><td>config_path</td><td>-</td><td>frpc.toml 配置文件路径</td></tr>
- <tr><td>protected_tunnels</td><td>-</td><td>受保护隧道名称(逗号分隔)</td></tr>
- <tr><td>auto_rollback</td><td>1</td><td>重启失败自动回滚(0/1)</td></tr>
- <tr><td>admin_addr</td><td>127.0.0.1</td><td>frpc Admin API 地址</td></tr>
- <tr><td>admin_port</td><td>7400</td><td>frpc Admin API 端口</td></tr>
- <tr><td>admin_user</td><td>-</td><td>frpc Admin 用户名</td></tr>
- <tr><td>admin_password</td><td>-</td><td>frpc Admin 密码</td></tr>
- </table>
- <h3>[log] 日志配置(v36 内存缓冲)</h3>
- <table>
- <tr><th>参数</th><th>默认值</th><th>说明</th></tr>
- <tr><td>enabled</td><td>1</td><td>内存缓冲模式(1=内存缓冲,0=直写文件)</td></tr>
- <tr><td>log_file</td><td>PlateRecApp.log</td><td>日志文件路径</td></tr>
- <tr><td>buffer_size_mb</td><td>20</td><td>内存缓冲区上限(MB)</td></tr>
- <tr><td>flush_time</td><td>23:20</td><td>每日定时刷盘时间(HH:MM)</td></tr>
- <tr><td>retention_days</td><td>30</td><td>日志文件保留天数</td></tr>
- <tr><td>redirect_stdout</td><td>1</td><td>捕获 stdout/stderr(0/1)</td></tr>
- <tr><td>auto_flush_on_exit</td><td>1</td><td>退出时立即刷盘(0/1)</td></tr>
- </table>
- </div>
- </div>
- <!-- 4. RTSP 摄像头配置 -->
- <div class="card" id="sec4">
- <div class="card-title" onclick="toggleCard(this)">4. RTSP 摄像头配置 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>摄像头地址格式</h3>
- <p>标准 RTSP 地址格式:</p>
- <pre>rtsp://用户名:密码@摄像头IP:554/stream</pre>
- <h3>四路摄像头说明</h3>
- <table>
- <tr><th>参数</th><th>方向</th><th>说明</th></tr>
- <tr><td>rtsp_url_front_in</td><td>前→进</td><td>前方摄像头,捕捉进场车辆</td></tr>
- <tr><td>rtsp_url_front_out</td><td>前→出</td><td>前方摄像头,捕捉出场车辆</td></tr>
- <tr><td>rtsp_url_side_in</td><td>侧→进</td><td>侧面摄像头,捕捉进场车辆</td></tr>
- <tr><td>rtsp_url_side_out</td><td>侧→出</td><td>侧面摄像头,捕捉出场车辆</td></tr>
- </table>
- <h3>硬件解码(树莓派5推荐配置)</h3>
- <table>
- <tr><th>模式</th><th>值</th><th>说明</th></tr>
- <tr><td>自动</td><td>auto</td><td>优先硬件解码,不可用则回退软件</td></tr>
- <tr><td>软件解码</td><td>soft</td><td>CPU 解码,兼容性最好</td></tr>
- <tr><td>DRM 硬件</td><td>drm</td><td>DRM 硬件加速(树莓派5推荐)</td></tr>
- </table>
- <div class="tip">树莓派 5 推荐:<code>hw_decode_mode=drm</code>,<code>hw_decode_device=/dev/dri/renderD128</code>,<code>rtsp_transport=tcp</code></div>
- </div>
- </div>
- <!-- 5. 车牌识别上传流程 -->
- <div class="card" id="sec5">
- <div class="card-title" onclick="toggleCard(this)">5. 车牌识别上传完整流程 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>识别流程</h3>
- <ol>
- <li><strong>摄像头抓拍</strong>:RTSP 视频流实时解码,检测到车辆运动时触发抓拍</li>
- <li><strong>车牌识别</strong>:HyperLPR3 引擎识别车牌号,返回车牌文本 + 置信度</li>
- <li><strong>置信度过滤</strong>:低于 <code>PLATE_CONFIDENCE_THRESHOLD</code> 则丢弃</li>
- <li><strong>时间窗口去重</strong>:同一车牌在 <code>TIME_WINDOW</code> 分钟内不重复上传</li>
- <li><strong>交替锁定检查</strong>:同一车牌进出间隔低于 <code>in_out_interval</code> 分钟则锁定</li>
- <li><strong>ROI 过滤</strong>:如启用 ROI,只识别指定区域内的车牌</li>
- <li><strong>数据上传</strong>:HTTP POST 将识别结果 + 照片上传至 <code>app_api</code></li>
- <li><strong>MQTT 推送</strong>:如启用 MQTT,同步推送识别结果</li>
- <li><strong>飞书通知</strong>:异常报警发送飞书群消息</li>
- </ol>
- </div>
- </div>
- <!-- 6. MQTT -->
- <div class="card" id="sec6">
- <div class="card-title" onclick="toggleCard(this)">6. MQTT 数据上报配置 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>启用条件</h3>
- <p>在 <code>[mqtt]</code> 段中填写 <code>MQTT_HOST</code> 即自动启用 MQTT 推送。</p>
- <h3>配置示例</h3>
- <pre>[mqtt]
- MQTT_HOST=mqtt.example.com
- MQTT_PORT=1883
- MQTT_USER=username
- MQTT_PASS=password
- MQTT_TOPIC=plate/recognition
- MQTT_CLIENT_ID=plate_rec_station_01</pre>
- <div class="warn">MQTT 连接失败时系统会自动重连,不影响识别和上传功能。</div>
- </div>
- </div>
- <!-- 7. 称重系统 -->
- <div class="card" id="sec7">
- <div class="card-title" onclick="toggleCard(this)">7. 称重系统对接 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>工作原理</h3>
- <p>称重系统通过 TCP 协议与称重地磅通信,车牌识别成功后自动读取称重数据并关联上传。</p>
- <h3>重量判定逻辑</h3>
- <ul>
- <li>连续 <code>STABLE_SAMPLE_COUNT</code> 次读数变化 < <code>STABLE_THRESHOLD_KG</code> 公斤,视为稳定</li>
- <li>稳定后取 <code>CANDIDATE_DATA_COUNT</code> 次读数的中值作为最终重量</li>
- <li>重量超过 <code>MAX_WEIGHT</code> 吨视为异常,丢弃</li>
- </ul>
- </div>
- </div>
- <!-- 8. ROI -->
- <div class="card" id="sec8">
- <div class="card-title" onclick="toggleCard(this)">8. ROI 区域识别配置 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>配置方式</h3>
- <ul>
- <li><strong>Web 可视化</strong>:首页连接状态面板中拖拽设置 ROI 区域</li>
- <li><strong>手动配置</strong>:在 config.ini 的 <code>[config]</code> 段填写坐标值</li>
- </ul>
- <h3>参数说明</h3>
- <table>
- <tr><th>参数</th><th>说明</th></tr>
- <tr><td>roi_in_x/y/w/h</td><td>进场 ROI 区域坐标和尺寸(像素)</td></tr>
- <tr><td>roi_in_enabled</td><td>1=启用进场 ROI</td></tr>
- <tr><td>roi_out_x/y/w/h</td><td>出场 ROI 区域坐标和尺寸</td></tr>
- <tr><td>roi_out_enabled</td><td>1=启用出场 ROI</td></tr>
- <tr><td>roi_debug_enabled</td><td>1=在抓拍图上绘制 ROI 框(调试用)</td></tr>
- </table>
- </div>
- </div>
- <!-- 9. 交替锁定 -->
- <div class="card" id="sec9">
- <div class="card-title" onclick="toggleCard(this)">9. 交替锁定机制 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>机制说明</h3>
- <p>防止同一车牌短时间内进出频繁触发(如车辆在门口调头)。同一车牌从"进"切换到"出"必须间隔 <code>in_out_interval</code> 分钟以上。</p>
- <div class="warn"><code>in_out_interval</code> 单位是<strong>分钟</strong>,不是秒!填 5 表示 5 分钟 = 300 秒。</div>
- </div>
- </div>
- <!-- 10. 认证与权限 -->
- <div class="card" id="sec10">
- <div class="card-title" onclick="toggleCard(this)">10. 登录认证与权限 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>角色定义</h3>
- <table>
- <tr><th>角色</th><th>Role值</th><th>可访问页面</th></tr>
- <tr><td>普通用户</td><td>0</td><td>首页、视频、称重、锁定管理</td></tr>
- <tr><td>管理员</td><td>1</td><td>普通用户 + 系统配置</td></tr>
- <tr><td>超级管理员</td><td>2</td><td>所有页面(含系统监控、frpc管理、SSH密钥、日志、帮助)</td></tr>
- </table>
- <h3>默认账号</h3>
- <table>
- <tr><th>用户名</th><th>密码</th><th>角色</th></tr>
- <tr><td>admin</td><td>zhongjin188A</td><td>超级管理员</td></tr>
- <tr><td>zhonjin</td><td>zhonjin</td><td>普通用户</td></tr>
- </table>
- <h3>安全特性</h3>
- <ul>
- <li>密码 bcrypt 加密存储(cost=12)</li>
- <li>连续登录失败锁定账号</li>
- <li>CSRF Token 防护</li>
- <li>Session 超时自动失效</li>
- <li>登录速率限制</li>
- </ul>
- </div>
- </div>
- <!-- 11. frpc.toml 详解 -->
- <div class="card" id="sec11">
- <div class="card-title" onclick="toggleCard(this)">11. frpc.toml 内网穿透配置详解 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>配置文件位置</h3>
- <p>frpc 配置文件路径由 <code>config.ini</code> 的 <code>[frpc] config_path</code> 指定,通常为安装目录下的 <code>frpc.toml</code>。</p>
- <h3>v2 方案 — nginx stream 分流(推荐)</h3>
- <p>使用 nginx stream + ssl_preread 方案,<strong>只需一个公网端口 40963</strong> 即可同时处理 HTTP 和 HTTPS:</p>
- <pre># frpc.toml — v2 方案(nginx stream 分流)
- serverAddr = "discover.zhonjin.com"
- serverPort = 9443
- auth.method = "token"
- auth.token = "你的frps认证Token"
- transport.tls.enable = true
- clientID = "ssd_40960"
- # frpc Admin HTTP API
- webServer.addr = "127.0.0.1"
- webServer.port = 7400
- webServer.user = "admin"
- webServer.password = "你的管理密码"
- # 隧道1:主服务(外网40963→本机nginx:40963,stream自动分流HTTP/HTTPS)
- [[proxies]]
- name = "plate_web"
- type = "tcp"
- localIP = "127.0.0.1"
- localPort = 40963 # ← 转发到 nginx stream,不是 C++ 的 8080
- remotePort = 40963
- # 隧道2:ttyd终端(外网40964→本机nginx:8082→ttyd:7681)
- [[proxies]]
- name = "ttyd_web"
- type = "tcp"
- localIP = "127.0.0.1"
- localPort = 8082 # ← nginx HTTPS 反向代理(SSL 终止 + WebSocket)
- remotePort = 40964</pre>
- <h3>隧道说明(v2)</h3>
- <table>
- <tr><th>隧道名</th><th>外网端口</th><th>本机端口</th><th>用途</th></tr>
- <tr><td>plate_web</td><td>40963</td><td>nginx stream:40963</td><td>HTTP/HTTPS 合一,stream 自动分流</td></tr>
- <tr><td>ttyd_web</td><td>40964</td><td>nginx HTTPS:8082</td><td>Web 终端(nginx SSL→ttyd:7681)</td></tr>
- </table>
- <h3>v2 数据流向</h3>
- <pre>HTTP 流量: 公网:40963 → frpc → nginx:40963 (stream) → $ssl_preread="" → 127.0.0.1:8081 (nginx HTTP) → 301 重定向到 HTTPS
- HTTPS 流量: 公网:40963 → frpc → nginx:40963 (stream) → $ssl_preread≠"" → 127.0.0.1:8080 (C++ HTTPS) → 直接处理
- Web SSH: 公网:40964 → frpc → nginx:8082 (HTTPS反向代理, SSL终止) → 127.0.0.1:7681 (ttyd HTTP)</pre>
- <div class="tip"><strong>v1→v2 迁移注意:</strong>不再需要 40965 端口。HTTPS 主服务统一使用 <code>https://mqtt.zhonjin.com:40963/</code>。</div>
- <h3>参数详解</h3>
- <table>
- <tr><th>参数</th><th>说明</th></tr>
- <tr><td>serverAddr</td><td>frps 服务器域名或 IP</td></tr>
- <tr><td>serverPort</td><td>frps 服务端口(默认 7000,本项目用 9443)</td></tr>
- <tr><td>auth.method</td><td>认证方式,固定为 <code>token</code></td></tr>
- <tr><td>auth.token</td><td>与 frps 约定的认证 Token</td></tr>
- <tr><td>webServer.addr/port</td><td>frpc Admin API 监听地址,PlateRecApp 通过此接口获取隧道状态</td></tr>
- <tr><td>webServer.user/password</td><td>Admin API 认证凭据(需与 config.ini [frpc] 段一致)</td></tr>
- <tr><td>[[proxies]] name</td><td>隧道唯一名称,PlateRecApp Web 界面按名称识别</td></tr>
- <tr><td>[[proxies]] type</td><td>隧道类型,本项目全部使用 <code>tcp</code>(透传 TCP 流)</td></tr>
- <tr><td>[[proxies]] localPort</td><td>本机目标端口,frpc 将外网流量转发到此端口</td></tr>
- <tr><td>[[proxies]] remotePort</td><td>frps 服务器暴露的外网端口,客户端通过此端口访问</td></tr>
- </table>
- <h3>隧道保护</h3>
- <p>在 <code>config.ini [frpc]</code> 段配置受保护隧道,防止 Web 界面误删关键隧道:</p>
- <pre>protected_tunnels = plate_web,ttyd_web</pre>
- <div class="warn">受保护的隧道无法通过 Web 管理界面删除。如需删除,必须先修改 config.ini 中的 <code>protected_tunnels</code> 字段。</div>
- <h3>frpc 管理命令</h3>
- <pre># 查看 frpc 状态
- systemctl status frpc
- # 重启 frpc
- sudo systemctl restart frpc
- # 查看 frpc 日志
- tail -f /var/log/frpc.log
- # 通过 Admin API 查看隧道状态
- curl -u admin:密码 http://127.0.0.1:7400/api/status/tcp</pre>
- </div>
- </div>
- <!-- 12. Nginx 反向代理详解 -->
- <div class="card" id="sec12">
- <div class="card-title" onclick="toggleCard(this)">12. Nginx stream + ssl_preread 配置详解(v2) <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>架构说明</h3>
- <p>v2 方案使用 nginx 的 <code>stream</code> 模块 + <code>ssl_preread</code> 功能,在 <strong>TCP 层面</strong>检测流量类型并自动分流:</p>
- <ul>
- <li><strong>端口 40963</strong>:nginx stream 监听,检测协议类型(TLS / HTTP)</li>
- <li><strong>TLS 流量</strong> → 透传到 C++ HTTPS 服务(127.0.0.1:8080)</li>
- <li><strong>HTTP 流量</strong> → nginx HTTP 模块(127.0.0.1:8081)→ 301 重定向到 HTTPS</li>
- </ul>
- <div class="tip"><strong>关键区别:</strong>stream 模块是 TCP 层代理,不解密 TLS 流量。SSL 证书由 C++ 应用自己管理,nginx 只做协议检测和分流。</div>
- <h3>nginx.conf 完整配置</h3>
- <p>文件路径:<code>/etc/nginx/nginx.conf</code>(替换整个文件)</p>
- <pre># 加载 stream 动态模块
- load_module modules/ngx_stream_module.so;
- events {
- worker_connections 1024;
- }
- # ============================================================
- # stream 块 — TCP 层协议分流(在 http 块外面)
- # ============================================================
- stream {
- # 根据 ssl_preread 检测结果选择后端
- # $ssl_preread_protocol 的可能值:
- # "" → HTTP 流量(非 TLS)
- # "TLSv1.2" → TLS 1.2
- # "TLSv1.3" → TLS 1.3
- map $ssl_preread_protocol $backend {
- "" http_backend; # HTTP → nginx HTTP 8081
- default tls_backend; # TLS → C++ HTTPS 8080
- }
- # TLS 后端 — C++ HTTPS 服务
- upstream tls_backend {
- server 127.0.0.1:8080;
- }
- # HTTP 后端 — nginx HTTP 301 重定向
- upstream http_backend {
- server 127.0.0.1:8081;
- }
- # 主服务器 — 监听公网端口
- server {
- listen 40963;
- proxy_pass $backend;
- ssl_preread on; # 启用 SSL 预读检测协议
- }
- }
- # ============================================================
- # http 块 — HTTP → HTTPS 301 重定向
- # ============================================================
- http {
- sendfile on;
- tcp_nopush on;
- tcp_nodelay on;
- keepalive_timeout 65;
- include /etc/nginx/mime.types;
- default_type application/octet-stream;
- access_log /var/log/nginx/access.log;
- error_log /var/log/nginx/error.log;
- # HTTP → HTTPS 301 重定向
- server {
- listen 8081;
- server_name _;
- return 301 https://$host:40963$request_uri;
- }
- # ============================================================
- # ttyd Web 终端 HTTPS 反向代理(端口 8082)
- # ============================================================
- # frpc 隧道:外网 40964 → nginx:8082 → ttyd:7681
- # nginx 做 SSL 终止,再通过 HTTP 代理到 ttyd(含 WebSocket 支持)
- server {
- listen 8082 ssl;
- server_name _;
- ssl_certificate /etc/nginx/ssl/plate_fullchain.pem;
- ssl_certificate_key /etc/nginx/ssl/plate_privkey.pem;
- ssl_protocols TLSv1.2 TLSv1.3;
- ssl_ciphers HIGH:!aNULL:!MD5:!RC4;
- ssl_prefer_server_ciphers on;
- ssl_session_cache shared:SSL_Ttyd:5m;
- ssl_session_timeout 1h;
- location / {
- proxy_pass http://127.0.0.1:7681;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- # WebSocket 支持(ttyd 核心通信方式)
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
- # ttyd 长连接超时
- proxy_read_timeout 86400s;
- proxy_send_timeout 86400s;
- }
- }
- }</pre>
- <h3>核心原理</h3>
- <table>
- <tr><th>组件</th><th>作用</th><th>说明</th></tr>
- <tr><td>stream 块</td><td>TCP 层代理</td><td>与 http 块平级,不处理 HTTP 协议,只做 TCP 转发</td></tr>
- <tr><td>ssl_preread on</td><td>SSL 预读</td><td>在 TLS 握手阶段读取 ClientHello,获取协议版本,不解密</td></tr>
- <tr><td>map $ssl_preread_protocol</td><td>协议分流</td><td>空字符串 = HTTP,非空 = TLS</td></tr>
- <tr><td>upstream tls_backend</td><td>TLS 后端</td><td>透传到 C++ 应用(8080),C++ 自己处理 TLS 握手</td></tr>
- <tr><td>upstream http_backend</td><td>HTTP 后端</td><td>转发到 nginx HTTP 8081,返回 301 重定向</td></tr>
- <tr><td>server 8082 ssl</td><td>ttyd HTTPS 代理</td><td>SSL 终止后代理到 ttyd:7681,支持 WebSocket</td></tr>
- </table>
- <h3>部署步骤</h3>
- <ol>
- <li>安装 stream 模块:<code>sudo apt install -y libnginx-mod-stream</code></li>
- <li>验证模块:<code>ls -l /usr/lib/nginx/modules/ngx_stream_module.so</code></li>
- <li>备份原配置:<code>sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak</code></li>
- <li>替换配置:<code>sudo cp nginx-stream.conf /etc/nginx/nginx.conf</code></li>
- <li>删除默认站点(如有):<code>sudo rm -f /etc/nginx/sites-enabled/default</code></li>
- <li>验证配置:<code>sudo nginx -t</code></li>
- <li>启动 nginx:<code>sudo systemctl enable nginx && sudo systemctl restart nginx</code></li>
- </ol>
- <h3>前置条件</h3>
- <table>
- <tr><th>项目</th><th>要求</th></tr>
- <tr><td>nginx 版本</td><td>≥ 1.11.5(支持 stream 模块)</td></tr>
- <tr><td>stream 模块</td><td>libnginx-mod-stream(Debian)或 nginx-mod-stream(CentOS)</td></tr>
- <tr><td>C++ 应用</td><td>必须启用 HTTPS,监听 127.0.0.1:8080</td></tr>
- <tr><td>SSL 证书</td><td>C++ 应用自行管理(config.ini 的 [ssl] 段)</td></tr>
- </table>
- <h3>验证方法</h3>
- <pre># 检查端口监听
- ss -tlnp | grep -E '40963|8080|8081'
- # 预期输出:
- # LISTEN 0.0.0.0:40963 nginx (stream)
- # LISTEN 127.0.0.1:8081 nginx (http 301)
- # LISTEN 0.0.0.0:8080 PlateRecApp (HTTPS)
- # 测试 HTTP 重定向(应返回 301)
- curl -I http://localhost:40963/
- # 预期:HTTP/1.1 301 Moved Permanently
- # Location: https://localhost:40963/
- # 测试 HTTPS(应返回 200)
- curl -kI https://localhost:40963/
- # 预期:HTTP/1.1 200 OK
- # 浏览器测试(清除缓存或用无痕模式)
- # 访问 http://mqtt.zhonjin.com:40963/ → 自动跳转到 https://mqtt.zhonjin.com:40963/</pre>
- <h3>端口规划总结</h3>
- <table>
- <tr><th>端口</th><th>服务</th><th>说明</th></tr>
- <tr><td><strong>40963</strong></td><td>nginx stream</td><td>公网入口,TLS/HTTP 分流</td></tr>
- <tr><td>8081</td><td>nginx http</td><td>HTTP 301 重定向(仅内部)</td></tr>
- <tr><td>8080</td><td>C++ HTTPS</td><td>PlateRecApp Web 服务(SSL 自管理)</td></tr>
- <tr><td><strong>40964</strong></td><td>nginx HTTPS→ttyd</td><td>Web 终端(nginx:8082 SSL终止→ttyd:7681)</td></tr>
- <tr><td>8082</td><td>nginx HTTPS 代理</td><td>ttyd Web 终端 HTTPS 反向代理(仅内部)</td></tr>
- <tr><td>7400</td><td>frpc Admin</td><td>隧道状态查询(仅 127.0.0.1)</td></tr>
- </table>
- </div>
- </div>
- <!-- 13. SSL/HTTPS 证书配置 -->
- <div class="card" id="sec13">
- <div class="card-title" onclick="toggleCard(this)">13. SSL/HTTPS 证书配置(v2 — C++ 应用自管理) <span class="arrow">▼</span></div>
- <div class="card-body">
- <div class="note"><strong>v2 方案变更:</strong>nginx stream 只做 TCP 层协议分流,不解密 TLS 流量。SSL 证书由 C++ 应用(PlateRecApp)自己管理,通过 config.ini 的 <code>[ssl]</code> 段配置。nginx 不再需要 SSL 证书。</div>
- <h3>config.ini [ssl] 段配置</h3>
- <pre>[ssl]
- enabled=1
- cert_path=ssl/plate_fullchain.pem
- key_path=ssl/plate_privkey.pem</pre>
- <div class="tip">v2 方案下 SSL 证书文件放在安装目录的 <code>ssl/</code> 子目录下(或任意自定义路径),不再需要 <code>/etc/nginx/ssl/</code>。</div>
- <h3>方式一:Let's Encrypt 证书 — 阿里云 DNS 验证(推荐)</h3>
- <p>本项目使用 frpc 内网穿透,<strong>无公网 80 端口</strong>,因此不能使用传统的 HTTP-01 验证。推荐使用 <strong>DNS-01 验证</strong>,通过阿里云 DNS API 自动完成,<strong>不需要任何端口</strong>。</p>
- <h4>方案对比</h4>
- <table>
- <tr><th>验证方式</th><th>端口要求</th><th>通配符</th><th>自动续期</th><th>本项目适用</th></tr>
- <tr><td>HTTP-01 (standalone)</td><td>公网 80</td><td>❌</td><td>✅</td><td>❌ 80 端口不可用</td></tr>
- <tr><td>TLS-ALPN-01</td><td>公网 443</td><td>❌</td><td>✅</td><td>❌ 443 端口不可用</td></tr>
- <tr><td><strong>DNS-01 (dns-aliyun)</strong></td><td><strong>无</strong></td><td><strong>✅</strong></td><td><strong>✅</strong></td><td><strong>✅ 推荐</strong></td></tr>
- <tr><td>手动 DNS</td><td>无</td><td>✅</td><td>❌ 手动</td><td>⚠️ 每 90 天手动操作</td></tr>
- </table>
- <h4>一键部署</h4>
- <pre># 1. 安装 certbot + 阿里云 DNS 插件
- sudo apt update
- sudo apt install -y certbot python3-pip
- sudo pip3 install certbot-dns-aliyun
- # 2. 配置阿里云 AccessKey(RAM 子账号,需 AliyunDNSFullAccess 权限)
- sudo mkdir -p /etc/letsencrypt
- sudo vim /etc/letsencrypt/aliyun.ini
- # 内容:
- # dns_aliyun_access_key = 你的AccessKeyID
- # dns_aliyun_access_key_secret = 你的AccessKeySecret
- sudo chmod 600 /etc/letsencrypt/aliyun.ini
- # 3. 一键申请通配符证书(自动通过 DNS API 验证)
- sudo certbot certonly \
- --authenticator dns-aliyun \
- --dns-aliyun-credentials /etc/letsencrypt/aliyun.ini \
- --dns-aliyun-propagation-seconds 30 \
- --server https://acme-v02.api.letsencrypt.org/directory \
- --agree-tos --no-eff-email \
- --email admin@zhonjin.com \
- -d mqtt.zhonjin.com \
- -d "*.zhonjin.com"
- # 4. 部署证书到 PlateRecApp
- mkdir -p ssl/
- sudo cp /etc/letsencrypt/live/mqtt.zhonjin.com/fullchain.pem ssl/plate_fullchain.pem
- sudo cp /etc/letsencrypt/live/mqtt.zhonjin.com/privkey.pem ssl/plate_privkey.pem
- sudo chown stevenroc:stevenroc ssl/*.pem
- chmod 644 ssl/plate_fullchain.pem
- chmod 600 ssl/plate_privkey.pem
- # 5. 配置自动续期(每天 3:00 检查,续期后自动部署)
- (crontab -l 2>/dev/null; echo "0 3 * * * certbot renew --quiet --deploy-hook /opt/openAI/project/003.PlateRecAPP/scripts/renew_ssl.sh") | crontab -
- # 6. 重启 PlateRecApp
- sudo systemctl restart PlateRecApp</pre>
- <h4>续期部署脚本 renew_ssl.sh</h4>
- <pre>#!/bin/bash
- # /opt/openAI/project/003.PlateRecAPP/scripts/renew_ssl.sh
- DOMAIN="mqtt.zhonjin.com"
- SSL_DIR="/opt/openAI/project/003.PlateRecAPP/ssl"
- cp /etc/letsencrypt/live/${DOMAIN}/fullchain.pem ${SSL_DIR}/plate_fullchain.pem
- cp /etc/letsencrypt/live/${DOMAIN}/privkey.pem ${SSL_DIR}/plate_privkey.pem
- chown stevenroc:stevenroc ${SSL_DIR}/*.pem
- chmod 644 ${SSL_DIR}/plate_fullchain.pem
- chmod 600 ${SSL_DIR}/plate_privkey.pem
- systemctl restart PlateRecApp
- echo "$(date) SSL 证书续期部署成功" >> /opt/openAI/project/003.PlateRecAPP/ssl_renew.log</pre>
- <h4>阿里云 RAM 权限配置</h4>
- <ol>
- <li>登录 <a href="https://ram.console.aliyun.com/" target="_blank">RAM 控制台</a> → 用户 → 创建用户</li>
- <li>勾选 <strong>OpenAPI 调用访问</strong>,保存 AccessKey ID 和 Secret</li>
- <li>添加权限:<code>AliyunDNSFullAccess</code>(云解析 DNS 管理)</li>
- </ol>
- <div class="tip">DNS 验证原理:certbot 通过阿里云 API 自动添加 <code>_acme-challenge.mqtt.zhonjin.com</code> TXT 记录,Let's Encrypt CA 查询 DNS 验证域名所有权,全程无需开放任何端口。</div>
- <div class="warn"><strong>前提:</strong>域名 mqtt.zhonjin.com 的 DNS 解析必须使用阿里云(<code>dns9.hichina.com</code>)。如果 DNS 在其他服务商,需先迁移到阿里云,或改用对应插件(如 <code>certbot-dns-cloudflare</code>、<code>certbot-dns-dnspod</code>)。</div>
- <h3>方式二:自签名证书</h3>
- <p>无公网域名时使用自签名证书,浏览器会显示警告但加密通信正常:</p>
- <pre># 创建证书目录
- mkdir -p ssl/
- # 生成自签名证书(10年有效期)
- openssl req -x509 -newkey rsa:2048 -nodes \
- -keyout ssl/plate_privkey.pem \
- -out ssl/plate_fullchain.pem \
- -days 3650 \
- -subj "/CN=mqtt.zhonjin.com/O=PlateRecApp/C=CN"
- # 设置权限
- chmod 600 ssl/plate_privkey.pem
- chmod 644 ssl/plate_fullchain.pem
- # 重启 PlateRecApp 加载证书
- sudo systemctl restart PlateRecApp</pre>
- <h3>证书文件说明</h3>
- <table>
- <tr><th>文件</th><th>用途</th><th>config.ini 参数</th></tr>
- <tr><td>plate_fullchain.pem</td><td>完整证书链(含中间 CA)</td><td>cert_path</td></tr>
- <tr><td>plate_privkey.pem</td><td>私钥文件(严禁泄露)</td><td>key_path</td></tr>
- </table>
- <h3>v1→v2 迁移说明</h3>
- <div class="warn"><strong>v1 方案:</strong>SSL 证书由 nginx 管理(<code>/etc/nginx/ssl/</code>),nginx 做 HTTPS 终止后转发 HTTP 到 C++。<br>
- <strong>v2 方案:</strong>SSL 证书由 C++ 应用管理,nginx stream 只做 TCP 分流,不解密 TLS。不再需要 <code>/etc/nginx/ssl/</code> 目录。</div>
- </div>
- </div>
- <!-- 14. 系统监控与日志 -->
- <div class="card" id="sec14">
- <div class="card-title" onclick="toggleCard(this)">14. 系统监控与日志 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>系统监控(实时)</h3>
- <ul>
- <li>CPU 使用率(delta 法,含每核使用率、负载均值)</li>
- <li>内存使用率(总量/已用/可用)</li>
- <li>磁盘使用率(根分区)</li>
- <li>CPU 温度,超阈值告警</li>
- <li>PlateRecApp 进程资源占用</li>
- <li>frpc/MQTT/称重连接状态</li>
- </ul>
- <h3>历史监控数据(v37+)</h3>
- <ul>
- <li>采集间隔:<code>monitor_interval</code>(默认 2 秒)</li>
- <li>定时刷盘:每日 <code>flush_time</code>(默认 23:20)写入 <code>system_metrics.db</code></li>
- <li>三级存储:原始数据 → 小时聚合 → 日聚合</li>
- <li>自动清理:原始数据保留 7 天,聚合数据保留 365 天</li>
- <li>历史查询 API:<code>/api/monitor/history?range=1h|6h|24h|7d|30d</code></li>
- </ul>
- <h3>SD 卡写入保护策略(v38)</h3>
- <ul>
- <li><strong>系统监控</strong>:内存缓冲,每日 23:20 一次写入,SD 卡写入从 2880 次/天降至 1 次</li>
- <li><strong>运行日志</strong>:内存环形缓冲区,Web 日志页面零磁盘 I/O,每日 23:20 写入 <code>PlateRecApp_YYYYMMDD.log</code></li>
- <li><strong>旧版日志清理</strong>:内存模式启用时自动跳过旧版 copytruncate,避免无意义读写</li>
- <li><strong>退出安全刷盘</strong>:SIGTERM/SIGINT 时立即执行最后一次刷盘</li>
- </ul>
- <h3>日志管理(v36 内存缓冲)</h3>
- <ul>
- <li>内存缓冲模式(默认):所有日志写入内存,Web 页面实时读取</li>
- <li>直写文件模式(<code>enabled=0</code>):传统模式回退</li>
- <li>支持手动触发刷盘(Web 页面操作)</li>
- </ul>
- </div>
- </div>
- <!-- 15. Web管理 -->
- <div class="card" id="sec15">
- <div class="card-title" onclick="toggleCard(this)">15. Web 管理功能 <span class="arrow">▼</span></div>
- <div class="card-body">
- <table>
- <tr><th>页面</th><th>路径</th><th>权限</th><th>说明</th></tr>
- <tr><td>监控首页</td><td>/</td><td>所有用户</td><td>实时监控、识别记录、连接状态</td></tr>
- <tr><td>视频预览</td><td>/video</td><td>所有用户</td><td>实时视频流</td></tr>
- <tr><td>称重记录</td><td>/weight</td><td>所有用户</td><td>称重数据</td></tr>
- <tr><td>锁定管理</td><td>/locks</td><td>所有用户</td><td>交替锁定记录</td></tr>
- <tr><td>帮助手册</td><td>/help</td><td>超级管理员</td><td>本文档</td></tr>
- <tr><td>系统配置</td><td>/config</td><td>管理员+</td><td>config.ini 在线编辑</td></tr>
- <tr><td>系统监控</td><td>/system</td><td>超级管理员</td><td>CPU/内存/温度/磁盘</td></tr>
- <tr><td>frpc 管理</td><td>/frpc</td><td>超级管理员</td><td>内网穿透状态和配置</td></tr>
- <tr><td>SSH 密钥</td><td>/ssh-keys</td><td>超级管理员</td><td>SSH 公钥管理</td></tr>
- <tr><td>日志管理</td><td>/logs</td><td>超级管理员</td><td>系统日志查看</td></tr>
- </table>
- </div>
- </div>
- <!-- 16. 数据库 -->
- <div class="card" id="sec16">
- <div class="card-title" onclick="toggleCard(this)">16. 数据库与备份 <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>数据库文件</h3>
- <table>
- <tr><th>文件</th><th>路径</th><th>说明</th></tr>
- <tr><td>认证数据库</td><td>data/auth.db</td><td>用户账号、密码、Session</td></tr>
- <tr><td>识别记录</td><td>data/upload_records.db</td><td>车牌识别上传记录</td></tr>
- <tr><td>系统监控</td><td>data/system_metrics.db</td><td>性能监控时序数据</td></tr>
- </table>
- <h3>备份建议</h3>
- <ul>
- <li>定期备份 <code>data/</code> 目录和 <code>config.ini</code></li>
- <li>nginx SSL 证书和配置文件备份:<code>/etc/nginx/ssl/</code>、<code>/etc/nginx/conf.d/</code></li>
- <li>frpc 配置修改时系统自动备份</li>
- </ul>
- </div>
- </div>
- <!-- 17. FAQ -->
- <div class="card" id="sec17">
- <div class="card-title" onclick="toggleCard(this)">17. 常见问题 FAQ <span class="arrow">▼</span></div>
- <div class="card-body">
- <h3>Q: HTTP 访问没有跳转到 HTTPS?</h3>
- <p>A: 检查以下几点:</p>
- <ul>
- <li>确认 nginx stream 模块已安装:<code>nginx -V 2>&1 | grep stream</code></li>
- <li>确认 nginx 配置正确:<code>sudo nginx -t</code></li>
- <li>确认 8081 端口正在监听:<code>ss -tlnp | grep 8081</code></li>
- <li>确认 frpc 隧道 <code>plate_web</code> 正常运行(localPort 为 40963)</li>
- <li>浏览器可能缓存了旧的重定向,尝试清除缓存或无痕模式</li>
- <li>测试本机重定向:<code>curl -I http://localhost:40963/</code>,应返回 301</li>
- </ul>
- <h3>Q: HTTPS 访问返回错误?</h3>
- <p>A: v2 方案下 TLS 由 C++ 应用处理,检查:</p>
- <ul>
- <li>PlateRecApp 是否正在运行:<code>systemctl status PlateRecApp</code></li>
- <li>PlateRecApp 是否启用了 HTTPS:<code>config.ini [ssl] enabled=1</code></li>
- <li>SSL 证书文件是否存在:<code>ls -l ssl/plate_fullchain.pem ssl/plate_privkey.pem</code></li>
- <li>nginx stream 是否正常监听:<code>ss -tlnp | grep 40963</code></li>
- <li>nginx 错误日志:<code>sudo tail -f /var/log/nginx/error.log</code></li>
- </ul>
- <h3>Q: <code>unknown directive "stream"</code>?</h3>
- <p>A: stream 模块未加载。执行:<code>sudo apt install -y libnginx-mod-stream</code>,确认 nginx.conf 顶部有 <code>load_module modules/ngx_stream_module.so;</code></p>
- <h3>Q: frpc 重启后隧道不生效?</h3>
- <p>A: 检查 frpc.toml 配置语法:</p>
- <pre>frpc verify -c /path/to/frpc.toml</pre>
- <p>常见错误:TOML 格式问题(缺少引号、缩进错误)。通过 Web 管理界面编辑配置时系统会自动校验。</p>
- <h3>Q: 自签名证书浏览器警告怎么消除?</h3>
- <p>A: 自签名证书无法消除浏览器警告(这是正常安全行为)。解决方案:</p>
- <ul>
- <li>方式1:使用 Let's Encrypt 免费证书(需域名解析到公网 IP)</li>
- <li>方式2:在客户端将自签名 CA 证书添加到受信任的根证书列表</li>
- <li>方式3:忽略警告,继续使用(加密通信正常,仅证书不受信任)</li>
- </ul>
- <h3>Q: 摄像头连接失败怎么办?</h3>
- <p>A: 确认 RTSP 地址格式正确,在 VLC 中测试播放。尝试 <code>rtsp_transport=tcp</code>。</p>
- <h3>Q: in_out_interval 填 5 是 5 秒还是 5 分钟?</h3>
- <p>A: <strong>5 分钟</strong>。单位是分钟,系统内部自动 ×60 转为秒。</p>
- <h3>Q: 如何重置管理员密码?</h3>
- <pre>cd /opt/openAI/project/003.PlateRecAPP
- python3 reset_passwords.py</pre>
- </div>
- </div>
- </div>
- <script>
- function toggleCard(el) {
- el.classList.toggle('collapsed');
- var body = el.nextElementSibling;
- body.classList.toggle('hidden');
- }
- </script>
- </body>
- </html>
|