引入
众所周知,tailscale 这个工具可以把位于防火墙/ NAT 后方的机器进行组网,并且可以自动处理打洞问题尽量获得直连的效果。
但是有一个非常大的问题,tailscale 官方不支持用你自己的域名!而且,即使使用官方的域名服务,启用 MagicDNS 时会造成系统 DNS 被抢夺,造成各种奇奇怪怪的网络问题……因此,我们通常都会这么做:
1 | |
来禁用 DNS 抢夺。
那么问题来了,我们难道真的束手无策吗?不能用上自己的域名,来访问内网 tailscale 的服务吗?
当然是可以的!但是,我们需要一点小 trick……
为了让你有个直观的印象,先来看看成品吧。

如果你试着键入这个域名,是打不开的——因为这是一个运行在我的 tailnet 上的网站,只有安装了 tailscale 并加入我的 tailnet 才能访问这个网站。你可以看到,ssl 完全正常,也没有用自签名证书,并且域名后面什么端口都不用加。
服务本身的要求
本文仅涉及「http 反向代理」的服务。ssh / rdp 这些需要用 Nginx 的 stream 进行代理,可自行探究,本文暂时不涉及
但是,在我们开始之前,必须先了解一下域名、DNS、反向代理、SSL 证书的知识。如果你已经知道这部分知识了,可以直接跳过下一章~
前置准备
放心,你不需要精通计算机网络,本文只是简略地介绍这些内容来辅助零基础的读者。比如,你不需要看下面这本书。

让我们开始吧!
域名和 DNS
我们先来看公网的情况。
你有没有想过,你键入一个域名之后,你的浏览器到底干了些什么?换句话说,它到底上哪里找网页递给你的?
我们当然知道网页和 Web 程序位于一台服务器上,而每台服务器都有一个 IP 地址,浏览器对这个 IP 发出请求,服务器再把网页返回给你。
而将「域名」解析为「IP 地址」的过程,就需要 DNS 服务的参与啦。当你给自己的域名设定好解析之后,全世界的 DNS 服务器就会通过逐层接力的方式,找到你设置的 IP 地址,并把它返回给请求你的网站的客户端。
反向代理
现在我们来看另外一个问题。你有台服务器,但是一台服务器上服务太多了,你想要一次开一堆网站怎么办?
当然是可行的了!
你既然都来到这里了,肯定知道服务可以绑定端口(tailscale ip + 端口,你肯定用过)。而给不同服务绑定不同端口,就可以实现在一个网站上开多个服务了。
但是我们现在绑定了域名。如果每次都要让用户在域名后面加端口,既不美观也不方便。那么,能否通过「请求的域名」来找到对应的服务呢?比如说,请求 a.example.com 就返回 1145 端口上运行的服务,请求 b.example.com 就返回1919 端口上运行的服务,请求 samhou.moe 的时候,就返回 4433 端口上运行的服务,等等。
小提示
不同二级域名也可以绑定同一个 ip。只要域名有任何字符不一样,绑定的网站就可以不同。
让我们隆重介绍——「反向代理」!
当我们键入域名,浏览器通过 DNS 请求到服务器 ip 时,会自动在请求头中带一个 Host。你可以动手用 curl 实操试试:
1 | |
输出中肯定有类似这样的信息……
1 | |
curl 已经自动帮你把 Host 放到请求头里面了!
这是一个非常、非常重要的性质——
反向代理可以通过 Host 头,来判断你要访问的是服务器上的哪一个网站。
反向代理通常运行在 80/443 端口上,根据 Host 头响应请求,将这些端口上的请求路由到对应设定的服务器。
默认端口
80 443 是默认端口,因此输入域名时不需要指定它们。这就让域名变得美观了!
Nginx 是一个老牌的 web 服务器,性能非常高,通过 config 文件的方式可以配置为反向代理。
那问题来了,Nginx config 怎么配呢?
先根据官方文档装好,然后打开 /etc/nginx,看看默认的 nginx.conf 怎么写的:
1 | |
望文生义一下,默认配置文件配置了user / log 文件 / pid 等东西,而 http 块内则有最重要的一行:
1 | |
这告诉我们,真正的配置在 conf.d 文件夹中。可以这么理解——该文件夹中的所有内容会「按原样复制」到这个配置文件中,生成最终的配置。
而关于具体的配置,在下文 tailscale 内网配置中会涉及到,现在你只需要记住配置在这个文件夹里面写就可以了。
现在嘛,我们已经扯了很久前置准备了,回到正题,tailscale 到底怎么绑定域名?
解析到 ts ip
tailscale 在你连接上 tailnet 的时候,会自动给这台设备分配一个 tailscale ip。它是一个私有地址,在安装了 ts 的设备上,访问这个 ip 时 tailscale 会接管对这个 ip 的请求,然后把请求发送到对应的机器上。
去你的域名后台增加一个解析,解析到你想要运行网站的那台设备的 tailscale ip:

看到了吗?如果你用的是 cloudflare,会直接提示「保留 IP」,说明这个地址是保留的私网地址,小黄云代理会自动关闭。
就这么简单!如果你的设备上已经在某个端口运行了服务,可以直接用域名 + 端口的方式访问这台设备上的对应服务。
如果你依然打不开,可以检查一下自己的路由器是否会丢弃解析到私网地址的 DNS 请求。比如,openwrt 中的「网络 - DNS - 过滤器 - 重绑定保护」选项,如果打开了,会直接造成私网 DNS 解析为空的问题,需要关闭:

不用记下 ip 用域名已经是巨大的进步了。但是,问题是它没有 SSL 支持,虽然 tailscale 本身就已经有一层加密,但是某些程序/网页可能必须要求安全的 https 连接。而且,每次都要记下哪个程序对应哪个端口,是一件非常废脑子的事情。
反向代理
所以,该怎么解决上面两个问题?
不知道你还记不记得前文提到的反向代理,如果在公网上可以这么干,为什么不直接应用到 tailscale 上呢!
也就是说,访问链路是这样的:
键入域名 - 请求域名 DNS 返回 ts ip - 请求 ts ip 上的 80/443 默认端口 - 目标机器上的 nginx 根据 host 头判断该交给哪个服务 - 对应服务收到你的请求,并返回内容。对,和前文提到的公网几乎就是一个道理,tailscale 只是影响了请求 ip 这一段,当你请求 ts ip 的时候代理你的请求,其余完全不变。
这就简单了,我们刚刚提过反向代理的配置,现在来看看具体怎么写 config。
化繁为简
本文受限于篇幅,无法讲清楚 Nginx 的所有配置。因此,只会丢出一些配置文件并指出重要的配置项。因为是 tailscale 内网比较安全,你可以抄作业。
看看我这里的成品 misskey.conf,它将 samhou.de 域名绑定到了 3000 端口的服务——
1 | |
它做了以下事情:
- 设定反向代理目标是 3000 端口的 misskey 服务
- 80 端口绑定域名
server_name samhou.de;(对,这里 server_name 就是前文所述匹配 Host 头的地方),然后 301 重定向到 443 端口(自动 http 到 https 跳转) - [::] 表示 IPv6 也监听。
- 443 端口 ssl 监听,设定证书
ssl_certificate /etc/nginx/samhou.de.cert.pem;,然后反向代理/(也就是域名根目录)到 misskey 服务proxy_pass http://misskey;
那问题来了,我们该配置什么证书呢?
当然是和域名对应的有效证书啦。浏览器才不管你请求了哪个 ip,只要远程服务器返回的证书和域名匹配,那么就可以证明这台服务器的身份。
对,获取证书的免费方法就是 acme。
但是,由于是私网 ip,公网验证是做不到了,只能通过添加 dns 解析来验证。
这部分大家应该都会,所以这里只放出几条命令,每个人的域名解析提供商都不同,可以参阅 acme 的文档来配置。
1 | |
证书签发之后,重启 nginx,现在访问网站就可以看到已经升级为安全连接了。
多个网站
我们已经看了一个示例网站,那么多个网站也不在话下了,只要简单地再创建一个 other_service.conf 反向代理配置文件,然后稍微复制改改就可以了(注意证书覆盖哦):
1 | |
保存,重载 Nginx,你会发现访问 a.example.com 和 samhou.de 这两个网站,会分别出现 1145 和 3000 端口上运行的服务。
后记
在这篇文章里,我们把反向代理和 tailscale 结合起来用,让你可以把域名绑定到 ts 上的服务。其实这整个过程和公网并无太大区别,所以本作也可以说是「部署公网服务」的教程(笑)。
啰啰唆唆了一大堆,其实和 ts 关系不大嘛。
总之,食用愉快~














