Etherpad生产部署指南:VPS上稳定运行MySQL+Node.js+Nginx

📅 2026/6/21 9:15:35
Etherpad生产部署指南:VPS上稳定运行MySQL+Node.js+Nginx
1. 为什么生产环境下的Etherpad不能只靠npm start跑起来Etherpad是个典型的“开箱即用但关箱即崩”的开源协作编辑器。我第一次在本地用npm install etherpad-lite npm start跑起来时兴奋地拉了三个同事一起试用——结果不到两小时编辑冲突频发、实时同步延迟飙升到15秒以上最后直接卡死在“正在加载”界面。后来翻遍GitHub Issues才发现几乎所有关于“Etherpad卡顿”“多人编辑不同步”“数据库连接超时”的报错根源都指向同一个事实开发模式启动的Etherpad压根没为生产环境做过任何加固设计。它默认用SQLite做后端存储而SQLite在并发写入场景下会强制串行化——当第4个用户开始敲字时第3个用户的光标位置更新请求就得排队等前3个请求全部完成它默认不启用进程守护SSH断开或终端关闭服务瞬间消失它默认监听localhost:9001外网根本访问不到它默认不配置HTTPS现代浏览器直接拦截混合内容它默认不设内存限制Node.js堆内存暴涨到2GB后自动OOM崩溃……这些不是Bug而是设计使然——Etherpad Lite的官方文档第一行就写着“This is a development version. For production, you need to configure it properly.”而VPSVirtual Private Server恰恰是生产部署最典型、也最容易踩坑的载体。它不像云平台有托管服务兜底也不像本地开发机可以随意重启。你拿到的是一个裸Linux系统从内核参数、防火墙规则、MySQL连接池大小到Node.js的GC策略、进程管理方式每一步都得亲手调校。更关键的是VPS资源有限——1核2G的甲骨文免费实例跑一个未优化的Etherpad连5个并发用户都撑不住。所以“How To Install Etherpad for Production”这个标题里的“Production”不是指“能跑起来”而是指“能稳住、能扩容、能监控、能排障”。这背后牵扯三个硬性技术锚点Node.js必须稳定运行在长期支持版LTS上MySQL必须启用事务与连接复用VPS系统必须完成基础安全加固与资源隔离。三者缺一不可。比如用Node.js v24.x当前尚未发布强行安装npm会报错error installing 24.16.0: node.js v24.16.0 is not yet released比如MySQL只装了5.7但没调innodb_buffer_pool_sizeInnoDB缓存命中率低于60%所有数据库操作都在疯狂读盘比如VPS没配fail2ban扫描脚本半小时内就能爆破出MySQL弱密码。这些都不是Etherpad的问题而是生产环境的入场券。所以本文不讲“怎么让Etherpad显示在浏览器里”而是讲“怎么让Etherpad在VPS上扛住真实业务流量”。接下来每一节都会对应一个真实线上事故的根因一次OOM崩溃教会我如何限制Node.js内存一次连接池耗尽让我重写MySQL配置一次SSH密钥登录失败暴露VPS基础安全漏洞。所有步骤都经过Ubuntu 22.04 MySQL 8.0 Node.js 20.18.0当前LTS最新稳定版实测验证拒绝任何“理论上可行”的纸上谈兵。1.1 生产级部署的四个不可妥协前提很多教程把“安装成功”当作终点但生产环境的起点恰恰是安装完成之后。我总结出四条铁律只要有一条不满足就不算进入生产状态第一进程必须脱离终端生命周期独立存活。npm start本质是启动一个前台进程一旦SSH会话断开网络抖动、本地休眠、终端意外关闭Node.js进程立即收到SIGHUP信号并终止。这不是Etherpad的缺陷而是Unix进程模型的基本规则。解决方案只能是引入进程管理器——pm2、systemd或supervisor。其中pm2对Node.js生态适配最成熟支持内存监控、自动重启、日志聚合且命令行交互友好。但要注意pm2 start默认以fork模式运行而Etherpad Lite内部已实现cluster多进程若再用pm2开启多实例反而导致端口冲突和会话不一致。因此必须强制pm2以--no-daemon配合--watch仅作单实例守护。第二数据库连接必须复用且可控。Etherpad默认配置中database字段只填host/port/dbname完全依赖底层驱动的默认连接池通常为10连接。当10个用户同时编辑同一Pad时每个用户操作可能触发多次SQL查询获取历史、保存变更、更新元数据连接池瞬间打满新请求排队等待表现为“点击保存无响应”。MySQL侧需同步调整max_connections建议≥200、wait_timeout避免空闲连接被服务端主动断开而Etherpad配置中必须显式声明connectionLimit: 50否则驱动不会创建足够连接。第三静态资源必须由反向代理缓存。Etherpad前端包含大量JS/CSS/图片每次页面加载都向Node.js后端发起30次HTTP请求。Node.js本身不是Web服务器处理静态文件效率远低于Nginx。实测数据显示在1核VPS上Nginx缓存静态资源后首屏加载时间从2.8秒降至0.6秒CPU占用率下降40%。这要求Nginx必须配置location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$规则并启用expires 1y和add_header Cache-Control public, immutable。第四HTTPS必须强制启用且证书自动续期。现代浏览器对非HTTPS站点的WebSocket连接Etherpad实时协同的核心实施严格限制Chrome 113已完全禁用ws://协议。Lets Encrypt的certbot虽好但手动续期极易遗漏。必须将certbot renew --quiet --post-hook systemctl reload nginx写入crontab且验证Nginx配置中ssl_certificate路径是否指向/etc/letsencrypt/live/your-domain.com/fullchain.pem而非过期的软链接。这四条不是可选项而是生产环境的准入门槛。跳过任意一条你的Etherpad就是一颗定时炸弹——它可能在凌晨3点用户量最低时突然崩溃也可能在老板演示关键功能时显示“Connection lost”。接下来的内容全部围绕如何扎实落地这四条展开。2. VPS系统层加固从裸机到可信运行环境VPS交付给你的往往是一个“干净得可怕”的Linux系统root密码明文邮件发送、SSH允许密码登录、UFW防火墙默认关闭、MySQL root账户无密码……这种状态连开发测试都不该容忍遑论生产。我曾管理过一批腾讯云VPS其中3台因未修改默认SSH端口上线24小时内就被暴力破解脚本攻陷MySQL被植入挖矿程序。所以Etherpad部署的第一步永远是把VPS变成一个可信的、最小权限的运行沙盒。2.1 SSH密钥认证与端口加固切断暴力破解入口腾讯云文档里提到“SSH密钥如何登录VPS”这其实是整个安全链的起点。密码登录的本质是“穷举攻击友好型接口”——只要密码复杂度不够脚本10分钟就能撞开。而SSH密钥认证是基于非对称加密的零知识证明客户端持有私钥服务端只存公钥中间人即使截获通信也无法伪造身份。具体操作分三步走本地生成密钥对在你的Mac或Windows WSL中执行ssh-keygen -t ed25519 -C your_emailexample.com。ed25519算法比RSA-2048更短、更快、更安全是当前最佳实践。生成的私钥id_ed25519必须严格保密公钥id_ed25519.pub用于上传。上传公钥并禁用密码登录通过腾讯云控制台的VNC或初始密码SSH登录后执行mkdir -p ~/.ssh echo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys然后编辑/etc/ssh/sshd_config确认以下三行PubkeyAuthentication yes PasswordAuthentication no PermitRootLogin no更换SSH端口并重启服务将Port 22改为Port 22222避开常见扫描端口执行sudo systemctl restart sshd。此时必须用新端口连接ssh -p 22222 -i ~/.ssh/id_ed25519 useryour-vps-ip。如果连接失败切勿直接退出当前会话先在另一终端验证sudo ss -tlnp | grep :22222确认端口监听正常再检查UFW是否放行。提示修改SSH配置后务必保留一个已登录的root会话作为“逃生通道”。我曾因误写PermitRootLogin without-password应为no导致无法登录幸亏有备用会话及时修正。2.2 防火墙与入侵防护用UFW和fail2ban筑起第一道墙UFWUncomplicated Firewall是Ubuntu内置的iptables前端配置简单但效果显著。针对Etherpad场景只需放行三个端口22222/tcpSSH管理端口按上节已修改80/tcp和443/tcpHTTP/HTTPS流量Nginx反向代理入口3306/tcpMySQL端口——但必须限制来源IP执行sudo ufw allow from 127.0.0.1 to any port 3306禁止外网直连数据库。Etherpad与MySQL同在VPS完全走localhost通信暴露3306到公网等于敞开大门。然而UFW只能拦住端口扫描对应用层暴力破解如MySQL登录、Etherpad管理后台无能为力。这时fail2ban登场。它实时分析日志如/var/log/auth.log、/var/log/mysql/error.log发现同一IP在10分钟内失败5次就自动添加iptables规则封禁该IP 1小时。安装配置极简sudo apt install fail2ban sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local # 编辑 /etc/fail2ban/jail.local取消以下注释并修改 [sshd] enabled true maxretry 3 bantime 3600 [mysqld-auth] enabled true filter mysqld-auth logpath /var/log/mysql/error.log maxretry 3然后sudo systemctl enable fail2ban sudo systemctl start fail2ban。实测表明启用fail2ban后SSH爆破尝试从日均2000次降至个位数。2.3 内核参数调优为高并发IO准备底层支撑VPS的1核2G配置看似寒酸但通过内核参数微调能显著提升MySQL和Node.js的IO吞吐。关键参数有三个vm.swappiness10控制内存交换倾向。默认值60意味着物理内存剩40%时就开始swap而swap是磁盘IO速度比内存慢3个数量级。Etherpad频繁读写数据库swap会直接拖垮响应。设为10后系统会尽量用完物理内存再考虑swap。net.core.somaxconn65535定义listen队列最大长度。当大量用户同时建立WebSocket连接时内核需要缓冲未完成三次握手的SYN包。默认128远远不够设为65535可应对突发流量。fs.file-max100000系统级文件描述符上限。每个TCP连接、每个打开的文件、每个管道都消耗一个fd。Node.js事件循环和MySQL连接池都依赖fd10万上限可支撑500并发连接。修改方法向/etc/sysctl.conf追加vm.swappiness10 net.core.somaxconn65535 fs.file-max100000然后执行sudo sysctl -p生效。验证命令sysctl vm.swappiness、cat /proc/sys/net/core/somaxconn。注意这些参数不是“越大越好”。fs.file-max设太高会增加内核内存开销net.core.somaxconn超过网卡队列深度反而造成丢包。我的实测结论是1核2G VPS上述值是性能与稳定性的最佳平衡点。3. MySQL深度配置从关系型存储到实时协同引擎Etherpad的数据库设计非常精巧它不把整篇文档存成一个大TEXT字段而是将每一次按键、每一次光标移动都记录为一条changeset变更集再通过pad表关联。这种设计保证了无限撤回、精细权限控制和实时冲突解决但也对MySQL提出了严苛要求——它必须高频写入、低延迟读取、强事务一致性。用默认配置的MySQL跑Etherpad就像用家用车拉集装箱能动但随时散架。3.1 版本选择与初始化为什么必须用MySQL 8.0网络热词里反复出现“mysql 5.7下载”“mysql安装教程详细步骤”但5.7已停止维护2023年10月且存在致命短板不支持原子DDL。Etherpad升级时会执行ALTER TABLE修改表结构5.7下该操作会锁表期间所有读写阻塞。而MySQL 8.0的原子DDL让表结构变更成为瞬时操作用户无感知。安装必须用官方APT仓库避免二进制包缺失依赖# 下载MySQL APT配置工具 wget https://dev.mysql.com/get/mysql-apt-config_0.8.24-1_all.deb sudo dpkg -i mysql-apt-config_0.8.24-1_all.deb # 安装时选择mysql-8.0不要选mysql-tools-preview sudo apt update sudo apt install mysql-server初始化后首要任务是删除匿名用户、禁用远程root、创建专用账号-- 登录MySQL sudo mysql -- 删除匿名用户5.7默认存在8.0已移除但为兼容性仍执行 DELETE FROM mysql.user WHERE User; -- 禁用root远程登录 DELETE FROM mysql.user WHERE Userroot AND Host NOT IN (localhost, 127.0.0.1, ::1); -- 创建Etherpad专用账号密码强度必须含大小写字母数字符号 CREATE USER etherpadlocalhost IDENTIFIED BY StrongPssw0rd2024!; GRANT SELECT, INSERT, UPDATE, DELETE ON etherpad.* TO etherpadlocalhost; FLUSH PRIVILEGES;提示“mysql设置唯一已经有重复数据库”这类问题根源常是初始化时未指定字符集。务必在创建数据库时显式声明CREATE DATABASE etherpad CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;。utf8mb4支持完整Unicode包括emoji而旧utf8只支持基本多语言平面。3.2 InnoDB核心参数调优让磁盘IO不再成为瓶颈MySQL 8.0默认使用InnoDB作为存储引擎其性能70%取决于innodb_buffer_pool_size——这是分配给InnoDB数据和索引缓存的内存。VPS只有2GB内存若按官方建议设为物理内存的75%1.5GB则留给Node.js和系统只剩500MB必然OOM。我的实测平衡方案是innodb_buffer_pool_size 1024M1GB。理由如下Etherpad的store表存变更集增长最快但单条记录很小1KB1GB缓存足以容纳数百万条热数据剩余1GB内存中Node.js预留512MB系统及Nginx预留300MBfail2ban等守护进程占200MB留有余量通过SHOW ENGINE INNODB STATUS\G查看Buffer pool hit rate稳定在99%以上即为健康。其他关键参数innodb_log_file_size 256M重做日志文件大小。增大后减少日志切换频率提升写入吞吐。注意修改此值需先停库、删除旧日志文件、再启库。innodb_flush_log_at_trx_commit 1确保每次事务提交都刷盘牺牲一点性能换取数据绝对安全Etherpad的协同编辑不容许丢失任何一次按键。max_connections 200如前所述Etherpad高并发场景必需。修改/etc/mysql/mysql.conf.d/mysqld.cnf[mysqld] innodb_buffer_pool_size 1024M innodb_log_file_size 256M innodb_flush_log_at_trx_commit 1 max_connections 200 wait_timeout 28800 interactive_timeout 28800重启MySQLsudo systemctl restart mysql。3.3 连接池与字符集Etherpad配置文件里的生死线Etherpad的settings.json中dbType、dbSettings字段直接决定数据库交互质量。一个常被忽略的细节是MySQL驱动默认不启用连接池必须显式配置。正确配置示例{ dbType: mysql, dbSettings: { user: etherpad, host: localhost, port: 3306, password: StrongPssw0rd2024!, database: etherpad, charset: utf8mb4, connectionLimit: 50, queueLimit: 0, acquireTimeoutMillis: 30000 } }connectionLimit: 50驱动最多维持50个空闲连接避免max_connections被耗尽queueLimit: 0连接请求队列无上限防止请求被丢弃宁可排队也不拒绝acquireTimeoutMillis: 30000获取连接超时30秒超时后Etherpad返回友好的错误页而非卡死。字符集charset: utf8mb4必须与数据库创建时一致否则中文、emoji存入后变乱码。验证方法在MySQL中执行SHOW CREATE TABLE store\G确认DEFAULT CHARSETutf8mb4。4. Node.js与Etherpad核心部署从安装到进程守护Node.js是Etherpad的运行时但“安装Node.js”绝非curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt-get install -y nodejs一句命令就能搞定。版本选择、全局模块管理、权限隔离、内存限制——每一步都关乎稳定性。4.1 LTS版本锁定与二进制安装避开v24.x等未发布陷阱网络热词中高频出现node.js v24.16.0 is not yet released这暴露了一个普遍误区盲目追求“最新版”。Node.js官网明确标注Current版本如v22.x是功能预览版LTS版本如v20.x才是企业级生产首选。v20.18.02024年6月LTS最新版已通过数千个npm包兼容性测试而v22.x的某些API在Etherpad插件中尚未适配。必须用NodeSource官方源安装拒绝nvm多版本管理器在VPS上易引发权限混乱# 清理可能存在的旧源 sudo apt remove nodejs npm sudo apt autoremove # 添加NodeSource LTS源v20.x curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt-get install -y nodejs # 验证 node -v # 应输出 v20.18.0 npm -v # 应输出 10.8.2注意“npm should be run outside of the node.js repl”错误源于在Node.js交互式环境中误输npm install。正确做法永远是在shell终端如bash中执行npm命令。4.2 Etherpad安装与权限隔离用非root用户运行是底线Etherpad官方强烈建议永不使用root用户运行。root权限下一个恶意插件或配置错误就能删库跑路。标准做法是创建专用系统用户sudo adduser --disabled-login --gecos etherpad sudo usermod -aG sudo etherpad # 切换用户并安装 sudo -u etherpad -H bash -c cd /opt \ git clone https://github.com/ether/etherpad-lite.git \ cd etherpad-lite \ ./bin/run.sh -s -s参数表示“静默安装”跳过交互式配置所有设置由后续settings.json控制。安装过程会自动创建/opt/etherpad-lite/var目录存放日志和数据库文件权限归属etherpad用户。4.3 pm2进程守护让Node.js真正“永生”./bin/run.sh只是启动脚本它不提供进程守护。必须用pm2接管# 全局安装pm2注意必须用etherpad用户安装避免权限冲突 sudo -u etherpad npm install -g pm2 # 切换到etherpad用户进入Etherpad目录 sudo -u etherpad -H bash -c cd /opt/etherpad-lite \ pm2 start ./node_modules/ep_etherpad-lite/node/server.js \ --name etherpad \ --watch \ --ignore-watchnode_modules \ --no-daemon \ --env production \ --max-memory-restart 512M \ --time # 保存进程列表开机自启 sudo -u etherpad pm2 save sudo pm2 startup systemd -u etherpad --hp /home/etherpad关键参数解析--no-daemon强制pm2以前台模式运行避免与Etherpad内置的cluster冲突--max-memory-restart 512MNode.js进程内存超512MB时自动重启防止内存泄漏累积--time日志中添加时间戳便于排查问题pm2 startup生成systemd服务文件确保VPS重启后自动拉起Etherpad。验证sudo -u etherpad pm2 status应显示onlinesudo journalctl -u pm2-etherpad -f可实时查看日志。5. Nginx反向代理与HTTPS让Etherpad拥有生产级入口至此Etherpad已在http://localhost:9001运行MySQL在localhost:3306待命但用户还无法访问——因为9001端口未开放且没有HTTPS。Nginx是解决这两个问题的黄金搭档它既是高性能Web服务器又是可靠的反向代理还能无缝集成Lets Encrypt。5.1 Nginx基础配置静态资源缓存与WebSocket透传安装Nginx后创建/etc/nginx/sites-available/etherpadupstream etherpad_backend { server 127.0.0.1:9001; } server { listen 80; server_name pad.your-domain.com; # 强制HTTP跳转HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name pad.your-domain.com; # SSL证书由certbot自动管理 ssl_certificate /etc/letsencrypt/live/pad.your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/pad.your-domain.com/privkey.pem; # 静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control public, immutable; add_header X-Frame-Options DENY; } # WebSocket关键配置 location / { proxy_pass http://etherpad_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; 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_buffering off; proxy_read_timeout 1d; proxy_send_timeout 1d; } }核心要点proxy_http_version 1.1和Upgrade头是WebSocket透传的必要条件缺一则实时协同失效proxy_read_timeout 1d防止长连接被Nginx主动断开Etherpad心跳间隔默认25秒设为1天足够proxy_buffering off禁用Nginx缓冲确保服务端推送消息即时到达客户端。启用配置sudo ln -sf /etc/nginx/sites-available/etherpad /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx。5.2 Lets Encrypt自动化用certbot实现零运维HTTPScertbot是Lets Encrypt官方客户端支持Nginx插件自动配置sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d pad.your-domain.com首次运行会引导你输入邮箱、同意协议并自动修改Nginx配置添加SSL指令。关键在于自动化续期# 检查续期命令是否有效 sudo certbot renew --dry-run # 添加到crontab每月1号和15号凌晨2:15执行 echo 15 2 1,15 * * root /usr/bin/certbot renew --quiet --post-hook \systemctl reload nginx\ | sudo tee -a /etc/crontab--post-hook确保证书更新后立即重载Nginx用户无感知。5.3 Etherpad安全加固关闭危险功能与启用CSRF保护Nginx只是入口Etherpad自身也有安全开关。编辑/opt/etherpad-lite/settings.json{ requireSession: true, // 强制所有请求需session防CSRF editOnly: false, // 关闭“仅编辑模式”允许创建新Pad minify: true, // 启用JS/CSS压缩减小传输体积 allowUnknownFileUploads: false, // 禁止上传未知类型文件防木马 disablePlugins: false, // 生产环境建议false但需审核插件来源 users: { // 启用基础认证可选 admin: { password: AdminPssw0rd2024!, is_admin: true } } }重启Etherpadsudo -u etherpad pm2 restart etherpad。提示“mysql error 2003 (hy000): cant connect to mysql server”通常是MySQL未启动、防火墙拦截或bind-address未设为127.0.0.1。检查sudo systemctl status mysql和sudo ss -tlnp | grep :3306。6. 故障排查实战从“Connection lost”到“502 Bad Gateway”的全链路诊断部署完成不等于高枕无忧。Etherpad生产环境最常见的三个报错“Connection lost”前端、“502 Bad Gateway”Nginx、“Error: connect ECONNREFUSED”Node.js日志它们像三颗齿轮咬合一个故障会引发连锁反应。下面以真实案例还原完整排查链路。6.1 案例一用户报告“Connection lost”但Nginx日志显示200现象用户编辑时频繁弹出“Connection lost”刷新页面后内容丢失。Nginx access.log中全是200error.log无报错。排查链路前端抓包用Chrome DevTools Network标签过滤ws://发现WebSocket连接在readyState0CONNECTING后立即关闭Status为(failed)Nginx日志深挖tail -f /var/log/nginx/etherpad-error.log发现upstream timed out (110: Connection timed out) while reading upstream定位超时源头proxy_read_timeout默认60秒但Etherpad心跳间隔25秒Nginx在60秒内未收到任何数据就断开连接验证Node.js状态sudo -u etherpad pm2 show etherpad发现memory列显示512MB/512MB已达--max-memory-restart阈值进程处于重启循环中根因确认sudo -u etherpad pm2 logs etherpad --lines 100日志末尾出现FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory。修复方案不是简单调大内存限制而是分析内存泄漏。通过pm2 monit观察发现ep_tables插件用于表格编辑在大量复制粘贴时未释放DOM引用。临时方案sudo -u etherpad pm2 restart etherpad --max-memory-restart 768M长期方案禁用该插件或升级至修复版本。6.2 案例二Nginx报502但Node.js进程显示online现象Nginx error.log持续输出connect() failed (111: Connection refused) while connecting to upstream但pm2 status显示Etherpad为online。排查链路确认Node.js端口监听sudo ss -tlnp | grep :9001发现无输出——说明Node.js进程虽在但未监听9001检查Etherpad日志sudo -u etherpad pm2 logs etherpad --lines 50发现Error: listen EADDRINUSE: address already in use 127.0.0.1:9001根因定位sudo lsof -i :9001发现另一个node进程占用了9001端口可能是上次异常退出未清理强制清理sudo kill -9 $(sudo lsof -t -i :9001)再sudo -u etherpad pm2 restart etherpad。预防措施在settings.json中添加port: 9001并确保/opt/etherpad-lite/settings.json文件权限为644避免pm2因权限问题读取失败而降级使用默认端口。6.3 案例三MySQL连接池耗尽Etherpad页面白屏现象用户访问https://pad.your-domain.com页面白屏浏览器控制台报GET https://pad.your-domain.com/socket.io/?EIO4transportpollingt... net::ERR_EMPTY_RESPONSE。排查链路直连Node.js端口curl -v http://localhost:9001返回503 Service Unavailable说明Etherpad已启动但拒绝服务检查Etherpad日志sudo -u etherpad pm2 logs etherpad --lines 100发现大量Error: Pool was destroyed和Error: connect ETIMEDOUT验证MySQL连接mysql -u etherpad -p -h localhost etherpad -e SELECT 1输入密码后立即返回1证明MySQL服务正常检查连接池状态sudo mysql -u root -p -e SHOW STATUS LIKE Threads_connected;输出Threads_connected 200已达max_connections200上限根因确认sudo mysql -u root -p -e SELECT user, host, db, command, time, state FROM information_schema.processlist ORDER BY time DESC LIMIT 10;发现200个连接中198个处于Sleep状态time列显示28800秒8小时正是wait_timeout值。修复方案在settings.json中增加connectionLimit: 50并重启Etherpad。同时sudo mysql -u root -p -e SET GLOBAL wait_timeout300;将超时缩短至5分钟让空闲连接更快释放。7. 性能监控与容量规划让VPS资源使用一目了然生产环境不能靠“感觉”运维。必须建立量化指标体系知道“当前负载多少”“还能撑多久”“瓶颈在哪里”。对于1核2G VPS我建立了三层监控7.1 系统层用htop和iotop看实时水位htop是top的增强版按F2进入Setup勾选Display options中的Tree view和Show custom thread names可清晰看到pm2进程树下node server.js占用CPU是否持续80%mysqld进程内存是否稳定在1GB左右nginxworker进程数是否随并发增长正常应为CPU核心数×2。iotop专看磁盘IO执行