在给博客加上 GPG 数字签名后,我开始思考一个问题:如何让读者更优雅地获取我的公钥?
传统的做法是把公钥上传到 Keyserver,或者直接贴个下载链接。但最极客的做法是支持 Web Key Directory (WKD) 协议。
简单来说,配置好 WKD 后,任何人只需在终端输入:
gpg --locate-key [email protected]
GPG 就会自动去我的域名下寻找并下载公钥。这不仅酷,更是将“身份”与“域名”进行了强绑定。
本文记录了在 Hugo + Cloudflare Pages 架构下的部署流程,以及在 Windows 环境下遇到的坑。
🛠️ 前置:解决 Windows Git Bash 的 GPG 冲突
在 Windows 上使用 Git Bash 时,最头疼的问题就是它自带了一个简版 GPG,无法读取安装在系统(Gpg4win/Kleopatra)里的密钥。
导致的结果就是:git commit -S 报错,或者运行脚本时提示 No secret key。
1. 强制 Git 使用系统 GPG
告诉 Git 不要用自带的,而是去调用 Gpg4win:
# 请根据实际安装位置修改路径
git config --global gpg.program "E:\Program Files (x86)\GnuPG\bin\gpg.exe"
2. 强制终端使用系统 GPG
为了在 Git Bash 命令行里直接敲 gpg 时也能调用系统程序,需要修改 ~/.bashrc:
# 编辑配置文件
code ~/.bashrc
# 在末尾加入别名
alias gpg='/e/Program\ Files\ \(x86\)/GnuPG/bin/gpg.exe'
保存后运行 source ~/.bashrc 生效。现在,环境终于打通了。
🟢 方法一:手动部署 (命令行流)
如果你不常更换密钥,手动生成一次是最快的方法。WKD 的原理其实就是在网站特定的目录下,放一个以 哈希值 命名的公钥文件。
1. 创建目录结构
Hugo 的静态文件放在 static 目录下:
mkdir -p static/.well-known/openpgp/wkd/hu
2. 获取 WKD 哈希值
WKD 使用 Z-Base32 算法对邮箱进行哈希。GPG 自带了计算功能:
gpg --list-keys --with-wkd-hash [email protected]
输出中 wkd/hu/ 后面那串 32位字符 就是我们要的文件名(例如 4n9x8k2d7fp1a3qy5j6h4bv0c8mz2s5r)。
3. 导出二进制公钥
注意:WKD 要求公钥必须是 二进制 (Binary) 格式,不能是 ASCII Armor(即不能包含 BEGIN PGP…)。
# 语法:gpg --no-armor --export 邮箱 > 目标路径/哈希文件名
gpg --no-armor --export [email protected] > static/.well-known/openpgp/wkd/hu/4n9x8k2d7fp1a3qy5j6h4bv0c8mz2s5r
4. 创建策略文件
协议要求存在一个空的 policy 文件:
touch static/.well-known/openpgp/wkd/policy
部署到 Cloudflare 后,WKD 即刻生效。
🐍 方法二:Python 脚本自动化 (DevOps 流)
作为一个工科男,我更喜欢把这个过程脚本化,集成到博客的工具箱里。
我编写了一个 Python 脚本,它会自动寻找系统 GPG 路径,计算哈希,并导出文件。
脚本路径:_tools/gen_wkd.py
import os
import subprocess
import sys
# === 配置区域 ===
TARGET_EMAIL = "[email protected]"
# 路径锚点
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_ROOT = os.path.dirname(SCRIPT_DIR)
WKD_BASE_DIR = os.path.join(PROJECT_ROOT, 'static', '.well-known', 'openpgp', 'wkd')
HU_DIR = os.path.join(WKD_BASE_DIR, 'hu')
# 自动寻找系统 GPG 路径 (兼容多盘符安装)
def find_gpg():
candidates = [
r"E:\Program Files (x86)\GnuPG\bin\gpg.exe",
r"C:\Program Files (x86)\GnuPG\bin\gpg.exe",
"gpg"
]
for path in candidates:
if os.path.exists(path): return path
return "gpg"
GPG_EXE = find_gpg()
def main():
# 强制 UTF-8 输出,防止 Windows 终端乱码
sys.stdout.reconfigure(encoding='utf-8')
print(f"🔐 开始生成 WKD 配置 (针对: {TARGET_EMAIL})...")
if not os.path.exists(HU_DIR):
os.makedirs(HU_DIR)
# 创建 policy 文件
policy_path = os.path.join(WKD_BASE_DIR, 'policy')
if not os.path.exists(policy_path):
open(policy_path, 'w').close()
try:
# 1. 获取哈希
cmd = [GPG_EXE, "--list-keys", "--with-wkd-hash", TARGET_EMAIL]
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
# 正则提取哈希
import re
match = re.search(r'wkd/hu/([a-z0-9]{32})', result.stdout)
if not match:
print("❌ 未找到 WKD 哈希,请检查邮箱或 GPG 版本。")
return
wkd_hash = match.group(1)
print(f" 🔍 哈希值: {wkd_hash}")
# 2. 导出公钥
output_file = os.path.join(HU_DIR, wkd_hash)
export_cmd = [GPG_EXE, "--no-armor", "--export", "--output", output_file, TARGET_EMAIL]
subprocess.run(export_cmd, check=True)
print(f" ✅ WKD 配置已生成至: static/.../hu/{wkd_hash}")
except Exception as e:
print(f"❌ 执行出错: {e}")
if __name__ == "__main__":
main()
验证
网站部署完成后,在任何一台安装了 GPG 的电脑上运行:
gpg --locate-key [email protected]
如果看到公钥被成功导入,说明你也拥有了自己的 Web Key Directory。
这不仅仅是一个技术配置,更是去中心化网络身份认证的重要一环。
💡 维护贴士
- 如果你更新了密钥(比如延长了有效期、添加了新子钥),记得重新运行一次导出命令(手动或脚本),并重新部署博客。