MoreRSS

site iconSB | 烧饼修改

持有 u.sb sb.sb sha.bi域名,专注于服务器运维、专业域名投资分析。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

SB | 烧饼的 RSS 预览

博客大联盟:一个给独立博客的收录与聚合站

2026-07-11 20:39:00

近几年我越来越不爱用搜索引擎找博客了,搜一个技术问题,前几页经常是采集站、营销软文和批量生成的内容。

社交平台也差不多。算法觉得您喜欢什么,就追着喂什么。刷起来很省事,想顺着一个人的文章慢慢读下去却不容易。

我认识的那些博客作者其实还在写,只是不太容易在搜索和信息流里碰到他们。于是,我做了一个叫「博客大联盟」的网站。

1、博客大联盟是什么

博客大联盟 是一个独立博客目录,顺便聚合每个博客的 RSS。

它的前身是我手工维护的朋友博客友链聚合 peng.you。后来实在嫌手工维护太麻烦,干脆写了个小系统,把博客名片和 RSS 聚合都自动化了。

每个博客都有一张名片,上面是名称、作者、简介、标签和最新文章。系统定时读取 RSS,新文章按照发布时间排列。没有猜你喜欢,也没有什么神奇的推荐算法,您可以翻目录、看标签,或者直接搜博客名称和作者。

博客大联盟中的烧饼博客详情页,展示已验证标记、博客简介与标签、首页预览和最新文章

目前暂时没打算把这货做成另一个信息流平台。先把各处的独立博客放到一个目录里,让大家能互相找到,这就够了。

2、怎么加入博客大联盟

整个流程是登录、填写资料、自动检查、验证域名,最后等管理员审核。

2.1 登录

打开 bo.ke,使用 GitHub 或 Google 一键登录即可,不需要另外注册账号和记一套新密码。第一次登录时,系统会自动创建账号,只读取昵称、头像和邮箱这些基本资料。您也可以通过我的邀请链接注册哦。

2.2 提交博客

登录后点击「提交博客」,填写下面这些信息:

  • 博客名称和链接;
  • RSS / Atom 订阅地址,没有也可以不填,不过建议独立博客还是配一个;
  • 作者和博客简介;
  • 从现有分类中选择 1 – 5 个标签;
  • 上传博客头像,或者使用 Gravatar、GitHub、Google 头像;
  • 如果已经放了博客大联盟的链接,也可以填写链接所在页面。

一个账号最多可以收录 5 个博客。

目前加入的条件如下:

  • 博客必须是独立的原创博客,有自己的独立域名,比如 example.comblog.example.com,或者使用 PSL 列表的二三级域名,比如 example.github.io
  • 博客内容必须是中文为主,不能是纯其他语言的博客;
  • 博客内容必须是公开的,不能是私密或需要登录才能访问的博客;
  • 博客必须有一定的更新频率,至少每一年能更新一次,特殊情况可以豁免;
  • 博客内容必须积极向上,不能包含违法、低俗、恶意攻击、政治敏感等内容;
  • 不能是采集站、资源下载站、营销软文或批量生成的内容。

2.3 自动检查

提交后,系统会检查博客链接能不能打开、RSS 能不能解析、头像能不能加载。页面会列出每一项的结果,有问题就改完再提交。全部通过以后,才会进入域名所有权验证。

2.4 验证域名并等待审核

自动检查通过后,需要证明这个域名确实属于您。完成验证,提交才会进入管理员审核。这一步稍微麻烦一点,下面仔细说。

3、域名所有权验证

DNS TXT、DNS CNAME 和文件验证三选一。页面会生成一个 token,下面的写法只是示例,实际操作时直接复制页面给出的内容。

假设您的域名是 example.com,那么有三种验证方式:

3.1 DNS TXT 验证

在域名的 DNS 解析中给您博客的域名添加一条 TXT 记录,内容如下:

bo-ke-verify=<您的 token>

不同 DNS 服务商的填写方式不太一样,有些要给 TXT 内容加引号,有些不需要,添加后记得看一眼服务商显示的完整记录哦。

加完解析记录后可以用 dignslookup 检查解析结果,确认 TXT 记录已经生效。

DNS 记录生效可能需要几分钟到几小时。等解析生效后,回到验证页面点击「开始验证」即可。

3.2 DNS CNAME 验证

为域名添加下面这条 CNAME 记录:

bo-ke-verify.example.com.  CNAME  verify-<token>.bo.ke.

不同 DNS 服务商的填写方式不太一样。有些只需要填 bo-ke-verify,有些要填完整域名,有些要给 CNAME 域名最后加点号,添加后记得看一眼服务商显示的完整记录哦。

加完以后可以用 dignslookup 检查解析结果,确认 CNAME 指向了 verify-<token>.bo.ke.。等解析生效后,回到验证页面点击「开始验证」即可。

