我见过不少 VPS 故障不是“服务挂了”,而是机器重启以后服务根本没自动起来。
最常见的场景是这样的:
- 商家维护,VPS 被重启了一次
- 自己升级内核,顺手
reboot - 机器卡住,后台点了强制重启
- Docker、Nginx、MySQL、Redis 这些服务里,总有一个没回来
人还在电脑前还好,SSH 登进去手动 systemctl start nginx 就能救回来。麻烦的是半夜自动重启,第二天才发现网站挂了一整晚。
这篇就按我自己排查的顺序来:先确认服务有没有起来,再看它有没有设置开机自启,最后查为什么自启失败。
重启后访问不了,不一定是同一个问题。
| 现象 | 更可能的问题 |
|---|---|
systemctl status 显示 inactive | 服务没设置开机自启,或者被 disable 了 |
| 显示 failed | 服务尝试启动了,但启动失败 |
| 服务 active,但网站打不开 | 端口、防火墙、Nginx 配置或上游服务有问题 |
| Docker 容器没起来 | 容器 restart policy 没设置,或 Docker 自己没起来 |
| 数据库没起来 | 配置错误、磁盘满、权限问题、上次异常退出 |
所以第一步不要凭感觉猜,先 SSH 上去看真实状态。
systemctl status nginx
systemctl status docker
systemctl status mysql
systemctl status redis
如果你的系统是 PostgreSQL 或 MariaDB,服务名可能是:
systemctl status postgresql
systemctl status mariadb
服务名不确定时可以搜一下:
systemctl list-units --type=service | grep -i nginx
systemctl list-units --type=service | grep -i mysql
很多人第一次部署服务时只做了这一步:
systemctl start nginx
这只是“现在启动”,不是“下次开机也启动”。
正确做法是:
systemctl enable nginx
systemctl enable docker
systemctl enable mysql
想确认有没有设置成功:
systemctl is-enabled nginx
systemctl is-enabled docker
systemctl is-enabled mysql
看到 enabled 才说明它会跟着系统启动。
如果输出是 disabled,那就解释得通了:你平时手动启动以后一直正常,一旦 VPS 重启,它就不会自己回来。
我自己现在部署完服务会顺手做一个小检查:
systemctl is-enabled nginx docker mysql
这条很简单,但能少踩很多坑。
如果 systemctl status 里看到的是 failed,就不是单纯没设自启了。
这时别只看最后一行,直接看完整日志:
journalctl -u nginx -b --no-pager
journalctl -u docker -b --no-pager
journalctl -u mysql -b --no-pager
这里的 -b 很有用,它只看本次启动以来的日志,不会把很久以前的错误混进来。
先测配置:
nginx -t
如果有问题,通常会直接告诉你哪一行错了。比如:
- 少了分号
server_name写错位置- 证书路径不存在
- 反向代理上游地址填错
修完以后再执行:
systemctl restart nginx
systemctl status nginx
MySQL / MariaDB 重启后起不来,我一般先看这几个:
df -h
journalctl -u mysql -b --no-pager
ls -ld /var/lib/mysql
如果磁盘满了,数据库很容易启动失败。之前我遇到过一次,真正的问题不是 MySQL 配置,而是日志把磁盘塞满了,数据库连写临时文件都写不了。
PostgreSQL 可以看:
journalctl -u postgresql -b --no-pager
systemctl status postgresql
不要看到数据库起不来就急着重装,先把日志里的第一条明确错误找出来。
Docker 是另一个重灾区。
很多人用 docker run 启动容器时没有加重启策略,容器当前能跑,但 VPS 重启以后不会自动回来。
先看容器状态:
docker ps -a
再看某个容器的重启策略:
docker inspect 容器名 --format '{{.HostConfig.RestartPolicy.Name}}'
如果输出是 no,那就不会自动重启。
常用修法:
docker update --restart unless-stopped 容器名
如果你用的是 Docker Compose,在 compose.yml 里加:
services:
app:
image: your-image
restart: unless-stopped
然后重新启动:
docker compose up -d
这里我更推荐 unless-stopped,而不是无脑 always。因为你手动停掉的容器,通常就是不希望它自己又偷偷起来。
这个也很常见。
systemctl status nginx 显示 active,不代表网站一定能访问。你还要看端口有没有监听:
ss -lntp
重点看:
:80:443- 应用自己的端口,比如
:3000、:8000、:8080
如果 Nginx 在,但后端应用没起来,访问时可能是 502。
这时按顺序看:
systemctl status nginx
systemctl status your-app
ss -lntp
curl -I http://127.0.0.1
如果本机能访问,外网不行,再看防火墙:
ufw status
iptables -S
云厂商还有一层安全组,也别忘了。很多人机器里配置都对,结果后台安全组没放 80/443,排查半天白忙。
有些服务手动启动没问题,但开机自动启动会失败,因为它启动得太早了。
比如:
- 应用比数据库先启动
- Nginx 比证书挂载目录先启动
- Docker 容器依赖的磁盘还没挂载
- 网络还没完全 ready,服务已经开始连外部接口
这类问题在 journalctl 里通常能看到“连接失败”“目录不存在”“端口不可用”之类的错误。
systemd 服务可以加依赖,比如:
[Unit]
After=network-online.target mysql.service
Wants=network-online.target
改完 unit 文件以后要执行:
systemctl daemon-reload
systemctl restart your-service
如果是 Docker Compose,可以用 depends_on,但要注意:depends_on 只能保证启动顺序,不等于保证数据库已经完全 ready。真正严谨的做法,是应用自己支持重试连接。
如果这台 VPS 上跑的是正式网站,我一般会做一次人工演练。
先确认服务都设置了自启:
systemctl is-enabled nginx docker mysql
然后重启:
reboot
等 1-2 分钟重新登录,检查:
systemctl --failed
systemctl status nginx docker mysql
ss -lntp
curl -I https://你的域名
如果是 Docker 项目,再看:
docker ps
这套检查不复杂,但很有用。因为真正出事时,你不一定刚好在线。
下次 VPS 重启后服务没恢复,可以按这个顺序来:
systemctl status 服务名:确认是 inactive、failed,还是 activesystemctl is-enabled 服务名:看有没有开机自启journalctl -u 服务名 -b --no-pager:看本次启动日志systemctl --failed:列出所有失败服务ss -lntp:确认端口有没有监听docker ps -a:如果用 Docker,看容器有没有起来df -h:数据库和日志相关问题先排磁盘curl -I http://127.0.0.1:区分本机服务问题和外网访问问题
别一上来就重装系统,也别只在面板里点重启。很多问题其实就是少了一个 enable,或者某个服务启动顺序不对。
真正要养成的习惯是:部署完以后主动重启演练一次。
能扛住一次人工重启的 VPS,才更有可能扛住半夜商家维护、内核升级、宿主迁移这些不可控情况。
