欢迎来到我的博客

Hugo 使用指南

Hugo 使用指南 适用版本:Hugo v0.168.0(Extended)。命令以 macOS/Linux 的 shell 为例。根据 Hugo 官方文档整理,主题私有配置以实际主题仓库为准。 1. 安装与版本检查 macOS(Homebrew): brew install hugo hugo version hugo env Linux 可使用对应发行版软件包或 Hugo 官方发布的二进制文件。使用 SCSS/Sass 或某些主题资产管道时,需要确认安装版本包含 Extended 功能。 2. 创建项目 hugo new project myblog cd myblog git init 典型目录结构: myblog/ ├── archetypes/ # 新文章模板 ├── assets/ # 需通过资源管道处理的资源 ├── content/ # Markdown 内容 ├── data/ # 数据文件 ├── i18n/ # 主题界面翻译 ├── layouts/ # 自定义模板,可覆盖主题模板 ├── static/ # 原样复制到网站根路径 ├── themes/ # 本地主题或 Git 子模块 ├── hugo.toml # 网站配置(也可使用 YAML 等格式) └── public/ # 构建产物(运行 hugo 后生成) Hugo 本体不附带完整博客外观。若没有可用主题或自定义布局,可能出现 found no layout file for "html" 的警告。 ...

October 17, 2026 · 3 min

用 YubiKey 保护 Git:FIDO2 SSH 认证与提交签名

Git 的仓库认证与提交签名是两个独立环节:前者决定能否拉取、推送代码,后者让接收者验证提交由哪把密钥签署。本文使用两对独立的 FIDO2 SSH 密钥,将这两个用途分开管理。 Git 支持使用 SSH 密钥签署 Commit 和 Tag,因此只围绕 Git 开发时,可以直接使用 YubiKey 的 FIDO2 功能,无须额外部署 GnuPG。需要遵循 OpenPGP 验签流程的项目,则应按项目要求选择 GPG 签名。 ...

October 25, 2026 · 5 min

OpenWrt IPv6 有地址却提示网络不可达:一次 mwan3 策略路由排查

WAN6 已拿到 IPv6 地址,但在 OpenWrt 上 ping 公网 IPv6 时,立即返回: ping: sendto: Network unreachable 最后发现,现场存在一条与 mwan3 一致的带标记不可达规则。删除它后,IPv6 恢复。这个案例说明:看到了默认路由,也不代表实际流量一定会使用它。 本文记录一次实际排查。公网源地址已替换为文档示例地址;设备名、规则优先级和 mark 应以自己的设备为准。卸载命令适用于使用 opkg 的 OpenWrt。 默认路由存在,为什么仍然不可达 最初排查时怀疑默认路由缺失,随后输出已经能看到带源地址条件的默认路由: default from 2001:db8:1234:5600::4 via fe80::1 dev eth1 proto static metric 512 pref medium default from 2001:db8:1234:5600::/64 via fe80::1 dev eth1 proto static metric 512 pref medium 排查中还临时补了一条普通默认路由: ip -6 route add default via fe80::1 dev eth1 metric 1024 但 ping 仍立即返回 Network unreachable。此时继续叠加默认路由已经没有帮助,需要检查实际选路和策略规则。 先确认上游网关可达 ping -6 -I eth1 -c 3 fe80::1 三次请求全部收到回复,说明 OpenWrt 到上游网关的链路本地通信正常。IPv6 使用 fe80:: 开头的链路本地地址作为下一跳是正常现象;这里指定设备,是为了确定该地址属于哪条链路。 ...

October 24, 2026 · 2 min

OpenList 夸克 WebDAV 上传内存过高:原因与优化