3.3 文件验证

如果不方便修改 DNS,也可以使用文件验证。在网站根目录放置下面这个纯文本文件:

bo-ke-verify-<token>.txt

文件内容就是 token 本身。验证页面会直接生成文件供您下载,上传到网站根目录后,确认下面这样的地址可以公开访问:

https://example.com/bo-ke-verify-<token>.txt

如果您的博客开了 WAF、防火墙或反爬虫的话,记得放行带有 bo.ke 关键字的 User-Agent,不然验证请求可能直接被挡在门外。

3.4 验证记录不要删除

无论选择哪一种方式,验证通过后都不要删除 DNS 记录或验证文件哦。

系统每 7 天重新检查一次。连续 3 次找不到验证记录,博客就会和账号解除关联。这个设计主要是防止域名转手以后,旧站长还能修改新站的资料。

所以不要在验证成功后顺手删掉记录,不然三个星期后还得重新认领。

4、认领已经存在的博客

以前 peng.you 里的数据有一部分导入了新站,管理员偶尔也会手工添加博客。这些条目还没有绑定账号,页面上会显示「认领此博客」。

如果发现自己的博客已经在里面,点击认领,再走一遍域名验证。通过后条目就会归到您的账号名下,以后可以自己修改资料。

5、互链不是门槛,但会加权

您可以在博客首页、友链页面或者任意内页,放一个指向 https://bo.ke/ 的链接。

互链不是收录条件,不放也能正常提交。系统会定期检查,找到链接后会提高博客的展示权重。

可以参考我们的友情链接页面,里面也放了博客大联盟。

6、收录以后能做什么

审核通过后,博客会出现在目录和标签页里,也可以按照名称、域名或作者搜索。博客名片下面会显示最新一篇文章。

如果填写了 RSS / Atom 地址,系统会每 6 小时抓取一次,每个博客保留最近 20 篇。全站文章也有提供 RSSAtom 订阅,丢进任何一个支持 RSS 的阅读器就能订阅。您也可以定制自己的专属订阅,屏蔽不想看到的博客。

如果你博客的资料有变化可以直接在控制台编辑,不用重新审核。

如果不想使用这个平台,在控制台删除博客即可,博客资料、聚合文章和认领记录会一起清除。

7、给喜欢折腾的人

博客大联盟有一套公开 JSON API,可以读取博客列表、全站最新文章和单个博客的最近文章。接口不用认证,支持跨域,做展示页或小工具都够用。数据每 6 小时才更新一次,别按秒轮询哦。

品牌资源页面放了深浅两色的 Logo 和徽标,提供 SVG、PNG、WebP 格式。颜色也可以在页面上改,做友链图标时比较省事。

访问统计用的是自建 Plausible,没有统计 Cookie,也不做跨站跟踪。

8、加入博客大联盟

如果您也在写博客,欢迎来加入博客大联盟

登录、填资料、验证域名,几分钟就能弄完,剩下的交给管理员审核。

如有问题可以随时联系我们

回归初心,文字为王

2026-07-07 10:00:00

这篇文章从一次博客重构说起,反思这些年从 WordPress、静态博客到 AI vibe coding 的不断折腾。技术和工具当然能让博客更快、更漂亮,但它们终究只是载体。真正能留下来的,不是框架、封面图或动画,而是一个人真实写下的文字和思考。与其追逐每一个新工具,不如回归初心,慢慢写博客,让文字重新成为博客的核心。

前言

从大学开始算起,本人写博客也快 20 年了。

这 20 年里,我见过各种各样的博客站点,也见过不少小伙伴从入坑到弃坑,再入坑,再弃坑。有的人写博客,是为了记录技术和生活上的点滴;有的人写博客,是为了 SEO,提高排名,顺便推广自己的产品;有的人写博客,是为了赚钱;更多的人,可能和我一样,纯属折腾。

从折腾 WordPress 主题和插件,到折腾静态化 HTML 博客程序,再到如今用 AI vibe coding 定制自己的博客系统,工具一代一代换,框架一轮一轮火。等夜深人静的时候,你大概也应该停下来问问自己:写博客的目的到底是什么?

是为了把网站做得更炫吗?是为了用上最新的框架吗?是为了让 Lighthouse 跑满分吗?还是为了把脑子里那些乱七八糟的想法,尽量诚实地留下来?

折腾

前段时间,我又开始折腾自己的博客首页。

再加上最近 AI 作图流行,我还给每篇文章都做了统一风格的封面图。刚开始看着还挺像那么回事,时间一久,越看越不顺眼。

一个好端端的分享技术的博客网站,要那么多图片干嘛?

