ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

9Router 云端部署实战指南:VPS、Docker 与 Nginx 反向代理完整方案

2026/9/11 17:42:01 拓冰建站 浏览量
9Router 云端部署实战指南:VPS、Docker 与 Nginx 反向代理完整方案 9Router 云端部署实战指南VPS、Docker 与 Nginx 反向代理完整方案【免费下载链接】9routerUnlimited FREE AI coding. Connect Claude Code, Codex, Cursor, Cline, Copilot, Antigravity to FREE Claude/GPT/Gemini via 40 providers. Auto-fallback, RTK -40% tokens, never hit limits.项目地址: https://gitcode.com/GitHub_Trending/9r/9router9Router 是一个开源 AI 网关可将 Claude Code、Codex、Cursor、Cline、Copilot、Antigravity 等工具连接到免费的 Claude/GPT/Gemini 模型并通过自动故障切换Auto-fallback与 RTK-40% Token等特性避免触达限额。本指南以 云端部署文档 为主体结合仓库源码package.json、Dockerfile、docker-compose.yml、custom-server.js、dashboardGuard.js 等深度讲解将 9Router 部署到 VPS 或 Docker 的完整流程。读完本文你将掌握从零搭建生产环境、配置 Nginx 反向代理与 SSL、加固安全策略以及日常监控与排障的完整实战能力。注意本文涉及的端口、环境变量与命令均以当前仓库实际代码为准。仓库根目录即为应用目录无app/子目录Web 仪表盘监听20127端口LLM API 代理监听20128端口具体实现见下文「端口与进程架构」一节。部署前的关键认知端口与进程架构在动手部署前先理解 9Router 的运行时架构能避免后续大量踩坑。从 package.json 的脚本定义可见dev: next dev --port 20127, start: next start --port 20127, build: next build --webpack20127 端口Next.js Web 应用仪表盘 页面默认监听端口20128 端口LLM API 代理 / OpenAI 兼容端点/v1所在端口README.md 中明确 Dashboard 为http://localhost:20128/dashboard、OpenAI 兼容 API 为http://localhost:20128/v1且 Dockerfile 中ENV PORT20128、cli/src/cli/api/client.js 默认port: 20128CLI 面板也提示Endpoint: http://localhost:20128/v1见 cli/src/cli/menus/settings.js。结合 Dockerfile 的EXPOSE 20128与ENV HOSTNAME0.0.0.0可以看出生产环境standalone custom-server.js中 20128 是统一入口。PORT环境变量用于覆盖监听端口Docker 镜像内部默认使用20128。因此在 Nginx 反向代理配置中仪表盘与/v1API 的proxy_pass目标端口要依据实际运行方式npm run start时为 20127Docker 时为 20128正确设置下文会分别给出对应配置。另外custom-server.js 是生产环境Docker standalone的实际入口它包装了 Node HTTP Server从 TCP socket 读取不可伪造的客户端真实 IP并删除客户端传入的X-Forwarded-For/X-Real-IP头只有在 TCP 对端是本机回环地址即存在本机反向代理时才信任转发头再以x-9r-real-ip内部头传递给应用。这意味着9Router 自身的限流、登录防护见 src/app/api/auth/login/route.js 的getClientIp基于真实 IP不会被攻击者伪造X-Forwarded-For绕过Nginx 反向代理必须运行在与应用相同的本机或通过回环地址转发转发头才能被信任。VPS 部署前置要求按文档要求VPS 需满足Ubuntu 20.04 或类似 Linux 发行版Node.js 20仓库 Dockerfile 使用node:22-alpinepackage.json 无 engines 字段但以 Node 20 为基准Gitroot 或 sudo 权限。步骤 1克隆仓库当前仓库根目录即为应用代码不存在文档所述app/子目录因此克隆后直接进入仓库目录即可git clone https://github.com/decolua/9router.git cd 9router步骤 2安装依赖npm install说明仓库将better-sqlite3放在optionalDependenciespackage.json 注释明确说明因此即使目标系统缺少编译工具链npm install也不会失败运行时数据库会回退到sql.js纯 WASM 实现这为无编译环境的生产机提供了良好兼容性。步骤 3构建应用npm run build构建产物为 Next.js standalone 模式next build --webpack输出到.next/standalone配合 custom-server.js 使用。步骤 4配置环境变量创建.env文件或导出变量export JWT_SECRETyour-secure-secret-change-this-to-random-string export INITIAL_PASSWORDyour-secure-password export DATA_DIR/var/lib/9router export NODE_ENVproduction环境变量表结合源码验证变量默认值说明源码依据JWT_SECRET自动生成并写入$DATA_DIR/jwt-secret生产环境必须修改用于 JWT token 签名HS25624 小时有效期src/lib/auth/dashboardSession.jsINITIAL_PASSWORD123456仪表盘首次登录密码设置密码后以数据库 bcrypt 哈希为准src/app/api/auth/login/route.jsDATA_DIR~/.9router数据库与数据存储路径目录不可写时自动回退默认目录src/lib/dataDir.jsNODE_ENVdevelopment部署时设为productionsrc/mitm/config.js 等按此分支ENABLE_REQUEST_LOGSfalse设为true启用 debug 请求/响应日志open-sse/utils/requestLogger.jsPORT20128Docker/ 20127npm run start服务监听端口Dockerfile、package.jsonHOSTNAME0.0.0.0Docker监听地址容器内必须为0.0.0.0Dockerfile源码细节印证JWT_SECRET若未设置dashboardSession.js 会用crypto.randomBytes(32).toString(hex)生成随机密钥并以0600权限写入$DATA_DIR/jwt-secret重启后仍有效。但为了多实例部署与可控性生产环境务必显式设置INITIAL_PASSWORD仅在数据库尚未设置密码哈希时生效storedHash为空一旦用户在仪表盘修改过密码环境变量将不再作为登录凭据DATA_DIR的解析在 dataDir.js 中实现Windows 平台会忽略 Unix 风格绝对路径EACCES/EPERM权限错误时回退~/.9router避免因目录不可写导致启动失败。步骤 5创建数据目录sudo mkdir -p /var/lib/9router sudo chown $USER:$USER /var/lib/9router数据目录承载 SQLite 数据库、JWT 密钥文件、请求详情记录等权限配置不当会触发 dataDir.js 的回退逻辑导致数据落在默认目录所以请务必保证目录属主为运行用户。步骤 6启动应用npm run start该命令实际执行next start --port 20127见 package.json仪表盘监听20127而 LLM API/v1由内部代理进程在20128提供服务。若需修改端口使用PORTxxxx npm run start并同步调整 Nginx 与防火墙规则。步骤 7用 PM2 部署到生产环境PM2 让应用持续运行、崩溃时自动重启# 全局安装 PM2 npm install -g pm2 # 用 PM2 启动 9Router pm2 start npm --name 9router -- start # 保存 PM2 配置 pm2 save # 设置开机自启 pm2 startup # 按上一条命令打印的提示执行PM2 管理命令# 查看日志 pm2 logs 9router # 重启应用 pm2 restart 9router # 停止应用 pm2 stop 9router # 查看状态 pm2 status # 监控资源 pm2 monitDocker 部署仓库已内置生产级 Dockerfile多阶段构建与 docker-compose.yml建议直接复用无需再从文档示例重新编写。下面先解读仓库自带 Dockerfile再给出开箱即用的运行方式。方式 1使用仓库内置 Dockerfile仓库 Dockerfile 要点基础镜像node:22-alpine可通过ARG NODE_IMAGE覆盖多阶段构建builder 阶段安装python3 make g linux-headers以支持原生模块编译如better-sqlite3NEXT_TELEMETRY_DISABLED1关闭遥测npm run build产出 standalone 产物运行阶段ENV NODE_ENVproduction、ENV PORT20128、ENV HOSTNAME0.0.0.0、ENV DATA_DIR/app/data关键拷贝除了.next/standalone还显式拷贝custom-server.js、open-sse、src/mitm、node-forge与next注释说明 standalone 文件追踪可能遗漏这些 MITM 子进程与运行时依赖数据目录mkdir -p /app/data并将/app/data-home符号链接到/root/.9router兼容默认数据路径的读取逻辑入口ENTRYPOINT [/entrypoint.sh]启动前chown -R node:node /app/data /app/data-home修正挂载卷权限再以su-exec node降权运行CMD [node, custom-server.js]端口EXPOSE 20128。构建并运行# 构建镜像 docker build -t 9router . # 运行容器 docker run -d \ --name 9router \ -p 20128:20128 \ -e JWT_SECRETyour-secure-secret-change-this \ -e INITIAL_PASSWORDyour-secure-password \ -e NODE_ENVproduction \ -e DATA_DIR/app/data \ -v 9router-data:/app/data \ 9router与原文档示例不同仓库镜像内部端口为20128非 3000映射-p 20128:20128后仪表盘与/v1API 均通过该端口对外提供服务。方式 2使用仓库内置 Docker Compose仓库 docker-compose.yml 实际包含两个服务services: 9router: image: decolua/9router:latest container_name: 9router restart: always ports: - 20128:20128 volumes: - 9router-data:/app/data env_file: - .env environment: DATA_DIR: /app/data PORT: 20128 HOSTNAME: 0.0.0.0 NODE_ENV: production HEADROOM_URL: http://headroom:8787 depends_on: - headroom headroom: image: ghcr.io/chopratejas/headroom:latest container_name: headroom restart: always ports: - 8787:8787 volumes: 9router-data: name: 9router-data要点headroom 服务9Router 的 RTKToken 节省能力依赖 headroom 代理服务compose 中通过HEADROOM_URL: http://headroom:8787将两个容器接入同一网络仓库中 headroom 相关实现可见 src/lib/headroom/detect.js 与 open-sse/rtk 目录.env文件env_file: .env会自动加载宿主机同目录.env因此务必在其中写入JWT_SECRET、INITIAL_PASSWORD等敏感变量不要提交到版本库数据卷命名卷9router-data挂载到/app/data配合 Dockerfile 的 entrypoint 自动修正权限。使用 Compose 运行# 先准备 .env参考上文环境变量表 # 启动服务 docker compose up -d # 查看日志 docker compose logs -f # 停止服务 docker compose down # 重新构建并重启本地镜像构建时 docker compose up -d --build仓库还提供了 start.sh 作为快速重建脚本停止并删除旧容器 → 构建镜像 → 以.env环境变量与数据卷运行适合开发迭代./start.shNginx 反向代理为什么使用 NginxSSL/TLS 终止统一管理证书应用层保持 HTTP域名映射对外暴露https://your-domain.com隐藏实际端口负载均衡多实例扩展时的入口分发更好的安全性统一入口控制、限流、隐藏后端指纹。步骤 1安装 Nginxsudo apt update sudo apt install nginx步骤 2配置 Nginx创建/etc/nginx/sites-available/9router。以下配置将HTTP 80 重定向到 HTTPS 443并在 443 上同时代理仪表盘根路径 → 20128若用npm run start部署则改为 20127与/v1LLM API→ 20128。SSE 支持是流式输出的关键proxy_buffering off与proxy_read_timeout 86400缺一不可否则 AI 流式响应会被缓冲或提前断开server { listen 80; server_name your-domain.com; # Redirect HTTP to HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name your-domain.com; # SSL certificates (use certbot to generate) ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; # SSL configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # Proxy to 9Router (Docker / PORT20128 时使用 20128npm run start 时为 20127) location / { proxy_pass http://localhost:20128; 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_cache_bypass $http_upgrade; # SSE support - CRITICAL for streaming proxy_buffering off; proxy_read_timeout 86400; } # API endpoint (OpenAI-compatible /v1) location /v1 { proxy_pass http://localhost:20128; 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; # SSE support - CRITICAL for streaming proxy_buffering off; proxy_read_timeout 86400; } }结合 custom-server.js 的实现Nginx 与 9Router 位于同一主机时转发头会被视为可信来源TCP 对端为回环地址应用据此还原真实客户端 IP 用于限流与日志X-Forwarded-Proto: https还会触发 dashboardSession.js 的shouldUseSecureCookie为auth_tokenCookie 自动启用Secure标志保证 HTTPS 下 Cookie 不泄露。步骤 3启用站点# 创建软链接 sudo ln -s /etc/nginx/sites-available/9router /etc/nginx/sites-enabled/ # 测试配置 sudo nginx -t # 重新加载 Nginx sudo systemctl reload nginx步骤 4使用 Lets Encrypt 配置 SSL# 安装 certbot sudo apt install certbot python3-certbot-nginx # 获取 SSL 证书 sudo certbot --nginx -d your-domain.com # 自动续期已自动配置 # 测试续期 sudo certbot renew --dry-run安全注意事项1. 修改默认凭据关键部署前修改JWT_SECRET和INITIAL_PASSWORD# 生成安全的 JWT secret openssl rand -base64 32 # 将该值用于 JWT_SECRET export JWT_SECRETgenerated-secret-here源码层面还有几层值得注意的加固逻辑默认密码强制改密src/app/api/auth/login/route.js 中当数据库未设置密码且未配置INITIAL_PASSWORD时远程客户端登录会返回mustChangePassword: true强制用户先修改密码再使用仪表盘避免默认密码123456暴露在公网登录限流同一 IP 连续失败会被锁定checkLock/recordFail返回 429 并附Retry-After有效抵御暴力破解远程 API 需要 KeydashboardGuard.js 规定/v1等 LLM API 前缀在远程访问时必须有合法 API KeyAuthorization: Bearer/x-api-key/x-goog-api-key/ URLkey参数均可本地回环访问除外本地专有接口/api/mcp/、/api/tunnel/*、/api/auth/reset-password、/api/headroom/*等会启动子进程或读取宿主机敏感信息的路由被列入LOCAL_ONLY_PATHS仅允许本机回环地址 合法 JWT或携带 CLI Token 的请求访问见 dashboardGuard.js 的canAccessLocalOnlyRoute。2. 防火墙配置# 允许 SSH sudo ufw allow 22/tcp # 允许 HTTP/HTTPS若使用 Nginx sudo ufw allow 80/tcp sudo ufw allow 443/tcp # 若不使用反向代理放开 9Router 端口 sudo ufw allow 20128/tcp # 启用防火墙 sudo ufw enable原文档示例为3000/tcp当前仓库实际对外端口为20128以及npm run start模式下的20127请按实际监听端口放行。3. 限制仪表盘访问如果只需要 API 访问可限制仪表盘端口仅允许 localhost 访问# 仅允许 localhost 访问仪表盘以 20128 为例或对 20127 执行同样操作 sudo ufw deny 20128/tcp注意直接deny端口也会同时阻断/v1API。若希望只开放 API 而隐藏仪表盘更稳妥的做法是不开放任何公网端口仅通过 SSH 隧道访问仪表盘API 则通过 Nginx 按路径分流并配合 dashboardGuard.js 的 API Key 校验实现。通过 SSH 隧道访问仪表盘ssh -L 3000:localhost:20128 useryour-server.com # 然后在浏览器打开 http://localhost:30004. 定期更新# 更新系统包 sudo apt update sudo apt upgrade -y # 更新 9Router当前仓库根目录即应用目录无需进入 app 子目录 cd /path/to/9router git pull npm install npm run build pm2 restart 9router5. 备份策略# 备份数据目录 tar -czf 9router-backup-$(date %Y%m%d).tar.gz /var/lib/9router # 每日自动备份加入 crontab注意 % 需转义 0 2 * * * tar -czf /backups/9router-$(date \%Y\%m\%d).tar.gz /var/lib/9router数据目录包含 SQLite 数据库、jwt-secret密钥文件与请求记录是恢复服务的唯一凭据务必纳入备份若使用 Docker 命名卷9router-data可通过docker run --rm -v 9router-data:/data -v $(pwd):/backup alpine tar czf /backup/9router-backup.tar.gz -C /data .备份卷内容。监控检查应用状态# PM2 状态 pm2 status # 查看日志 pm2 logs 9router --lines 100 # 监控资源 pm2 monitNginx 日志# 访问日志 sudo tail -f /var/log/nginx/access.log # 错误日志 sudo tail -f /var/log/nginx/error.log系统资源# CPU 和内存使用 htop # 磁盘使用 df -h # 网络连接确认监听端口 netstat -tulpn | grep -E 20127|20128如需更细粒度的请求调试可设置ENABLE_REQUEST_LOGStrue并重启应用open-sse/utils/requestLogger.js 会输出 debug 级请求/响应日志便于定位代理链路问题生产环境建议仅在排查时临时开启。故障排除应用无法启动# 查看日志 pm2 logs 9router # 检查端口是否被占用 sudo lsof -i :20127 sudo lsof -i :20128 # 检查环境变量 pm2 env 9router若日志中出现[DATA_DIR] ... not writable → fallback ~/.9router之类的警告说明DATA_DIR指向的目录权限不足见 src/lib/dataDir.js数据落到了默认目录需修正目录属主并重启。Nginx 502 Bad Gateway# 检查 9Router 是否运行 pm2 status # 查看 Nginx 错误日志 sudo tail -f /var/log/nginx/error.log # 测试 Nginx 配置 sudo nginx -t502 的常见原因包括后端端口与 Nginxproxy_pass不一致例如npm run start为 20127 却代理到 20128、Docker 容器未启动、防火墙拦截了回环流量等。SSE 流式输出无法工作确保 Nginx 配置中已设置proxy_buffering off配合proxy_read_timeout 86400这是流式响应不被缓冲的关键同时确认proxy_http_version 1.1与Upgrade/Connection头已按上文示例配置。权限被拒绝错误# 修复数据目录权限 sudo chown -R $USER:$USER /var/lib/9router chmod 755 /var/lib/9routerDocker 场景下若挂载卷出现权限问题可检查 Dockerfile 内置的/entrypoint.sh启动时会自动chown -R node:node /app/data /app/data-home必要时手动修正宿主机卷属主。下一步完成云端部署后可继续阅读仓库内相关文档连接提供商配置 Claude / Gemini / GPT 等提供商订阅配置组合利用自动故障切换组合多个提供商避免触达限额集成工具将 Cursor、Claude Code 等工具接入部署好的 9Router 网关其他部署场景可参考 localhost 部署 与 快速开始。【免费下载链接】9routerUnlimited FREE AI coding. Connect Claude Code, Codex, Cursor, Cline, Copilot, Antigravity to FREE Claude/GPT/Gemini via 40 providers. Auto-fallback, RTK -40% tokens, never hit limits.项目地址: https://gitcode.com/GitHub_Trending/9r/9router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考