使用 rclone 将本地文件通过 OpenList 的 WebDAV 接口上传到夸克网盘时,OpenList 的内存占用可能明显增长,甚至触发容器 OOM。排查后发现,关键在于夸克驱动上传前的整文件缓存,以及容器统计中包含的文件页缓存。 本文分析针对 OpenList v4.2.7、普通夸克驱动、Docker 和 cgroup v2。其他驱动、其他版本应重新核对实现。 夸克上传为什么需要缓存 OpenList 的 WebDAV 入口把 HTTP 请求体包装成文件流,再交给目标存储驱动。这一步本身不统一将整个文件读入内存。 但普通夸克驱动会先取得文件的 MD5 和 SHA1。WebDAV 上传路径没有向文件对象提供这两个哈希,因此驱动调用: stream.CacheFullAndWriter(&up, io.MultiWriter(writers...)) 这个调用在计算哈希的同时,缓存完整文件。随后,驱动向夸克提交预上传和哈希请求;如果不能秒传,再从缓存中读取数据、分片上传。 哈希计算可以使用很小的内存,真正占空间的是为后续回读而保留的文件内容。 即使夸克支持分片上传,也不代表前面的整文件缓存不存在。 v4.2.7 的 HybridCache 有内存和文件两类后备方式。允许使用内存时,会尝试扩充缓存,分配受限后再切换至文件;其中部分内存通过匿名 mmap 管理。因此不能仅靠调整 Go GC 参数约束所有缓存占用。 rclone 的 --transfers 控制同时传输的文件数。两个文件并发上传,意味着两份整文件缓存可能同时存在。降低 rclone 自身的 --buffer-size 并不能直接限制 OpenList 进程中的这部分缓存。 为什么有临时目录仍占用内存 例如: "temp_dir": "data/temp" 这只指定临时文件保存位置,不强制每次缓存都写入磁盘。该相对路径还要结合 OpenList 的工作目录、Docker 挂载判断实际位置。 此外,v4.2.7 的缓存扩容检查使用系统可用内存统计,没有在该检查中直接读取容器的 memory.max 和 memory.current。这使得宿主机尚有空闲内存时,容器仍可能先撞上自己的内存限额。 改用磁盘临时文件 先暂停上传并备份配置,在 config.json 顶层设置: "min_free_memory": -1 这是字段片段,不是完整配置文件,修改时应保留其他内容和合法的 JSON 结构。 ...

October 24, 2026 · 2 min

排查旁路由 DNS 超时:sing-box 上游查询走错网络接口

在一台用作旁路由的 Armbian 上同时运行 sing-box 和 WireGuard。旁路由本机可以解析内网域名,下游终端将其设为 DNS 服务器却始终超时。最终发现问题不在 DNS 匹配规则,而在 sing-box 向上游 DNS 发出的流量选错了出口接口。 本文示例地址均为重写后的示意值,不是原始网络配置;保留了私有网络的拓扑关系与协议行为。 网络拓扑与现象 角色 示例地址 作用 下游终端 192.168.10.20 DNS 客户端 旁路由 LAN 192.168.10.254 / eth0 sing-box DNS 监听地址 旁路由 WireGuard 10.77.0.11 / wg0 隧道客户端 内网 DNS 10.77.0.1:53 WireGuard 对端 DNS 拓扑如下: 终端 192.168.10.20 │ DNS 查询 ▼ 旁路由 192.168.10.254:53 (sing-box DNS 入站) │ 期望:由 wg0 向 10.77.0.1:53 查询 ▼ WireGuard 对端 DNS 10.77.0.1:53 内网测试域名采用 service.home.arpa(示例)。现象是: ...

October 23, 2026 · 2 min

Armbian 上 sing-box 开启 auto_redirect 后 IPv6 HTTPS 超时:一次回环地址缺失的排查

在 Armbian 上部署 sing-box TUN 后,我遇到了一个不太直观的问题:IPv6 ping 能通,但开启 auto_redirect 后,IPv6 HTTPS 连接超时。 最终发现,故障并不在 IPv6 公网路由或代理节点,而是 Linux 回环接口 lo 缺少 ::1/128 地址。本文记录定位过程和修复方法。 环境 Linux:Armbian,ARM64,6.18 系列内核 sing-box:1.14.x 网络管理:Netplan + NetworkManager 透明代理:TUN,auto_route: true,auto_redirect: true IPv6:上游自动配置,接口已有全局 IPv6 地址和 RA 默认路由 为保护隐私,本文省略了真实公网地址、MAC、路由器地址、域名及自定义内部路由表编号。以下示例中的 ULA 地址和测试目标用于演示。 故障现象 直接测试 IPv6 HTTPS: curl --noproxy '*' -6 -v --connect-timeout 5 \ --resolve 'cloudflare.com:443:[2606:4700::6810:85e5]' \ https://cloudflare.com/ 开启 sing-box 后: * Trying [2606:4700::6810:85e5]:443... * Connection timed out after 5002 milliseconds curl: (28) Connection timed out 对照实验: ...

