Android 私有云搭建与内网穿透完全指南
基于 Termux + Ubuntu,在手机上搭建博客与对象存储,并通过 frp / Ngrok 暴露到公网的完整实践笔记。
📌 关于 MinIO 公网暴露方案
本文第 2 节记录的 MinIO 暴露方式是早期方案(frp 隧道 + Cloudflare 灰云直连),
其中 9000 / 9001 端口分离带来的控制台资源加载问题并未彻底解决。后续已改用 Cloudflare Tunnel(cloudflared) 方案,统一走 Cloudflare Edge,
并用双子域名 + ingress 分别路由 9000 / 9001。最新且推荐的方案请见
《家庭服务器全栈部署完全指南》第 6.5 节。本文的 frp 方案仍可作为「国内直连优先」场景的参考,但请优先阅读上述新方案。
1. 私有云架构总览
整套服务运行在 Android 手机的 Termux + Ubuntu 环境中,通过 frp 内网穿透将本地服务暴露到公网,并借助 Cloudflare 进行 DNS 解析与代理。
公网用户 |
架构要点说明:
| 组件 | 作用 | 运行环境 |
|---|---|---|
| Termux | Android 上的终端模拟器 | 手机原生 |
| Ubuntu | 完整 Linux 环境 | Termux 内 proot 容器 |
| Nginx | 博客 Web 服务器 | Ubuntu 内 |
| MinIO | S3 兼容对象存储 | Ubuntu 内 |
| frp | 内网穿透,将本地端口映射到公网 | Ubuntu 内(frpc 客户端) |
| Cloudflare | DNS 解析 + HTTPS 代理 | 云端 |
2. 各组件配置清单
2.1 内网穿透(frp)
frp 客户端(frpc)运行在 Ubuntu 内,通过两条隧道分别将博客和 MinIO 服务暴露到公网。
| 隧道 | 配置文件 | 类型 | 本地端口 | 公网地址 |
|---|---|---|---|---|
| 博客 | nginx.ini |
http |
8080 |
https://blog.nesthub.dpdns.org |
| MinIO | minio.ini |
http |
9000 |
http://minio.nesthub.dpdns.org |
配置示例(frpc.ini 风格):
# nginx.ini |
# minio.ini |
2.2 Nginx(博客服务)
Nginx 作为博客的 Web 服务器,监听 8080 端口,对外提供静态网站服务。
| 配置项 | 值 |
|---|---|
| 配置文件路径 | /etc/nginx/sites-available/blog |
| 监听端口 | 8080 |
| 域名 | blog.nesthub.dpdns.org |
| 网站根目录 | /var/www/blog |
| 运行状态 | ✅ 运行中 |
Nginx 配置要点:
server { |
提示:Nginx 监听 8080 而非 80,是为了避免与 Termux 环境中可能存在的端口冲突,同时 frp 隧道也指向 8080。
2.3 MinIO(对象存储)
MinIO 是一个 S3 兼容的高性能对象存储服务,用于存储图片等静态资源。
| 配置项 | 值 |
|---|---|
| 启动命令 | minio server /data/minio --console-address :9001 --address :9000 |
| API 端口 | 9000 |
| 控制台端口 | 9001 |
| Access Key | <用户名> |
| Secret Key | <密码> |
| 数据目录 | /data/minio |
| 运行状态 | ✅ 运行中 |
端口说明:
- 9000 端口:S3 API 接口,用于程序化访问(PicGo 上传、mc 命令等)
- 9001 端口:Web 管理控制台,用于浏览器可视化操作
安全提示:这里的凭据已脱敏为占位符。实际使用时请设置强密码,并通过环境变量
MINIO_ROOT_USER和MINIO_ROOT_PASSWORD传入,避免写死在命令或配置文件里。
2.4 Cloudflare 设置
Cloudflare 负责域名解析,对博客启用代理(橙云)以获得 HTTPS,对 MinIO 使用仅 DNS 模式(灰云)以保持直连速度。
| 子域名 | 记录类型 | 目标 | 云朵状态 | SSL/TLS 模式 |
|---|---|---|---|---|
blog |
CNAME | uk.frp.one |
🟠 橙色(代理) | Flexible(灵活) |
minio |
CNAME | uk.frp.one |
⚪ 灰色(仅 DNS) | — |
两种模式的区别:
- 橙云(代理模式):流量经过 Cloudflare 代理,自动获得 HTTPS、DDoS 防护、CDN 加速。适合博客等面向用户的 Web 服务。
- 灰云(仅 DNS):Cloudflare 仅做 DNS 解析,流量直连服务器。适合需要低延迟的 API 服务(如 MinIO),避免 Cloudflare 海外节点增加延迟。
2.5 SSL 证书
| 配置项 | 值 |
|---|---|
| 证书路径 | /etc/nginx/ssl/nesthub.crt |
| 私钥路径 | /etc/nginx/ssl/nesthub.key |
| 签发工具 | acme.sh |
| 签发方式 | 手动 DNS 验证(Let’s Encrypt) |
| 有效期 | 90 天 |
| 续期方式 | 手动执行续期命令 |
续期命令:
./acme.sh --renew -d nesthub.dpdns.org --dns dns_manual --server letsencrypt --force |
重要:由于使用手动 DNS 验证,无法自动续期。请在证书到期前手动执行上述命令,并在域名 DNS 中添加对应的 TXT 记录。
2.6 mc 命令行工具
mc 是 MinIO 客户端工具,用于在命令行中操作 MinIO 对象存储。
设置别名:
mc alias set myminio http://minio.nesthub.dpdns.org <用户名> <密码> |
设置别名后,即可通过 mc 命令方便地管理存储桶和文件,无需每次输入完整的连接信息。
3. 关键命令速查表
服务管理
| 操作 | 命令 |
|---|---|
| 启动 Nginx | nginx |
| 重载 Nginx 配置 | nginx -s reload |
| 测试 Nginx 配置 | nginx -t |
| 启动 MinIO(后台) | nohup minio server /data/minio --console-address :9001 --address :9000 > /tmp/minio.log 2>&1 & |
| 启动 frpc - 博客隧道 | cd /root/frp && nohup ./frpc -c nginx.ini >> /var/log/frpc-nginx.log 2>&1 & |
| 启动 frpc - MinIO 隧道 | cd /root/frp && nohup ./frpc -c minio.ini >> /var/log/frpc-minio.log 2>&1 & |
日志与诊断
| 操作 | 命令 |
|---|---|
| 查看 frpc 博客日志 | tail -20 /var/log/frpc-nginx.log |
| 查看 MinIO 日志 | tail -20 /tmp/minio.log |
| 测试博客(本地) | curl -I http://127.0.0.1:8080 |
| 测试 MinIO(本地) | curl -I http://127.0.0.1:9000/minio/health/live |
MinIO 存储管理
| 操作 | 命令 |
|---|---|
| 列出所有存储桶 | mc ls myminio |
| 创建存储桶 | mc mb myminio/picture |
| 设置存储桶为公开只读 | mc anonymous set download myminio/picture |
| 上传文件 | mc cp localfile.jpg myminio/picture/ |
| 列出存储桶内文件 | mc ls myminio/picture |
4. 已知局限与注意事项
4.1 Termux 环境限制
Termux 是 Android 上的终端模拟器,并非完整的 Linux 环境,存在以下限制:
netstat、ss、lsof等网络工具功能受限或无法使用- 推荐使用
curl -I测试服务状态,代替端口扫描工具 - 部分系统级操作需要 proot 模拟,性能有一定损耗
- 后台进程可能被 Android 系统省电策略杀掉,需注意保活
4.2 SSL 证书续期(重要)
证书使用手动 DNS 验证方式签发,无法自动续期:
- 有效期为 90 天
- 到期前需手动执行续期命令(见 2.5 SSL 证书)
- 续期时需要在 DNS 中添加 TXT 记录进行验证
- 续期完成后需重载 Nginx 使新证书生效
4.3 MinIO 访问方式
| 访问方式 | 地址 | 说明 |
|---|---|---|
| Web 控制台 | http://minio.nesthub.dpdns.org:9001 |
需在 frp 中额外转发 9001 端口 |
| API / S3 访问 | http://minio.nesthub.dpdns.org |
已通过 frp 转发 9000 端口 |
当前仅转发了 9000 端口,如需通过公网访问 Web 控制台,需在 frp 中新增一条 9001 端口的隧道配置。
4.4 PicHoro 等手机 App 连接 MinIO 的问题
部分手机端 S3 客户端在连接 MinIO 时可能遇到兼容性问题:
- 部分 App 无法正确处理自定义 Endpoint 或非标准端口
- 建议优先使用
mc命令行工具进行管理 - 或更换为 Simple S3 Browser、S3Drive 等兼容性更好的工具
5. 当前具备的能力
| 能力 | 说明 |
|---|---|
| ✅ HTTPS 公网博客 | 通过 https://blog.nesthub.dpdns.org 访问 Hexo 博客 |
| ✅ HTTP 公网对象存储 | 通过 http://minio.nesthub.dpdns.org 访问 MinIO(S3 兼容) |
| ✅ mc 命令行管理 | 完整的 MinIO 存储桶和文件管理能力 |
| ✅ 国内直连高速访问 | MinIO 使用灰云直连,速度不受 Cloudflare 海外节点影响 |
| ✅ 低功耗低维护 | 所有服务运行在 Android 手机的 Termux Ubuntu 中 |
6. 后续优化建议
设置定时任务自动续期证书
- 如果改用 Cloudflare API 模式签发,可实现全自动续期
- 配合
crontab定期执行 acme.sh 续期命令
配置 MinIO 的 HTTPS 访问
- 如需公网加密访问 MinIO,可改用 TCP 隧道 + 本地证书方案
- 或在 Nginx 层做反向代理,由 Nginx 处理 TLS
添加更多服务
- 复用同样的 frp 隧道模式,可扩展 Nextcloud(私有云盘)、Jellyfin(媒体服务器)等
- 每个服务新增一条 frp 隧道和一条 Cloudflare DNS 记录即可
使用 tmux 或 screen 管理后台进程
- 避免 SSH 断开连接时服务停止
- 推荐
tmux new -s services创建专用会话
配置防火墙与访问控制
- 限制 MinIO 的公开访问权限,仅对特定存储桶开放只读
- 定期更换 Access Key / Secret Key
7. Ngrok 内网穿透指南
7.1 Ngrok 基础认知
什么是 Ngrok?
Ngrok 是一个内网穿透工具,可以将本地运行的 Web 服务(如 localhost:80)暴露到一个公网可访问的 URL 上,极大地方便了开发和测试。
核心命令解析
以命令 ngrok http --url=<你的域名>.ngrok-free.app 80 为例:
| 参数 | 说明 |
|---|---|
ngrok http |
建立 HTTP 隧道,将公网流量转发到本地端口 |
80 |
本地服务监听的端口号(如 Nginx、Apache 或本地 Web 项目) |
--url=<你的域名>.ngrok-free.app |
强制绑定固定的公网子域名 |
固定子域名的特点:
- 全球唯一,先到先得
- 需提前在 ngrok 官网后台(Dashboard → Cloud Edge → Domains)进行认领(Reserve)
- 未认领时执行命令会报错:
This domain is not reserved for your account - 免费版认领的域名长期无流量可能被回收
7.2 免费版拦截页面问题
问题现象
访问 ngrok 免费版提供的 URL 时,会看到警告页面,需要手动点击 “Visit Site” 才能继续访问:
You are about to visit: xxx.ngrok-free.app |
产生原因
这是 ngrok 为防止平台被滥用(如网络钓鱼)而设置的安全措施。所有免费版用户首次访问时都会遇到此拦截。
绕过方案对比
| 方案 | 操作方式 | 适用场景 | 成本 |
|---|---|---|---|
| 添加请求头 | 请求时携带 ngrok-skip-browser-warning: true |
API 调用、后端服务、程序化访问 | 免费 |
| 手动点击 | 首次访问时在浏览器点击 “Visit Site” | 个人临时测试(浏览器保存 7 天免验证 Cookie) | 免费 |
| 升级付费计划 | 购买 Pro 及以上套餐 | 生产环境、客户演示、彻底免打扰 | 付费 |
7.3 Typora 图片无法预览问题
问题描述
- 使用 PicGo 上传图片至 ngrok 搭建的图床
- Typora 中粘贴图片后显示裂图(无法加载)
- 浏览器直接打开图片链接会被 ngrok 拦截,显示警告页面
根本原因
- Typora 通过 URL 加载图片时,相当于浏览器请求
- ngrok 返回拦截页面(HTML)而非图片数据(JPEG/PNG),Typora 无法将 HTML 渲染为图片
- Typora 1.6.7 版本的 Bug:
conf.user.json中配置的customHeaders(用于添加ngrok-skip-browser-warning)失效
解决方案 A:本地代理中转(推荐,最稳定)
核心思路:在本地运行一个代理服务,转发图片请求至 ngrok,并自动添加”免拦截”请求头。
方式一:使用 Docker(快捷)
docker run -d --name ngrok-proxy -p 8080:80 igops/ngrok-skip-browser-warning |
方式二:使用 Python Flask(无需 Docker)
from flask import Flask, request, Response |
PicGo 配置修改:
将图床设置中的**”自定义URL”或“URL前缀”**修改为 http://127.0.0.1:8080。
⚠️ 修改后需重新上传图片,Typora 中的链接才会替换为新地址。
解决方案 B:Cloudflare Workers 云端代理(不依赖本地)
核心思路:在 Cloudflare 边缘网络部署 Worker,无需在本地运行任何程序。
完整 Worker 脚本:
const TARGET_URL = 'https://<你的域名>.ngrok-free.app'; |
部署步骤:
- 登录 Cloudflare Dashboard → Workers & Pages
- 创建新 Worker,粘贴上述脚本
- 部署后获得
xxx.workers.dev域名 - 修改 PicGo 的 URL 前缀为
https://你的Worker域名.workers.dev
优点:
- 每天 10 万次免费请求,个人使用绰绰有余
- 无需本地运行任何程序,全云端代理
- 不受本地网络环境影响
7.4 Linux 服务器自动化运维
编写启动脚本
保存路径 /root/start-ngrok.sh:
|
赋予执行权限:
chmod +x /root/start-ngrok.sh |
一键创建脚本(使用 heredoc)
sudo cat > /root/start-ngrok.sh << 'EOF' |
配置 .bashrc 实现登录自启
需求:每次登录时检查 ngrok 是否运行,若未运行则启动,防止重复执行。
在 /root/.bashrc 末尾添加:
# 自动启动 ngrok(仅当尚未运行时) |
命令解析:
pgrep -f:根据完整的命令行字符串匹配进程- 若匹配不到进程,则执行启动脚本
- 该检查机制确保了无论是第一次登录还是多次
source,ngrok 都只会运行一份实例
7.5 排错与最佳实践
常见错误排查
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
command not found: ngrok |
ngrok 未安装或未加入 PATH | 安装 ngrok 并执行 export PATH=$PATH:/path/to/ngrok |
This domain is not reserved |
未认领该固定域名 | 登录 ngrok 官网,在 Cloud Edge → Domains 中认领 |
| Typora 仍显示裂图 | PicGo 自定义 URL 未修改 | 检查 PicGo 设置,将域名改为代理地址;重新上传图片 |
| ngrok 后台进程被杀 | 关闭终端导致进程终止 | 必须使用 nohup 启动,并配合 & 放到后台 |
管理命令速查
| 操作 | 命令 |
|---|---|
| 查看实时日志 | tail -f /tmp/ngrok.log |
| 查看进程 | ps aux | grep ngrok |
| 停止服务 | pkill ngrok 或 kill <PID> |
推荐生产环境替代品
如果长期依赖内网穿透且需要稳定、无拦截服务,可考虑:
| 方案 | 优点 | 缺点 |
|---|---|---|
| Cloudflare Tunnel(cloudflared) | 官方免费、无拦截页面、自带 HTTPS | 需要域名托管在 Cloudflare |
| frp | 开源免费、完全自控、支持 TCP/UDP | 需要有公网服务器作为中转 |
| Ngrok 付费版 | 支持自定义域名、并发限制更高、无警告页 | 需要付费 |
8. 方案对比与选型总结
| 维度 | frp 方案(私有云) | Ngrok 方案(图床代理) |
|---|---|---|
| 适用场景 | 长期稳定运行的服务 | 临时开发测试、图床中转 |
| 域名 | 自有域名 + Cloudflare DNS | ngrok 提供的子域名 |
| HTTPS | Cloudflare 代理 / acme.sh 证书 | 免费版有拦截页 |
| 稳定性 | 高(自建服务器) | 中(依赖 ngrok 服务) |
| 成本 | 0(已有 frp 服务器) | 0(免费版)/ 付费版 |
| 推荐指数 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐(临时使用) |
总结:对于长期运行的私有云服务(博客、对象存储),推荐使用 frp + Cloudflare 方案;对于临时开发测试或图床代理,可使用 Ngrok 配合代理绕过方案。两者也可组合使用,互为补充。



