Skip to content

跑一个代理或 VPN

一台机器上有二十个容器,共用一个地址。这一页讲外面来的连接怎么找到那一个: 第 2、3 节是具体怎么加,第 5 到 7 节是为什么只能这么加。

其余的事 —— 你跑什么、怎么配、给谁用 —— 都在你自己的盒子里,是你的事。

(有一类东西在这里根本起不来:要自己建网卡、接管路由表的那一种。 不多,但如果你打算用,先跳到第 10 节,省一个下午。)


1. 先分清你要哪一种

它在线路上长什么样它怎么进来一条普通的 TLS 连接一个域名 —— 和机器上所有名字共用 443一套自己的协议一个公网端口 —— 一个号码,房东来开UDP,不管什么协议一个公网端口 —— 同上

两行底下是同一句话:机器要把连接交给对的容器, 前提是这条连接明文告诉它,它是给谁的。 TLS 握手会说,别人自己设计的协议不会。

第一种自己加,第二、三种要向房东要。下面分别是怎么加。


2. 加一个域名(走 443 这条路)

先把 DNS 指过来。 在你的域名服务商那里加一条 A 记录,指向机器的地址。 地址在面板的容器页面上,也可以在容器里 app-setup dashboard net 里看。 这一步不做,后面全都白搭。

然后三条路,任选一条,做的是同一件事。

在容器里,一条命令

sh
# 你自己在容器里终结 TLS —— 机器只拼接,私钥不出容器。
# 这是这一页要的那一种。8443 是你容器里监听的 TLS 端口。
app-setup domain add example.com 8443 self-hosted

# 不写 self-hosted 的话,默认是「机器替你签证书」,机器会解密。
# 8080 是你容器里监听的明文 HTTP 端口。
app-setup domain add example.com 8080

# 自己终结 TLS,同时 80 端口也转到容器的 8080(明文)
app-setup domain add example.com 8443 self-hosted 8080

app-setup domain ls                 # 现在有哪些名字
app-setup domain del example.com    # 不要了

这条命令的默认值是反的,值得记一下:不写 self-hosted, 你拿到的是「机器替你签证书并且解密」。走这一页的用途,self-hosted 得自己敲上去。 (面板界面和 API 那两条路的默认值相反,是 SNI 直通。第 7 节讲这个区别为什么要紧。)

泛域名写 *.example.com,只支持第一段。

在面板界面里

容器页面 → 域名 卡片 → 添加域名,填名字。 加完点名字那一行展开,里面是这些:

域名example.com添加域名example.com启用 HTTPS你的证书 · SNI 直通8443后端 HTTPS 端口我们的证书 · 替你签发8080转发到 HTTP 端口启用 HTTP

两个模式是一对单选。选你的证书 · SNI 直通, 填的是你容器里那个 TLS 端口。在这里新加的名字,默认就是这一个。

用 API

sh
# 认领名字
curl -sS -b jar.txt -X POST "$PANEL/me/containers/$CID/domains" \
  -H 'content-type: application/json' -d '{"domain":"example.com"}'

# 配这个名字怎么走。mode 不填就是 sni。
curl -sS -b jar.txt -X PUT "$PANEL/me/containers/$CID/routes/example.com" \
  -H 'content-type: application/json' \
  -d '{"http":{"enabled":false,"port":80},
       "https":{"enabled":true,"mode":"sni","port":8443}}'

完整参考在面板 REST API


3. 要一个公网端口(走号码这条路)

这个你自己开不了,而且不是权限没给到位:/me/containers/{cid}/ports 下面根本没有注册 POSTDELETE,写过去拿到的是路由器给的 404。 为什么是这样,第 6 节讲。

你这一侧:去要,然后确认

跟房东说两件事就够了:

  • 你的服务在容器里监听哪个端口(777751820,随便多少)
  • TCP 还是 UDP

外面那个号码由他们挑,你不用指定 —— 除非外面已经有东西认死了某个号码 (已经发出去的客户端配置、一条 DNS SRV 记录),那就说清楚要哪个。

开好之后,在容器页面的端口卡片上看,或者在容器里:

sh
app-setup dashboard ports

卡片分两段。你要的那条在来自互联网下面, 左边是你发给别人的地址,右边的 :3000 是容器里必须有东西在听的端口。

房东那一侧:一个按钮

容器页面 → 端口开一个端口

开一个端口容器端口公网端口协议7777自动留空 = 自动挑一个tcp保存保存并应用取消