October 23, 2026 · 3 min

Docker 信任自签名 CA 证书

Docker 使用私有 CA(例如 step-ca)签发的 HTTPS 证书时,需要区分 Docker Engine 拉取镜像 和 容器内应用访问 HTTPS 两种场景。它们的证书信任库不一定相同。 一、Docker Engine 信任私有 CA 适用于 docker login、docker pull、docker push 访问私有镜像仓库。 仅信任指定 Registry(推荐) 假设 Registry 地址为 registry.example.com:5000: sudo mkdir -p /etc/docker/certs.d/registry.example.com:5000 sudo cp root_ca.crt /etc/docker/certs.d/registry.example.com:5000/ca.crt 目录名称应与实际访问的 Registry 主机名及端口一致;默认 HTTPS 443 端口通常可省略。ca.crt 应为 PEM 格式的 CA 证书,而不是私钥。 验证: docker login registry.example.com:5000 Ubuntu / Debian 宿主机全局信任 sudo cp root_ca.crt /usr/local/share/ca-certificates/my-root-ca.crt sudo update-ca-certificates Linux 上 Docker 通常会使用宿主机的系统 CA 信任库。通常不必重启 Docker;如果仍未生效,可检查 Docker 日志及证书配置,再决定是否重启(重启可能影响运行中的容器)。 ...

October 23, 2026 · 1 min

UFW 与 sing-box TUN auto_redirect 冲突:动态端口被拦截的排查

在 Linux 旁路由上同时运行 UFW 和 sing-box TUN 时,可能出现一种容易误判的故障:sing-box 本机运行正常,但局域网设备通过旁路由访问互联网失败。即使放行了当时被拦截的 TCP 端口,重启 sing-box 后问题也可能再次出现。 本文记录一种实际观察到的原因和待回归验证的修复方式。示例均使用文档保留地址,不对应真实网络。 环境和症状 Linux 旁路由,LAN 接口为 eth0,地址 192.0.2.1(仅作示例)。 下游终端 192.0.2.20,使用旁路由作为 IPv4 网关。 sing-box 的 TUN 接口名为 tun0,开启 auto_route 和 auto_redirect。 UFW 默认拒绝未经允许的入站流量。 sing-box 的关键配置: { "type": "tun", "interface_name": "tun0", "auto_route": true, "auto_redirect": true } 故障期间日志类似: [UFW BLOCK] IN=eth0 OUT= SRC=192.0.2.20 DST=192.0.2.1 PROTO=TCP DPT=24461 SYN DPT=24461 只是一次运行时观察到的动态端口,不应该把它永久写死在 UFW 里。OUT= 为空,提示包正在进入本机的 INPUT 路径,而不只是穿过 FORWARD 路径。 追踪 NAT 重定向 检查 sing-box 监听: sudo ss -lntup | grep sing-box 检查 nftables: ...

October 23, 2026 · 2 min

使用 CrowdSec 为 Debian 服务器实现恶意 IP 自动封禁

使用 CrowdSec 为 Debian 服务器实现恶意 IP 自动封禁 公网服务器每天都会遇到各种自动化扫描。 即使没有主动公开服务地址,SSH 端口也经常会收到针对 root、admin、test 等用户名的登录尝试。Web 服务则可能遭遇针对 .env、wp-admin、phpinfo.php 等路径的探测。 这些请求大多来自自动化扫描程序。虽然不一定构成实际入侵,但会产生大量无意义的日志,同时增加服务暴露面。 单纯依靠防火墙静态规则,难以根据攻击行为动态调整封禁名单。 因此,我选择尝试 CrowdSec,通过服务器日志识别恶意行为,再联动 nftables 自动封禁攻击来源。 本文记录在 Debian 12 上部署 CrowdSec 的过程,以及它如何判断一个 IP 是否应该被封禁。 一、CrowdSec 是什么? CrowdSec 是一个开源的入侵检测与安全响应系统。 它通过分析 SSH、Web Server 等服务产生的日志,检测暴力破解、漏洞扫描、恶意爬虫等行为。 与传统的静态 IP 黑名单不同,CrowdSec 主要根据行为特征决定是否封禁,并且可以利用社区威胁情报。 CrowdSec 的工作可以分为两部分: Security Engine:读取日志,识别攻击,生成封禁决策。 Remediation Component(Bouncer):执行封禁决策,例如修改防火墙规则。 两者相互独立。 也就是说,仅安装 CrowdSec Security Engine,并不会自动阻止网络连接。 1.1 工作流程 SSH / Caddy / Nginx | v Application Logs | v CrowdSec Parser | v Detection Scenarios | v Security Alerts | v Decision Profiles | v Local API | v Firewall Bouncer | v nftables | v Block IP CrowdSec 将日志分析与防火墙执行解耦,意味着它既可以在单台服务器上使用,也能通过中心 API 向多台服务器下发封禁决策。 ...

