refactor: Cloudflare Tunnel + frp SSH 中转变更

- 新增 cloudflared Docker 服务替代原 Bandwagon frp 方案
- 新增 frpc 转发 Git SSH 到阿里云 VPS
- 为所有服务添加 web entrypoint 路由(兼容 cloudflared HTTP)
- HedgeDoc 添加 X-Forwarded-Proto 中间件修复 CSP 登录问题
- Homepage 添加 xiteng.site 根域名路由
- Gitea 配置 SSH_DOMAIN=git.xiteng.site
- 更新 README 反映当前架构
- .gitignore: frpc.toml / credentials / letsencrypt
This commit is contained in:
2026-05-25 16:13:02 +08:00
parent 90d7db8782
commit c824e22b53
9 changed files with 173 additions and 46 deletions

10
.gitignore vendored
View File

@@ -17,3 +17,13 @@ Thumbs.db
# 忽略环境变量文件
.env
# 忽略 cloudflared 凭据
cloudflared/credentials.json
# 忽略 frp 配置(含 token
frpc/frpc.toml
# 忽略 Traefik 证书
traefik/letsencrypt/
.aider*

121
README.md
View File

@@ -1,56 +1,95 @@
针对你的硬件资源(一台高性能无公网的本地宿主机 + 一台国内低延迟弱鸡 VPS + 一台免备案海外弱鸡 VPS + 一个域名),我们可以设计一套既能保证私有数据安全、国内访问低延迟,又能对外提供特定 Web 服务的混合架构。
# Homelab
以下是一套推荐的重构与部署方案:
部署在 CachyOS 上的全套家庭服务,通过 Cloudflare Tunnel + 阿里云 VPS SSH 中转向公网开放。
### 第一阶段:网络架构重构 (FRP + Mesh VPN 混合网络)
## 架构
以前你主要用 `frp`,这在暴露单点服务时很好用,但对于全面的 homelab 管理,引入 **Mesh VPN (如 Tailscale 或 ZeroTier)** 会让体验产生质的飞跃。
```
公网用户
├─ Web (443) ──→ Cloudflare Tunnel ──→ cloudflared (Docker) ──→ Traefik (反向代理)
│ │
└─ SSH (22) ──→ 阿里云 VPS (frps) ──→ frpc (Docker) ──→ Gitea │
┌───────────────┤
▼ ▼
各 Web 服务 Gitea SSH
```
* **私有访问与管理核心 (Tailscale / ZeroTier):** * 在台式机、笔记本、手机上全部安装 Tailscale。这会为你组建一个虚拟大内网。
* **发挥国内云服务器的优势:** 阿里云虽然性能弱且不能绑域名建站(没备案会拦截 80/443 端口),但它的**国内网络极佳**。你可以将其配置为 Tailscale 的自定义 DERP 中继服务器(或 ZeroTier 的 Moon 节点)。这样,当你在国内异地访问家里的台式机,且 P2P 打洞失败时,流量会从阿里云高速中转,极其丝滑,非常适合 SSH、大文件拉取或远程桌面。
* **公共 Web 服务暴露 (Bandwagon + FRP):**
* 由于域名没有备案,必须且只能将域名解析到 Bandwagon。
* 在 Bandwagon 上部署 `frps` 和反向代理(推荐 Nginx Proxy Manager 或 Traefik
* 台式机运行 `frpc`**只把需要对外公开的服务**(比如想分享给他人的文档、你的个人博客等)通过 FRP 穿透到 Bandwagon再通过域名访问。
* 像 MinIO 这类存储重型、或者纯私人的服务,坚决不走 Bandwagon 公网暴露VPS 带宽太小会成为瓶颈),而是直接通过刚才建好的 Tailscale 大内网用虚拟 IP 访问。
| 入口 | 域名 | 传输 | 延迟 |
|------|------|------|:--:|
| Web | `*.xiteng.site` | Cloudflare Tunnel → Traefik | ~50ms |
| Git SSH | `git.xiteng.site` | 阿里云 VPS → frp → Gitea | ~5ms |
### 第二阶段:台式机服务部署规范 (Docker Compose)
## 服务一览
在滚动更新的 CachyOS 上,强烈建议所有服务全部容器化,避免日后系统滚挂或者依赖冲突。
| 服务 | 地址 | 说明 |
|------|------|------|
| Homepage | [xiteng.site](https://xiteng.site) | 导航面板 |
| Gitea | [gitea.xiteng.site](https://gitea.xiteng.site) | 代码托管, `git clone git@git.xiteng.site:…` |
| HedgeDoc | [notes.xiteng.site](https://notes.xiteng.site) | Markdown 协作 |
| Uptime Kuma | [uptime.xiteng.site](https://uptime.xiteng.site) | 服务监控 |
| MinIO | 内网 | 对象存储(不暴露公网) |
| Traefik | 内网 | 反向代理 |
1. **统一目录结构:**
建立一个统一的 `/opt/homelab``~/homelab` 目录。
```text
homelab/
├── compose.yml # 核心网络和基础代理配置
├── minio/
│ ├── compose.yml
│ └── data/ # 挂载的持久化数据
├── hedgedoc/ # CodiMD 的社区继承版本,推荐用这个
│ ├── compose.yml
│ └── data/
└── .env # 统一管理数据库密码、密钥等敏感信息
```
2. **网络隔离:** 在 Docker 中创建一个自定义 bridge 网络(比如 `homelab_net`),让相关的服务可以通过容器名互相通信,而无需暴露端口到宿主机。
## 目录结构
### 第三阶段:服务推荐与规划
```
homelab/
├── compose.yml # 共享网络定义 (homelab_net)
├── .env # 统一环境变量敏感gitignore
├── cloudflared/
│ ├── compose.yml
│ └── config.yml
├── frpc/
│ ├── compose.yml
│ └── frpc.toml # 敏感gitignore
├── gitea/
│ ├── compose.yml
│ └── data/
├── hedgedoc/
│ ├── compose.yml
│ └── data/
├── homepage/
│ ├── compose.yml
│ └── config/
├── minio/
│ ├── compose.yml
│ └── data/
├── traefik/
│ ├── compose.yml
│ └── letsencrypt/ # gitignore
└── uptime-kuma/
├── compose.yml
└── data/
```
除了你提到的基础服务,结合日常的开发需求(比如写代码、开发游戏),你可以考虑部署以下组合:
## 网络
**1. 生产力与存储 (你已有的)**
* **MinIO:** 对象存储。部署时注意挂载你台式机上性能最好、容量最大的硬盘。
* **HedgeDoc (原 CodiMD):** 实时协作 Markdown 笔记。建议搭配 PostgreSQL 数据库容器一起部署。
所有服务加入 `homelab_net` 自定义 bridge 网络,通过容器名互访,不暴露端口到宿主机。
**2. 开发与代码托管 (新服务推荐)**
* **Gitea / Forgejo:** 非常轻量级的 Git 托管服务。对于开发《Silidox》这种游戏项目或者管理多线程编程的实验代码在本地有一个极速的 Git 仓库体验极佳,尤其是 Push/Pull 大量游戏美术资产时,局域网/Tailscale 速度远超 Github。
* **Gitea Actions 或 Jenkins:** 轻量级 CI/CD 平台。可以用来自动打包你的 C++ 项目或游戏,甚至写脚本自动化执行单元测试。
## 快速启动
**3. 运维监控与导航**
* **Uptime Kuma:** 极简的监控面板。不仅可以监控你的各个服务是否存活,还可以监控你的阿里云和 Bandwagon VPS 的网络状态。
* **Homepage 或 Dashy:** 一个好看的导航页。把 MinIO、HedgeDoc、路由器后台等全放在上面设为浏览器主页。
```bash
# 按依赖顺序启动
docker compose -f compose.yml up -d # 创建网络
docker compose -f traefik/compose.yml up -d
docker compose -f gitea/compose.yml up -d
docker compose -f hedgedoc/compose.yml up -d
docker compose -f uptime-kuma/compose.yml up -d
docker compose -f homepage/compose.yml up -d
docker compose -f cloudflared/compose.yml up -d
docker compose -f frpc/compose.yml up -d
```
---
## 所需外部资源
**下一步怎么走?**
| 资源 | 用途 |
|------|------|
| Cloudflare DNS | 域名托管 + Tunnel |
| 阿里云 ECS (上海) | Git SSH 中转 (frps) |
| Cloudflare Tunnel | Web 流量入口 |
我们可以先从最核心的基础设施开始。你是想先**把 Tailscale + 阿里云高速中继的网络架构搭起来**,还是想先**在 CachyOS 上把基础的 Docker Compose 环境和目录结构规范好**?我可以为你提供具体的配置文件和步骤。
## 备案说明
所有 Web 流量走 Cloudflare Tunnel境外边缘终止 TLS域名未备案。SSH 通过阿里云 IP 直连,不受备案约束。

15
cloudflared/compose.yml Normal file
View File

@@ -0,0 +1,15 @@
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel run
volumes:
- ./config.yml:/etc/cloudflared/config.yml:ro
- ./credentials.json:/etc/cloudflared/credentials.json:ro
networks:
- homelab_net
networks:
homelab_net:
external: true

9
cloudflared/config.yml Normal file
View File

@@ -0,0 +1,9 @@
tunnel: 809bc417-103b-4654-bc81-7cf11fbea964
credentials-file: /etc/cloudflared/credentials.json
ingress:
- hostname: xiteng.site
service: http://traefik:80
- hostname: "*.xiteng.site"
service: http://traefik:80
- service: http_status:404

13
frpc/docker-compose.yml Normal file
View File

@@ -0,0 +1,13 @@
services:
frpc:
image: snowdreamtech/frpc:latest
container_name: frpc
restart: unless-stopped
volumes:
- ./frpc.toml:/etc/frp/frpc.toml:ro
networks:
- homelab_net
networks:
homelab_net:
external: true

View File

@@ -15,28 +15,37 @@ services:
restart: unless-stopped
env_file: ../.env
environment:
USER_UID: 1000
USER_GID: 1000
USER_UID: 964
USER_GID: 964
GITEA__database__DB_TYPE: postgres
GITEA__database__HOST: db:5432
GITEA__database__NAME: giteadb
GITEA__database__USER: gitea
GITEA__server__SSH_PORT: 22
GITEA__server__SSH_LISTEN_PORT: 22
GITEA__server__SSH_DOMAIN: git.xiteng.site
volumes:
- ./data:/data
# 保留 SSH 端口以便通过 SSH 推送代码(可选),移除 HTTP 宿主端口,由 Traefik 暴露
ports:
- "3004:3000"
- "222:22"
labels:
# --- 1. Traefik 路由设置 ---
- "traefik.enable=true"
- "traefik.http.routers.gitea.rule=Host(`gitea.xiteng.site`)"
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
- "traefik.http.routers.gitea.entrypoints=websecure"
# --- 新增:开启 TLS 并指定解析器 ---
# --- HTTP 入口(来自 cloudflared tunnel---
- "traefik.http.routers.gitea-http.rule=Host(`gitea.xiteng.site`)"
- "traefik.http.routers.gitea-http.service=gitea"
- "traefik.http.routers.gitea-http.entrypoints=web"
# --- 开启 TLS 并指定解析器 ---
- "traefik.http.routers.gitea.tls=true"
- "traefik.http.routers.gitea.tls.certresolver=cfresolver"
# TCP Config (SSH)
- "traefik.tcp.routers.gitea-ssh.rule=HostSNI(`*`)" # SNI must be * for SSH
- "traefik.tcp.routers.gitea-ssh.entrypoints=ssh"
- "traefik.tcp.services.gitea-ssh.loadbalancer.server.port=22"
# --- 2. Homepage 自动发现设置 ---
- "homepage.group=生产力工具" # 分组名称
- "homepage.name=Gitea" # 显示名称

View File

@@ -34,6 +34,14 @@ services:
- "traefik.http.services.hedgedoc.loadbalancer.server.port=3000"
# 强制使用 websecure (443端口) 入口
- "traefik.http.routers.hedgedoc.entrypoints=websecure"
# --- HTTP 入口(来自 cloudflared tunnel---
- "traefik.http.routers.hedgedoc-http.rule=Host(`notes.xiteng.site`)"
- "traefik.http.routers.hedgedoc-http.service=hedgedoc"
- "traefik.http.routers.hedgedoc-http.entrypoints=web"
# --- 中间件:强制 X-Forwarded-ProtoCloudflare Tunnel 用 HTTP 连 Traefik但用户端是 HTTPS---
- "traefik.http.middlewares.force-https.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.routers.hedgedoc-http.middlewares=force-https"
- "traefik.http.routers.hedgedoc.middlewares=force-https"
# --- 新增:开启 TLS 并指定解析器 ---
- "traefik.http.routers.hedgedoc.tls=true"
- "traefik.http.routers.hedgedoc.tls.certresolver=cfresolver"

View File

@@ -16,6 +16,16 @@ services:
- "traefik.http.routers.homepage.rule=Host(`home.xiteng.site`)"
- "traefik.http.services.homepage.loadbalancer.server.port=3000"
- "traefik.http.routers.homepage.entrypoints=websecure"
# --- 根域名 xiteng.site ---
- "traefik.http.routers.homepage-root.rule=Host(`xiteng.site`)"
- "traefik.http.routers.homepage-root.service=homepage"
- "traefik.http.routers.homepage-root.entrypoints=websecure"
# --- HTTP 入口(来自 cloudflared tunnel---
- "traefik.http.routers.homepage-root-http.rule=Host(`xiteng.site`)"
- "traefik.http.routers.homepage-root-http.service=homepage"
- "traefik.http.routers.homepage-root-http.entrypoints=web"
- "traefik.http.routers.homepage-root.tls=true"
- "traefik.http.routers.homepage-root.tls.certresolver=cfresolver"
# --- 新增:开启 TLS 并指定解析器 ---
- "traefik.http.routers.homepage.tls=true"
- "traefik.http.routers.homepage.tls.certresolver=cfresolver"

View File

@@ -8,9 +8,23 @@ services:
ports:
- "3001:3001"
labels:
# --- 1. Traefik 路由设置 ---
- "traefik.enable=true"
- "traefik.http.routers.uptime.rule=Host(`uptime.homelab`)"
- "traefik.http.routers.uptime.rule=Host(`uptime.xiteng.site`)"
- "traefik.http.services.uptime.loadbalancer.server.port=3001"
- "traefik.http.routers.uptime.entrypoints=websecure"
# --- HTTP 入口(来自 cloudflared tunnel---
- "traefik.http.routers.uptime-http.rule=Host(`uptime.xiteng.site`)"
- "traefik.http.routers.uptime-http.service=uptime"
- "traefik.http.routers.uptime-http.entrypoints=web"
- "traefik.http.routers.uptime.tls=true"
- "traefik.http.routers.uptime.tls.certresolver=cfresolver"
# --- 2. Homepage 自动发现设置 ---
- "homepage.group=生产力工具" # 分组名称
- "homepage.name=Uptime Kuma" # 显示名称
- "homepage.icon=uptime" # 图标 (支持 si, mdi 等前缀)
- "homepage.href=https://uptime.xiteng.site" # 点击跳转的链接
- "homepage.description=网站监控工具" # 副标题描述
networks:
- homelab_net