或者一个调用:

sh
curl -sS -b jar.txt -X POST "$PANEL/machines/$MID/containers/$CID/ports" \
  -H 'content-type: application/json' -d '{"proto":"tcp","container":7777}'

那两个保存按钮是有区别的,而且区别落在别人身上。保存并应用会立刻重启这个 容器的网络:大约半秒,但那半秒里走这个容器其他端口的连接会断 —— 包括租户正开着的 SSH。保存只把映射记下来,什么都不打断,容器下次重启时生效。 API 上这就是 applynownext_start

还有一件在面板里看不出来的事:机器上开了号码,不等于云厂商的安全组放行了。 把整个池子一次放开(没改过的话是 30000–32767,TCP 和 UDP), 以后就不用再想。不放的话,面板上一切正常,卡片写着生效中,而外面连不上。

公网端口是这件事的完整版。


4. 整条路,以及这一页管到哪儿

一条连接的整条路访客机器:443 → 按名字:31000 → 按号码你的容器你跑的那个程序互联网上的目标第 1–3 节:机器把连接送到你门口从这里往右:容器里面,你自己的事

左边那两段是第 1 到 3 节讲的:机器按名字、或者按号码, 把连接送到你容器的门口。到这里为止是面板和机器的事, 而且只有这一段有「只能这么做」的规矩。

从容器门口往里,是你自己的事。 里面跑什么程序、怎么配它、 怎么让它开机自己起来 —— 这一页不写,也不推荐任何软件。

两个原因都挺实在:这类东西版本换得快,配置写下来过几个月就过期了; 而且选哪一个、怎么用,取决于你的用途,以及你要守的规矩(第 11 节)。

真要做,三条路随便走:翻那个软件自己的文档,问 AI, 或者就在容器里自己试 —— 这是一整台 Linux,你是 root, 装什么都行(除了第 10 节那一类)。

跟容器里的系统有关的那部分,这个站上是有的: 使用 Alpine使用 Debian 讲装包、 让程序开机自启、看日志、查内存 —— 不管你最后跑的是什么,这几件事都得用上。


5. 名字是怎么被分开的

一条 TLS 连接的开头有一小段是明文的,里面写着客户端要找的服务器名字。

一条 TLS 连接,从左往右example.com之后的每一个字节都是加密的明文 —— 只有这一小段机器照搬,不解密,也没有钥匙机器只看这里

为什么它必须是明文:服务器这时候还没把证书拿出来, 而不知道对方要哪个名字,它就不知道该拿哪一张。所以名字得先说,加密在后面。

机器读的就是这一个字段。读完去查域名表,查到是哪个容器, 接下来它就只做一件事:把字节从这头搬到那头,两个方向,直到有一头挂断。

一千个名字,共用同一个 443a.example.comb.example.comc.example.com机器一个地址,一个 :443读名字 → 查表别人的容器你的容器别人的容器做分流的是名字,不是号码 —— 所以域名你自己加,不用问谁

由此三件事:

  • 一千个名字共用一个 443。 名字不花机器什么,所以第 2 节里你自己就能加。
  • 机器手上没有钥匙。 它没解密过,也就不存在「它本可以看到」的那一刻。 证书在你的容器里 —— 前提是模式选对了,见第 7 节。
  • 名字得能解析到这台机器。 这就是第 2 节第一句话说的那条 A 记录。

80 端口是同一件事,只是名字在 HTTP 的 Host 头里,查的是同一张表。


6. 为什么自己的协议要占一个号码

一条连接进来,机器得决定它是给哪个容器的 —— 而且得在还不知道这些字节是什么意思之前就决定。

443 上有名字可读。换成一套别人自己设计的协议,开头是什么全看作者当初怎么定: 机器不认识,也不可能认识,靠猜不能算设计。

于是只剩唯一一样它已经知道的东西:这条连接敲的是哪个号码。

走域名走自己的协议,或者 UDP名字加密的内容机器读得到 → 查表你的容器不占机器的号码机器不认识这些字节它唯一知道的是号码:31000你的容器一个号码,一个容器 —— 要向房东要

这就是公网端口:机器地址上的一个号码,事先接到一个容器上。

也正因为如此,第 3 节里这个按钮在房东手上。名字不花钱,所以没人限量; 号码在一台共用的机器上就那么一个,两个租户都要 31000,得有人来定。