October 19, 2026 · 6 min

中国秸秆禁烧政策的历史:从传统农耕到现代环境治理

中国秸秆禁烧政策的历史,实际上是中国农业现代化、农村能源转型、环境治理和基层行政管理方式演变的一个缩影。 最关键的历史结论是:中国并非自古存在大规模秸秆焚烧问题,也不是近年来才开始禁止烧秸秆。现代秸秆禁烧制度在20世纪90年代逐步建立,1999年形成全国性的管理规定,2008年前后明显强化,2013年以后进一步纳入大气污染防治体系。 更值得研究的,是政策治理目标与执行方式之间的变化: 最初的重点是公共安全。 尤其是机场、铁路、公路附近的焚烧风险,同时兼顾大气污染。 后来逐渐转向区域空气质量管理。 秸秆焚烧与城市雾霾、PM2.5治理建立了更紧密的政策联系。 再后来出现基层执行范围扩大和管理方式强化的问题。 一些地方采取全面禁烧、网格巡查和责任追究,导致政策成本与农民生产需求之间的矛盾。 政策争论的核心不是焚烧是否产生污染,而是应当禁止到什么程度,以及由谁承担处理秸秆的经济成本。 一、历史时间线:秸秆禁烧如何一步步形成 20世纪80年代以前 秸秆是有使用价值的农业资源 主要用于烧饭取暖、牲畜饲料、垫圈积肥、堆肥和建材。露天焚烧存在,但大量秸秆并非没有用途。 1980年代末—1990年代 大规模集中焚烧成为社会问题 农业机械化、农村生活燃料转型、粮食增产及农业劳动力转移,使部分地区秸秆集中剩余,焚烧逐渐成为快速清田的方式。 1999—2000年 全国性禁烧管理制度确立 1999年六部门发布《秸秆禁烧和综合利用管理办法》;2000年修订《大气污染防治法》,明确特定区域的秸秆露天焚烧禁令。 2008年 奥运空气质量保障推动强化禁烧 京津冀及周边多个省份实施重点时段严格禁烧,城市及重点区域管控范围扩大。 2013—2017年 与PM2.5及大气污染防治绑定 大气污染防治行动全面推进。2015年修订《大气污染防治法》,规定由省级人民政府划定禁烧区域,并明确相关法律责任。 2018年至今 基层精细化监管与政策争议并存 网格监管、卫星火点监测及秸秆综合利用持续推进,部分地区也探索分区、分时段的焚烧管理。 上面的阶段划分依据国家层面的重要政策节点,而非认为每一年全国都同步改变。 二、1949—1980年代:为什么过去农民很少需要大规模集中烧秸秆? 要解释今天的禁烧政策,必须先理解一个历史变化: 秸秆从过去的生产生活资源,逐渐变成了部分地区需要付费处理的农业副产物。 1. 传统农村社会有较完整的秸秆利用体系 过去的小农经济中,秸秆具有多种实际用途。 用途 农村的典型做法 生活燃料 使用麦秸、稻草、玉米秆烧饭取暖 牲畜饲料 秸秆切碎后喂牛、羊等反刍动物 农业肥料 堆肥、沤肥、垫圈积肥、直接还田 生活材料 编织草席、制作草绳、屋顶覆盖 农业辅助 覆盖地面、保墒、防止部分土壤侵蚀 这并不意味着过去不存在焚烧。农民同样会焚烧残茬、杂草,或通过草木灰补充部分矿质养分。 ...

October 17, 2026 · 2 min