portless 无交互环境指南:CI 与任务运行器中没有 TTY 时如何正确启动
【免费下载链接】portlessReplace port numbers with stable, named local URLs. For humans and agents.项目地址: https://gitcode.com/GitHub_Trending/por/portless
portless 是一款用稳定的命名本地 URL(如https://myapp.localhost)替代端口号的开发工具,让人类和 AI Agent 都能通过固定域名访问本地应用。但把它放进CI 流水线或turborepo 任务运行器这类无 TTY 的无交互环境时,直接运行portless往往会失败。这篇指南带你快速搞懂 portless 的非交互行为,并给出 3 种正确启动方式,让任务运行器"零提示、秒失败、可诊断"。
为什么 portless 在没有 TTY 时会拒绝继续?
在本地终端里,portless 启动代理(proxy)绑定 443 端口时可能需要sudo 提权,此时它会弹出交互提示等你确认。但在 CI、脚本、任务运行器里,根本没有人在"确认"。
portless 的设计原则是:无交互环境直接报错退出,而不是挂起等待输入。这样 turborepo、CI 脚本能在第一时间拿到清晰错误信息,而不是卡死半小时。
| 环境 | portless 行为 |
|---|---|
有 TTY 的终端(且未设CI=1) | 正常交互,可提示输入 sudo 密码 |
| 无 TTY(CI、脚本、任务运行器) | 输出描述性错误并立即退出(exit 1) |
相关实现可参见 cli.ts 中的交互性判断与错误提示逻辑,官方说明见 README.md。
portless 如何判定"非交互模式"
portless 的判定条件只有两个(见 cli.ts):
process.stdin.isTTY为 false—— 标准输入不是终端(管道、CI 环境常见)CI=1环境变量已设置—— 即使有 TTY,也强制进入非交互模式
💡 小贴士:如果你的脚本其实可以交互(比如本地 cron 有终端),但被 CI 平台注入了
CI=1,portless 也会按非交互处理。调试时可以先unset CI验证。
最常见的报错场景是:代理没在运行 + 需要 sudo(端口 < 1024)+ 没有 TTY。此时 portless 会打印两条出路:
# Option 1: 在终端里手动启动代理(会提示 sudo) sudo portless proxy start # Option 2: 使用非特权端口,无需 sudo portless proxy start -p 1355其中1355是 portless 内置的回退端口常量,见 cli-utils.ts。
方式一:先在交互终端预启动代理(最快上手)
最朴素的做法:代理由"人"启动,应用由"机器"启动。
- 在自己的终端执行
sudo portless proxy start(首次会生成本地 CA 并提示信任) - 代理常驻后台后,CI / 任务运行器里直接运行
portless myapp next dev即可,不再触发任何交互
代理的启动配置(端口、TLS、TLD)会持久化复用,重启机器后不会悄悄回退到默认值。适合开发机 + 本地任务运行器的组合。
方式二:用非特权端口 1355,彻底绕开 sudo
无 TTY 场景下最省心的一招:让代理绑定 1355 等非特权端口,全程不需要 sudo。
portless proxy start -p 1355 # 之后访问 https://myapp.localhost:1355也可以用环境变量固化端口,避免每次传参(环境变量清单见 README.md):
PORTLESS_PORT=1355 portless proxy start⚠️ 注意:非特权端口时,URL 会带上
:1355端口号。对本地开发无影响,但如果你的框架需要把 URL 写入配置,记得带上端口。
方式三:安装系统启动服务(CI 常驻机器的推荐姿势)
如果目标机器(比如自建 CI Runner、长期在线的开发服务器)每次开机都需要代理,最优雅的方案是让操作系统替你启动:
portless service install # 安装启动服务(launchd / systemd / 任务计划程序) portless service status # 查看端口、HTTPS 模式、TLD 等状态 portless service uninstall # 卸载- macOS / Linux 会安装 root 级服务,开机即可绑定 443 端口;Windows 则安装以 SYSTEM 运行的任务计划程序(见 service.ts)
- 安装一次,之后任何无 TTY 进程都能直接使用代理,无需 sudo、无需预启动
portless clean会自动清理该服务
这也是 skills/portless/SKILL.md 中给 AI Agent 的建议:任务运行器场景应预先确保代理可用。
任务运行器(turborepo)集成清单
针对 monorepo + turborepo 的常见组合,按下面 4 步检查即可:
- ✅确认代理已就绪:跑一次
portless service status或portless doctor,确认代理存活 - ✅在
package.json中配置:将真实命令放入独立脚本,如"dev": "portless"+"dev:app": "next dev",完整写法见 README.md - ✅避免脚本内触发 sudo:若代理尚未启动,CI 会拿到"两条出路"的报错(cli.ts),此时按报错提示选择方式一或方式二
- ✅需要时关闭 turbo 直连模式:
portless.json中可将turbo设为false改用直接子进程方式(字段说明见 README.md)
无交互环境快速排障
出问题时按顺序执行:
portless doctor # 检查代理、路由、DNS、CA 信任,并给出修复建议 portless list # 查看当前活跃路由 portless prune # 清理上次崩溃会话残留的孤儿进程- 报错 "no TTY is available for sudo":走本文方式二或方式三
- 报错 "Proxy is already running ... different config":先
portless proxy stop再重启,portless 在非交互环境下不会替你改配置,而是直接退出 - 历史背景:早期版本曾在非交互终端(如 IDE 任务运行器)中自动启动失败,已在 CHANGELOG.md 对应版本中修复
总结
| 场景 | 推荐方式 |
|---|---|
| 本地开发机 + 偶尔跑任务 | 方式一:终端预启动代理 |
| 脚本 / 一次性 CI 任务 | 方式二:-p 1355非特权端口 |
| 常驻 CI Runner / 服务器 | 方式三:portless service install |
记住一句话:让需要"人"的事情(sudo、信任 CA)发生在终端里,让需要"机器"的事情(跑应用、注册路由)发生在无 TTY 环境里。portless 用"快速失败 + 清晰报错"帮你在 CI 里第一时间定位问题,而不是无声挂起。
【免费下载链接】portlessReplace port numbers with stable, named local URLs. For humans and agents.项目地址: https://gitcode.com/GitHub_Trending/por/portless
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考