UDP 更彻底:连握手都没有,也没有一个「机器有资格拆开看」的首包, 没有字段可读就没有东西可以分流。所以 UDP 一律要一个号码,不管它承载什么。 另外,面板上的测试按钮对 UDP 帮不了你 —— 一个后面什么都没有的 UDP 端口, 和一个好好工作着的,从外面看一模一样。用真正要用它的那个客户端去试。


7. 模式选错,前面全白做

第 2 节那两个模式的区别在这里。这是这一页唯一一个选错了「看上去还是好的」的地方。

你的证书 · SNI 直通客户端加密机器 · 只拼接加密你的容器 · 钥匙在这全程加密。机器没有钥匙,也就没有能读到的时刻。我们的证书 · 替你签发客户端加密机器 · 有钥匙,解密明文你的容器机器替你签证书 —— 代价是它先解密。给网站够用,这个用途不是。
你在哪里加不额外指定的话,你拿到的是
app-setup domain add <名字> <端口>替你签发(机器解密)。要直通就加 self-hosted
面板界面 域名 卡片你的证书 · SNI 直通
API PUT /routes/{domain}https.mode 不填sni

三条路的默认值不一致,CLI 是反的那一个。选完回头在面板的域名卡片上看一眼, 那两个单选哪个亮着,就是实际生效的。

选了直通,证书就归你自己在容器里申请和续期,私钥一直待在容器里。


8. 两件会让人白花一个下午的事

  • 0.0.0.0,不要绑 127.0.0.1 上面两条路都是从容器自己的 loopback 之外来找你的服务的。只监听 127.0.0.1 的服务,你 SSH 进去测它,它答; 换成别人,谁都不答 —— 而这件事的症状看上去跟端口没开一模一样。
  • 这些流量全都计费。 替别人搬的流量也是流量,两个方向都算进配额, 而且这一类服务恰恰是那种「你没在看的时候数字自己往上爬」的。 在容器里 app-setup dashboard net,或者看容器页面。到 100% 容器会被停用 —— 是关掉,不是删掉 —— 窗口滚过去它就回来。

9. 这台机器能看到什么

这不是一句「我们不会那么做」的承诺,是数据通路的形状,你可以自己核对:

  • 443 上选了 SNI 直通,机器不持有你这个名字的钥匙, 也从来没有和你的客户端完成过一次握手。整条路径上不存在 「你的流量以明文出现」的那一个点,所以没有东西可供审查。
  • 公网端口就是一个号码接到一个号码,路径上没有任何东西去解析穿过它的内容。
  • 流量表数的是两个方向各多少字节。它不知道那些字节是什么,别的组件也没在看。

hqnode 是一个虚拟化程序。它做的事是把一台机器切开、把每一份隔开、然后计数。 它不审查你搬运的内容,而在上面这两条路径上,它也没有能力审查。

关于这一点有两条老实话,不说这一页就是在推销东西:

  • 上面说的是这个程序。机器的主人拥有这台机器,在上面有 root。 要么信任你的房东,要么自己跑一台机器
  • 这里没有任何东西隐藏「有流量」这件事本身,也不隐藏有多少、 以及配了哪些号码和名字。计量本来就是这个产品的用途。

10. 有一类在这里跑不起来

前面九节讲的都是用户态的东西:一个普通程序,拿着一个普通 socket —— 收一个连接,对字节做点什么,再往外开一个连接。绝大多数人用的就是这一类, 它和别的程序一样地跑。

跑不起来的是另一类:要自己建一块网卡、接管路由表的那一种。 容器拿不到 CAP_NET_ADMIN,里面也没有 /dev/net/tun, 所以不是慢,也不是功能残缺 —— 设备建不出来,它起不来。

原因是计费,不是怀疑。有了 CAP_NET_ADMIN,租户可以把计流量的那块 tap0 改名, 再用同一个名字立一块计数从零开始的新设备,这个月的流量表读到的就是零。 这个决定是写下来的,代价当时也说明白了:没有 nftables,没有 tun, 容器里没有内核态 VPN。


11. 法律是你自己要弄清楚的事

这一页讲的是一台机器怎么搬字节。你在它上面跑什么、给谁用、落在哪里, 都是你的事 —— 弄清楚哪些规定适用于这些事,同样是你的事。

这一类服务的规定,各个国家和地区差别很大, 既管你所在的地方也管机器所在的地方,而且会变。 真要用,就针对你自己的情况认真查清楚。 这一页上的任何内容都不是法律意见,也没有谁替你核对过。


接下来