/var/local/docs/ 下的 .md 文档渲染成 HTML 展示参照 vi.starbugs.net 的「nginx 反代 127.0.0.1 服务」模式:
外网 → nginx (443 ssl/quic, blog.starbugs.net) → 反代 → 127.0.0.1:8010 (blog-md Python 服务)
↓ 渲染
/var/local/docs/*.md
/opt/markdown-blog/app.pyThreadingHTTPServer,仅监听 127.0.0.1:8010GET / 目录索引;GET /d/<name>.md 渲染单篇extra、codehilite(代码高亮)、toc、sane_lists、
pymdownx.arithmatex(数学公式,配 MathJax CDN)realpath 校验前缀、仅允许目录内 .md)python3-markdown (3.5.2)、python3-pygments、python3-pymdownx (9.5)/etc/systemd/system/blog-md.serviceDynamicUser=yes、ProtectSystem=strict、ReadOnlyPaths=/var/local/docs、Restart=on-failureenable --now,开机自启,状态 active/var/www/blog.starbugs.net/.well-known/acme-challenge/(owner nginx)/etc/nginx/conf.d/blog.starbugs.net.conf
(仅含 ACME location + 其余 404,nginx -t 通过并已 reload)curl 127.0.0.1:8010/ 列出 4 篇文档及标题HTTP 200blog.starbugs.net 证书暂时签不了(见下方阻塞点),故先把同一个渲染服务挂到已有
证书的 vi.starbugs.net 的 /blog 子路径下对外提供访问:
https://vi.starbugs.net/blog/proxy_set_header X-Forwarded-Prefix /blog;
告知前缀,app.py 据此生成 /blog/... 链接;无该头时按根路径生成
(将来 blog.starbugs.net 恢复后根路径访问无需改代码)。vi.starbugs.net.conf 的 443 server 块新增:nginx
location = /blog { return 301 /blog/; }
location /blog/ {
proxy_pass http://127.0.0.1:8010/; # 末尾斜杠:剥掉 /blog 前缀
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;
proxy_set_header X-Forwarded-Prefix /blog;
proxy_redirect off;
}
--resolve vi.starbugs.net:443:127.0.0.1):/blog → 301 → /blog//blog/ 索引 HTTP/2 200,链接均带 /blog/ 前缀/blog/d/dcf-valuation.md 200,MathJax / arithmatex / codehilite 正常,「返回目录」指向 /blog//blog/d/../../etc/passwd → 404待 blog.starbugs.net 证书签发后,可保留此
/blog入口,或在 blog 域名根路径独立提供,二者共用同一服务。
certbot certonly --webroot 失败,CA 报错:
Domain: blog.starbugs.net
Type: unauthorized
Detail: 43.174.225.201: Invalid response from
https://dnspod.qcloud.com/static/webblock.html?d=blog.starbugs.net
原因:blog.starbugs.net 在 DNSPod 做了地域智能解析——
49.235.116.153(正常)43.174.225.201),返回 DNSPod webblock 页Let's Encrypt 的验证节点在境外,取到的是 EdgeOne 边缘,.well-known challenge
被拦截,故 HTTP-01 验证无法通过。对比 vi.starbugs.net 全球均解析到源站,所以 vi 能签发。
在 DNSPod 控制台对 starbugs.net 操作:
blog(类型 A)的境外/国外线路记录(或指向 EdgeOne 的记录)。49.235.116.153,或直接删除该 EdgeOne 加速记录,
只保留 默认 线路 A → 49.235.116.153(全地域回源,与 vi 一致)。自检(应只剩源站 IP):
curl -s "https://dns.google/resolve?name=blog.starbugs.net&type=A"
# 期望 Answer 仅含 49.235.116.153
bash
certbot certonly --webroot -w /var/www/blog.starbugs.net -d blog.starbugs.net \
--non-interactive --agree-tos --register-unsafely-without-email --keep-until-expiring
/etc/nginx/conf.d/blog.starbugs.net.conf
(仿 vi,注意 HTTP/3 不要重复 reuseport,该参数已被 vi 的 443 quic 占用):```nginx server { listen 80; server_name blog.starbugs.net;
location /.well-known/acme-challenge/ {
root /var/www/blog.starbugs.net;
}
location / {
return 301 https://$host$request_uri;
}
}
server { listen 443 ssl; listen 443 quic; # 不加 reuseport(vi 已占用) http2 on; http3 on;
server_name blog.starbugs.net;
ssl_certificate /etc/letsencrypt/live/blog.starbugs.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/blog.starbugs.net/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
add_header Alt-Svc 'h3=":443"; ma=86400' always;
add_header QUIC-Status $http3 always;
location / {
proxy_pass http://127.0.0.1:8010;
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;
proxy_redirect off;
}
} ```
bash
nginx -t && systemctl reload nginx
curl --noproxy '*' -I --http2 --resolve blog.starbugs.net:443:127.0.0.1 https://blog.starbugs.net
curl --noproxy '*' -s --resolve blog.starbugs.net:443:127.0.0.1 https://blog.starbugs.net | head
certbot renew --dry-run
期望:HTTP/2 200、响应头含 alt-svc: h3=":443"、正文为文档索引。
/opt/markdown-blog/app.py/etc/systemd/system/blog-md.service/etc/nginx/conf.d/blog.starbugs.net.conf(当前为临时 80 配置)/var/www/blog.starbugs.net//var/local/docs//etc/letsencrypt/live/blog.starbugs.net//etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh# 服务
systemctl status blog-md --no-pager
journalctl -u blog-md -n 50 --no-pager
systemctl restart blog-md
# 本地访问(证书签发前即可测)
curl -s --noproxy '*' http://127.0.0.1:8010/
# 新增/修改文档:直接放入 /var/local/docs/*.md,刷新即生效(无需重启服务)
127.0.0.1,不直接对外,外部一律经 nginx 反代。reuseport 全机每个 address:port 只能设一次,已被 vi 的 listen 443 quic reuseport 占用,
blog 的 listen 443 quic 必须省略 reuseport,否则 nginx -t 报 duplicate。mirrors.tencentyun.com 经代理不可达,
apt 源含所需包且由发行版维护,更稳。