记一次 CNB 开发的踩坑
环境:云端 VSCode(CNB 云原生开发环境,容器 IP
172.17.0.50,代理域名*.cnb.run) 项目:Astro 静态站点(astro@7.1.1,npm run dev起开发服务器) 目标:让页面在云端环境里能被浏览器正常访问
一、背景:请求是怎么到页面的
浏览器 ──▶ cnb.run 代理 ──▶ 容器(172.17.0.50)里的 Astro(端口 4321)
点击 http://ceustg4pqx-4321.cnb.run,请求先到平台代理,再由代理转发进容器里的 4321 端口。
关键点:
云开发环境下,本地浏览器和跑 Astro 的容器不是同一台机器,中间隔着平台的一层代理转发。 终端里的 localhost:4321 链接,点开后是平台做的「端口转发」隧道进容器,并非客户端机器本机端口。
二、踩坑全过程
坑 1:连接被拒绝(connection refused)
现象
dial tcp 172.17.0.50:4321: connect: connection refused
原因
Astro 默认只监听 127.0.0.1(容器内部回环),而平台代理是从「容器外部网络」去连 4321 的,门只对房间内部开,外部敲不开。
解决:让服务监听所有网卡。
// astro.config.mjs
export default defineConfig({
server: {
host: true, // 监听 0.0.0.0,允许容器外部访问
port: 4321,
},
});
重启后日志出现 Network: http://172.17.0.50:4321/,说明已对外暴露。
坑 2:Host 被拦截(Blocked request)
现象
Blocked request. This host ("ceustg4pqx-4321.cnb.run") is not allowed.
To allow this host, add "ceustg4pqx-4321.cnb.run" to `server.allowedHosts` in vite.config.js.
原因
代理转发时,请求带的 Host 头是 ceustg4pqx-4321.cnb.run(平台随机分配)。而Vite(Astro 底层的开发服务器)默认校验 Host 头防 DNS 重绑定攻击,不在白名单就拒绝。
解决:放行代理域名。
// astro.config.mjs
export default defineConfig({
server: {
host: true,
port: 4321,
allowedHosts: true, // 允许反向代理域名(如 cnb.run)访问
},
});
坑 3:旧进程没杀干净,配置「不生效」
现象
改完配置 npm run dev 重启,日志却显示 Dev server already running at ... (pid 旧),用的还是旧配置。
原因 旧 dev 进程仍占着 4321 端口,新进程起不来,自然沿用旧监听/旧白名单。
解决:重启前先彻底结束旧进程。
# 用 astro 自带命令
astro dev stop
# 或直接 kill 具体 pid
kill -9 <旧pid>
教训:每次改
server配置重启前,必须确认旧进程已退出,否则会误以为配置无效。
三、最终可用配置
// astro.config.mjs
// @ts-check
import { defineConfig } from 'astro/config';
export default defineConfig({
server: {
host: true, // 监听 0.0.0.0,允许容器外部访问
port: 4321,
allowedHosts: true, // 允许反向代理域名(如 cnb.run)访问
},
});
访问方式
- 平台代理入口:
http://ceustg4pqx-4321.cnb.run - IDE 端口转发:
http://localhost:4321/ - 容器 IP 直连:
http://172.17.0.50:4321/
四、概念小课堂
什么叫「监听」(host)
服务器启动后会在容器里「开一扇门」等请求,这叫监听。
- 默认只开「只对房间内部开放」的门(
127.0.0.1)→ 外部代理敲门被拒。 host: true把门改成「对整栋楼所有网卡开放」(0.0.0.0)→ 代理能敲到了。
什么叫「放行」(allowedHosts)
门敲开后还有个**门卫(Vite 安全校验)**查访客报的「名字」(Host 头)。
- 访客报
ceustg4pqx-4321.cnb.run,不在白名单 →Blocked request。 allowedHosts: true→ 门卫不再查名字,谁来都放。
五、安全性讨论(host / allowedHosts 全开安全吗?)
| 设置 | 当前 | 更优 | 说明 |
|---|---|---|---|
host |
true |
保持 true |
开发容器 IP 是私有网段,外部不可直连,风险被网络隔离抵消 |
allowedHosts |
true |
改为具体域名 | 缩小放行范围,更规范 |
-
host: true:容器 IP172.17.0.50属内部私有网段,互联网直连不到,所有流量经平台代理,实际暴露面很小,开发环境不必改。 -
allowedHosts: true:关掉了 Host 头校验(原用于防 DNS 重绑定)。因容器 IP 私有、外部不可指向,攻击前提不成立,风险低;更规范的做法是只放行真实域名:allowedHosts: ['ceustg4pqx-4321.cnb.run'](若平台域名前缀会变动,
true是更省事的折中。)
重要区分:以上都属于 astro dev(开发服务器)的配置,不是生产配置。正式上线用 astro build 生成静态文件部署到托管平台,Host 校验由平台网关统一处理,与本地这套无关。
六、为什么 localhost:4321 也能直接访问了
因为 host: true 把监听从「只听回环」变成「听所有网卡」。无论哪种到达容器 4321 的方式——平台 cnb.run 代理、IDE 的 localhost 端口转发、容器 IP 直连——卡的是同一个点(门没对外开)。门一开,三者一起通。
这也印证了排障顺序:先过「连接被拒」(监听),才轮到「Host 拦截」(白名单)。两道关卡是串行的。
七、小结
让 Astro 页面在 CNB 云端环境可访问,核心就两步:
- 监听
0.0.0.0(host: true)——让外部能连进容器端口; - 放行代理域名 Host(
allowedHosts)——让 Vite 不拦代理请求。
顺带提醒:这些坑本质属于「前端工具链 / 开发环境 / 部署」,并非前端页面本身的逻辑复杂度。