📋 通用指南
保康县 AI 编程人才孵化基地 & 统计局 · 技术文档
更新:2026-07-07 · 保康县
🏗️ 部署架构指南
Cloudflare Tunnel + Docker Nginx 反向代理 · 域名体系 · 网络兜底
📐 整体架构
所有站点采用统一的 Cloudflare Tunnel → Docker Nginx → 静态HTML/容器 三层架构。 公网零暴露端口,全部流量经 Cloudflare Edge 加密隧道进入。
宿主机:WSL2 (Ubuntu) on Windows 11
容器编排:Docker Compose · nginx 版本 1.31 (alpine)
内网互联:Tailscale (备用通道)
存储挂载:Windows 宿主机 /mnt/c/AI-Workspace/docker-stack/nginx/html/
🌐 域名体系
| 域名 | 用途 | 说明 |
|---|---|---|
bearqh.fun |
技术 & 工具 | 主技术域名,托管 AI 孵化基地、Gitea、Portainer、n8n、Dify、MinIO 等 |
保康.top |
政府统计 | 官方站点 tj.保康.top、NB保康 nb.保康.top、AI孵化基地 ai.保康.top |
熊.online |
个人项目 | 个人门户、知识库浏览器 vault.熊.online、股票看板、论坛、用户管理、短链等 |
🔁 域名映射流程
用户请求经过的链路:CF Tunnel 的 public hostname → nginx server_name → root / proxy_pass
# 每个 public hostname 映射一个 nginx 子站 tunnel: xxxx-xxxx-xxxx credentials-file: /home/nonroot/.cloudflared/xxxx.json ingress: # bearqh.fun 子站 - hostname: ai.bearqh.fun service: http://nginx-tj:80 - hostname: gitea.bearqh.fun service: http://nginx-tj:80 - hostname: n8n.bearqh.fun service: http://nginx-tj:80 # 保康.top 子站 - hostname: tj.保康.top service: http://nginx-tj:80 - hostname: nb.保康.top service: http://nginx-tj:80 # 熊.online 子站 - hostname: vault.熊.online service: http://nginx-tj:80 - hostname: chat.熊.online service: http://nginx-tj:80 # 兜底:所有未匹配的 hostname - service: http_status:404
# 静态 HTML 站点 (info站点) server { listen 80; server_name info.熊.online; root /usr/share/nginx/html/info; index index.html; location / { try_files $uri $uri/ =404; } } # 反向代理到 Docker 容器 (股票看板API) server { listen 80; server_name xn--2vx.online; # 熊.online 的 punycode # 股票搜索接口 → 东方财富 suggest location /api/stock/search { proxy_pass https://searchadapter.example.com; proxy_set_header Host searchadapter.example.com; proxy_set_header X-Real-IP $remote_addr; # CORS 头注入 add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # OPTIONS 预检请求直接返回 if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header Content-Length 0; add_header Content-Type text/plain; return 204; } } }
🔓 CORS 处理策略
浏览器端 JavaScript 调用第三方 API 时面临跨域限制。采用以下三级策略:
| 策略 | 适用场景 | 实现方式 |
|---|---|---|
| 方案A | 自有nginx代理的接口 | proxy_pass + add_header Access-Control-Allow-Origin * |
| 方案B | API 本身支持 CORS | 前端直接 fetch(),无需代理 |
| 方案C | 不支持 CORS 的外部 API | 切换数据源或使用 JSONP 方式(降级) |
🌍 网络兜底策略
部分中国境内 API(如东方财富、腾讯行情)通过 HTTPS 访问时,因网络环境(Tailscale、WSL 路由、防火墙等)可能出现 TLS 握手失败、连接重置 等问题。
备选方案 — 腾讯 HTTP API:
// 腾讯行情 API(HTTP) const TENCENT_QT_API = 'http://qt.gtimg.cn/q='; // 腾讯 K线 API(HTTP) const TENCENT_KLINE_API = 'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param='; // 自动降级逻辑 async function fetchWithFallback(primaryUrl, fallbackUrl) { try { const res = await fetch(primaryUrl, { signal: AbortSignal.timeout(5000) }); if (!res.ok) throw new Error('HTTP ' + res.status); return await res.text(); } catch (e) { console.warn('Primary API failed, falling back: ', e.message); const res2 = await fetch(fallbackUrl); return await res2.text(); } }
核心原则:HTTPS 失败自动降级到 HTTP,优先使用腾讯 API 系列(速度最快、数据最全)。
🧠 Obsidian 知识工作流
知识包含模型 · 五槽模型 · 标签体系 · Web 发布 · 日报与决策日志
📚 知识包含模型(L0–Ln 六层架构)
知识库采用分层架构,从原始记录到最终输出逐层提炼:
| 层级 | 名称 | 内容 | 示例 |
|---|---|---|---|
L0 | 原始 | 未加工的数据、截图、链接 | 网页剪藏、API 返回结果 |
L1 | 摘要 | 精炼要点,去冗余 | 会议纪要、文章摘要 |
L2 | 结构化 | 分类、表格、流程图 | 技术架构图、对比表格 |
L3 | 关联 | 跨笔记链接、双向关系 | 知识图谱、[[双链]] |
L4 | 融合 | 多来源综合,形成新认知 | 研究报告、方案设计 |
Ln | 输出 | 对外发布的成品 | 博客文章、技术文档 |
🧩 五槽模型
每条笔记在 Obsidian 中通过五个维度进行标注(Frontmatter 或 inline fields):
🏷️ 标签体系
| 标签 | 含义 | 使用场景 |
|---|---|---|
#待完善 |
草稿 / 不完整 | 笔记尚未完成,需要后续补充 |
#已验证 |
已确认可用 | 代码片段、配置经过实际测试 |
#经验 |
踩坑 / 心得 | 部署过程中的教训和解决方案 |
#项目 |
归档项目 | 完整项目文档,含架构和决策记录 |
🌐 Web 发布
Obsidian 知识库通过 vault.熊.online 发布为可浏览的 Web 页面。 支持全文搜索、双向链接导航。目前收录 64+ 篇笔记,涵盖技术、金融、AI 等领域。
📝 日报自动编写 + 决策日志
每日自动生成日报模板,记录当日工作内容、进度和遇到的问题。 决策日志(Decision Log)记录关键架构和技术选型的 背景、方案、结论:
日期:2026-07-07
决策:选择腾讯 HTTP API 作为股票数据兜底方案
背景:HTTPS 连接在某些 WSL 网络环境下不稳定
方案对比:① 腾讯 HTTP(无CORS问题,速度最快)② 东方财富(需nginx代理)③ 新浪(数据延迟)
结论:腾讯 HTTP 为首选降级方案,nginx 代理东方财富为辅
🔧 站点运维指南
站点清单 · Docker · Nginx · Cloudflare Tunnel · 域名新增
📋 所有站点列表
| 子域名 | 类型 | 目标 | 说明 |
|---|---|---|---|
ai.bearqh.fun | 反向代理 | 静态HTML | AI编程人才孵化基地(公益) |
gitea.bearqh.fun | Docker容器 | gitea:latest | 自托管 Git 服务 |
n8n.bearqh.fun | Docker容器 | n8n:latest | 工作流自动化引擎 |
dify.bearqh.fun | Docker容器 | dify:1.15 | AI应用开发平台 |
minio.bearqh.fun | Docker容器 | minio:latest | 对象存储控制台 |
portainer.bearqh.fun | Docker容器 | portainer:latest | Docker管理面板 |
tj.保康.top | 静态HTML | nginx静态文件 | 保康统计局官网 |
nb.保康.top | 静态HTML | nginx静态文件 | NB保康展示页 |
vault.熊.online | 静态HTML | nginx静态文件 | Obsidian 知识库 Web 版 |
chat.熊.online | Docker容器 | open-webui | AI 聊天界面 |
info.熊.online | 静态HTML | nginx静态文件 | 本文档所在站点 |
xn--2vx.online/stock/ | 静态HTML | nginx静态文件 | 股票看板 (子路径) |
🐳 Docker 容器管理常用命令
# 查看所有运行容器 docker ps # 查看所有容器(含停止) docker ps -a # 进入容器内部 docker exec -it <container_name> sh # 重启 nginx docker exec nginx-proxy nginx -s reload # 或 docker restart nginx-proxy # 查看nginx日志 docker logs nginx-proxy --tail 50 -f # 查看容器资源占用 docker stats # 启动/停止/重启整个栈 docker compose -f /path/to/docker-compose.yml up -d docker compose -f /path/to/docker-compose.yml down docker compose -f /path/to/docker-compose.yml restart
📄 Nginx 配置要点
# 静态站点配置 server { listen 80; server_name info.熊.online; # 根目录(容器内路径) root /usr/share/nginx/html/info; index index.html; # 共享资源(common.css 等) location /_shared/ { alias /usr/share/nginx/html/_shared/; expires 7d; add_header Cache-Control "public, immutable"; } location / { try_files $uri $uri/ =404; } # 安全头 add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; } # 反向代理到 Docker 容器 server { listen 80; server_name gitea.bearqh.fun; location / { proxy_pass http://gitea:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # WebSocket 支持 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }
🔄 Cloudflare Tunnel 重启流程
# 查找 cloudflared 容器 docker ps | grep cloudflared # 重启 tunnel docker restart cloudflared # 查看日志确认隧道状态 docker logs cloudflared --tail 20 # 如果容器内手动启动 docker exec -it cloudflared cloudflared tunnel run <tunnel_name> # 验证隧道是否正常运行(日志中应有) # "Connection xxxxxxxx registered" 或 "Connected to ... "
➕ 域名新增流程
新增一个子站点需要完成以下 4 步:
- DNS 解析:在 Cloudflare Dashboard 添加 CNAME 记录,指向隧道域名(如
xxx-xxx-xxx.cfargotunnel.com) - CF Tunnel 配置:在 cloudflared
config.yml的ingress中添加hostname→service: http://nginx-tj:80 - Nginx 配置:在
/etc/nginx/conf.d/下新增server块,指定server_name和root或proxy_pass - 重启服务:
docker restart cloudflared+docker exec nginx-proxy nginx -s reload
使用 curl -H "Host: 新域名" http://localhost 在宿主机直接测试 nginx 是否响应正确,排除隧道问题后再测试公网访问。
📈 炒股看板技术文档
数据源 · CORS 处理 · WSL 网络问题 · 搜索功能
📡 数据源清单
| 功能 | API | 协议 | CORS | 说明 |
|---|---|---|---|---|
| 搜索 | 东方财富 suggest |
HTTPS | 需代理 | 股票代码/名称模糊搜索 + 拼音缩写 |
| K线 | 腾讯 |
HTTP/HTTPS | 直接调用 | 日/周/月 K 线,支持前复权 |
| 行情 | 腾讯 QT |
HTTP | 直接调用 | 实时五档行情、盘口数据 |
| 详情 | 腾讯 QT |
HTTP | 直接调用 | 公司信息、财务指标、分红送配 |
| 指数 | 东方财富 → 腾讯(兜底) |
HTTPS/HTTP | 需代理/直连 | 大盘指数行情,东方财富为主 |
🔓 CORS 处理方案
前端 JavaScript 无法直接调用不支持 CORS 的 API,采用以下分级方案:
方案 1:nginx 代理(适用于东方财富)
location /api/stock/search {
# 东方财富 suggest 接口
proxy_pass https://searchadapter.eastmoney.com/api/suggest/get_v2;
proxy_set_header Host searchadapter.eastmoney.com;
proxy_set_header Referer https://quote.eastmoney.com/;
proxy_set_header User-Agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64)";
# CORS 头
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
# 预检请求
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
}
方案 2:有 CORS 的直接调用(腾讯 API)
// 腾讯行情 QT API — 支持 CORS,可直接 fetch const url = `http://qt.gtimg.cn/q=sh600519,sz000001`; async function fetchStocks(codes) { const res = await fetch(`http://qt.gtimg.cn/q=${codes.join(',')}`); const text = await res.text(); return parseQtData(text); // 自行解析 ~ 格式特殊 } // 腾讯 K线 API async function fetchKline(code, period = 'day') { const url = `http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param=${code},${period},,,20,qfq`; const res = await fetch(url); return await res.json(); }
方案 3:数据源切换
当主数据源不可用时,自动切换到备用数据源:
⚠️ WSL 网络问题:Tailscale 导致 HTTPS reset
在 WSL2 环境下启用 Tailscale 后,部分 HTTPS 请求出现 TCP 连接重置 (RST)。 表现为浏览器中跨域 HTTPS API 调用失败,尤其是对中国境内 API。
兜底策略:
- 优先使用 HTTP 协议调用腾讯 API(腾讯 QT 同时支持 HTTP/HTTPS)
- 使用 nginx 代理转发 HTTPS 请求,避免浏览器直接发起到目标地址的 HTTPS 连接
- 临时关闭 Tailscale 的 MagicDNS / 路由功能(
tailscale down后测试) - 最终方案:股票看板前端实现 自动降级逻辑,HTTPS 失败后自动切换到 HTTP
🔍 搜索功能
股票搜索组件支持三种搜索方式,通过 nginx 代理统一入口调用:
| 功能 | 说明 | 示例 |
|---|---|---|
| 代码搜索 | 输入股票代码(如 600519) |
跳转至贵州茅台详情 |
| 名称搜索 | 输入中文名称(如 贵州茅台) |
东方财富 suggest 返回匹配 |
| 拼音缩写 | 输入首字母缩写(如 gzmt → 贵州茅台) |
东方财富 suggest 内置支持 |
防抖处理
搜索输入框采用 200ms 防抖,避免每次按键都触发 API 请求:
// 防抖函数 function debounce(fn, delay = 200) { let timer = null; return function(...args) { clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), delay); }; } // 搜索函数 async function doSearch(keyword) { if (!keyword || keyword.length < 1) return; const url = `/api/stock/search?input=${encodeURIComponent(keyword)}`; const res = await fetch(url); const data = await res.json(); // 渲染搜索结果... } // 绑定防抖 searchInput.addEventListener('input', debounce((e) => { doSearch(e.target.value); }, 200));
拼音缩写支持
东方财富 suggest 接口原生支持拼音首字母搜索,无需额外逻辑。
例如输入 gzmt 自动匹配 贵州茅台 (600519)、zgrm 匹配 中国人民保险 等。
GET /api/stock/search?input=gzmt
→ nginx 代理转发至 https://searchadapter.eastmoney.com/api/suggest/get_v2?input=gzmt
→ 返回 JSON 包含股票代码、名称、类型等信息