云服务器搭建个人博客最容易卡住的位置不在博客程序上,而在放行规则与目录权限这两层。
这次的经过不复杂。一台新加坡区域的实例,系统是 Ubuntu 22.04,上面只放一个静态博客的输出目录。
域名做了 A 记录,指向这台实例的公网地址。
SSH 连得上,浏览器打开首页却一直转圈,等几十秒之后提示超时。
真正花掉时间的不是装 nginx,是判断请求在哪一层被拦住。装的环节本身没花多少时间,找断点的过程占了大半。

一、背景:这台实例只服务一个静态站点
这台实例只服务一个静态站点,问题范围也就收窄到 Web 服务器与它前面的网络层。
这台云主机上只跑一个静态博客:没有数据库,没有后端进程,只有一份 HTML 输出目录,和一个负责把请求映射到这个目录的 Web 服务器。
静态博客的结构就是这样:页面在部署时已经生成好。访问时既不查库,也不执行脚本。
可变量少是好事,判断的依赖也就落在顺序上。
二、云服务器搭建个人博客:超时,而访问日志里是空的
打开超时,访问日志里却空着,说明请求在到 nginx 之前就被丢弃了,入口那层要先去查。
第一个现象出现在连接阶段。curl 停在 Trying 那一行不动,最后返回超时。
第一反应是服务没起来,转圈看起来最像进程挂了。
第二个现象更关键:这段时间里 nginx 的访问日志一条记录都没有。日志文件本身是存在的,只是没有新增行。
请求根本没有交到 Web 服务器手上。
超时和拒绝是两种不同的表现。端口上没有进程在听,一般返回拒绝;数据包在中间被丢掉,表现才是超时。
安全组是云平台加在实例外侧的一层放行规则,它的判定发生在流量进入网卡之前。
规则里没有某个端口的放行条目时,数据包会被静默丢弃,不回任何拒绝。
这条机制解释了日志为什么那么干净:请求连机器都没碰到。要判断断点在哪一层,先把这两类表现分开看就够了。
三、排查:先解析,再放行,然后监听与文件
这次排查按四层顺序走下来,前一层没有排除之前,后一层的配置没有动。
第一层:解析
把 A 记录指向的地址和实例的公网地址比一遍,这一步一条命令就够。
dig +short A blog.example.com
返回的地址与实例一致,解析这一层可以排除。
第二层:放行
控制台的入方向规则当时只有一条,端口 22。
80 与 443 都没有单独的条目,而这两条正是站点要用的。放行条目是按端口逐条写的,缺哪一条,对应的协议就不通。
第三层:监听
确认进程状态与端口占用,两条命令的分工不一样。
ss -lntp | grep -E ':80|:443'
curl -I http://blog.example.com
ss 看的是本机监听状态,curl -I 只取响应头,用来区分连不上与返回错误码。
第一条命令列出了 nginx 的监听记录,进程本身是正常的。
第二条命令仍然超时。这一组结果把范围收窄到了入口规则上。
监听正常而入口不通,落点就在放行这一层。补上 80 的放行条目之后,首页有了响应,返回码是 403。
403 是服务器收到了请求并明确拒绝,和超时不是一回事。
第四层:文件
这时候要看的位置换成了错误日志,它在 /var/log/nginx/error.log,取末尾五十行就够。最新一次的失败就落在最后几行。
日志里留下的原话是 Permission denied,指向站点目录里的那个索引文件。
据 nginx 官方文档的 error_log 指令说明页,这个日志默认记录 error 级别及更严重的失败。权限类的问题一定会落在里面。
四、根因:两个都出在默认状态上
两个根因都落在默认状态上:入方向规则只放行了 SSH 端口,站点路径上少了一级目录的执行位。
那条规则是照部署笔记配的,笔记写到远程登录这一步就结束了。80 与 443 没有放行条目,站点的请求全部被丢在实例外面。
另一个根因在文件路径上:站点路径里有一级目录对其他人没有执行位。
目录的执行位决定能不能穿过这一级目录,与目录里文件的可读位是两件事。少了这一位,路径就断在中间那一级。
站点放在某个用户的家目录下面,家目录的权限被收紧到了 750。
nginx 的工作进程以 www-data 身份运行,不是这个目录的所有者。穿过这一级目录时被拒绝,403 就是这样来的。
403 配上 Permission denied 这一组,指向的是目录权限这一层。

五、方案:改完之后用两条命令确认
改动只有两处,一处是在控制台里补入方向规则,一处是把站点路径上的执行位补齐。
入方向补上 80 与 443 两条规则,保存之后首页立刻能打开。规则对新连接即时生效,不需要重启实例。
目录这一处不用把权限放到所有人可读,只要把路径上的执行位补齐。
chmod o+x /home/deploy
确认效果比反复刷新浏览器可靠,返回码和日志各看一次。
返回码是 200,并且错误日志不再新增 Permission denied,这两层就算通了。
HTTPS 放在 HTTP 通之后再动。证书签发的验证走 80 端口,这一环没有问题。
浏览器打开 https 仍然超时,原因还在入方向:443 那一条这时候漏了。这一步的报错和证书无关,浏览器连握手的机会都没有。
先跑通 HTTP 再补 443,这个次序能少一次把问题归到证书上的误判。
六、复盘:不通的表现只有两种
复盘的时候把两个根因放到一起看,性质是一样的,都是默认状态没有被显式打开。
入方向的默认是收紧,只有写进规则的端口才通过。新建目录的默认权限是 755,一旦被收紧过,路径上的执行位就要单独去看。
这两种情况的共同点是不报错,只表现为打不开。
判断顺序可以固定成四步。先核对解析,再看放行,接着看监听,最后落到文件上。
前一层的现象没有消失之前,改后一层的配置只会多出可变量。
个人博客这类结构简单的站点,出问题的位置本来就不多。把这个顺序固定下来,比任何排查技巧都省时间。
判断一次排查看没看对,标准是两条:能不能说出请求停在哪一层;改动之后有没有一条可复核的返回码。
两条都有,问题就不在猜的范围里了。
七、常见问题
三个问题都落在配置位置这一层上。答案与博客程序本身无关。
首页能打开,内页返回 404 该怎么定位? 先看站点根目录指向的是输出目录还是它的上一级。路径差一级时,首页常因为索引文件命中而正常,内页会全部 404。
换域名之后要改哪些位置? A 记录改到新域名,nginx 配置里的 server_name 跟着改,证书按新域名重新签发一次。
一台实例上放两个博客怎么分? 用两个 server 块按 server_name 区分,各自指定自己的 root 目录,端口共用 80 与 443。