更何况我又没什么艺术细胞,AI 的确能作图,但没艺术细胞的人用 AI 做出来的图,基本上一眼也能看出是 AI 做的。它可能很精致,也可能很「正确」,但就是少了点人味。甚至有些时候,那些图并不是在帮文章表达什么,而是在证明我也跟上了某种潮流。

于是趁着这个周末,我又一次折腾了自己的博客。

这次从 Next.js 换到了构建速度更快、也更适合纯静态内容的 Astro。同时,我撤掉了所有文章封面图,OG 图片也改成由程序自动生成。至于 SEO、文章内页 ToC 这些东西,交给 AI 来处理就行了,不再让它们喧宾夺主。

最后选定的架构大概如下:

选型 版本
运行时 / 包管理 Bun 1
框架 Astro(纯静态输出,零运行时框架) 7
样式 Tailwind CSS(@tailwindcss/vite 插件,CSS-first 配置) 4
内容格式 MDX(@astrojs/mdxoptimize: true 7
交互 原生 JS(<script> 块,无 React/Vue 运行时) -

放在以前,这种事情不折腾几个星期大概是做不完的。现在有了 AI,一晚上就能搞定。

这当然很爽。

但爽完以后,我又不得不问自己:这么折腾来折腾去,目的到底是什么?

是为了体验最新科技?是为了追逐更快的 build 速度?是为了证明自己还没有被前端时代抛弃?还是只是因为我们这些老网民,总觉得网站不改点什么就浑身难受?

技术当然重要。一个轻量、快速、结构清晰的博客系统,可以让写作这件事变得更舒服。但技术终究只是水管,不是水本身。框架再新,页面再快,动画再丝滑,如果文章本身没有内容,那也只是一个加载速度很快的空壳。

博客最重要的东西,始终不是首页长什么样,不是封面图够不够统一,也不是用了哪个新框架,而是文字本身有没有留下你的思考。

文字

现在的互联网越来越像信息流水线。

社交平台追求即时反馈,短视频追求几秒钟的刺激,AI 负责把内容变得更快、更满、更像样。每个人都可以很快生成一篇文章、一张图、一个视频,甚至一个看起来完整的个人网站。

但也正因为如此,真正稀缺的东西反而变了。

以前稀缺的是发布能力。你得会建站,会写 HTML,会折腾服务器,才能拥有自己的一个小角落。现在稀缺的不是发布,而是判断;不是表达能力,而是诚实表达;不是内容数量,而是你到底有没有真正想过。

AI 可以帮你写得更顺,帮你修语法,帮你生成摘要,甚至帮你做图。但 AI 不能替你活过那些日子,也不能替你在某个深夜突然想明白一件小事。

博客的价值,恰恰在这里。

它不一定要服务算法,也不一定要讨好读者。它可以很慢,可以很个人,可以有点啰嗦,甚至可以有点笨。它像是你在互联网上留给自己的一个锚点:过了几年再回头看,你会知道当时的自己在想什么,关心什么,又为什么要这样折腾。

这也是我越来越觉得,博客不应该被做成一个小型媒体站,也不一定非要变成作品集、流量入口或者商业落地页。

博客首先应该是一个人说话的地方。

总结

我们这些互联网老人的折腾精力和速度,已经越来越跟不上科技的发展了。

现在 AI 大爆发,几乎每周,甚至每天都有新的模型、新的工具、新的框架、新的工作流冒出来。你当然可以一直追,也可以一直改,一直重构,一直把自己的博客当成前端实验田。

但到最后,真正能留下来的,大概率还是那些你亲手写下来的文字。

所以,就让我们回归初心吧。

少一点花里胡哨的 JS、CSS 动画和 AI 作图,少一点为了折腾而折腾的冲动,多一点安静写字的耐心。

毕竟,博客不是展示工具链的地方,而是留下思考的地方。

文字,才是自己真正的原创。

不是嘛?

Ubuntu 24.04 Noble 升级 Ubuntu 26.04 Resolute

2026-05-20 03:12:04

本文将指导如何升级 Ubuntu 24.04 Noble Numbat 到 Ubuntu 26.04 Resolute Raccoon。

相关教程:Ubuntu 22.04 Jammy 升级 Ubuntu 24.04 Noble

准备工作

除非你是物理服务器,以及没有用过奇奇怪怪定制或修改的内核的 KVM 构架的 VPS 和云主机,否则升级大版本更新内核是有一定机率导致 Grub 加载失败的,切记备份重要数据!

OpenVZ 和 LXC 构架的 VPS 是无法升级的,因为他们没有自己独立的内核

再强调一遍,一定要备份重要数据!

Ubuntu 26.04 LTS 已经正式发布,不过 Ubuntu LTS 版本的自动升级提示通常会等到第一个小版本发布后才会开放。如果你在 Ubuntu 26.04.1 LTS 发布前从 Ubuntu 24.04 LTS 升级,do-release-upgrade 需要加上 -d 参数。

以下操作需要 root 权限,本文命令均已带上 sudo 前缀,请确保当前用户拥有 sudo 权限;或者直接使用 root 用户操作并省略命令中的 sudo

更新系统

首先需要更新你当前的系统

sudo apt update
sudo apt upgrade -y
sudo apt dist-upgrade -y
sudo apt autoclean
sudo apt autoremove -y

如果内核更新了,可以重启让最新的内核生效,也可以直接进行升级。

升级系统

这里有两种升级系统的方法,第一种是使用 do-release-upgrade 命令,第二种是手动更新 apt 源文件。

方法一:使用 do-release-upgrade 命令

首先需要安装 ubuntu-release-upgrader-core 包:

sudo apt install ubuntu-release-upgrader-core

然后修改 /etc/update-manager/release-upgrades 文件,确保 Prompt 值为 lts

cat /etc/update-manager/release-upgrades | grep lts

显示如下内容即可:

root@ubuntu ~ # cat /etc/update-manager/release-upgrades | grep lts
#  lts    - Check to see if a new LTS release is available.  The upgrader
Prompt=lts

最后执行以下命令升级系统:

sudo do-release-upgrade -d

等 Ubuntu 26.04.1 LTS 发布并开放 LTS 自动升级后,可以直接使用:

sudo do-release-upgrade

方法二:手动更新 apt 源文件

Ubuntu 24.04 的默认软件源配置文件已经变更为 DEB822 格式,路径为 /etc/apt/sources.list.d/ubuntu.sources。我们可以直接替换 nobleresolute

sudo sed -i 's/noble/resolute/g' /etc/apt/sources.list.d/ubuntu.sources

如果你的系统里仍然有传统 One-Line-Style 的源文件,也可以一并替换:

sudo sed -i 's/noble/resolute/g' /etc/apt/sources.list
sudo sed -i 's/noble/resolute/g' /etc/apt/sources.list.d/*.list

如果没有对应文件会提示诸如 sed: can't read /etc/apt/sources.list: No such file or directory 的错误,忽略即可。

或者直接一行命令:

sudo sed -i 's/noble/resolute/g' /etc/apt/sources.list /etc/apt/sources.list.d/*.{list,sources} 2>/dev/null

使用 DEB822 格式的源文件 /etc/apt/sources.list.d/ubuntu.sources 应该是类似这样的:

Types: deb
URIs: https://archive.ubuntu.com/ubuntu
Suites: resolute resolute-updates resolute-backports
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

Types: deb
URIs: http://security.ubuntu.com/ubuntu
Suites: resolute-security
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

国内服务器可以替换 archive.ubuntu.comsecurity.ubuntu.commirrors.tuna.tsinghua.edu.cn

如果你有第三方源或 PPA,建议先备份并根据情况临时禁用,升级完成后再确认是否支持 Ubuntu 26.04:

sudo mkdir -p /root/apt-sources-backup
sudo cp -a /etc/apt/sources.list.d /root/apt-sources-backup/

第三方源通常需要单独检查,不能简单把 noble 替换成 resolute

然后我们再次执行更新系统:

sudo apt update
sudo apt upgrade -y
sudo apt full-upgrade -y

更新过程中会提示一些软件是否需要自动重启,选 Yes 即可,以及一些软件的配置文件是否需要更新,按照自己的情况选择即可,默认回车即视为使用旧的配置文件,一般会出现在 OpenSSH 等软件的更新上。

更新后删除不必要的软件和依赖:

sudo apt autoclean
sudo apt autoremove -y

然后我们使用 sudo reboot 命令重启系统,耐心等待后,查看最新的系统版本:

root@ubuntu ~ # lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 26.04 LTS
Release:	26.04
Codename:	resolute
root@ubuntu ~ # uname -a
Linux Nana 7.0.0-15-generic #15-Ubuntu SMP PREEMPT_DYNAMIC Wed Apr 22 16:06:43 UTC 2026 x86_64 GNU/Linux

这时我们就已经更新到了最新的 Ubuntu 26.04 Resolute 和内核了。

WSL 2 使用 Docker 桥接模式网络访问 HTTPS 超时的解决方法

2026-01-21 12:53:46

本文介绍在 WSL 2 中使用 Docker 的桥接模式(bridge network)访问 HTTPS 时出现超时问题的解决方法。

最近一直在 Windows 下使用基于 WSL 2 的 Debian 进行开发。许多场景下需要使用 Docker 构建镜像,但过程中遇到一个奇怪的问题,在 Docker 容器内部访问 HTTP 站点时一切正常:

$ docker run --rm curlimages/curl time curl -s http://ip.gs
192.0.2.2
real    0m 0.02s
user    0m 0.00s
sys     0m 0.00s

一旦切换为 HTTPS,访问就会明显变慢,并且有一定概率出现超时:

$ docker run --rm curlimages/curl time curl -s https://ip.gs
192.0.2.2
real    0m 6.52s
user    0m 0.00s
sys     0m 0.00s

然而,如果将 Docker 切换到 Host 模式(--network=host),访问又恢复正常:

$ docker run --rm --network=host curlimages/curl time curl -s https://ip.gs
192.2.0.2
real    0m 0.28s
user    0m 0.00s
sys     0m 0.00s

在排查了 WSL 2 的 Debian 系统配置后,最终请教 ChatGPT 得到结论:

Path MTU 与防火墙流量检查(inspection)不兼容导致问题

解决方法很简单:将 WSL 2 虚拟网络的 MTU 下调为 1400 即可。

1、添加 Docker 配置

在 WSL 2 的系统里,使用 root 权限(sudo)修改 /etc/docker/daemon.json 文件:

{
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "20m",
        "max-file": "3"
    },
    "mtu": 1400,
    "dns": [
      "8.8.8.8",
      "1.1.1.1"
    ]
}

其中 "mtu": 1400, 是关键配置。

然后在 Windows 下把 WSL 2 关闭:

wsl --shutdown

2、修改 WSL 2 网卡配置

在 Windows 下使用管理员身份运行 Powershell,检查网卡名称:

PS C:\Users\showfom> Get-NetAdapter | Where-Object { $_.Name -like "*WSL*" }

Name                      InterfaceDescription                    ifIndex Status       MacAddress             LinkSpeed
----                      --------------------                    ------- ------       ----------             ---------
vEthernet (WSL (Hyper-V … Hyper-V Virtual Ethernet Adapter #3          41 Up           12-34-56-78-AB-CD        10 Gbps

PS C:\Users\showfom> Get-NetAdapter | Format-Table -AutoSize

Name                               InterfaceDescription                      ifIndex Status       MacAddress        Lin
                                                                                                                    kSp
                                                                                                                    eed
----                               --------------------                      ------- ------       ----------        ---
vEthernet (Default Switch)         Hyper-V Virtual Ethernet Adapter               35 Up           12-34-56-78-AB-AB …ps
vEthernet (WSL (Hyper-V firewall)) Hyper-V Virtual Ethernet Adapter #3            41 Up           12-34-56-78-AB-CD …ps

输出可以看到完整名称为 vEthernet (WSL (Hyper-V firewall)),然后为其设置 MTU:

netsh interface ipv4 set subinterface "vEthernet (WSL (Hyper-V firewall))" mtu=1400 store=persistent

出现 Ok. 字样即代表设置成功。

3、测试 WSL 2 中的 Docker 网络

然后重新运行 WSL 2 虚拟机:

wsl -d debian

再次测试:

$ docker run --rm curlimages/curl time curl -s https://ip.gs
192.0.2.2
real    0m 0.28s
user    0m 0.00s
sys     0m 0.00s

问题已完美解决,可以继续愉快地 Vibe Coding 了! ★,°:.☆( ̄▽ ̄)/$:.°★

Debian / Ubuntu 下使用 nginx-acme 自动签发并配置 SSL 证书

2026-01-16 11:05:21

本文将介绍在 Debian 或 Ubuntu 下使用 nginx-acme 自动签发并配置 SSL 证书的方法。

以下操作需要 root 权限,本文命令均已带上 sudo 前缀,请确保当前用户拥有 sudo 权限;或者直接使用 root 用户操作并省略命令中的 sudo

1、什么是 nginx-acme

nginx-acme 是 Nginx 官方开发的基于 ACME 协议自动签发 SSL 证书的模块,隔壁 Caddy 都出了几百年的功能, Nginx 也终于赶上了。

和 Nginx 使用 C 语言开发不同,这个模块是用 Rust 语言开发的,这里就不做评价。

这个模块支持 RFC8555RFC8737RFC8738draft-ietf-acme-profiles 等规范,目前我实际测试下来已经基本可以用于生产环境。

2、安装 N.WTF

这里我们使用烧饼博客打包的 N.WTF,这个项目已经集成了 nginx-acme 模块,可以做到开箱即用。

首先,安装一些必要的软件包:

sudo apt update
sudo apt upgrade -y
sudo apt install curl vim wget gnupg dpkg apt-transport-https lsb-release ca-certificates

然后加入 N.WTF 的 GPG 公钥和 apt 源:

curl -sSL https://n.wtf/public.key | sudo bash -c 'gpg --dearmor > /usr/share/keyrings/n.wtf.gpg'
sudo bash -c 'echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/n.wtf.gpg] https://mirror-cdn.xtom.com/sb/nginx/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/n.wtf.list'

国内机器可以用清华 TUNA 的国内源:

curl -sSL https://mirrors.tuna.tsinghua.edu.cn/n.wtf/public.key | sudo bash -c 'gpg --dearmor > /usr/share/keyrings/n.wtf.gpg'
sudo bash -c 'echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/n.wtf.gpg] https://mirrors.tuna.tsinghua.edu.cn/n.wtf/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/n.wtf.list'

Debian 下也可以直接使用 extrepo:

sudo apt update
sudo apt install extrepo -y
sudo extrepo enable n.wtf

接着更新系统并安装 Nginx:

sudo apt update
sudo apt install nginx-extras -y

3、nginx-acme 准备工作

准备工作很简单,我们需要建立一个目录来存放 SSL 证书并给予正确的权限,这里我们以 /var/cache/nginx/letsencrypt 为演示:

sudo mkdir -p /var/cache/nginx
sudo mkdir -p /var/cache/nginx/letsencrypt
sudo chown 33:33 /var/cache/nginx -R

然后别忘了把域名解析到你的服务器哦!

4、配置 Nginx 站点

我们以 example.com 为例,假设你的邮箱是 [email protected],需要配置的域名是 example.comwww.example.com,并且希望访问 www.example.com 跳转到 example.com

直接修改 /etc/nginx/sites-enabled/default 文件:

resolver 8.8.8.8:53 ipv6=off valid=5s;

acme_issuer letsencrypt {
    uri         https://acme-v02.api.letsencrypt.org/directory;
    contact     [email protected];
    state_path  /var/cache/nginx/letsencrypt;
    accept_terms_of_service;
    ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
    ssl_verify on;
}

acme_shared_zone zone=ngx_acme_shared:1M;

server {
    # Listen on port 80 for all IPv4 and IPv6 addresses
    listen 80 default_server;
    listen [::]:80 default_server;
   
    # Match all domain names
    server_name _;

    location /.well-known/ {
        return 404;
    }

    location / {
        # Redirect all other HTTP requests to HTTPS using 301 permanent redirect
        return 301 https://$host$request_uri;
    }
}

server {
    # Standard TLS listening
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    # HTTP/2 protocol support
    http2 on;
   
    # HTTP/3 QUIC protocol support
    listen 443 quic reuseport;
    listen [::]:443 quic reuseport;
    add_header Alt-Svc 'h3=":443"; ma=86400' always;
    add_header X-Protocol $server_protocol always;

    server_name example.com;
    root /var/www/html;
    index index.html;

    # modern configuration
    ssl_protocols TLSv1.3;
    ssl_ecdh_curve X25519:prime256v1:secp384r1;
    ssl_prefer_server_ciphers off;

    acme_certificate letsencrypt;

    ssl_certificate       $acme_certificate;
    ssl_certificate_key   $acme_certificate_key;

    # do not parse the certificate on each request
    ssl_certificate_cache max=2;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    http2 on;

    listen 443 quic;
    listen [::]:443 quic;

    add_header Alt-Svc 'h3=":443"; ma=86400' always;
    add_header X-Protocol $server_protocol always;

    server_name www.example.com;
    return 301 https://example.com$request_uri;

    ssl_protocols TLSv1.3;
    ssl_ecdh_curve X25519:prime256v1:secp384r1;
    ssl_prefer_server_ciphers off;

    acme_certificate letsencrypt;

    ssl_certificate       $acme_certificate;
    ssl_certificate_key   $acme_certificate_key;

    # do not parse the certificate on each request
    ssl_certificate_cache max=2;
}

然后验证 Nginx 配置并重新加载:

sudo nginx -t
sudo nginx -s reload

此时,在默认的 Nginx 日志文件 /var/log/nginx/access.log 中可以看到 Let's Encrypt 验证服务器的请求记录:

23.178.112.210 - - [15/Jan/2026:16:08:18 +0000] "GET /.well-known/acme-challenge/blablablablablablablablablablablablablablab HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
34.212.137.78 - - [15/Jan/2026:16:08:18 +0000] "GET /.well-known/acme-challenge/blablablablablablablablablablablablablablab HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
18.222.179.58 - - [15/Jan/2026:16:08:18 +0000] "GET /.well-known/acme-challenge/blablablablablablablablablablablablablablab HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
16.171.19.61 - - [15/Jan/2026:16:08:18 +0000] "GET /.well-known/acme-challenge/blablablablablablablablablablablablablablab HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
13.228.72.222 - - [15/Jan/2026:16:08:18 +0000] "GET /.well-known/acme-challenge/blablablablablablablablablablablablablablab HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
2600:3000:2710:200::81 - - [15/Jan/2026:16:08:20 +0000] "GET /.well-known/acme-challenge/blablablablablablablablablablablablablablab HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
2600:1f14:804:fd02:f7fd:3c68:dec7:a062 - - [15/Jan/2026:16:08:20 +0000] "GET /.well-known/acme-challenge/blablablablablablablablablablablablablablab HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
2600:1f16:269:da00:c9ce:508c:ea69:9c2 - - [15/Jan/2026:16:08:20 +0000] "GET /.well-known/acme-challenge/blablablablablablablablablablablablablablab HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
2a05:d016:39f:3101:8b83:62b8:2603:d15d - - [15/Jan/2026:16:08:20 +0000] "GET /.well-known/acme-challenge/blablablablablablablablablablablablablablab HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
2406:da18:85:1401:1f69:967a:a988:cdc8 - - [15/Jan/2026:16:08:20 +0000] "GET /.well-known/acme-challenge/blablablablablablablablablablablablablablab HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"

等待数秒后即可访问 https://example.com/ 了。

如果要给 IP 地址签发证书,则需要在 acme_issuer letsencrypt {} 段里添加一行 profile shortlived;,并且 server_name 必须写入完整的 IP 地址,不能直接用 server_name _ 哦。

不过目前 nginx-acme 最新版本 0.3.1 签发 IP 证书还是会失败,开发版已经修复,应该需要等下一个版本才能使用。

目前最新版本已经支持 IP 地址证书的签发,可以在 accept_terms_of_service; 下方加入一条 profile shortlived; 并且自行修改 server_name example.com; 为你的 IP 地址,比如 server_name 192.0.2.2 2001:db8::2; 即可。

读者们在使用过程中如果遇到问题,可以在 V2EX 交流讨论:

https://be.st/Mv7j

使用 acme.sh 配置 Let's Encrypt 签发的 IP 地址 SSL 证书

2025-12-18 00:13:37

本文将介绍使用 acme.sh 配置 Let's Encrypt 为 IP 地址签发 SSL 证书。

acme.sh 本身不强制 root 运行(官方也写了 "You don't have to be root then, although it is recommended"),但本文的证书需要写入 /etc--reloadcmd 需要重载服务,均需要 root 权限,所以建议先使用 sudo -i 切换到 root 用户再执行本文命令。

之前写过一篇使用 acme.sh 签发证书的教程,但在很长一段时间里,Let's Encrypt 只能给域名签发证书。

经过几个月的测试之后,现在终于可以对 IP 地址 下手了。

为什么要给 IP 签发证书

在很多场景下,我们并不一定需要域名,但确实需要 HTTPS。比如:

  1. DNS over HTTPS(DoH)服务无需依赖域名解析

直接通过 IP 提供 DoH 服务,避免「为了安全先做一次不安全的域名解析」这种哲学问题。

  1. Web 服务默认站点隐藏真实域名

默认站点只暴露 IP,不暴露真实域名,顺便还能挡掉一部分不太礼貌的爬虫。

  1. 临时服务或测试环境

临时起个服务,只想加个锁,不想再去 DNS 那边折腾。

  1. 避免证书透明日志(Certificate Transparency Log)暴露域名,保护隐私

有些域名不太想出现在公开日志里,低调一点总是好的。

准备工作

首先更新 acme.sh 到最新版本:

acme.sh --upgrade

因为 IP 证书目前只能通过 http-01tls-alpn-01 方式进行验证,所以你需要检查服务器的防火墙,设置允许 TCP 80 和 TCP / UDP 443 端口在公网可以访问。

配置 Nginx 80 端口的默认站点

这里我只介绍在 Nginx 下的配置吧,我们可以直接写入 80 端口的默认配置:

如果你在 Debian 或 Ubuntu 下安装 Nginx,可以直接覆盖 /etc/nginx/sites-available/default 文件:

server {
    # Listen on port 80 for all IPv4 and IPv6 addresses
    listen 80 default_server;
    listen [::]:80 default_server;
   
    # Match all domain names
    server_name _;

    # Merge Let's Encrypt and SSL verification path configuration
    location ~ ^/.well-known/(acme-challenge|pki-validation)/ {
        add_header Content-Type text/plain;
        root /var/www/letsencrypt;
    }

    # Redirect all other HTTP requests to HTTPS using 301 permanent redirect
    location / {
        return 301 https://$host$request_uri;
    }
}

然后创建两个目录并重新加载 Nginx:

mkdir -p /var/www/letsencrypt
mkdir -p /etc/nginx/ssl
nginx -t
nginx -s reload

使用 acme.sh 签发 IP 证书

假设你服务器的 IP 地址是 192.0.2.22001:db8::2

acme.sh --issue --server letsencrypt -d 192.0.2.2 -d 2001:db8::2 \
  -w /var/www/letsencrypt \
  --certificate-profile shortlived \
  --days 3

注意这里我们必须使用 shortlived 这个 Profile,因为 Let's Encrypt 的 IP 证书有效期只有 6.66666 天(160 小时),同时 acme.sh 需要更短的时间来进行检查更新证书,所以可以设置 --days 3 参数,让它 3 天检查并更新一次,你也可以设置 4 或 5,但是不要设置 6,否则可能证书过期了都没更新哦。

执行命令以后会看到类似的申请成功返回:

[Wed Dec 17 05:46:28 AM UTC 2025] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Wed Dec 17 05:46:28 AM UTC 2025] Multi domain='IP:192.0.2.2,IP:2001:db8::2'
[Wed Dec 17 05:46:30 AM UTC 2025] Getting webroot for domain='192.0.2.2'
[Wed Dec 17 05:46:30 AM UTC 2025] Getting webroot for domain='2001:db8::2'
[Wed Dec 17 05:46:30 AM UTC 2025] Verifying: 192.0.2.2
[Wed Dec 17 05:46:31 AM UTC 2025] Pending. The CA is processing your order, please wait. (1/30)
[Wed Dec 17 05:46:34 AM UTC 2025] Success
[Wed Dec 17 05:46:34 AM UTC 2025] Verifying: 2001:db8::2
[Wed Dec 17 05:46:35 AM UTC 2025] Pending. The CA is processing your order, please wait. (1/30)
[Wed Dec 17 05:46:38 AM UTC 2025] Success
[Wed Dec 17 05:46:38 AM UTC 2025] Verification finished, beginning signing.
[Wed Dec 17 05:46:38 AM UTC 2025] Let's finalize the order.
[Wed Dec 17 05:46:38 AM UTC 2025] Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/blablablablablablablabla/blablablablablablablabla'
[Wed Dec 17 05:46:41 AM UTC 2025] Downloading cert.
[Wed Dec 17 05:46:41 AM UTC 2025] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/blablablablablablablabla'
[Wed Dec 17 05:46:42 AM UTC 2025] Cert success.
-----BEGIN CERTIFICATE-----
blablablablablablablablablablablablablablablablablablabla
-----END CERTIFICATE-----
[Wed Dec 17 05:46:42 AM UTC 2025] Your cert is in: /root/.acme.sh/192.0.2.2_ecc/192.0.2.2.cer
[Wed Dec 17 05:46:42 AM UTC 2025] Your cert key is in: /root/.acme.sh/192.0.2.2_ecc/192.0.2.2.key
[Wed Dec 17 05:46:42 AM UTC 2025] The intermediate CA cert is in: /root/.acme.sh/192.0.2.2_ecc/ca.cer
[Wed Dec 17 05:46:42 AM UTC 2025] And the full-chain cert is in: /root/.acme.sh/192.0.2.2_ecc/fullchain.cer

然后我们可以把申请好的证书放在 /etc/nginx/ssl 目录:

mkdir -p /etc/nginx/ssl

acme.sh --install-cert -d 192.0.2.2 \
  --key-file       /etc/nginx/ssl/ip.key  \
  --fullchain-file /etc/nginx/ssl/ip.crt \
  --ca-file        /etc/nginx/ssl/ip.ca.crt \
  --reloadcmd     "systemctl restart nginx"

配置 Nginx 443 端口的默认站点

安装完证书后我们即可配置 Nginx 默认的 443 端口了,你可以把这段配置一起放入 /etc/nginx/sites-available/default 文件:

# HTTPS Server block - Handle all HTTPS requests
server {
    # Standard TLS listening
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    # HTTP/2 protocol support
    http2 on;
   
    # HTTP/3 QUIC protocol support
    listen 443 quic reuseport;
    listen [::]:443 quic reuseport;
    add_header Alt-Svc 'h3=":443"; ma=86400' always;
    add_header X-Protocol $server_protocol always;
   
    # Match all domain names
    server_name _;
    return 403;

    # modern configuration
    ssl_protocols TLSv1.3;
    ssl_ecdh_curve X25519:prime256v1:secp384r1;
    ssl_prefer_server_ciphers off;

    ssl_certificate /etc/nginx/ssl/ip.crt;
    ssl_certificate_key /etc/nginx/ssl/ip.key;
}

然后检查并重新加载 Nginx:

nginx -t
nginx -s reload

一切就绪以后就可以直接访问 https://192.0.2.2/ 并返回 403 错误页面,我们可以看到证书里 Subject Alt Names 字段也显示 IP Address 了:

证书详情中 Subject Alt Names 字段显示 IP Address

读者们在使用过程中如果遇到问题,可以在 V2EX 交流讨论或在下方评论:

https://be.st/pGx9