想在手机上打开 Mac 正在运行的网页。在电脑上输入 http://localhost:4173 一切正常,把同样的地址输进手机,却什么也看不到。有时,在家里 Wi-Fi 下能打开的地址,出门后也用不了了。网页明明没变,换一台设备、换一个网络,到底有什么不同?
要弄清连接过程,需要同时看 URL 中的目的地址,以及服务器接收连接的条件。IP 地址指向网络中的目的地,端口指向这个目的地上的通信入口。绑定决定服务器使用哪个本地地址和端口,进程则是正在运行的程序。 通往目的地的路径和访问权限也得具备,页面才能打开。
下面以手机访问 Mac 上的 Node Web 服务器为例。这个服务器通过 TCP 端口 4173 提供网页。4173 是本例的设置,服务器也可以配置为使用其他端口。

这张图表达的是从不同网络出发,连接到同一台电脑上的服务器。它是概念插图,并非实际网络拓扑或产品界面的记录。
IP 地址和端口分别告诉我们什么?
在 http://100.x.y.z:4173 中,http 表示通信方式,100.x.y.z 是目的 IP 地址,4173 是目的端口。这里的 x.y.z 只是示意用的占位符;连接时,要换成实际分配给 Mac 的数字。
| 概念 | 回答的问题 | 本文的例子 |
|---|---|---|
| IP 地址 | 发往网络中的哪个地址? | Mac 的局域网地址或 Tailscale 地址 |
| 端口 | 发往这个地址上的哪个通信入口? | TCP 4173 |
| 绑定 | 服务器使用哪个本地地址和端口? | 127.0.0.1:4173 或 0.0.0.0:4173 |
| 进程 | 实际由哪个程序处理请求? | 正在运行的 Node 程序 |
把 IP 地址想成设备的名牌,有助于入门。不过,一台电脑可以有多个地址。Mac 的 Wi-Fi 地址、Tailscale 地址和指向自己的回环地址,各有用途。所以,问“Mac 的 IP 是多少”时,还得补上一个条件:准备从哪里、沿哪条路径连接?
端口是操作系统用来区分网络通信的编号。TCP 和 UDP 各自使用端口号,即使数字相同,也属于不同的通信入口。编号范围是 0–65535,其中 0 是保留端口。IANA 端口注册表
多个进程也可以共享同一个服务端口。例如,Node 的 cluster 能让多个工作进程分担同一服务器端口上的连接。只看端口号,无法断定背后有多少个进程在处理请求。Node.js cluster 文档
多个访客也能连接到同一个 4173 端口。TCP 通过连接两端的 IP 地址和端口组合来区分连接。手机这一端同样有源端口,因此,发往同一服务器端口的连接可以分别管理。TCP 规范 RFC 9293
手机上的 localhost 指向手机自己
localhost 和 IPv4 回环地址 127.0.0.1 指向的是发出请求的设备本身。在 Mac 上输入,就指向 Mac;在手机上输入,就指向手机。回环地址不会像普通的远程目的地址那样被转发出去。IANA 特殊用途 IPv4 地址注册表
因此,在手机上要使用 Mac 实际的局域网地址或 Tailscale 地址。选对了地址却仍然连不上,下一步就看服务器在哪里等待连接。
绑定决定服务器监听哪个地址
如果服务器只绑定了 127.0.0.1:4173,它就通过 Mac 自己的回环地址接收连接。手机发往 Mac 其他 IP 地址的请求,不在这个监听套接字接收的范围内。监听套接字,就是服务器端等待新连接的套接字。
0.0.0.0:4173 表示在所有本地 IPv4 地址上监听,而不是只选一个。手机浏览器里的目的地址,仍然要填 Mac 的实际地址。 0.0.0.0 不是任何人都能用来找到这台电脑的公网地址。
在 Node 中省略 host 时,如果系统支持 IPv6,服务器就在 :: 上监听,否则使用 0.0.0.0。IPv6 监听套接字是否也接收 IPv4 连接,取决于操作系统和配置。排查连接问题时,应同时查看服务器日志中的地址和实际监听状态。Node.js server.listen 文档
| 服务器配置的监听地址 | 含义 | 仅凭这项设置无法保证的事 |
|---|---|---|
127.0.0.1:4173 |
在 Mac 的回环地址上监听 | 手机可以直接访问 |
192.168.x.x:4173 |
在指定的局域网地址上监听 | 同一 Wi-Fi 下的所有设备都能访问 |
100.x.y.z:4173 |
在指定的 Tailscale 地址上监听 | Tailnet 中的所有成员都有访问权限 |
0.0.0.0:4173 |
在所有本地 IPv4 地址上监听 | 公网可访问、防火墙放行或登录认证 |
确认监听地址后,还要检查路径、防火墙和访问策略。即使绑定正确,中途的限制仍可能让请求无法到达服务器。
同一个 Wi-Fi 下,不必绕到公网再回来
如果手机和 Mac 位于同一个允许彼此通信的局域网中,手机可以连接 Mac 的局域网地址。数据经过 Wi-Fi 接入点等本地网络设备到达 Mac,由操作系统交给相应的服务器套接字。这个过程不需要先出公网,再绕回来。
即使两台设备显示同一个 Wi-Fi 名称,访客网络、设备间隔离设置或 Mac 的防火墙仍可能阻止连接。这时,除了绑定设置,还要检查网络的访问限制。
出门后再输入 192.168.x.x,遇到的就是另一类问题。这类私有地址无法在公共互联网上唯一指向家里的 Mac,别的人家也可以使用同样的数字。从移动网络进入家里的局域网,需要另有一条路径。私有地址为什么不具有全球统一的含义,可以参考 RFC 1918。
Tailscale 提供从外部连接的路径
两台设备都连接 Tailscale 后,即使手机和 Mac 处在不同的物理网络,也可以加入同一个称为 Tailnet 的私有网络。Tailscale 的 IPv4 地址通常来自 100.64.0.0/10,也就是 100.64.0.0–100.127.255.255。并非所有以 100 开头的地址都属于 Tailscale。Tailscale 地址文档
IANA 将这一范围归类为共享地址空间,并未将其视为可通过公共互联网全球访问的地址。IANA IPv4 注册表
两台设备最初通过 DERP 中继交换连接信息,并尝试建立直连路径。如果无法直连,就使用可用的 Peer Relay,或者继续通过 DERP 中继。三种方式都使用 WireGuard 进行端到端加密;通常,直连在延迟和吞吐量方面更有优势。Tailscale 连接方式
采用这种配置,无需在家里的路由器上配置端口转发,将 Web 服务器的 4173 端口向公网开放。但如果所在网络阻止了 Tailscale 自身的连接,就需要先排查这项限制。
一次请求会经历以下步骤:
- 手机浏览器尝试连接 Mac 的 Tailscale 地址上的 TCP
4173。 - 两台设备上的 Tailscale 通过直连或中继传输流量。
- 如果访问策略和 Mac 的防火墙允许,且目的地址与端口上有监听套接字等待,连接就能建立。
- Node 程序处理 HTTP 请求,浏览器收到响应后显示页面。
即使在同一个 Tailnet 中,Tailscale 的 grants 或 ACL 等策略也能限制哪些用户、设备可以访问哪些目的地址和端口。服务器是否接收连接,以及用户是否有访问权限,需要分别确认。Tailscale grants 文档
页面打不开时,一步步缩小范围
一次改动多个设置,很容易弄不清问题原本出在哪里。可以按下表逐步缩小排查范围。同一种现象可能有多种原因,每一行都只是开始检查的位置。
| 观察到的现象 | 优先检查什么 |
|---|---|
| 在 Mac 本机也打不开页面 | 服务器进程是否在运行,端口是否确实为 4173,服务器日志是否有错误 |
| Mac 上能打开,手机上打不开 | 手机的 URL 是否使用了 localhost,服务器是否只绑定了回环地址 |
| 同一个 Wi-Fi 下也连不上局域网地址 | Mac 当前的局域网地址、防火墙、访客网络或设备间隔离设置 |
| 局域网地址能连,Tailscale 地址不能连 | 两台设备的 Tailscale 连接状态、目的地址、访问策略、对应地址上的监听套接字 |
| 能连接,但显示错误页面 | HTTP 状态码、服务器日志、请求路径、应用的认证条件 |
Tailscale 的排障文档同样建议检查设备状态、策略、防火墙和服务访问条件。VPN 显示已连接,并不代表 Web 服务器已经正常工作。Tailscale 设备连接排障文档
如果使用 Mac 的 launchd 管理服务器运行,还应查看任务配置。是否重启取决于 KeepAlive 等设置。也可以配置为先打开套接字,再把它交给程序;不过,进程管理本身不会提供外部网络路径或应用认证。Apple launchd 指南
修改 http://Mac的实际IP:4173 中的 IP、调整服务器的绑定、修改 Tailscale 策略,处理的是不同的问题。下次页面打不开时,可以把“服务器有问题”继续拆开:请求发往哪个地址,经过哪条路径,到达时那里又有什么在等待?