本来以为这会是一件很简单的事。

买台阿里云轻量应用服务器,装个 Docker,跑个 Halo,配个域名,再加个 HTTPS,不就完了么?

结果真正做起来,发现每一步都在提醒我:“你以为会,和你真的会,是两回事。”

这一晚,我踩了不少坑:

  • Docker 没权限

  • Docker Hub 拉不下来镜像

  • Halo 明明跑起来了,打开却是 404

  • 阿里云控制台里“添加域名”报角色不存在

  • 证书申请反复失败

  • TXT 记录加了,但又像没加

  • DNS 解析明明改了,结果不同地方查到的值还不一样

  • 最后还被 Let’s Encrypt 限流了一小时

但是好在,最终还是跑通了。
现在我的博客已经可以正常通过下面两个地址访问:

  • 前台:https://blog.glaube-ty.top

  • 后台:https://blog.glaube-ty.top/console/

所以这篇文章,我不想写成那种冷冰冰的“部署手册”,而是想把这一晚我是怎么一步一步把博客搭起来的,怎么踩坑、怎么排查、怎么最终解决的,完整记下来。

如果你也打算在阿里云轻量应用服务器上用 Docker 部署 Halo,这篇文章应该能帮你少绕很多弯路。


先说最终方案

我最后跑通的方案是这样的:

  • 服务器:阿里云轻量应用服务器

  • 应用:Halo 2

  • 数据库:MySQL 8.0

  • 运行方式:Docker Compose

  • 反代:Nginx

  • 域名:blog.glaube-ty.top

  • 证书:Let’s Encrypt

  • HTTPS:Nginx 自己接证书,然后反向代理到 Halo

最终链路大概是这样:

浏览器 -> blog.glaube-ty.top -> Nginx(80/443) -> 127.0.0.1:8090 -> Halo

也就是说,Halo 本体其实还是跑在 8090 端口上,只是我不再直接把 8090 暴露给公网,而是让 Nginx 接管外部访问。

这是后面整个架构能稳定下来的关键。


第一件事:先别急着部署 Halo,先把 Docker 搞定

我最开始的错误,就是太心急。

看到服务器已经买好了,就想直接一把梭:

  • 安装 Docker

  • 拉镜像

  • 启动容器

结果第一步就被打了脸。

当我用普通用户执行 Docker 命令时,收到的是类似这样的错误:

permission denied while trying to connect to the Docker daemon socket

一开始我还以为是 Docker 没装好,后来才发现根本不是。

真正的问题是什么?

问题非常朴素:当前登录用户没有访问 Docker 的权限。

Docker 的 socket 在 /var/run/docker.sock,普通用户默认没有权限直接用,所以就会报这个错。

我是怎么解决的?

把当前用户加入 docker 用户组:

sudo usermod -aG docker admin

然后退出 SSH,重新登录

这一步一定不要偷懒。
你如果不重新登录,用户组信息不会马上生效,后面你会以为自己改了,其实系统并没有真正按新权限运行。

重新登录之后,我用下面两个命令确认:

groups
docker info

只要 groups 里已经出现 docker,并且 docker info 能正常输出信息,这一步才算真的结束。

这一段最大的教训

以后再遇到 Docker 问题,我肯定会先问自己一句:

是 Docker 真坏了,还是只是当前用户没权限?

很多看起来很吓人的报错,其实根本不是“大问题”,只是基础没打通而已。


第二件事:不要死磕 Docker Hub

Docker 权限解决之后,我以为终于可以愉快地拉 Halo 镜像了。

结果拉镜像的时候,又卡住了。

最典型的报错长这样:

Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection
Client.Timeout exceeded while awaiting headers

我一开始还怀疑是 Halo 官方镜像有问题,就去试了个 hello-world,结果一样拉不下来。

这一下就明白了:
不是 Halo 的问题,是这台服务器访问 Docker Hub 本身就不稳定。

这一步如果继续死扛,会发生什么?

你会进入一种很痛苦的循环:

  • 改镜像加速器

  • 重启 Docker

  • 再拉一次

  • 再失败

  • 再换一个源

  • 再失败

最后浪费很多时间,事情却一点没推进。

我最后怎么处理的?

我直接放弃继续从 Docker Hub 拉 Halo,改成使用国内镜像:

