基于 Node.js + Express + Socket.IO 的 Markdown 在线预览与协作网页服务器。
- 单人模式:仅在当前浏览器页面内存中编辑与预览
- 合作模式:通过房间共享同一份 Markdown 文本
- Markdown 解析:
marked.js(浏览器端) - 代码高亮:
highlight.js(浏览器端) - 用户系统:基于 Cookie + IP 绑定的虚拟账号,同一 IP 在不同浏览器下默认复用同一账户
- 管理员入口:访问
/admin,管理员账户名为admin - 管理员登录:输入管理员暗号后写入
adminpassCookie,服务端按 Cookie 校验权限 - 管理员面板:查看全部房间、在线玩家、服务器负载、系统属性
- 管理员能力:删除任意房间、封禁指定在线玩家、修改管理员暗号
- 玩家封禁:被封禁玩家仍可查看房间列表并进入房间,但无法创建房间、删除房间、修改房间内容
- 房间限制:每个账户最多创建 3 个房间,每个房间最多
maxPerson人在线 - 在线成员列表:所有成员可见
- 房间日志窗口:房间内可查看内容变更日志,区分哪个用户添加/删除了内容
- 服务器负载角标:显示连接数、房间数、内存、运行时长、系统负载
.
├─ server.js
├─ package.json
└─ public/
└─ index.html
npm installnpm start默认监听:
http://localhost:3000
当前项目支持以下环境变量:
| 变量名 | 默认值 | 说明 |
|---|---|---|
PORT |
3000 |
服务监听端口 |
ADMIN_COOKIE_CODE |
1145 |
管理员 Cookie 暗号 |
DEFAULT_MAX_PERSON |
5 |
默认房间最大在线人数 |
示例:
PORT=3000 ADMIN_COOKIE_CODE=9527 DEFAULT_MAX_PERSON=8 npm start在 Windows PowerShell 中:
$env:PORT=3000
$env:ADMIN_COOKIE_CODE=9527
$env:DEFAULT_MAX_PERSON=8
npm start本项目 当前不使用数据库。
所有数据均保存在 Node.js 进程内存中,包括:
- 房间列表
- 房间内容
- 房间编辑日志
- 房主信息
- 在线成员
- 管理员设置(当前进程生命周期内有效)
- IP 与用户映射
- 封禁玩家列表
这意味着:
- 重启服务后数据会丢失
- 管理员暗号运行期可在后台修改,但服务重启后仍回到环境变量默认值
- 不需要配置 MySQL / PostgreSQL / Redis / MongoDB
- 若后续需要持久化,可再扩展数据库层
所以对于“数据库配置”这一项,当前版本的正确配置结论是:
无需数据库配置
本项目使用 Socket.IO 做房间内实时同步。
- 客户端连接
/socket.io/ - 用户加入房间后,服务器执行
socket.join(roomId) - 用户编辑文本时,客户端发送
sync-content - 服务端接收后更新房间内存内容
- 然后通过:
socket.to(roomId).emit('remote-content', ...)广播给同房间的其他成员,不回发给发送者
如果你把 Node.js 放在 Nginx 后面,必须确保:
- 开启 HTTP/1.1
- 透传
Upgrade和Connection头 - 允许
/socket.io/正常反向代理
否则 WebSocket 升级会失败,协作功能无法正常工作。
以下示例基于 Debian 12。
sudo apt update
sudo apt install -y curl nginx
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node -v
npm -v假设部署目录为:
/var/www/markdown-lab
将项目上传到服务器后执行:
cd /var/www/markdown-lab
npm installPORT=3000 ADMIN_COOKIE_CODE=1145 DEFAULT_MAX_PERSON=5 npm start确认日志输出正常后,按 Ctrl + C 停止,继续配置 systemd。
创建:
/etc/systemd/system/markdown-lab.service
内容如下:
[Unit]
Description=Markdown Lab Node.js Server
After=network.target
[Service]
Type=simple
WorkingDirectory=/var/www/markdown-lab
ExecStart=/usr/bin/node /var/www/markdown-lab/server.js
Restart=always
RestartSec=3
Environment=NODE_ENV=production
Environment=PORT=3000
Environment=ADMIN_COOKIE_CODE=1145
Environment=DEFAULT_MAX_PERSON=5
User=www-data
Group=www-data
[Install]
WantedBy=multi-user.target启动并设置开机自启:
sudo systemctl daemon-reload
sudo systemctl enable markdown-lab
sudo systemctl start markdown-lab
sudo systemctl status markdown-lab查看日志:
sudo journalctl -u markdown-lab -f创建站点配置:
/etc/nginx/sites-available/markdown-lab
内容如下:
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:3000;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /socket.io/ {
proxy_pass http://127.0.0.1:3000/socket.io/;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}启用配置:
sudo ln -s /etc/nginx/sites-available/markdown-lab /etc/nginx/sites-enabled/markdown-lab
sudo nginx -t
sudo systemctl reload nginx如果有域名,建议使用 Certbot:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com服务端启动时通过环境变量读取默认管理员暗号:
ADMIN_COOKIE_CODE=1145例如改成 9527:
ADMIN_COOKIE_CODE=9527 npm start或者在 systemd 中配置:
Environment=ADMIN_COOKIE_CODE=9527当前版本不再使用旧的 admin=1145 Cookie 方案。
正确流程为:
- 打开网站,或直接访问:
http://localhost:3000/admin
- 将当前昵称改为:
admin
- 点击“保存昵称”后,输入管理员暗号
- 校验成功后,浏览器会写入:
adminpass=<base64后的管理员暗号>
- 此后访问
/admin即可进入管理员页面
若未登录或暗号错误,访问 /admin 会显示“无权限访问”。
管理员页面位于右侧主内容区,当前支持:
- 查看全部房间
- 删除任意房间
- 查看在线玩家
- 封禁指定在线玩家
- 查看服务器负载
- 设置房间人数上限
- 设置违禁词
- 查看 / 编辑封禁玩家列表
- 修改管理员暗号
管理员页面“属性设置”中提供:
新管理员暗号(数字/字母)
- 留空:不修改暗号
- 输入后保存:当前运行中的管理员暗号立即更新
- 更新成功后:旧暗号失效,新暗号生效
注意:管理员暗号的运行期修改仅保存在内存中。若服务重启,仍会回到
ADMIN_COOKIE_CODE环境变量对应的值。
管理员面板当前支持:
maxPerson:每个房间最大在线人数bannedWords:用户名 / 房间名违禁词bannedPlayers:被封禁玩家列表adminCode:运行期管理员暗号
默认值:
maxPerson = 5
bannedWords = 78, 91, sb
说明:
- 违禁词匹配为“包含即拦截”
- 匹配时不区分大小写
- 用户名和房间名都受此规则约束
admin不会被加入违禁词列表- 被封禁玩家仍可查看房间列表并进入房间,但不能创建房间、删除房间、修改内容
返回房间列表、当前公共设置、服务器负载。
管理员查看房间列表、设置、服务器负载。
请求体示例:
{
"maxPerson": 8,
"bannedWords": ["78", "91", "sb"],
"bannedPlayers": ["UserA", "UserB"],
"adminCode": "9527"
}请求体示例:
{
"username": "UserA"
}管理员删除指定房间。
- 当前数据为内存存储,服务重启后会丢失
- 如果部署在 Nginx 后,必须保留 WebSocket 升级头
- 管理员暗号请不要写成公开弱口令,生产环境建议改掉默认值
adminpass为浏览器端 base64 编码值,不是强安全加密方案,更适合内网 / 轻量管理场景- 若需要长期保留房间、日志、封禁列表或暗号,需自行增加持久化存储
最简部署流程:
npm install
ADMIN_COOKIE_CODE=1145 DEFAULT_MAX_PERSON=5 npm start浏览器访问:
http://localhost:3000