跳转至内容
BakeHub 工科开源社群

社区讨论

经验分享

7主题 12帖子

沉淀实践经验与可复用的方法

此版块可通过开放社交网络使用标识符 blogs@127.0.0.1:14581 关注

  • 看群主的前端源码,如何爆破思路

    2
    2赞同
    2帖子
    90浏览
    @KongChar 给捞哥网页底裤都说出来了
  • BakeHub 外部 Markdown 发帖工具

    pythonnodebb自动化
    1
    1赞同
    1帖子
    48浏览
    背景:为什么要写一个外部发帖工具? BakeHub 是基于 NodeBB 搭建的工科开源社群,日常发帖通常要在网页编辑器里手敲 Markdown。但当你有一篇几千字的技术复盘、或者想批量迁移本地笔记库时,网页编辑器就成了瓶颈——没有本地版本控制、不能 vim 键位、不能 grep、不能 diff。于是我用 F12 抓了一下 NodeBB 的发帖请求,顺手写了一个 零依赖 的 Python 脚本,直接用本地 Markdown 文件发帖。这篇帖子既是工具发布,也是把抓包分析过程完整记录下来,方便后来人复用。 第一步:F12 抓包分析 NodeBB 发帖流程 打开 BakeHub 首页,按 F12 切到 Network 面板,勾上 Preserve log,然后手动走一遍「登录 → 进版块 → 发帖」的流程。关键请求按时间顺序如下: 1. 登录请求 POST /login HTTP/1.1 Host: 203.195.163.189 Content-Type: application/x-www-form-urlencoded x-csrf-token: <从 /api/config 拿到的 token> Referer: http://203.195.163.189/ username=KongChar&password=********&remember=on&returnTo= 服务器返回 {"next":"/"} 并 Set-Cookie: express.sid=...,这个 session cookie 就是后续所有请求的身份凭证。注意 CSRF token 必须通过 x-csrf-token 请求头 传回去,而不是放在 body 里——这是 NodeBB 的硬性要求,漏掉会直接 403。 2. 获取 CSRF token GET /api/config HTTP/1.1 Accept: application/json 返回的 JSON 里关键字段: 字段 含义 csrf_token 写操作必须带的 token,每次会话变化 loggedIn true/false,判断当前 session 是否已登录 uid 当前用户 id,游客为 0 maximumPostLength 单帖最大字符数(本站 32767) maximumTagsPerTopic 每帖最多标签数(本站 5) 3. 发帖请求(NodeBB v3 API) POST /api/v3/topics HTTP/1.1 Content-Type: application/json x-csrf-token: <同上> { "cid": 3, "title": "帖子标题", "content": "Markdown 正文", "tags": ["工具", "Python"] } 返回 {"topic": {"tid": 123, "slug": "123/xxx", ...}},帖子 URL 就是 /topic/{tid}/{slug}。 4. 列版块 GET /api/categories 返回 categories 数组,每项含 cid / name / slug / topic_count。本站当前版块: cid 名称 用途 1 项目复盘 复盘总结 2 开源求助 提问 3 经验分享 技术分享(本帖所在) 4 学习路线 路线规划 第二步:踩过的坑 抓包看似简单,实际写脚本时踩了三个坑,值得单独说一下: 坑 1:Connection reset by peer。 服务器对短时间高频请求会直接 RST 连接,第一次跑 cats 子命令就挂了。解决办法是给底层请求加 指数退避重试,失败后 sleep 1.5s / 3s / 4.5s 再试。 坑 2:Accept 头重复。 一开始在 opener.addheaders 里写了 Accept,又在 _request 里 append 一次,导致请求头里出现两个 Accept,服务器偶尔会拒绝。统一在 _request 里追加,addheaders 只放 User-Agent 和 Referer。 坑 3:CSRF token 会过期。 长时间不操作后再发帖,会收到 403 [[error:invalid-csrf-token]]。所以每次发帖前都重新 GET /api/config 刷新一次 token,而不是登录时拿一次就缓存到底。 第三步:完整工具代码 下面是 bakehub-poster.py 的完整源码,零第三方依赖,只用 Python 标准库。把它存成文件直接 python3 bakehub-poster.py 就能跑。 #!/usr/bin/env python3 """ bakehub-poster.py — BakeHub (NodeBB) 外部 Markdown 发帖工具 用法: python bakehub-poster.py post --file post.md --title "帖子标题" --cid 3 --tags "工具,Python" python bakehub-poster.py cats # 列出所有版块 python bakehub-poster.py login # 仅登录并保存会话 依赖: 仅 Python 标准库 (urllib / http / json / argparse) 作者: KongChar """ import argparse import http.cookiejar import json import os import time import urllib.parse import urllib.request # ===== 配置区 ===== BASE_URL = "http://203.195.163.189" DEFAULT_CID = 3 # 经验分享 COOKIE_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bakehub.cookies.txt") UA = ("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") class BakeHubClient: def __init__(self, base_url=BASE_URL): self.base = base_url.rstrip("/") self.cj = http.cookiejar.MozillaCookieJar(COOKIE_FILE) if os.path.exists(COOKIE_FILE): self.cj.load(ignore_discard=True, ignore_expires=True) self.opener = urllib.request.build_opener( urllib.request.HTTPCookieProcessor(self.cj)) self.opener.addheaders = [ ("User-Agent", UA), ("Referer", self.base + "/"), ] self.csrf = "" # ---------- 底层请求(带重试) ---------- def _request(self, path, method="GET", data=None, headers=None, content_type="application/x-www-form-urlencoded", accept_json=True, retries=3): url = self.base + path last_err = None for attempt in range(retries): body = None h = list(self.opener.addheaders) if accept_json: h.append(("Accept", "application/json")) if headers: h.extend(headers.items()) if data is not None: if isinstance(data, (dict, list)): body = json.dumps(data).encode("utf-8") h.append(("Content-Type", "application/json")) elif isinstance(data, str): body = data.encode("utf-8") h.append(("Content-Type", content_type)) else: body = data h.append(("Content-Type", content_type)) req = urllib.request.Request(url, data=body, method=method) for k, v in h: req.add_header(k, v) try: with self.opener.open(req, timeout=30) as r: return r.status, r.read().decode("utf-8", errors="replace") except urllib.error.HTTPError as e: return e.code, e.read().decode("utf-8", errors="replace") except (urllib.error.URLError, ConnectionError, TimeoutError) as e: last_err = e if attempt < retries - 1: time.sleep(1.5 * (attempt + 1)) continue raise RuntimeError(f"请求 {path} 失败(重试 {retries} 次): {last_err}") # ---------- 公开方法 ---------- def fetch_csrf(self): """从 /api/config 拿 CSRF token""" status, text = self._request("/api/config") if status != 200: raise RuntimeError(f"获取 CSRF 失败: HTTP {status} {text[:200]}") cfg = json.loads(text) self.csrf = cfg.get("csrf_token", "") if not self.csrf: raise RuntimeError("CSRF token 为空") return self.csrf def login(self, username, password): """登录并保存 cookie""" self.fetch_csrf() form = urllib.parse.urlencode({ "username": username, "password": password, "remember": "on", "returnTo": "", }) status, text = self._request( "/login", method="POST", data=form, headers={"x-csrf-token": self.csrf}) if status != 200: raise RuntimeError(f"登录失败: HTTP {status} {text[:200]}") try: resp = json.loads(text) except json.JSONDecodeError: resp = {"raw": text} # 保存 cookie self.cj.save(COOKIE_FILE, ignore_discard=True, ignore_expires=True) # 验证登录 self.fetch_csrf() status2, text2 = self._request("/api/config") cfg = json.loads(text2) if not cfg.get("loggedIn"): raise RuntimeError("登录后仍为游客,请检查账号密码") return resp def list_categories(self): status, text = self._request("/api/categories") if status != 200: raise RuntimeError(f"获取版块失败: HTTP {status}") data = json.loads(text) return data.get("categories", []) def create_topic(self, cid, title, content, tags=None): """创建新主题。content 为 Markdown 文本""" if not self.csrf: self.fetch_csrf() payload = { "cid": int(cid), "title": title, "content": content, "tags": tags or [], } status, text = self._request( "/api/v3/topics", method="POST", data=payload, headers={"x-csrf-token": self.csrf}) if status not in (200, 201): raise RuntimeError(f"发帖失败: HTTP {status} {text[:300]}") return json.loads(text) def reply(self, tid, content): if not self.csrf: self.fetch_csrf() payload = {"tid": int(tid), "content": content} status, text = self._request( "/api/v3/topics/" + str(tid), method="POST", data=payload, headers={"x-csrf-token": self.csrf}) if status not in (200, 201): raise RuntimeError(f"回复失败: HTTP {status} {text[:300]}") return json.loads(text) # ===== CLI ===== def cmd_login(args): c = BakeHubClient() r = c.login(args.user, args.password) print("[OK] 登录成功,会话已保存到", COOKIE_FILE) print(" 返回:", r) def cmd_cats(args): c = BakeHubClient() cats = c.list_categories() print(f"{'cid':>4} {'name':<20} {'slug':<20} topics") print("-" * 60) for cat in cats: print(f"{cat.get('cid'):>4} {cat.get('name'):<20} " f"{cat.get('slug'):<20} {cat.get('topic_count')}") def cmd_post(args): with open(args.file, "r", encoding="utf-8") as f: content = f.read() tags = [t.strip() for t in (args.tags or "").split(",") if t.strip()] c = BakeHubClient() # 自动登录(若会话失效) try: c.fetch_csrf() except Exception: c.login(args.user, args.password) # 二次确认登录态 status, text = c._request("/api/config") cfg = json.loads(text) if not cfg.get("loggedIn"): print("[INFO] 会话已过期,重新登录...") c.login(args.user, args.password) result = c.create_topic(args.cid, args.title, content, tags) print("[OK] 发帖成功!") if isinstance(result, dict): topic = result.get("topic", result) slug = topic.get("slug") or topic.get("tid") print(" tid:", topic.get("tid")) print(" URL:", f"{BASE_URL}/topic/{topic.get('tid')}/{slug}") def main(): p = argparse.ArgumentParser( description="BakeHub (NodeBB) 外部 Markdown 发帖工具") p.add_argument("--user", default="KongChar", help="用户名") p.add_argument("--password", default="csj123456", help="密码") sub = p.add_subparsers(dest="cmd", required=True) sub.add_parser("login", help="仅登录并保存会话").set_defaults(func=cmd_login) sub.add_parser("cats", help="列出所有版块").set_defaults(func=cmd_cats) pp = sub.add_parser("post", help="发布 Markdown 帖子") pp.add_argument("--file", required=True, help="Markdown 文件路径") pp.add_argument("--title", required=True, help="帖子标题") pp.add_argument("--cid", type=int, default=DEFAULT_CID, help="版块 cid") pp.add_argument("--tags", help="标签,逗号分隔") pp.set_defaults(func=cmd_post) args = p.parse_args() args.func(args) if __name__ == "__main__": main() 第四步:使用方法 把上面的代码存为 bakehub-poster.py,然后: 1. 首次登录(保存会话,后续免登录): python3 bakehub-poster.py login # 输出: [OK] 登录成功,会话已保存到 .../bakehub.cookies.txt 2. 查看版块列表: python3 bakehub-poster.py cats # cid name slug topics # ------------------------------------------------------------ # 1 项目复盘 1/项目复盘 3 # 2 开源求助 2/开源求助 5 # 4 学习路线 4/学习路线 2 # 3 经验分享 3/经验分享 6 3. 用本地 Markdown 文件发帖: cat > my-post.md <<'EOF' ## 我的第一篇外部发帖 这是用脚本发的帖子,正文支持完整 Markdown 语法。 - 列表 - **加粗** / *斜体* / `代码` - [链接](https://example.com) EOF python3 bakehub-poster.py post \ --file my-post.md \ --title "我的第一篇外部发帖" \ --cid 3 \ --tags "工具,Python,自动化" # 输出: # [OK] 发帖成功! # tid: 17 # URL: http://203.195.163.189/topic/17/我的第一篇外部发帖 这篇帖子本身就是用这个工具发出来的 —— 自举成功。脚本、Markdown 源文件、cookie 缓存都在本地,可以 git 管理,可以 diff 历史版本,再也不用在网页编辑器里反复粘贴了。 设计取舍说明 为什么不用 requests 库?因为想保证 零依赖,任何一台装了 Python 3 的机器都能直接跑,不用 pip install。urllib 的 API 确实啰嗦,但封装一层 _request 之后用起来和 requests 差不多。 为什么 cookie 用 Netscape 格式落盘?因为 http.cookiejar.MozillaCookieJar 是标准库原生支持的,文件可以直接被 curl -b 复用,方便调试——脚本跑挂了可以手动 curl -b bakehub.cookies.txt ... 排查。 为什么 CSRF token 每次都重新取?因为 NodeBB 的 token 会随 session 状态变化,缓存反而更容易踩 403。一次 GET /api/config 才几 KB,代价可以忽略。 后续可扩展的方向 当前版本只覆盖了「登录 + 列版块 + 发主题 + 回复」四个核心动作。如果有人想接着做,几个方向值得考虑: 图片上传:NodeBB 的上传接口是 POST /api/v3/topics/upload,需要 multipart/form-data,目前脚本没实现,长帖里的图片还得手动传。 草稿同步:把本地 .md 文件的 frontmatter(标题、tags、cid)解析出来,做到一篇文件 = 一篇帖子,git diff 就能看出改了啥。 批量迁移:遍历一个目录下所有 .md 文件,按 frontmatter 里的 cid 自动分发到对应版块,适合从 Obsidian / Hexo 仓库一键搬迁。 WebSocket 监听:NodeBB 用 socket.io 推实时通知,接上之后可以做到「别人回复你的帖子时本地弹通知」。 欢迎在评论区交流改进思路,或者直接 fork 这个脚本改一版发上来。
  • 使用deepssk做出的BakeHub自动发帖工具,证明爱群主

    2
    1赞同
    2帖子
    107浏览
    @鲁迪乌斯 能用来经验+3吗
  • 1赞同
    1帖子
    7浏览
    大家好!今天给大家分享几个GitHub上超有意思的STM32超频开源项目,喜欢折腾硬件的朋友们千万别错过~ MCU超频这件事,就像给芯片"开外挂",虽然超出原厂规格有风险,但那种把一块便宜板子榨干性能的快感,只有玩过的人才懂!下面三个项目分别对应不同的STM32系列,各有各的玩法。 项目一:stm32-overclocking-challenge(蓝药丸极限超频竞赛) 项目地址: https://github.com/m3y54m/stm32-overclocking-challenge 目标芯片: STM32F103C8T6(经典蓝药丸BluePill) 这个项目有多野? 这是一个专门针对STM32F103的极限超频挑战项目,作者直接用汇编来写时钟配置代码,就是为了榨干每一滴性能! 亮点: 测试不同PLL配置下的极限频率 GPIO翻转速度测试,看看到底能跑多快 纯汇编级别的时钟寄存器操作,硬核到底 附带稳定性测试代码 有趣在哪? STM32F103官方标称最高72MHz,但很多"大雷"板子其实能跑到128MHz甚至更高!这个项目就像一场硅片体质大抽奖,有的人的蓝药丸只能稳80MHz,有的神仙体质能冲150MHz+。 而且用GPIO翻转来测频率特别直观——用示波器一看就知道你的芯片到底超没超成功,波形密到什么程度。 ️ 项目二:stm32f303k8-template(F303超频工程模板) 项目地址: https://github.com/dimtass/stm32f303k8-template 目标芯片: STM32F303 Nucleo开发板 实用派超频代表 这个项目就比较"工程化"了,不是单纯追求极限,而是提供了一个完整的、超频到128MHz的工程模板,拿来就能用。 亮点: 直接超频到128MHz稳定运行(官方标称72MHz) ️ 完整的Makefile工程模板,开箱即用 配置好了Flash等待周期,不会跑飞 支持Nucleo开发板,硬件门槛低 有趣在哪? F303系列带硬件浮点单元(FPU),超频之后做DSP运算性能提升特别明显!如果你用它做电机控制、数字信号处理,超个频相当于免费升级了芯片。 而且这个项目最良心的地方是——它不是那种"能点亮就算成功"的demo,而是真的把整个系统时钟树都调好了,外设也能正常工作,拿来做实际项目都没问题。 项目三:overclocking-STM32F37x_16(F37x时钟魔改) 项目地址: https://github.com/qidfpv/overclocking-STM32F37x_16 目标芯片: STM32F37x系列 温和超频派 这个项目相对保守一些,把F37x从官方72MHz超到80MHz,属于"安全小超"的范畴。 亮点: 修改系统时钟文件system_stm32f37x.c 从72MHz提升到80MHz,约11%性能提升 ️ 超频幅度小,稳定性有保障 直接替换时钟配置文件即可 有趣在哪? 别看只超了8MHz,对于很多对时序要求严格的应用来说,这已经是很大的提升了!而且这种"甜点频率"基本所有芯片都能稳住,不需要挑体质,量产项目都敢用。 这个项目最适合新手入门超频——改动小,风险低,成功了有成就感,失败了也不容易烧片子。 超频小科普:为什么MCU能超频? 很多人可能好奇,为什么官方标72MHz的芯片能跑到128MHz?其实原因很简单: 厂商留有余量:为了保证量产良率和长期稳定性,标称频率通常都比较保守 温度影响: datasheet里的参数一般是工业级温度范围(-40~85℃),室温下潜力更大 体质差异:同一条生产线出来的芯片,极限频率也不一样,这就是所谓的"大雷"和"大雕" ️ 重要提醒 超频虽爽,但一定要注意: 超频会失去原厂质保 功耗和发热会明显增加 Flash等待周期必须对应调整,否则直接HardFault 外设时钟(UART/SPI/I2C)会跟着变,通信波特率可能错乱 极限超频有烧坏芯片的风险,做好散热和电流监控 最后 STM32超频就像是硬件圈的"装机超频"文化,便宜的几块钱的蓝药丸,超一超性能翻倍,那种DIY的乐趣真的很棒! 如果你也玩过STM32超频,欢迎在评论区分享你的战绩——你的芯片最高稳在了多少MHz?
  • SillyTavern:把 AI 对话变成角色、世界与长期故事

    ai 聊天工具
    4
    1赞同
    4帖子
    92浏览
    @鲁迪乌斯 老哥太佬了
  • 教你如何搭建属于自己的机场,Docker Compose 部署 sing-box + Hysteria2

    1
    2赞同
    1帖子
    17浏览
    使用 Docker Compose 部署 sing-box + Hysteria2 本文介绍 sing-box 的作用,并以 Hysteria2 服务端为例,给出一套可维护的 Docker Compose 部署与客户端使用方法。文中的域名、密码和路径均为示例,请替换后再使用。 一、项目地址与官方资料 开源仓库:SagerNet/sing-box 官方文档:sing-box.sagernet.org Docker 部署文档:Docker - sing-box Hysteria2 服务端配置:Hysteria2 Inbound Hysteria2 客户端配置:Hysteria2 Outbound 官方图形客户端:Graphical Clients sing-box 官方将其定义为“The universal proxy platform”,即通用代理平台。项目采用 Go 开发,主体按 GPL-3.0-or-later 发布。 二、sing-box 有什么作用 sing-box 是一个可同时充当代理服务端和客户端的网络代理核心。它通过 JSON 配置文件组合入站、出站、DNS 和路由规则,支持 Hysteria2、Shadowsocks、Trojan、VLESS、TUIC、WireGuard 等多种协议。 典型用途包括: 在自己的服务器和设备之间建立加密代理通道; 根据域名、IP、端口或规则集进行分流; 在 Android、iOS、macOS、Windows 和 Linux 上使用统一配置; 作为其他网关或代理软件的底层网络核心。 本文使用的 Hysteria2 基于 QUIC,主要承载在 UDP 上。在高延迟或存在一定丢包的网络中,它通常比传统 TCP 代理更容易保持吞吐量,但它并不能突破服务器带宽上限,也不能解决所有线路质量问题。 请仅在法律和服务条款允许的范围内使用。 三、本文部署结构 客户端 | | Hysteria2 + TLS + UDP/8443 v 云服务器公网 IP | v Docker(host 网络) | v sing-box hysteria2 inbound | v direct outbound -> 目标网站 使用 network_mode: host 后,容器直接监听宿主机 UDP 端口,不需要在 Compose 中编写 ports 映射。Hysteria2 是 QUIC/UDP 服务,所以防火墙必须放行 UDP,而不是只放行同端口的 TCP。 四、服务器准备 建议准备: 一台具有公网 IPv4 或 IPv6 的 Linux 服务器; Ubuntu 22.04 或更新版本; 一个解析到服务器公网 IP 的域名,例如 hy2.example.com; Docker Engine 与 Docker Compose Plugin; 云厂商安全组和系统防火墙均允许目标 UDP 端口。 安装 Docker 下面以 Ubuntu 为例。若服务器已经安装 Docker,可跳过这一节。 sudo apt-get update sudo apt-get install -y ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg  -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc ​ echo  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" |  sudo tee /etc/apt/sources.list.d/docker.list >/dev/null ​ sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ​ sudo docker version sudo docker compose version 配置域名和防火墙 将 hy2.example.com 的 A 记录指向服务器公网 IPv4。若使用 IPv6,再添加 AAAA 记录。 使用 UFW 时可以这样放行: sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 8443/udp sudo ufw status 80/tcp 用于 Certbot 申请和续期证书。如果服务器上已有 Nginx 或 Caddy,应改用与现有 Web 服务兼容的 ACME 验证方式。云厂商安全组也需要单独放行 8443/udp。 申请可信 TLS 证书 sudo apt-get update sudo apt-get install -y certbot ​ sudo certbot certonly --standalone  -d hy2.example.com  --agree-tos  --email admin@example.com  --non-interactive 证书通常位于: /etc/letsencrypt/live/hy2.example.com/fullchain.pem /etc/letsencrypt/live/hy2.example.com/privkey.pem 生产环境推荐使用受信任 CA 签发的证书。自签名证书也能工作,但客户端必须安全地取得并信任该证书;不建议长期使用“跳过证书验证”。 五、创建服务端配置 创建部署目录: sudo install -d -m 700 /opt/sing-box-hy2 cd /opt/sing-box-hy2 生成两个彼此独立的随机密码: openssl rand -base64 32 openssl rand -base64 32 第一个作为用户认证密码,第二个作为 Salamander 混淆密码。不要把密码提交到 Git 仓库,也不要直接放进公开博客。 创建 /opt/sing-box-hy2/config.json: {  "log": {    "level": "info",    "timestamp": true },  "inbounds": [   {      "type": "hysteria2",      "tag": "hy2-in",      "listen": "::",      "listen_port": 8443,      "up_mbps": 100,      "down_mbps": 300,      "obfs": {        "type": "salamander",        "password": "请替换为混淆密码"     },      "users": [       {          "name": "user1",          "password": "请替换为认证密码"       }     ],      "tls": {        "enabled": true,        "server_name": "hy2.example.com",        "alpn": [          "h3"       ],        "certificate_path": "/etc/letsencrypt/live/hy2.example.com/fullchain.pem",        "key_path": "/etc/letsencrypt/live/hy2.example.com/privkey.pem"     }   } ],  "outbounds": [   {      "type": "direct",      "tag": "direct"   } ] } up_mbps 和 down_mbps 是 Hysteria2 拥塞控制使用的最大带宽参数,单位为 Mbps。应按照线路的实际可用带宽设置,不是填写得越大越好。服务端和客户端需要使用合理、匹配的带宽值。 限制配置文件权限: sudo chmod 600 /opt/sing-box-hy2/config.json 六、创建 Docker Compose 文件 创建 /opt/sing-box-hy2/docker-compose.yml: services: sing-box-hy2: image: ghcr.io/sagernet/sing-box:latest container_name: sing-box-hy2 restart: unless-stopped network_mode: host volumes: ./config.json:/etc/sing-box/config.json:ro /etc/letsencrypt:/etc/letsencrypt:ro command: -D /var/lib/sing-box -C /etc/sing-box run logging: driver: json-file options: max-size: 10m max-file: "3" 官方文档使用 ghcr.io/sagernet/sing-box 镜像。生产环境更稳妥的做法是先验证版本,再把 latest 改为经过测试的具体版本标签,避免上游更新后出现不兼容变化。 七、检查并启动服务 先让 sing-box 检查配置语法: cd /opt/sing-box-hy2 sudo docker compose run --rm sing-box-hy2 -C /etc/sing-box check 确认没有错误后启动: sudo docker compose pull sudo docker compose up -d sudo docker compose ps sudo docker compose logs --tail=100 sing-box-hy2 检查 UDP 端口: sudo ss -lunp | grep ':8443' Hysteria2 使用 UDP,不能用浏览器、curl 或普通 TCP 端口检测来判断它是否正常。最可靠的验证方式是查看服务日志并使用配置正确的 Hysteria2 客户端实际连接。 八、客户端怎么配置 官方图形客户端包括: Android:sing-box for Android iOS、macOS、Apple tvOS:sing-box for Apple platforms Windows、Linux:sing-box for Desktop 在图形客户端中新建 Hysteria2 节点时,各字段与服务端的对应关系如下: 客户端字段示例必须与服务端一致Server / 地址hy2.example.com是Port / 端口8443是Password / 认证密码服务端 users[].password是Obfs typesalamander是Obfs password服务端 obfs.password是TLS开启是Server name / SNIhy2.example.com必须匹配证书ALPNh3建议一致Allow insecure关闭生产环境应关闭 保存节点后,选择该配置并开启系统代理或 TUN/VPN 模式。只创建节点但没有启用系统代理或 VPN 模式时,系统流量不会自动经过该节点。 使用 sing-box JSON 客户端 下面是一份适合命令行或桌面端导入的最小客户端示例。它在本机 127.0.0.1:2080 提供 HTTP/SOCKS 混合代理: { "log": { "level": "info", "timestamp": true }, "inbounds": [ { "type": "mixed", "tag": "mixed-in", "listen": "127.0.0.1", "listen_port": 2080 } ], "outbounds": [ { "type": "hysteria2", "tag": "hy2-out", "server": "hy2.example.com", "server_port": 8443, "up_mbps": 20, "down_mbps": 100, "obfs": { "type": "salamander", "password": "请替换为混淆密码" }, "password": "请替换为认证密码", "tls": { "enabled": true, "server_name": "hy2.example.com", "alpn": [ "h3" ] } } ], "route": { "final": "hy2-out", "auto_detect_interface": true } } 启动客户端核心后,把浏览器或操作系统代理设置为: 地址:127.0.0.1 端口:2080 类型:HTTP 或 SOCKS5 如果服务端使用自签名证书 更安全的做法是通过可信渠道把服务端的公开证书 cert.pem 传给客户端,并在客户端 TLS 配置中加入: { "enabled": true, "server_name": "证书中的域名", "certificate_path": "/客户端上的安全路径/cert.pem", "alpn": [ "h3" ] } insecure: true 会接受任意服务器证书,容易受到中间人攻击,只适合短时间排障,不应作为正式配置。 九、日常维护 查看状态和日志: cd /opt/sing-box-hy2 sudo docker compose ps sudo docker compose logs --tail=200 sing-box-hy2 sudo docker stats sing-box-hy2 修改配置后,先检查再重启: sudo docker compose run --rm sing-box-hy2 -C /etc/sing-box check sudo docker compose restart sing-box-hy2 更新镜像: sudo docker compose pull sudo docker compose up -d sudo docker image prune 十、常见问题 客户端一直超时 重点检查云安全组和 UFW 是否放行 8443/udp,以及服务端是否真的监听 UDP 端口。只开放 8443/tcp 没有作用。 出现证书验证失败 检查客户端 server_name 是否与证书域名一致、域名是否解析到正确 IP、证书是否过期。自签名证书还需要客户端显式信任对应证书。 日志提示认证失败 客户端的认证密码必须与服务端 users[].password 完全一致。用户名只是服务端用于区分用户,sing-box 的 Hysteria2 认证核心字段是密码。 开启 Salamander 后无法连接 客户端和服务端的 obfs.type、obfs.password 必须同时一致。排查时可以在两端同时暂时移除 obfs,不能只改一端。 节点连接成功但应用没有流量 确认图形客户端已启用系统代理或 TUN/VPN 模式。若只使用本地 mixed 入站,还需要把应用代理指向 127.0.0.1:2080。 总结 sing-box 是一个通用代理平台,Hysteria2 只是它支持的协议之一。部署成功的关键点并不多:服务端开放正确的 UDP 端口、两端认证与混淆参数一致、TLS 域名匹配,并在客户端真正启用系统代理或 TUN/VPN 模式。生产环境还应固定经过验证的镜像版本、限制日志大小、保护配置权限,并建立证书续期后的重启机制。
  • 我发现是不是只要我一直发主题,然后再删了,就可以一直加五分

    1
    0赞同
    1帖子
    57浏览
    我发现是不是只要我一直发主题,然后再删了,就可以一直加五分