registry.fit2cloud.com/halo/halo:2

这个镜像一换,局面就彻底不一样了。
之前一直拉不下来的 Halo,终于能正常拉取了。

这一段最大的教训

如果你在国内服务器上部署东西,不要把“能连 Docker Hub”当成默认前提
尤其是博客这种应用,目的不是研究网络连通性,而是把站搭起来。能用国内镜像就直接用,别和 Docker Hub 拼意志。


第三件事:Halo 还没初始化时,看到 404 不要慌

镜像终于拉下来,容器也能跑起来了,我那时候真的以为最难的已经过去了。

结果浏览器一打开,根路径给我来了一句大意是:

Template index was not found

或者直接给我一个 404。

当时第一反应就是:完了,Halo 没起来。

后来才发现,这个判断完全错了。

这个 404 是什么意思?

它并不是说 Halo 没启动,恰恰相反,它说明:

  • 应用已经启动了

  • 请求已经到了 Halo

  • 只是首页模板还没准备好,或者站点还没完成初始化

所以这个时候,你不能用根路径 / 的表现来判断 Halo 是否成功。

正确的入口其实是后台

真正该访问的是:

/console/

也就是:

http://你的域名/console/

只有进入这里,才能看到 Halo 的初始化页面或者后台登录入口。

这一段最大的教训

以后如果再部署 Halo,我会先记住一件事:

根路径不通,不代表应用没起来;后台入口才更有参考价值。


第四件事:H2 可以用,但我没继续用

当 Halo 初始化页终于出来时,它给了我一个提示:当前使用的是 H2 数据库。

如果只是随便体验一下,H2 其实没什么问题。
但我这次是打算把博客长期用起来的,所以我很快就决定:不继续用 H2,直接切到 MySQL。

原因也很简单:

  • H2 更像“快速试跑”

  • MySQL 更适合“长期运行”

尤其是博客这种东西,后面你会发文章、装主题、改设置、备份、迁移。
这些场景下,MySQL 会让人心里踏实很多。


第五件事:Compose 配置里,直接把 Halo 和 MySQL 一起拉起来

我最后用的是 Docker Compose 来跑 Halo 和 MySQL。

核心思路很简单:

  • 一个容器是 MySQL

  • 一个容器是 Halo

  • Halo 通过环境变量连到 MySQL

Compose 配置大概是这样的:

services:
  mysql:
    image: mysql:8.0
    container_name: halo-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: <你的MySQLRoot密码>
      MYSQL_DATABASE: halo
      MYSQL_USER: halo
      MYSQL_PASSWORD: <你的Halo数据库密码>
    command:
      - --default-authentication-plugin=mysql_native_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
    volumes:
      - ./mysql-data:/var/lib/mysql

  halo:
    image: registry.fit2cloud.com/halo/halo:2
    container_name: halo
    restart: always
    depends_on:
      - mysql
    ports:
      - "8090:8090"
    environment:
      SPRING_PROFILES_ACTIVE: prod
      HALO_EXTERNAL_URL: http://blog.glaube-ty.top
      SPRING_R2DBC_URL: r2dbc:pool:mysql://mysql:3306/halo
      SPRING_R2DBC_USERNAME: halo
      SPRING_R2DBC_PASSWORD: <你的Halo数据库密码>
      SPRING_SQL_INIT_PLATFORM: mysql
    volumes:
      - ./data:/root/.halo2

启动命令:

cd ~/halo
docker compose up -d

然后配合下面几个命令检查状态:

docker ps
docker logs -f halo
docker logs -f halo-mysql

这里我还踩了一个小坑

我一开始直接把数据库密码写在 Compose 里,又在排查过程中截图发来发去,后来才意识到:
这种密码最好后面改掉,不要一直用暴露过的值。

所以如果你也像我这样在折腾过程中频繁截图,记得最后把数据库密码再换一次。


第六件事:别指望阿里云轻量服务器控制台帮你一键加域名

我最开始还试图用阿里云轻量应用服务器控制台里的“添加域名”功能,想省点事。

结果它直接给我来了一句类似:

role not exists

大概意思就是某个服务关联角色没创建成功。

这时候我其实有两种选择:

  1. 继续和阿里云控制台死磕

  2. 直接绕过去,自己做 DNS 和 Nginx

