From b383f59e0ab7905b0654768a01348b062703bfcc Mon Sep 17 00:00:00 2001 From: Yin Kou Date: Fri, 6 Nov 2026 21:59:56 +0800 Subject: [PATCH] feat(gateway): deploy Cloudflare DDNS daemon, wildcard SSL cert, and Caddy HTTPS reverse proxy on 10443 --- .gitignore | 4 ++ CHANGELOG.md | 16 ++++++++ PLAN.md | 7 ++-- configs/router-shellcrash-config.yaml | 2 + scripts/cloudflare-ddns.sh | 57 +++++++++++++++++++++++++++ stacks/gateway/Caddyfile | 28 +++++++++++++ stacks/gateway/docker-compose.yml | 17 ++++++++ stacks/lucky/docker-compose.yml | 6 +-- 8 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 .gitignore create mode 100755 scripts/cloudflare-ddns.sh create mode 100644 stacks/gateway/Caddyfile create mode 100644 stacks/gateway/docker-compose.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1a04c7b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.env +stacks/gateway/certs/*.key +stacks/gateway/certs/*.pem +stacks/lucky/goodluck/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 32ece31..2f3290e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,5 +82,21 @@ - 恢复 ShellCrash 配置:`cat ~/homelab/backups/router/config.yaml.bak | ssh 192.168.31.1 "cat > /userdisk/ShellCrash/yamls/config.yaml && /userdisk/ShellCrash/start.sh bfstart"` - 删除端口转发:`ssh 192.168.31.1 "uci delete firewall.@redirect[-1] && uci commit firewall && /etc/init.d/firewall reload"` +### 9. 配置 Cloudflare DDNS 自动守护进程、`*.home.961504.xyz` 泛域名 SSL 证书与 HTTPS 反代网关 +- **操作时间**:2026-11-06 21:56 ~ 21:58 +- **目标设备**:Mac mini (`192.168.31.164`) & Cloudflare (`961504.xyz`) & 小米路由器 (`192.168.31.1`) +- **变更内容**: + 1. **Cloudflare DDNS**:编写 [`scripts/cloudflare-ddns.sh`](file:///Users/ixvii0iv/homelab/scripts/cloudflare-ddns.sh) 并在 Mac mini 注册 `~/Library/LaunchAgents/com.homelab.cf-ddns.plist`(每 5 分钟自动运行),已将 `home.961504.xyz` 与 `*.home.961504.xyz` 解析至当前联通公网 IP `124.90.142.21`。 + 2. **泛域名 HTTPS 证书 (`acme.sh`)**:通过 Cloudflare DNS-01 验证自动签发 `home.961504.xyz` + `*.home.961504.xyz` ECC 泛域名证书,存放于 `~/homelab/stacks/gateway/certs/`。 + 3. **明文 HTTPS 反代网关 (`home-gateway`)**:部署 [`stacks/gateway/docker-compose.yml`](file:///Users/ixvii0iv/homelab/stacks/gateway/docker-compose.yml) 与 [`stacks/gateway/Caddyfile`](file:///Users/ixvii0iv/homelab/stacks/gateway/Caddyfile),监听 `10443` 端口提供: + - `https://nas.home.961504.xyz:10443` (`z4.home.961504.xyz:10443`) -> 极空间 Z4 (`192.168.31.185:5055`) + - `https://lucky.home.961504.xyz:10443` -> Lucky (`16601`) + - `https://clash.home.961504.xyz:10443` -> 路由器 Mihomo 面板 (`192.168.31.1:9999`) + 4. **路由器直连优化**:在 [`configs/router-shellcrash-config.yaml`](file:///Users/ixvii0iv/homelab/configs/router-shellcrash-config.yaml) 中新增 `DOMAIN-SUFFIX,home.961504.xyz,全球直连`,避免内网访问家庭域名时绕行境外代理。 +- **回滚方式**: + - 停止 DDNS:`ssh mini "launchctl unload ~/Library/LaunchAgents/com.homelab.cf-ddns.plist"` + - 停止反代网关:`ssh mini "cd ~/homelab/stacks/gateway && docker compose down"` + + diff --git a/PLAN.md b/PLAN.md index ef4d2cd..62c0708 100644 --- a/PLAN.md +++ b/PLAN.md @@ -24,9 +24,10 @@ - [x] **2.1 路由器固定 IP 与端口映射**: - 已在小米路由器 (`192.168.31.1`) 中将 Mac mini (`c8:80:6d:50:23:b1`) 绑定为静态 IP `192.168.31.164`。 - 已配置防火墙 DNAT 端口转发:将联通公网 (`124.90.142.21`) 的 `10443` (TCP/UDP) 转发至 Mac mini (`192.168.31.164:10443`)。 -- [x] **2.2 部署 Lucky 容器(家庭公网瑞士军刀)**: - - 已在 Mac mini 启动 `lucky` 容器(管理端:`http://192.168.31.164:16601`,统一 HTTPS 反代入口:`10443`)。 - - 待配置:Cloudflare DNS API Token、开启 `*.home.961504.xyz` DDNS 动态解析与 ACME 免费泛域名 SSL 证书。 +- [x] **2.2 配置 Cloudflare DDNS 与 `*.home.961504.xyz` 泛域名 HTTPS 反代网关**: + - 已配置 [`scripts/cloudflare-ddns.sh`](file:///Users/ixvii0iv/homelab/scripts/cloudflare-ddns.sh) 并注册 macOS `LaunchAgent` (`com.homelab.cf-ddns.plist`,每 5 分钟自动检测并同步公网 IP 至 `home.961504.xyz` 与 `*.home.961504.xyz`)。 + - 已通过 `acme.sh` + Cloudflare DNS API 自动签发 `home.961504.xyz` 与 `*.home.961504.xyz` 免费泛域名 SSL 证书。 + - 已部署明文 Git 管理的 `home-gateway` ([`stacks/gateway/Caddyfile`](file:///Users/ixvii0iv/homelab/stacks/gateway/Caddyfile)),监听 `10443` 端口反代极空间 Z4 (`https://nas.home.961504.xyz:10443`)、Lucky (`https://lucky.home.961504.xyz:10443`) 与 Clash 面板 (`https://clash.home.961504.xyz:10443`)。 - [ ] **2.3 部署 Tailscale(打通 MacBook + Mac mini + Azure 2C4G)**: - 三端登录同一 Tailnet,开启 Mac mini 的 Subnet Router(子网路由:`192.168.31.0/24`),实现在外网免配置直接用 `192.168.31.x` 访问家里极空间与路由器。 - [ ] **2.4 配置 Azure 2C4G 联动服务**: diff --git a/configs/router-shellcrash-config.yaml b/configs/router-shellcrash-config.yaml index 1ae1a25..c223fe1 100644 --- a/configs/router-shellcrash-config.yaml +++ b/configs/router-shellcrash-config.yaml @@ -55,6 +55,7 @@ dns: - '*' - '+.lan' - '+.local' + - '+.home.961504.xyz' - '+.msftconnecttest.com' - '+.msftncsi.com' - '+.pool.ntp.org' @@ -159,6 +160,7 @@ rule-providers: cn: {type: http, behavior: domain, format: mrs, path: ./ruleset/cn.mrs, interval: 86400, url: https://testingcf.jsdelivr.net/gh/juewuy/ShellCrash@update/bin/geodata/mrs_geosite_cn.mrs} rules: + - DOMAIN-SUFFIX,home.961504.xyz,全球直连 - RULE-SET,applications,全球直连 - DOMAIN,clash.razord.top,全球直连 - DOMAIN,yacd.haishan.me,全球直连 diff --git a/scripts/cloudflare-ddns.sh b/scripts/cloudflare-ddns.sh new file mode 100755 index 0000000..0fd9221 --- /dev/null +++ b/scripts/cloudflare-ddns.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# ============================================================================== +# cloudflare-ddns.sh +# 用途:定时检测家庭宽带真实公网 IPv4 并自动同步至 Cloudflare (home.961504.xyz & *.home.961504.xyz) +# 运行频率:通过 macOS LaunchAgent 每 5 分钟自动执行一次 +# ============================================================================== +set -euo pipefail + +# 从环境变量或 .env 读取 Token +if [ -f "$HOME/homelab/.env" ]; then + # shellcheck disable=SC1091 + source "$HOME/homelab/.env" +fi + +ZONE_ID="${CF_ZONE_ID:-8cf327569373837f075fa7f9e5bb7edd}" +TOKEN="${CF_API_TOKEN}" + +# 获取国内真实出口公网 IP(绕过国外代理分流) +WAN_IP=$(curl -4 -s --max-time 5 https://myip.ipip.net | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n 1 || true) +if [ -z "$WAN_IP" ]; then + WAN_IP=$(curl -4 -s --max-time 5 http://members.3322.org/dyndns/getip | tr -d '[:space:]' || true) +fi + +if [ -z "$WAN_IP" ]; then + echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: 无法获取当前家庭宽带公网 IP" + exit 1 +fi + +CACHE_FILE="$HOME/homelab/backups/last_wan_ip.txt" +LAST_IP=$(cat "$CACHE_FILE" 2>/dev/null || true) + +if [ "$WAN_IP" = "$LAST_IP" ]; then + echo "[$(date '+%Y-%m-%d %H:%M:%S')] OK: 公网 IP 未变化 ($WAN_IP)" + exit 0 +fi + +echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO: 检测到公网 IP 更新 ($LAST_IP -> $WAN_IP),正在同步至 Cloudflare..." + +for NAME in "home.961504.xyz" "*.home.961504.xyz"; do + REC_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=A&name=$NAME" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" | /opt/homebrew/bin/jq -r '.result[0].id // empty') + if [ -n "$REC_ID" ]; then + curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$REC_ID" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + --data "{\"type\":\"A\",\"name\":\"$NAME\",\"content\":\"$WAN_IP\",\"ttl\":60,\"proxied\":false}" >/dev/null + else + curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + --data "{\"type\":\"A\",\"name\":\"$NAME\",\"content\":\"$WAN_IP\",\"ttl\":60,\"proxied\":false}" >/dev/null + fi +done + +echo "$WAN_IP" > "$CACHE_FILE" +echo "[$(date '+%Y-%m-%d %H:%M:%S')] SUCCESS: 已将 home.961504.xyz 与 *.home.961504.xyz 更新为 $WAN_IP" diff --git a/stacks/gateway/Caddyfile b/stacks/gateway/Caddyfile new file mode 100644 index 0000000..9ed040f --- /dev/null +++ b/stacks/gateway/Caddyfile @@ -0,0 +1,28 @@ +# ============================================================================== +# 家庭公网 HTTPS 统一反向代理网关 (Mac mini: 10443 端口) +# 证书:/certs/fullchain.pem & /certs/privkey.pem (由 acme.sh 自动续签 *.home.961504.xyz) +# ============================================================================== +{ + auto_https disable_redirects +} + +# 1. 极空间 Z4 NAS (https://z4.home.961504.xyz:10443 或 https://nas.home.961504.xyz:10443) +nas.home.961504.xyz:10443, z4.home.961504.xyz:10443 { + tls /certs/fullchain.pem /certs/privkey.pem + encode zstd gzip + reverse_proxy 192.168.31.185:5055 +} + +# 2. Lucky 控制台 (https://lucky.home.961504.xyz:10443) +lucky.home.961504.xyz:10443 { + tls /certs/fullchain.pem /certs/privkey.pem + encode zstd gzip + reverse_proxy host.docker.internal:16601 +} + +# 3. 路由器 Mihomo / Clash 面板 (https://clash.home.961504.xyz:10443) +clash.home.961504.xyz:10443 { + tls /certs/fullchain.pem /certs/privkey.pem + encode zstd gzip + reverse_proxy 192.168.31.1:9999 +} diff --git a/stacks/gateway/docker-compose.yml b/stacks/gateway/docker-compose.yml new file mode 100644 index 0000000..73e8841 --- /dev/null +++ b/stacks/gateway/docker-compose.yml @@ -0,0 +1,17 @@ +services: + caddy: + image: caddy:2-alpine + container_name: home-gateway + restart: always + ports: + - "10443:10443/tcp" + - "10443:10443/udp" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - ./certs:/certs:ro + - ./caddy_data:/data + - ./caddy_config:/config + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + - TZ=Asia/Shanghai diff --git a/stacks/lucky/docker-compose.yml b/stacks/lucky/docker-compose.yml index 1a5af8a..fb6355e 100644 --- a/stacks/lucky/docker-compose.yml +++ b/stacks/lucky/docker-compose.yml @@ -3,11 +3,9 @@ services: image: gdy666/lucky:latest container_name: lucky restart: always - # 在 macOS (OrbStack) 下,使用端口映射暴露管理端口与统一反代端口 + # 在 macOS (OrbStack) 下暴露管理端口 (10443 统一反代由 stacks/gateway 中的 Caddy 承担以实现明文 Git 版本管理) ports: - - "16601:16601/tcp" # Lucky Web 管理后台端口 (仅内网或配置安全入口后访问) - - "10443:10443/tcp" # 家宽公网统一 HTTPS 反向代理入口端口 (TCP) - - "10443:10443/udp" # HTTP/3 QUIC 支持 (UDP) + - "16601:16601/tcp" # Lucky Web 管理后台端口 volumes: - ./goodluck:/goodluck - /etc/localtime:/etc/localtime:ro