抽屉里那台退役手机,屏幕有点花,但电池还能撑一整天,扔了可惜。我家宽带没有公网 IP,也不想去路由器后台折腾端口映射,但又想给跑在局域网里的几个小服务(一个 Web 面板、一个 Termux 里的 API)开个公网入口。Cloudflare Tunnel 正好对症:设备主动反向连到 Cloudflare 边缘节点,外部流量由边缘转发进来,全程不需要公网 IP、不用开任何端口。于是这台旧手机就被我改造成了一个自带 HTTPS、还能套 Zero Trust 访问控制的轻量内网入口。
下面是我实际走通的两条路,以及把它从”能跑”变成”挂着不掉线”的过程里踩到的坑。
先想清楚走哪条路
动手前我纠结过一阵:到底是在 Termux 里直接跑,还是丢进 proot Debian。后来发现判断标准其实只有一条——这台机器上还要不要跑别的 Linux 工具。
| 方案 | 什么时候选它 | 复杂度 | 资源占用 |
|---|---|---|---|
| Termux + Token | 只想把本地端口透出去 | 低 | 低 |
| proot Debian + cert | 同一套环境里还跑着别的 Debian 服务 | 中 | 中 |
我那台旧手机只干透传端口一件事,所以主力是 Token 方案;proot 那套是后来在另一台当开发机用的设备上才用上的。两条都记在这儿。
开工前先把这几样备齐:
-
一个已经托管在 Cloudflare 的域名(NS 必须切到 Cloudflare);
-
从 GitHub Releases 装的 Termux——别用 Google Play 版,那个早停更了,我一开始就是踩在这上面,新指令各种缺;
-
进 Termux 第一件事更新源:
Terminal window pkg update && pkg upgrade
方案 A:Termux + Token(我的主力)
装 cloudflared
省心的是 Termux 官方源直接收录了 cloudflared,不用自己找包:
pkg install cloudflaredcloudflared --version # 出版本号就算装好了在控制台开隧道
- Networks → Tunnels → Create a tunnel,连接器选
Cloudflared; - 起个名字,下一步会给一整条安装命令——我只需要末尾那串 token,复制出来;
- 切到 Public Hostname,把要暴露的子域名指到
http://localhost:<本地端口>,比如home.example.com→http://localhost:8080; - 保存,回 Termux。
起隧道
cloudflared tunnel --edge-ip-version auto --protocol http2 run --token <粘贴你的 Token>几秒后刷出 Registered tunnel connection 之类的日志,控制台里隧道转成绿色的 HEALTHY,浏览器打开子域名就通了。
这里我特意加了
--protocol http2。默认走 QUIC,但我家这边网络一跑 QUIC 就时断时续——后面”踩坑”那节细说。网络环境好的话可以去掉,让它走默认。
方案 B:proot Debian + cert 登录
如果机器上已经有一套 proot Debian 在跑别的东西,让 cloudflared 跟它们共用同一个 rootfs 会更顺手。
装 proot Debian
pkg install proot-distroproot-distro install debianproot-distro login debian进容器后补上基础工具:
apt update && apt install -y wget curl装 cloudflared
Termux + proot 的设备绝大多数是 ARM64:
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.debdpkg -i cloudflared-linux-arm64.deb登录并建隧道
cloudflared tunnel login # 把日志里的 URL 复制到系统浏览器授权cloudflared tunnel create my-tunnelcloudflared tunnel list # 记下 UUID写配置
配置写在 ~/.cloudflared/config.yml——注意目录是 .cloudflared,结尾多一个 d,我手抖少打过一次,排查了半天才发现:
tunnel: <Tunnel-UUID>credentials-file: /root/.cloudflared/<Tunnel-UUID>.json
ingress: - hostname: home.example.com service: http://localhost:8080 - service: http_status:404 # 这条兜底不能省,否则 cloudflared 直接拒绝启动绑 DNS 再起
cloudflared tunnel route dns my-tunnel home.example.comcloudflared tunnel run my-tunnel要管多条隧道,就给每条单独写一份 yaml,启动时用 --config /path/to/config.yml 指定。
真正费时间的是让它”挂住”
跑通只花了十分钟,后面熄屏几分钟就断流这事,才是真把我折腾够呛。Android 回收后台进程非常激进,直接 & 扔后台用不了多久就被杀。两步才稳住:
第一步,抓住唤醒锁,不让系统休眠 Termux:
termux-wake-lock不用了再 termux-wake-unlock 放掉。生效后通知栏会一直挂着提示,这个提示就是我判断锁有没有拿到的依据。
第二步,交给 termux-services 托管,进程崩了能自动拉起:
pkg install termux-services# 装完重启一次 Termux,让 sv 环境加载进来
mkdir -p $PREFIX/var/service/cloudflared/logcat > $PREFIX/var/service/cloudflared/run <<'EOF'#!/data/data/com.termux/files/usr/bin/shexec cloudflared tunnel --protocol http2 run --token YOUR_TOKEN 2>&1EOFchmod +x $PREFIX/var/service/cloudflared/run
sv-enable cloudflaredsv up cloudflaredsv status cloudflared # 看到 run: cloudflared 就正常了日志落在 $PREFIX/var/service/cloudflared/log/main/current,出问题第一时间翻这里。
光做这两步还不够。最后我还去系统设置里把 Termux 塞进了厂商的「电池白名单 / 自启动白名单 / 受保护应用」——三件套配齐,这台旧手机才算真正能长期挂着不掉。
我踩过的坑
proot 里第一次跑就甩了我一脸 x509: certificate signed by unknown authority。
原因是 proot Debian 默认证书库不全。补上就好:
apt install -y ca-certificates && update-ca-certificates隧道在面板上一直 DOWN,日志却说早连上了。
我盯着面板以为没连成功,白折腾。其实是仪表板缓存延迟,等个 30 秒就转绿。要是还不对,回头检查 Public Hostname 里的 service URL 填没填对,再确认本地端口确实在监听(ss -ltnp)。
熄屏几分钟就断——这个最坑,因为不熄屏时一切正常,容易误判成网络问题。
根因要么是没拿到唤醒锁,要么被厂商系统强杀。先确认 termux-wake-lock 生效(看通知栏那条常驻提示在不在),再去系统设置给 Termux 解除后台限制。
QUIC 死活建不了连。
显式加 --protocol http2 切回 HTTP/2 就好。部分国内 ISP 对 UDP/443 有干扰,默认的 QUIC 会卡在握手。我前面命令里一直带着这个参数,就是为它。