TSLinkTSLink 文档

Vite 在 ts.net 地址上报 Blocked request 怎么办

Vite 拒绝 ts.net 主机并提示 Blocked request。把 .ts.net 加入 server.allowedHosts,或通过 TSLink 地址访问开发服务器。

最后更新于

查看 Markdown

如果 Vite 在 Tailscale 地址上显示下面的报错:

代码
Blocked request. This host ("<device>.<tailnet>.ts.net") is not allowed.
To allow this host, add "<device>.<tailnet>.ts.net" to server.allowedHosts in vite.config.js.

原因是 Vite 的 Host 校验:请求带着 ts.net 的 Host 头到达,而这个主机名不在 server.allowedHosts 里,开发服务器就拒绝了它。 有两种修法。一种是把 .ts.net 加入 server.allowedHosts,另一种是通过 TSLink 地址访问开发服务器。TSLink 默认把 Host 头改写成上游地址,Vite 看到的就是它自己的地址。2026-10-22 我们用 Vite 8.3.5 实测,没有修改 Vite 配置,页面和 HMR WebSocket 都能正常工作。TSLink 是独立项目,并非由 Tailscale 出品。

修法一:在 Vite 里放行这个主机

Vite 的 server.allowedHosts 列出开发服务器可以响应的主机名。默认值是空列表,localhost、.localhost 下的域名和所有 IP 地址默认放行。以点开头的字符串会放行该主机名及其全部子域名:

js
// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  server: {
    allowedHosts: ['.ts.net'],
  },
});

.ts.net 是公开报告里使用的写法(portless issue 310 展示了这个报错,jhin 的一个 pull request 加入了 allowedHosts: [".ts.net"])。Vite 文档建议只添加解析归你控制的主机,并提醒不要添加顶级域名这类过宽的条目。更收紧的选择是你自己的 tailnet 后缀,例如 .<tailnet>.ts.net,只放行你自己 tailnet 下的名字。如果运行的是 vite preview 而不是开发服务器,则要设置 preview.allowedHosts,它默认取 server.allowedHosts 的值。

不用修改 vite.config.js,直接注册开发服务器(假设监听 5173):

bash
tslink add web --proxy localhost:5173 --allow you@example.com
tslink url web --wait

把登录名换成你的 Tailscale 账号,然后在手机或 tailnet 里的其他设备上打开打印出的 <name>.<tailnet>.ts.net 地址。用完执行 tslink remove web。首次运行可能打印一个入网链接(needs_login),在浏览器里打开一次即可。

能生效的原因在于 TSLink 的一个默认行为:它的 HTTP 代理把 Host 头改写成本地目标,并转发 WebSocket 升级请求。--preserve-host 参数会改变这一点,让节点转发自己的外部 Host。如果传了这个参数,Vite 又会看到 ts.net 名字,这时需要用修法一。

我们测了什么

  • 环境: 全新的 npm create vite@latest vanilla 应用,Vite 8.3.5,监听 127.0.0.1:5197,TSLink 0.0.0-local.20261020.0149.1+3739bb9b,日期 2026-10-22。
  • 不经过 TSLink: 直接请求并带上 Host: vite-probe.<tailnet>.ts.net,返回 403,正文是 Blocked request. This host ("vite-probe.<tailnet>.ts.net") is not allowed.
  • 经过 TSLink: 用 tslink add vite-probe --proxy localhost:5197 --allow <login> --ephemeral 注册。通过返回的 vite-probe.<tailnet>.ts.net 地址访问,/ 返回 200(text/html),没有 Blocked 字样;/@vite/client 和 /src/main.js 返回 200;HMR WebSocket(Sec-WebSocket-Protocol: vite-hmr)返回 101 Switching Protocols。vite.config 没有改动。
  • 收尾: tslink remove vite-probe 成功,列表中不再出现该服务,URL 也不再响应。

这次测试只覆盖一个 Vite 版本和 vanilla 模板,没有覆盖自带额外检查的插件、其他框架,也没有测试带 --preserve-host 的注册。如果你的环境属于这些情况,请先自己验证,再依赖这个结论。

Next.js 有自己的校验

Next.js 有另一个设置,叫 allowedDevOrigins。它的文档说明,开发服务器已经放行 localhost、它的子域名和启动时使用的主机名,其他主机名都需要一条配置。我们没有测试过 TSLink 配合 Next.js 的情况,请假定你的 ts.net 名字仍然需要这条配置:

js
// next.config.js
module.exports = {
  allowedDevOrigins: ['*.<tailnet>.ts.net'],
};

按这套语法,* 恰好代表一级标签,因此这条规则匹配 web.<tailnet>.ts.net。公开例子里有 agent 添加这一行的 Scouthosting pull request 131 和 kingdom-sites pull request 23。

  • 只想在一台机器上消除这个报错。 vite.config.js 里加一行就够了,不需要多一个工具。
  • 希望修复写在项目里。 修法一随仓库一起走,修法二依赖 TSLink 的默认 Host 处理。
  • 你用的是 Next.js。 无论如何都要计划添加 allowedDevOrigins。
  • 需要跨主机的稳定名字或自己的域名。 关于 Tailscale Services,见一台机器多个服务;TSLink 只提供 *.ts.net 名字。
  • 开发服务器必须在没有 Tailscale 的情况下可访问。 TSLink 的私有应用要求打开它的设备装有 Tailscale。

相关页面

以上 Tailscale、Vite 与 Next.js 官方来源访问日期:2026-10-22。TSLink 行为以 v0.2.0 为准。TSLink 是 anydoor7 的独立项目,并非由 Tailscale 制作或背书。

目录