本手册面向「云服务器(Linux)+ 考场终端(考试机 / 考台)」的部署形态,覆盖网络规划、端口开放、 安全组配置、双向连通验证、常见故障排查五个环节。按本手册逐项执行,可确保考试管理中心、 考试机考台、平台超管三端稳定联通。
先定拓扑,再动配置。拓扑不清楚时不要直接改防火墙,否则极易把自己锁在门外。
| 形态 | 网络关系 | 适用场景 | 考台如何连服务器 |
|---|---|---|---|
| A 全内网 | 服务器、考试机同处一个考场局域网(如 10.168.99.0/24) | 单考场、无外网需求,最稳 | 直连内网 IP |
| B 云服务器 + 考场专线 | 云服务器公网 IP,考场通过 VPN / 专线把 60 台考试机汇入同一网段 | 多考场统一管理,推荐生产使用 | 经 VPN 隧道访问云端内网地址 |
| C 云服务器 + 公网直连 | 考试机直接访问云服务器公网 IP:8080 | 临时考场、考台数量少 | 公网 IP + 端口白名单 |
/platform.html 通过 Nginx 加一层 IP 白名单或二次认证。
裸奔在公网的 8080 会被端口扫描批量探测。
| 端口 | 协议 | 所在机器 | 用途 |
|---|---|---|---|
8080 | TCP | 云服务器 | 考试管理系统 HTTP 服务(页面 + REST API) |
443 | TCP | 云服务器 | Nginx HTTPS(推荐,摄像头抓拍必须 HTTPS 或 localhost) |
22 | TCP | 云服务器 | SSH 运维,务必限制来源 IP |
19196 | TCP | 考试机本地 | 身份证读卡器本地服务,仅 127.0.0.1 监听,不对外 |
http://公网IP:8080 打开考试界面,监考视频与抓拍会全部失败。
生产环境必须上 HTTPS(Nginx + 证书),这是最容易被忽略的一条。
以 CentOS 7+/Rocky、Ubuntu 20.04+/Debian 11+ 为例,两套命令都给出。
# 系统版本
cat /etc/os-release
# 内网 IP(云厂商分配,注意可能是 172.x / 10.x)
ip -4 addr show | grep inet
# 公网 IP(以云控制台为准)
curl -s ifconfig.me; echo
# 确认 8080 是否被占用
ss -lntp | grep 8080
本系统所有心跳、抓拍、考试成绩都带时间戳。服务器时间漂移会导致考台「假离线」、 成绩单时间错乱。云服务器默认时钟可能偏差数分钟。
# 查看当前时间偏差
timedatectl status
# 开启 NTP 同步(系统自带 chrony 或 systemd-timesyncd)
sudo timedatectl set-ntp true
sudo timedatectl set-timezone Asia/Shanghai
timedatectl status # 应显示 System clock synchronized: yes
系统要求 Node.js 18 及以上(推荐 20 LTS / 22 LTS)。若使用本系统自带的一键安装包, 可跳过本节——安装脚本会内置运行时。
# 方式一:官方二进制包(推荐,免外网源依赖)
cd /tmp
curl -O https://nodejs.org/dist/v20.18.0/node-v20.18.0-linux-x64.tar.xz
sudo mkdir -p /usr/local/lib/nodejs
sudo tar -xJf node-v20.18.0-linux-x64.tar.xz -C /usr/local/lib/nodejs
sudo ln -sf /usr/local/lib/nodejs/node-v20.18.0-linux-x64/bin/node /usr/local/bin/node
node -v
# 方式二:包管理器(Ubuntu / Debian)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
不要让服务以 root 运行。系统用固定低权限账号 drvexam,数据目录归其所有。
sudo useradd -r -s /usr/sbin/nologin -d /opt/drvexam drvexam
sudo mkdir -p /opt/drvexam
sudo chown -R drvexam:drvexam /opt/drvexam
云服务器有两层防火墙:云厂商「安全组」(在控制台配)+ 系统「firewalld/ufw」。两层都要放行。
| 方向 | 协议 | 端口 | 来源 | 说明 |
|---|---|---|---|---|
| 入方向 | TCP | 443 | 0.0.0.0/0 | HTTPS,考官与考试机访问 |
| 入方向 | TCP | 8080 | 考场出口 IP 段 | 直连模式必开;有 Nginx 反代时可改为仅 127.0.0.1 监听后关闭本行 |
| 入方向 | TCP | 22 | 运维固定 IP /32 | 禁止 0.0.0.0/0 |
| 出方向 | 全部 | 全部 | 0.0.0.0/0 | 默认允许 |
# CentOS / Rocky / Alibaba Cloud Linux(firewalld)
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
# Ubuntu / Debian(ufw)
sudo ufw allow 8080/tcp
sudo ufw allow 443/tcp
sudo ufw reload
sudo ufw status verbose
# 仅内网形态 A/C 需要:从指定网段访问 8080
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.168.99.0/24" port protocol="tcp" port="8080" accept'
把 8080 藏在 Nginx 后面,对外只开 443,既能解决摄像头 HTTPS 限制,也便于加 IP 白名单。
server {
listen 443 ssl http2;
server_name exam.example.com;
ssl_certificate /etc/nginx/ssl/exam.crt;
ssl_certificate_key /etc/nginx/ssl/exam.key;
# 抓拍图片可能较大,放宽上传体积
client_max_body_size 20m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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;
proxy_read_timeout 120s;
}
# 平台超管入口加 IP 白名单(可选但强烈建议)
location = /platform.html {
allow 10.168.99.0/24;
allow 203.0.113.10;
deny all;
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 80;
server_name exam.example.com;
return 301 https://$host$request_uri;
}
X-Forwarded-For。Nginx 反代后,
登录限流按真实 IP 计,不会把整个考场当成一个 IP 而误伤。
若不做反代直接暴露 8080,请确认没开云厂商的「七层负载均衡」,否则同样会丢失真实 IP。
60 台考试机要能稳定访问云端,考场侧的三件事:网段、DHCP/固定 IP、出口带宽。
| 项目 | 建议 |
|---|---|
| 考场内网网段 | 10.168.99.0/24(本项目默认示例),至少预留 /24,容纳 60 台 + 网关 + 服务器 |
| 考试机地址 | 优先 DHCP 保留绑定(按 MAC 固定),避免 DHCP 租约变化导致考台错位 |
| 考台号与 IP | 建议末段与考台号对应,如 A-001 → 10.168.99.11,便于现场排查 |
| 网关/DNS | 网关指向考场出口路由器;DNS 至少配两个(如 223.5.5.5 / 114.114.114.114) |
单台考试机日常开销:心跳约 2 KB / 3 秒,考试中抓拍 3 张约 300 KB / 场, 交卷成绩单约 10 KB。60 台同时开考的总带宽需求很低(< 2 Mbps), 真正的瓶颈在考场出口 NAT 的并发连接数与链路的丢包率。
server 填写云端 VPC 内网地址(如 http://172.16.0.10:8080),不写公网 IP。考场机器若装过「上网加速」「安全卫士」类软件,常会写入系统代理,导致 API 请求被劫持到代理服务器。
# Windows 考试机:检查代理
netsh winhttp show proxy
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable
# Linux 服务器:检查环境变量(本项目启动脚本会清理)
env | grep -i proxy
http_proxy 与 HTTP_PROXY 同时存在导致
Start-Process 报错」的问题;Linux 侧同样建议在 systemd 单元中用
Environment= 显式清空代理变量。
按「服务器自检 → 考场到云端 → 云端到考场」三步走,每步都有明确判定标准。
# 服务是否在监听(应为 0.0.0.0:8080 或 127.0.0.1:8080)
ss -lntp | grep 8080
# 本机回环访问(必须 200)
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/api/health
# 健康检查返回内容(应含 ok:true 与 version)
curl -s http://127.0.0.1:8080/api/health | head -c 300; echo
# 用内网 IP 再验一次(验证不是只听 127.0.0.1)
curl -s -o /dev/null -w "%{http_code}\n" http://$(hostname -I | awk '{print $1}'):8080/
| 现象 | 判定 | 下一步 |
|---|---|---|
ss 无输出 | 服务未启动 | 查 journalctl -u drvexam -n 100 |
ss 只显示 127.0.0.1:8080 | 只听回环 | 启动参数需 0.0.0.0(本系统默认已是 0.0.0.0) |
curl 返回 200 且 ok:true | 通过 | 进入第二步 |
在考场任意一台考试机上执行。Windows 与 Linux 命令都给:
# Windows 考试机
ping exam.example.com
curl.exe -s -o NUL -w "%{http_code}\n" http://exam.example.com/api/health
# Linux / macOS 考场机
ping -c 4 exam.example.com
curl -s -o /dev/null -w "%{http_code}\n" http://exam.example.com/api/health
# 端口层探测(判断是防火墙丢包还是应用没响应)
telnet exam.example.com 8080
# 或
nc -zv exam.example.com 8080
登录考试管理中心 → 考台测试 → 「全部考台测试」,或点「联网小助手」一键诊断。 云端主动探测考台的连通性,用于确认反向链路(如抓拍图片回传、远程锁屏指令下发)。
# 服务器侧抓 8080 包,看是否有 SYN 进来
sudo tcpdump -i any -nn 'tcp port 8080' -c 50
# 只看 SYN(有 SYN 无 SYN-ACK 说明回包被拦)
sudo tcpdump -i any -nn 'tcp[tcpflags] & tcp-syn != 0 and port 8080' -c 20
考试机安装后,配置存放在安装目录的 config.json,改完需重启考试机程序。
| 字段 | 类型 | 说明 |
|---|---|---|
server | string | 考试管理系统地址,含协议与端口,如 http://10.168.99.10:8080。不要带结尾斜杠 |
seatNo | string | 考台号,如 A-001,必须与后台分配一致 |
token | string | 考台安装令牌(X-Exam-Token),由管理中心「考台分配」生成 |
heartbeatSec | number | 心跳间隔,默认 3 秒,不建议大于 10 |
camera | boolean | 是否启用摄像头抓拍 |
kiosk | boolean | 全屏锁定模式(考试机专用) |
{
"server": "https://exam.example.com",
"seatNo": "A-001",
"token": "安装时由管理中心下发",
"heartbeatSec": 3,
"camera": true,
"kiosk": true
}
考试机包内附带 config.example.json。批量部署时可用一条命令改完全部:
# Windows 批量(在考试机安装目录执行,改完重启程序)
powershell -NoProfile -Command ^
"$f='config.json'; $j=Get-Content $f -Raw | ConvertFrom-Json; $j.server='https://exam.example.com'; $j | ConvertTo-Json -Depth 5 | Set-Content $f -Encoding UTF8"
按「现象 → 原因 → 处理」对照表逐条排查,覆盖现场 90% 的联通问题。
config.json 的 server 是否写错(常见多写结尾斜杠、端口写成 80);
② 在考试机上 curl http://服务器地址:8080/api/health,返回非 200 说明网络不通;
③ 检查考台号 seatNo 是否与后台分配的考台号一致,不一致会被拒绝注册;
④ 检查令牌是否已失效(考台被后台删除后,旧令牌失效)。
ss -s 看 connections 数量;再看考场出口路由器会话数上限。
现场应急:把 heartbeatSec 调到 5、后台「考试参数」里心跳超时调到 60 秒。
SECRET → 旧令牌签名失效。生产环境务必在 systemd 中固定
Environment=SECRET=一长串随机值;
② 考区被平台停用 → 该考区会话被强制注销;
③ 服务器时间跳变 → 令牌 exp 判定异常,检查 NTP。
http://当前配置地址:8080/api/health,
对比返回的 hostname 是否为预期的云服务器主机名。
client_max_body_size(默认 1m 会截断);
检查服务器磁盘空间 df -h;抓拍失败时系统会如实计数并在成绩单上标注,不会伪造。
Authorization 头,或浏览器缓存了旧前端 JS。
确认 Nginx 未设置 proxy_set_header Authorization "";,
并在浏览器强制刷新(Ctrl+F5)。
建议打印张贴在考场控制台,每场考试前逐项打勾。
| # | 检查项 | 判定标准 |
|---|---|---|
| 1 | 云服务器服务运行 | systemctl status drvexam 为 active (running) |
| 2 | 健康检查 | /api/health 返回 ok:true,version 与预期一致 |
| 3 | 磁盘空间 | df -h 根分区使用率 < 80% |
| 4 | 时间同步 | timedatectl 显示 synchronized: yes |
| 5 | 考台在线率 | 考试机监控页在线数 = 实际考台数(100%) |
| 6 | 考台测试 | 全部考台结果为「通过」,无「仅单向连通」 |
| 7 | 摄像头 | 随机抽 3 台看监考画面正常 |
| 8 | 题库就绪 | 考试中心「题库就绪情况」科目一/科目四题量均达标 |
| 9 | 考生数据 | 考生人数 = 应考人数,抽 2 人核对姓名与身份证号 |
| 10 | 权限确认 | 当前账号「考区管理员」及以上,科目已授权 |
| 11 | 应急通道 | 记录云服务器 SSH 与重启命令,确认手机可联系运维 |