1. 阿里云上 app.js 报 EADDRNOTAVAIL:先把监听地址从公网 IP 换掉
把 Nodejs 项目部署到阿里云,node app.js报Error: listen EADDRNOTAVAIL时,我喜欢用 TaoToken 给 Codex 配统一 API 通道来排查。先去 TaoToken 拿 Key,把 Base URL 填成 https://taotoken.net/api,再让模型读 app.js 的server.listen。这个错最常见的原因,是server.listen(3000, '47.98.xx.xx')把阿里云的公网 IP 当成了 bind 地址,而云主机的操作系统里根本没有这个网卡地址。
排查的思路很直接:把监听地址改成 0.0.0.0,让 Nodejs 监听本机所有网络接口。下面从报错原理开始,逐步把 Codex 配置、代码修改、外网验证串起来。
1.1 公网 IP 不是给你 bind 的
云服务器和本地虚拟机有一点本质区别:阿里云的公网 IP 是映射出来的,操作系统看到的往往是内网 IP。你可以登录服务器执行ip addr,里面会出现类似172.16.x.x或192.168.x.x的网卡地址,但看不到控制台上那个公网地址。Nodejs 的server.listen(port, host)要求 host 必须是当前机器网卡上真实存在的地址,所以把公网 IP 写进去,bind 阶段就会报 EADDRNOTAVAIL。
0.0.0.0的意思是监听本机所有网络接口上的指定端口,不管请求从内网 IP 进来,还是从公网映射进来,都能被 Nodejs 接收。这是阿里云部署 Nodejs 最稳的监听方式。注意这里不是让你把127.0.0.1当万能答案,127.0.0.1只在本机内部可访问,外网请求进不来。0.0.0.0和127.0.0.1都指向本机,但绑定范围完全不同。
// 这样写大概率 EADDRNOTAVAIL server.listen(3000, '47.98.xx.xx', () => { console.log('服务器启动成功'); }); // 改成本机所有接口 server.listen(3000, '0.0.0.0', () => { console.log('服务器启动成功'); });改成0.0.0.0之后,服务会暴露在所有网卡上,生产环境建议配合安全组限制来源 IP,不要让 3000 端口完全裸奔。监听地址只是启动条件,安全边界靠安全组控制。
1.2 还有一道安全组在 3000 端口前面
即使监听地址改成0.0.0.0且node app.js正常打印了「服务器启动成功」,也不代表外网能访问。阿里云安全组是独立于操作系统防火墙的一层规则,入方向默认只放行 22、80、443 等常用端口,3000 这种业务端口需要手动加规则。检查方法是在控制台找到安全组,添加入方向规则:协议选 TCP,端口写 3000,授权对象选0.0.0.0/0。
所以要把两类问题分开看。node app.js报 EADDRNOTAVAIL,是代码问题;node app.js正常但外网 telnet 不通,多半是安全组或域名解析。前者让 Codex 读代码就能定位,后者要去控制台改规则,不能混为一谈。
2. 在 ~/.codex/config.toml 里把 Codex 接到 TaoToken
配好 Codex 是为了让排障过程少一点翻来覆去。平时用一个模型试到额度不够,又要换 Key、换供应商,非常打断思路。TaoToken 在这一环只负责提供一个统一的 API 通道,你拿一把 Key 配进去,Codex 就能稳定跑完整个监听排查,中途不用再折腾账号。
2.1 需要提前准备好的清单
开始部署前,先把材料准备齐。大多数东西在原文的部署流程里都要用到,TaoToken 的 API Key 是额外的一件,只用来让 Codex 走 API 通道,不改变你的部署路径。
- 阿里云服务器:轻量应用服务器即可,系统选 Ubuntu 或 CentOS。轻量服务器支持不少应用镜像,能省去手动装环境的时间。
- Node 和 npm:
node -v、npm -v能正常输出。 - MongoDB:如果项目依赖数据库,安装完成后准备一个数据目录,例如
/root/mymongodb/data。 - XShell / Xftp 或网页终端:XShell 连远程终端,Xftp 传项目文件。
- Codex CLI:
codex --version可用。 - API Key:打开 TaoToken 注册,进控制台创建一把 Key,然后把 Key 填到后面的环境变量里。
这里有个细节:Codex 默认按自己的方式找模型供应商,不配置的话它只认 OpenAI 的地址。我们要做的是在~/.codex/config.toml里新增一个 provider,让 Codex 把请求发到 TaoToken。
2.2 config.toml 的 provider 配置
打开~/.codex/config.toml,写成下面这样。model字段先留占位符,模型 ID 以 模型广场 当时列表为准,不要照抄网上流传的 ID。
model = "MODEL_ID_FROM_TAOTOKEN" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY"注意:
base_url只填https://taotoken.net/api,末尾不要带/v1,也不要拼到具体模型路径上。官网落地页和控制台是两个地方,填进 Codex 的一定是/api这个接口地址。
保存后,在终端导出 Key:
export TAOTOKEN_API_KEY=YOUR_API_KEYenv_key字段告诉 Codex 从哪个环境变量取 Key,所以变量名必须和配置里的名字一致。想验证配置是否生效,可以跑一句最简单的:
codex exec "用一句话说明 0.0.0.0 和 127.0.0.1 的区别"能正常返回,说明 Codex 已经能走 TaoToken 通道访问模型。这一步过了,再去检查 app.js。
3. 让 Codex 读 app.js 的 server.listen,回到 vim 改 0.0.0.0
配置通了之后,剩下的活就交给 Codex 来定位。这里要说清楚边界:Codex 只负责读代码、解释代码、生成修改建议,真正改文件和重启服务的动作由你在服务器上完成,改完再把结果贴回来,这样不容易出现模型直接操作生产环境的意外。
3.1 把报错原文交给 Codex
先把报错原样丢给 Codex,并给出明确的文件路径。prompt 里同时包含报错信息和目标文件,Codex 才能快速定位到server.listen那一段。
cd /root/project codex exec "app.js 启动时报 Error: listen EADDRNOTAVAIL。请读取 app.js,找出 server.listen 这一行,分析当前的监听地址写成了什么,并告诉我应该改成哪个值。"Codex 大概率会返回这样一段结论:当前监听地址写成了公网 IP,云服务器上 bind 不了,应该改成0.0.0.0,或者直接把 host 参数删掉只保留端口。显式写0.0.0.0更清楚,后面的人看到也知道这是故意监听所有接口。如果项目里还有别的服务需要监听指定内网 IP,Codex 也会提醒你这两者的区别。
拿到建议后,你自己在服务器上改文件:
vim /root/project/app.js按i进入编辑模式,把server.listen的 host 改成'0.0.0.0',按Esc退出,输入:wq保存。
3.2 服务器上 mongod 和 node 两个窗口怎么配合
很多 Nodejs 项目部署时要用 MongoDB,mongod 必须单独占一个终端窗口,否则node app.js会一直报连接数据库失败。这个报错看起来也像「服务起不来」,但和监听 IP 无关,排查时要分开看。
# 终端 1:先启动 mongod cd /root/mongodb/bin ./mongod --dbpath=/root/mymongodb/data # 终端 2:再启动 node 服务 cd /root/project node app.jsmongod 窗口出现waiting for connection on port 27017,说明数据库正常。node 窗口打印「服务器启动成功」,说明监听地址已经被接受。如果项目第一次上传,记得先执行npm install把依赖装好,这一步 Codex 不会替你跑。
4. 0.0.0.0 改完外网仍不通:安全组和域名挨个查
监听地址改对后,最常见的现象变成:终端显示服务器启动成功,但浏览器还是打不开。这时候不要急着怀疑 Codex 给的建议,先按网络路径一层层查。
4.1 先在本机 curl,再放行安全组
先在服务器本机验证一次,确认 Nodejs 进程确实在监听:
curl 127.0.0.1:3000有响应说明监听没问题。接下来在外网机器上执行:
telnet 你的阿里云公网IP 3000能连上说明监听和网络链路都通;连不上说明被安全组或防火墙挡了。这一步能帮你把问题准确切到「代码层」还是「网络层」,也让 Codex 的判断更有边界感。
提示:
curl 127.0.0.1:3000只验证本机,外网访问还要看安全组。阿里云控制台的安全组规则里没有放行 3000 时,外网通常表现为连接超时,而不是连接被拒绝。
去阿里云控制台找到这台服务器的安全组,添加入方向规则:协议 TCP,端口 3000,授权对象0.0.0.0/0。如果只想给固定办公网 IP 开放,授权对象写你的公网出口 IP 更严谨。端口改了的话,规则也要跟着改。
4.2 域名解析、备案和 XShell 窗口占用
域名部署时,先在 DNS 控制台加一条 A 记录,把域名指向公网 IP。解析是否生效可以ping 域名看返回的 IP,但 ping 只能验证解析,端口还是要 telnet。域名未备案时,阿里云会弹出「该网站禁止访问」的拦截页面,4G 网络下基本必拦,Wi-Fi 下多刷新几次偶尔能正常打开。这是部署时的常见坑,容易让人误判成服务没起来。
另外要注意 XShell 或网页终端的窗口占用。mongod 独占一个窗口,那个窗口一旦关闭,数据库进程跟着退出,node app.js又会报连接不上 27017。表面看是监听失败,实际是数据库没了。排障时把这类前提告诉 Codex,它给出的建议会更准。
5. 部署路上的两个暗坑:相对路径 ./ 和 3000 端口残留
监听地址改成0.0.0.0之后,服务能启动了,但后续还有两个高频问题,和监听失败一样容易让人绕圈子。
5.1 相对路径导致的静态资源 404
页面能打开,但 CSS、JS、图片全 404,通常是路径问题。Nodejs 里相对路径是相对你执行node app.js时所在的目录,不是相对 app.js 文件所在目录。比如 app.js 放在/root/project,你在/root目录执行node project/app.js,代码里的./public会被解析成/root/public,而不是/root/project/public。
// 不推荐,依赖启动目录 app.use(express.static('./public')); // 推荐,用 __dirname 定位 const path = require('path'); app.use(express.static(path.join(__dirname, 'public')));部署脚本或 systemd 的 WorkingDirectory 不一致时,./就会指向错误目录。可以让 Codex 扫一遍 app.js 里的路径写法,提前发现这类问题,而不是等浏览器报 404 再猜。
5.2 重复启动 app.js 导致端口被占
开发时反复敲node app.js,旧进程没退出,新进程会报Error: listen EADDRINUSE。这个错和 EADDRNOTAVAIL 长相接近,都在启动阶段出现,但原因不同:一个是端口被占,一个是地址绑不上。把报错贴给 Codex 时,尽量带上完整的错误名。
lsof -i:3000 kill -9 PID node app.jsCodex 看到 EADDRINUSE,第一反应是让你查端口占用;看到 EADDRNOTAVAIL,第一反应是问你监听地址。两个状态混在一起描述,模型给出的命令会绕远路。
6. 用刚才的 Key 去控制台对一次 Codex 调用
排障跑通后,建议顺手验证一下这次调用有没有正常记账,免得下次排查时发现 Key 状态不对。
6.1 验证 Key 和模型 ID 是否匹配
在 TaoToken 模型对话 里用同一把 Key 发一条测试消息,确认模型 ID 和 Base URL 没填错。对话页能正常回,说明 Key 有效、模型 ID 正确;如果 Codex 那边报鉴权错误,就检查TAOTOKEN_API_KEY环境变量有没有真的 export 上,变量名和env_key是否一致。
6.2 按使用频率看 Coding Plan 和 Key 管理
如果你打算让 Codex 在之后的日常开发里长期跑这种排查任务,可以打开 Coding Plan 看套餐是否够用。新 Key 在 控制台 API Keys 创建,需要多把 Key 分场景使用时,可以在这里统一管理。之前用 Claude Code 的同事,也可以对照 Claude Code 接入文档 把环境变量配到同一把 Key 上。
先把 app.js 的监听地址改掉,再用这把 Key 把 Codex 拉起来,两分钟就能判断问题是出在监听行还是安全组。