本来以为这会是一件很简单的事。
买台阿里云轻量应用服务器,装个 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
大概意思就是某个服务关联角色没创建成功。
这时候我其实有两种选择:
继续和阿里云控制台死磕
直接绕过去,自己做 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 还在返回旧值
这时候如果你看见有地方还是旧值,就贸然点回车,很可能还是失败。
我后来是怎么判断“现在可以继续了”的?
我重点查了这几类:
权威 NS
8.8.8.8223.5.5.5
我最后的判断逻辑变成了:
如果权威 NS 已经是新值
主流公共 DNS 也已经查到新值
那就可以继续
这一步其实让我对 DNS 的“不是立刻全网统一”有了更直观的理解。
第十五件事:限流真的会来,而且来得比你想的快
因为前面 TXT 反复填错、值混用、没等传播就按回车,我最后直接撞上了 Let’s Encrypt 的失败限流。
报错的大意就是:
这一小时失败次数太多了,请稍后再试
那一刻我真的有点想笑。
明明离成功已经很近了,结果被自己的急躁又拽回去了一个小时。
这一坑的教训非常简单
只要是 DNS 手动验证,宁可慢一点,也不要急着回车。
每失败一次,都不是“再来一次就好”,它是在消耗你真正能重试的次数。
第十六件事:证书终于申请成功的那一刻,真有点像通关了
后来,在限流过去之后,我又重新按照正确流程做了一遍:
运行 certbot 手动 DNS 验证
记下这一轮新的 TXT 值
去 DNS 面板更新成这次的新值
先查权威 NS 和公共 DNS
确认看到的值和 certbot 当前页面完全一致
再按回车继续
终于,我看到了成功的输出。
证书和私钥路径类似:
/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.tophttps://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,我大概率会直接按下面这条路线走:
先解决 Docker 权限
直接用国内 Halo 镜像
直接上 MySQL,不走 H2
先把
blog.glaube-ty.top做好 A 记录解析先跑通 Halo + Nginx 的 HTTP
直接用 DNS 手动验证签证书
Nginx 切到 HTTPS
修改
HALO_EXTERNAL_URL删除临时 TXT
关闭公网 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.tophttps://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 的那一刻,成就感也会非常直接。
如果你也在折腾自己的博客,希望这篇记录能帮你少走一点弯路。
折腾了一整晚,我终于把 Halo 博客跑在了 blog.glaube-ty.top 上
https://blog.glaube-ty.top/archives/019d8aa1-3840-71be-8a24-e4d1e9f4ee7b
评论