## 一、问题现象
在 Linux 服务器上部署网站时,如果某个端口已经被其他进程占用,通常会出现以下几种现象:
- 应用启动失败,提示 address already in use 或 EADDRINUSE - Nginx 反向代理到本地端口时返回 502 Bad Gateway - 浏览器访问网站时提示连接被拒绝 - PM2 显示应用不断重启,但始终无法正常对外提供服务 - 新旧服务切换时,旧进程没有完全释放端口,导致新服务无法接管
这种问题在 Node.js、Next.js、Python、Java、PHP-FPM、自定义后台服务部署中都非常常见。
## 二、最常见的原因
端口被占用,一般不是端口坏了,而是有进程正在使用它。常见原因有:
1. 上一次启动的网站进程没有正常退出 2. PM2、systemd、Supervisor 等进程管理工具重复拉起了服务 3. Nginx、Apache、Node.js 程序使用了相同端口 4. 部署脚本重复执行,造成多个实例同时存在 5. 测试程序跑在后台忘记关闭 6. 某些异常退出的进程仍然残留
## 三、先确认到底是哪个端口有问题
排查时,不要盲目 kill 进程,先确认被占用的是哪个端口。
常见网站端口包括:
- 80:HTTP - 443:HTTPS - 3000:Next.js / Node.js 常见开发或生产端口 - 8000:Python / 测试服务常见端口 - 8080:Java / Web 服务常见端口
如果你的程序报错里已经写明端口,比如 3000 或 8080,就直接查对应端口。
## 四、查看端口占用的 3 种常用方法
### 方法一:使用 lsof
```bash lsof -i :3000 ```
作用:查看 3000 端口被哪个进程占用。
典型输出会包含:COMMAND、PID、USER、NAME
如果你看到某个 node、nginx、python、java 进程在使用这个端口,就说明问题找到了。
### 方法二:使用 ss
```bash ss -ltnp | grep 3000 ```
作用:查看当前监听状态下的 TCP 端口及其对应进程。
这个命令在很多 Linux 服务器上都很好用,而且通常比 netstat 更常见。
### 方法三:使用 netstat
```bash netstat -ltnp | grep 3000 ```
如果系统中没有 netstat,可以安装 net-tools:
```bash sudo apt install net-tools -y ```
## 五、拿到 PID 后,不要急着杀
假设你查到输出类似这样:
``` node 118923 root 20u IPv6 ... TCP *:3000 (LISTEN) ```
这里最重要的是 PID,也就是 118923。
此时应该先进一步确认这个进程到底是什么:
```bash ps -fp 118923 ```
这个命令可以查看:
- 进程启动命令 - 启动用户 - 进程是否是你当前网站的一部分
如果它就是你的网站旧进程,那可以结束。 如果它是数据库、Nginx 或别的关键服务,就不能乱杀。
## 六、如何正确结束占用端口的进程
最稳妥的做法是先温和结束:
```bash kill 118923 ```
然后再查端口是否释放:
```bash lsof -i :3000 ```
如果进程还在,再强制结束:
```bash kill -9 118923 ```
注意:
- kill -9 虽然直接,但不适合乱用。 - 如果是数据库、消息队列、正在写文件的关键进程,强制 kill 可能造成数据问题。
## 七、如果是 PM2 管理的应用,不要只 kill 进程
如果你的网站是用 PM2 跑的,直接 kill 某个 PID 往往只是临时解决,因为 PM2 可能马上又把它拉起来。
这时应该先看 PM2 状态:
```bash pm2 status ```
再看具体日志:
```bash pm2 logs 应用名 --lines 50 ```
如果你确认是某个 PM2 应用占用了端口,可以先停掉:
```bash pm2 stop 应用名 ```
或者直接删除旧任务:
```bash pm2 delete 应用名 ```
之后再重新启动:
```bash pm2 start npm --name 你的应用名 -- run start ```
## 八、如果是 Nginx 占用 80 或 443 端口
如果你发现 80 或 443 端口被占用,通常是 Nginx 或 Apache。
查看:
```bash lsof -i :80 lsof -i :443 ```
如果是 Nginx:
```bash systemctl status nginx ```
重启 Nginx:
```bash sudo systemctl restart nginx ```
如果你本来就需要 Nginx 使用 80/443,那么这不是错误,而是正常现象。 你真正要避免的是:应用程序也试图直接抢占 80/443,和 Nginx 冲突。
正确做法通常是:
- Nginx 占用 80/443 - 应用跑在 3000、8080 等内部端口 - Nginx 反向代理到应用端口
## 九、端口释放后,如何再次确认服务正常
端口释放并重新启动应用后,建议按顺序检查:
1. **本机访问** ```bash curl http://127.0.0.1:3000 ```
2. **反向代理状态** ```bash systemctl status nginx ```
3. **PM2 状态** ```bash pm2 status ```
4. **网站最终访问结果** 浏览器打开域名或公网 IP 查看页面是否正常
如果本机 3000 可以返回 HTML,但域名访问失败,问题通常在 Nginx、SSL、域名解析或防火墙。 如果本机 3000 都打不开,说明问题还在应用本身。
## 十、如何避免端口占用问题再次发生
想要长期稳定,建议这样做:
- 每个服务固定端口,不要混用 - 用 PM2 或 systemd 管理进程,不要重复手动启动 - 每次发布前先检查旧进程是否已退出 - Nginx 只负责 80/443,应用只跑内部端口 - 部署脚本中加入端口检查步骤 - 发生异常重启时,优先查日志,不要反复强制启动
## 十一、我常用的一套排查顺序
如果我在线上遇到网站起不来、端口冲突、Nginx 代理失败这类问题,通常按这套顺序排查:
1. 第一步:确认报错端口 2. 第二步:用 lsof 或 ss 查占用者 3. 第三步:用 ps -fp 看进程来源 4. 第四步:判断它是不是旧服务残留 5. 第五步:如果是 PM2 管理,就先停 PM2 而不是直接硬杀 6. 第六步:释放端口后重启应用 7. 第七步:本机 curl 测试 8. 第八步:再检查 Nginx 和最终访问结果
这一套流程比上来就 kill -9 更稳,也更适合线上环境。
## 十二、总结
Linux 端口被占用,本质上是进程冲突问题,而不是网络本身坏了。 只要你能做到:
- 先查端口 - 再查进程 - 判断是否能结束 - 按服务架构重新启动 - 最后验证本机和外部访问
大多数网站启动失败、反向代理失败、连接被拒绝的问题,都能很快定位并解决。
如果你的网站正在部署中,建议把端口排查命令单独整理成一份常用清单,后面会非常省时间。
问题求助
没能解决你的问题?直接问我
如果你遇到任何技术问题无法解决,可以在这里提交求助。我会尽快查看并回复你。
支持作者
如果这篇文章帮到了你,可以支持我
扫码打赏,支持我持续更新原创排障文章。
