我想构建一个类似于 ngrok 的服务,并且我正在尝试了解 ngrok 隧道服务子域管理背后的架构。据我所知,ngrok 为每个隧道提供了独特的子域(如 abcde.ngrok.io),但我对他们如何大规模管理它感到困惑。
具体:
主要问题:有没有办法为较小规模的项目实施类似的系统?关键部件是什么?
任何对实现此类系统的潜在架构或最佳实践的见解将不胜感激!谢谢!
他们如何为其 IP 动态添加新的 DNS 记录?
首先,通配符子域。 DNS 支持名为
*.example.com
的记录,它将自动覆盖 .example.com
的任何(一级)子域,除非另有明确定义。
第二:DNS 记录,与 HTTP URL 类似,不需要在某个地方添加,因为没有子域的中央数据库;相反,该信息仅由 Ngrok 自己的名称服务器提供。因此,就像 HTTP webapp 可以通过代码动态响应各种 URL 一样,可以编写一个动态响应各种子域的 DNS 服务器。
如果不同的子域由相同的IP地址管理,那么ngrok如何理解我连接到a.ngrok.io,而不是b.ngrok.io(如果它们都具有相同的IP地址)?我知道,有像 SNI 这样的技术,但是如果我在没有 TLS 加密的情况下建立 TCP 隧道,它如何工作?
对于普通 TCP 隧道,他们并不真正了解这一点。据我了解他们的系统,他们只使用 TCP 端口号来区分隧道,因为你永远不会真正获得整个子域 - 你只能在该 IP 地址上获得一个 TCP 端口。
主要问题:有没有办法为较小规模的项目实施类似的系统?关键部件是什么?
取决于规模。在真的小规模(比如可能有0-3个用户),只要隧道大部分是静态的并且手动配置是可以的,就有很多现有的TCP代理可供选择,从像“rinetd”这样的小型代理到像HAProxy这样的网络规模代理或 Nginx(流代理模式)。
事实上,即使标准 SSH 服务器也可以使用
ssh -R
提供相同类型的隧道(Ngrok 甚至为其自定义后端提供相同类型的 SSH 风格接口)。
此类服务的基本代码并不复杂;您打开一个侦听套接字,对于每个收到的连接,您都会建立一个传出连接并创建一个 poll() 循环,将数据从一个套接字传送到另一个套接字。接下来的步骤是拥有多个侦听套接字(以及本地地址:端口到目标地址:端口的映射),这是一种通过某种 IPC 机制动态配置套接字的方法,从而达到所需的性能水平...