我最后选的是第二种。

为什么?

因为我越来越明显地感受到:
我真正想要的是“博客上线”,不是“研究阿里云某个控制台功能为什么出错”。

所以我直接换思路:

  • 域名自己在 DNS 面板里手动解析

  • Nginx 自己写配置

  • HTTPS 自己申请

这条路虽然看起来“更原始”,但其实更可控,排错也更直接。

这一段最大的教训

只要不是那种非用不可的平台功能,
一旦控制台工具开始拖后腿,就果断绕过去。


第七件事:域名解析要早点做,而且最好先确认没有 AAAA

我最终决定把博客挂到这个子域名上:

blog.glaube-ty.top

所以 DNS 里加了一条 A 记录:

  • 主机记录:blog

  • 类型:A

  • 值:服务器公网 IP

比如:

blog -> 服务器公网 IP

加完之后,我没有急着继续下一步,而是先查了解析:

nslookup -type=A blog.glaube-ty.top
nslookup -type=AAAA blog.glaube-ty.top

为什么我专门查了 AAAA?

因为后来我在申请证书时吃了很多苦,才意识到一个道理:

有时候你明明看着域名是对的,但如果它还带着一个你没注意到的 IPv6 记录,证书验证就会变得非常诡异。

这次还好,我查出来的结果是:

  • A 记录正常

  • AAAA 没有

这就少了一个坑。


第八件事:Nginx 反代才是稳定访问的真正入口

域名解析好之后,我装了 Nginx,并且给它写了一份最基础的反代配置。

一开始先不做 HTTPS,只做最简单的 HTTP 反代:

server {
    listen 80;
    server_name blog.glaube-ty.top;

    client_max_body_size 50m;

    location / {
        proxy_pass http://127.0.0.1:8090;
        proxy_http_version 1.1;

        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 Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

然后检查并重启:

sudo nginx -t
sudo systemctl restart nginx

再测试:

curl -I http://blog.glaube-ty.top
curl -I http://blog.glaube-ty.top/console/

这一步的重要意义

这一步让我第一次真正确认了一件事:

域名、Nginx、Halo 三者之间的访问链路已经打通了。

虽然这时候 HTTPS 还没搞好,但只要 HTTP 能稳定通,后面的问题就只剩“怎么把证书加上”,而不是“我的博客到底跑没跑起来”。


第九件事:端口不一致这种低级问题,真的会卡你很久

这次还有个很典型但也很容易忽略的坑。

一开始我 Halo 容器映射的是 8090,但轻量应用服务器防火墙里放行的是 8089

结果表现就很迷惑:

  • 本机访问通

  • 容器运行正常

  • 浏览器外网访问就是不通

当时我绕来绕去检查了半天,最后才发现是端口对不上。

这件事告诉我什么?

很多时候问题并不高级,甚至不复杂。
它可能只是:

你以为你放行了端口,其实你放行的是另一个端口。

后来因为我改成了 Nginx 反代,所以最终公网只开放:

  • 22

  • 80

  • 443

这样 8090 就不再需要直接暴露给公网了,整个系统也更干净一点。


第十件事:HTTPS 才是今晚真正的“主战场”

如果说前面那些是热身,那真正让我折腾得最久的,其实是 HTTPS。

我最开始天真地觉得,装了 Nginx,直接来一句:

sudo certbot --nginx -d blog.glaube-ty.top

不就完了么?

结果它回给我的,是一连串 403。

第一次失败:HTTP 验证路径返回 403

我看到的核心报错大概是:

Invalid response from http://blog.glaube-ty.top/.well-known/acme-challenge/...: 403

这句话一开始很让人懵,因为它不像“完全访问不到”,它是“能访问到,但被拒绝”。

这说明:

  • 域名不是完全错的

  • 请求也不是完全没到

  • 而是到了某一步,被挡住了

于是我开始尝试各种传统办法:

  • --nginx

  • --webroot

  • --standalone

结果都不顺利。

第二次失败:我以为 webroot 放通了,其实外部视角不是这样

有一阵子,我已经能在服务器本机用 curl 访问到验证文件了,我以为这就说明没问题。

结果 Let’s Encrypt 外部还是拿到 403。

这时候我才意识到一个很重要的排查思路:

服务器本机能访问,不代表 Let’s Encrypt 外部也能看到一样的内容。

这也是这次排错里一个很重要的认识。


第十一件事:折腾到这里,我决定不再和 HTTP 验证硬碰硬

反复试下来,我发现一个事实:

HTTP 验证虽然理论上简单,但在我的这套环境里,它就是不稳定。

而且更糟糕的是,我还因为连续失败太多,直接撞上了 Let’s Encrypt 的限流。

那一刻我就知道,这条路不能再硬扛了。

所以我做了一个重要决定:

不再继续试 HTTP 验证,直接改走 DNS 验证。

这也是最终成功的关键转折点。


第十二件事:DNS 手动验证,其实难点不在“加 TXT”,而在“不要加错”

我最后使用的命令是:

sudo certbot certonly --manual --preferred-challenges dns -d blog.glaube-ty.top

运行之后,它会让你添加一条 TXT 记录。

看起来好像很简单,对吧?

但真正折腾人的地方恰恰就在这里。

我踩的第一个坑:主机记录写错

certbot 提示里的记录名是完整的:

_acme-challenge.blog.glaube-ty.top

可是在阿里云 DNS 面板里,你不能把“主机记录”直接写成这个完整域名。
你真正应该填的是:

_acme-challenge.blog

因为面板会自动补主域名 glaube-ty.top

如果你把完整域名也写进去,就会变成重复拼接,结果查的时候直接是 NXDOMAIN

这是我前面一个很典型的坑。


第十三件事:certbot 每次给你的 TXT 值,都是“只对当前这一轮有效”

这是整晚最容易把人绕晕的地方。

我第一次跑 certbot,它给我一个 TXT 值,我加上去了。
但那次验证失败了。

然后我又重新运行了一次 certbot。
问题来了:第二次 certbot 给我的 TXT 值,和第一次不一样。

如果你这时候没有意识到这一点,就会发生什么?

  • 你 DNS 里还留着第一次的旧值

  • 但第二次 certbot 正在等待的是新值

  • 你以为自己已经加过 TXT 了,就按回车

  • 然后继续失败

我就是这样连续翻车了好几次。

这一步最重要的经验

以后只要手动跑 DNS 验证,我一定会记住这句话:

certbot 当前这一轮显示的 TXT 值,才是唯一有效值。

旧值必须删掉或者覆盖,绝对不能混用。


第十四件事:DNS 生效这件事,不是“改完就算完”

即使 TXT 记录加对了,也不代表你马上就能点回车。

因为 DNS 是有传播和缓存的。

我后来检查的时候发现:

  • 权威 DNS 已经是新值

  • 8.8.8.8 也是新值

  • 223.5.5.5 还在返回旧值

这时候如果你看见有地方还是旧值,就贸然点回车,很可能还是失败。

我后来是怎么判断“现在可以继续了”的?

我重点查了这几类:

  1. 权威 NS

  2. 8.8.8.8

  3. 223.5.5.5

我最后的判断逻辑变成了:

  • 如果权威 NS 已经是新值

  • 主流公共 DNS 也已经查到新值

  • 那就可以继续

这一步其实让我对 DNS 的“不是立刻全网统一”有了更直观的理解。


第十五件事:限流真的会来,而且来得比你想的快

因为前面 TXT 反复填错、值混用、没等传播就按回车,我最后直接撞上了 Let’s Encrypt 的失败限流。

报错的大意就是:

这一小时失败次数太多了,请稍后再试

那一刻我真的有点想笑。
明明离成功已经很近了,结果被自己的急躁又拽回去了一个小时。

这一坑的教训非常简单

只要是 DNS 手动验证,宁可慢一点,也不要急着回车。

每失败一次,都不是“再来一次就好”,它是在消耗你真正能重试的次数。


第十六件事:证书终于申请成功的那一刻,真有点像通关了

后来,在限流过去之后,我又重新按照正确流程做了一遍:

  1. 运行 certbot 手动 DNS 验证

  2. 记下这一轮新的 TXT 值

  3. 去 DNS 面板更新成这次的新值

  4. 先查权威 NS 和公共 DNS

  5. 确认看到的值和 certbot 当前页面完全一致

  6. 再按回车继续

终于,我看到了成功的输出。

证书和私钥路径类似:

/etc/letsencrypt/live/blog.glaube-ty.top/fullchain.pem
/etc/letsencrypt/live/blog.glaube-ty.top/privkey.pem

到这里,这套 HTTPS 才算真的拿下来了。


第十七件事:证书有了之后,Nginx 就该切到 HTTPS 了

证书申请成功之后,我把 Nginx 配置改成了最终版。

HTTP 直接跳转 HTTPS,HTTPS 再反代到 Halo:

server {
    listen 80;
    server_name blog.glaube-ty.top;

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    server_name blog.glaube-ty.top;

    ssl_certificate /etc/letsencrypt/live/blog.glaube-ty.top/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/blog.glaube-ty.top/privkey.pem;

    client_max_body_size 50m;

    location / {
        proxy_pass http://127.0.0.1:8090;
        proxy_http_version 1.1;

        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 https;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

然后检查并重启:

sudo nginx -t
sudo systemctl restart nginx

这一步完成之后,HTTPS 入口就真正可用了。


第十八件事:别忘了把 Halo 自己的外部地址也改成 HTTPS

这一步非常容易漏。

我一开始如果只是把 Nginx 换成 HTTPS,而 Compose 里 Halo 的外部地址还是 HTTP,就会出现一些链接、跳转或者回调行为不对的情况。

所以我最后把 Compose 里的这一行:

HALO_EXTERNAL_URL: http://blog.glaube-ty.top

改成了:

HALO_EXTERNAL_URL: https://blog.glaube-ty.top

然后重新启动 Halo:

cd ~/halo
docker compose down
docker compose up -d

到这一步,网站就算真正完整切到 HTTPS 了。


第十九件事:上线之后,记得把一些临时东西收掉

部署成功以后,有几件事最好顺手做掉。

1. 删除临时 TXT 记录

证书签好以后,_acme-challenge.blog 这条 TXT 就可以删掉了,不然一直留着没有意义。

2. 不再开放 8090 到公网

既然现在外部流量都走 Nginx,那公网只需要保留:

  • 22

  • 80

  • 443

不用再让外部直接访问 8090。

3. 确认博客和后台地址都正常

最终应该能正常访问:

  • https://blog.glaube-ty.top

  • https://blog.glaube-ty.top/console/


第二十件事:这次部署下来,我觉得最值钱的经验是什么?

如果只让我选几条最有价值的经验,我会选这些。

1. 不要把问题想得太复杂,先把基础跑通

Docker 权限、镜像拉取、容器状态,这些基础没通时,不要急着怀疑更深层的原因。

2. Docker Hub 不通时,直接换国内镜像

这比反复试加速器、反复重启更直接。

3. Halo 的根路径不是判断启动成功的最佳入口

/console/ 和日志,比盯着 / 有用得多。

4. 用了 Nginx 之后,公网就尽量只留 80/443

应用端口不要长期直接暴露。

5. 手动 DNS 验证的核心不是“会不会加 TXT”,而是“每一轮都要用当前值”

这一点如果没理解透,后面就会一直翻车。

6. DNS 生效不是一个“瞬间动作”

不同 DNS 服务器看到的新值可能不同步,所以查多个结果非常重要。

7. 不要在没确认值一致前就按回车

我这一晚最大的时间成本,几乎都浪费在这一类“明明再等一下就好,却提前点了继续”的错误上。


二十一、如果以后让我重新来一遍,我会怎么做?

如果以后我再从零部署一次 Halo,我大概率会直接按下面这条路线走:

  1. 先解决 Docker 权限

  2. 直接用国内 Halo 镜像

  3. 直接上 MySQL,不走 H2

  4. 先把 blog.glaube-ty.top 做好 A 记录解析

  5. 先跑通 Halo + Nginx 的 HTTP

  6. 直接用 DNS 手动验证签证书

  7. Nginx 切到 HTTPS

  8. 修改 HALO_EXTERNAL_URL

  9. 删除临时 TXT

  10. 关闭公网 8090

这条路线比我这次实际走过的试错路线,要干净很多。


二十二、到这里,博客已经上线了,但还有一件事没结束:证书续期怎么办?

这次我拿证书用的是 Certbot 的手动 DNS 验证方式,也就是:

sudo certbot certonly --manual --preferred-challenges dns -d blog.glaube-ty.top

这种方式的特点是:

  • 能签到证书

  • 非常适合当前这种环境

  • 不会自动续期

也就是说,证书到期前,我还得再手动续一次。

下面我把“以后证书到期怎么续”也一起写上。


证书到期后,怎么手动续期?

一、先看证书什么时候到期

最直接的方式是用 Certbot 看:

sudo certbot certificates

它会列出当前证书和到期时间。

如果你想直接看证书文件,也可以:

sudo openssl x509 -enddate -noout -in /etc/letsencrypt/live/blog.glaube-ty.top/fullchain.pem

我自己的建议是:

  • 平时一个月看一次

  • 到期前 30 到 45 天开始处理


二、手动续期命令

等快到期时,执行和当初申请时同样的命令

sudo certbot certonly --manual --preferred-challenges dns -d blog.glaube-ty.top

这条命令会再次给你一条新的 TXT 验证记录。

注意,是新的,不是你上次那条。


三、续期的正确步骤

第 1 步:运行命令,记下当前这一轮新的 TXT 值

它会提示你添加类似:

_acme-challenge.blog.glaube-ty.top

对应的 TXT 记录。

在 DNS 面板里,主机记录仍然写:

_acme-challenge.blog

记录值则填写 certbot 当前这次会话给你的那串新值。


第 2 步:删掉旧 TXT,或者直接覆盖成新值

这里最重要的一点是:

不要保留旧值,不要拿上次的值继续用。

每次新的验证,都以 当前这一轮 certbot 提示出来的值 为准。


第 3 步:不要立刻按回车,先查 TXT 是否真的生效

推荐查这几个:

nslookup -type=TXT _acme-challenge.blog.glaube-ty.top 8.8.8.8
nslookup -type=TXT _acme-challenge.blog.glaube-ty.top dns25.hichina.com
nslookup -type=TXT _acme-challenge.blog.glaube-ty.top dns26.hichina.com

只要这些查询结果都已经返回当前这次 certbot 给的新值,再回到 certbot 那个界面按回车。


第 4 步:验证成功后,证书文件会自动更新到原路径

成功之后,证书路径仍然还是:

/etc/letsencrypt/live/blog.glaube-ty.top/fullchain.pem
/etc/letsencrypt/live/blog.glaube-ty.top/privkey.pem

因为 Nginx 用的就是这两个路径,所以你只需要重启 Nginx 即可:

sudo nginx -t
sudo systemctl restart nginx

第 5 步:验证 HTTPS 是否正常

curl -I https://blog.glaube-ty.top

然后浏览器再看一下:

  • https://blog.glaube-ty.top

  • https://blog.glaube-ty.top/console/


四、手动续期时最容易踩的坑

如果以后我自己再续一次,我最提醒自己注意的,就是下面这几件事:

1. 不要拿旧 TXT 值继续用

每次 certbot 都可能给新值。

2. 不要 TXT 还没传播就按回车

这是最容易浪费重试次数的地方。

3. 不要连续失败太多次

Let’s Encrypt 会限流,失败多了要等很久。

4. 不要把主机记录写成完整域名

主机记录写:

_acme-challenge.blog

不是写成:

_acme-challenge.blog.glaube-ty.top

五、我现在这套方案的状态

到今天为止,我这套博客已经实现了:

  • Docker 部署 Halo

  • MySQL 持久化

  • Nginx 反向代理

  • 自定义子域名访问

  • HTTPS 正常启用

唯一还没有自动化的,就是:

  • 证书续期仍然是手动

但这件事并不影响现在博客正常使用。
我后面如果再折腾,下一步大概率会去做的,就是证书自动续期方案。


最后

这一晚折腾下来,最大的感受其实不是“终于搭好了一个博客”,而是:

很多看起来像“大问题”的问题,最后都只是某个小细节没对上。

有时候是权限。
有时候是镜像源。
有时候是端口。
有时候是 TXT 记录里那一个旧值。

但也正因为这些坑都是自己一步一步趟过去的,最后真的能打开 https://blog.glaube-ty.top 的那一刻,成就感也会非常直接。

如果你也在折腾自己的博客,希望这篇记录能帮你少走一点弯路。