编码代理与终端 · 收录于 2026-08-29 · 适用 1 工具 ✓ 实测验证

docker run / compose up 报 port is already allocated / address already in use(端口被占用)

已验证 2026-08-29端口已占用——先 docker ps 看是不是容器占的,再看 ss -tlnp 宿主机进程,最后换端口。

快速修复

# 一键:先看是不是 docker 容器占的,再看宿主机进程,最后换端口
docker ps | grep <端口> ; ss -tlnp | grep <端口>

你会遇到什么

docker run -p <宿主端口>:<容器端口> 或 docker compose up 时容器创建失败,报 failed to bind host port 0.0.0.0:8080/tcp: address already in use 或 Bind for :::8090 failed: port is already allocated。

同一个 -p 命令之前能跑通,某天突然报错——宿主端口被占了。

本文路径:快速修复(30 秒一段命令)→ 一步步排查(可跳读)→ 原理与变体(症状/原因/证据)。赶时间直接跳到「快速修复」。

为什么会这样

-p 宿主端口:容器端口 会在宿主机上创建端口转发监听(docker-proxy 监听 0.0.0.0:宿主端口)。宿主端口同一时间只能被一个进程/容器占用。两大类占用来源:

占用来源例子
宿主机其它进程python http.server、nginx、VSCode 端口转发
其它 docker 容器另一个容器映射同一宿主端口(compose 两个服务撞端口、旧容器没删干净)

-p 宿主端口:容器端口 会在宿主机创建一个转发监听(docker-proxy 监听 0.0.0.0:宿主端口),语义是「宿主端口 → 容器端口」的映射。宿主端口是宿主机全局资源,同一时间只能有一个监听者——不管占用者是宿主进程还是另一个容器的转发规则。

确定性推论:报 port is already allocated 先 ss -lntp | grep <端口> 看监听者是谁;监听进程是 docker-proxy = 另一个容器占着,docker ps -a 找旧容器——已退出的容器保留端口映射,docker ps 看不到不代表端口空闲;监听者是宿主进程 = 换端口或停进程。

一步步来

1. 先看是不是 docker 容器占的 — 必做

docker ps

看 Ports 列有没有该端口。有就 docker rm -f <旧容器>(或 stop + rm),确认没有别的服务需要它再删。

2. 再看宿主机进程 — 必做

ss -tlnp | grep <端口>

(或 lsof -i:<端口> / netstat -tulpn | grep <端口>)看到 PID/进程名就能定位是谁占的——是临时进程就停掉,是长期服务就换端口。

3. 换宿主端口(最省事) — 必做

docker run -p 8081:80 <镜像>

compose 里改 ports: 左侧的宿主端口(如 "8081:80"),或写成环境变量统一管理(${LOBE_PORT}:3210 这类)。

4. 排查 compose 内部冲突 — 排查

同一个 compose 文件里两个服务映射同一宿主端口会互相打架,逐个检查 ports: 左侧值是否唯一。

怎么确认修好了

换端口后正常(实测输出形态):

docker run -p 8081:80 → 成功
docker port <容器> → 80/tcp -> 0.0.0.0:8081

其它环境的表现

环境说明
宿主进程占用ss -tlnp 定位 PID,停进程或换端口(实测链 A)
容器占用docker ps Ports 列定位,rm -f 旧容器(实测链 B)
compose 内部ports 左侧值唯一
IPv6 侧Bind for :::8090 failed = 容器占用形态(实测)

症状

docker run -p <宿主端口>:<容器端口> 或 docker compose up 时容器创建失败,两种典型报错:

# 形态 1:宿主上其它进程占了端口
docker: Error response from daemon: failed to set up container networking:
driver failed programming external connectivity on endpoint <name>:
failed to bind host port 0.0.0.0:8080/tcp: address already in use

# 形态 2:另一个 docker 容器占了端口(常报 IPv6 侧)
docker: Error response from daemon: failed to set up container networking:
driver failed programming external connectivity on endpoint <name>:
Bind for :::8090 failed: port is already allocated

特征:报错里一定带 port is already allocated 或 address already in use,且明确指向宿主端口(0.0.0.0:PORT / :::PORT);同一个 -p 命令之前能跑通,某天突然报错;或照教程/别人的 compose 起服务时报错(端口撞车)。

原因

-p 宿主端口:容器端口 会在宿主机上创建一个端口转发监听(docker-proxy 监听 0.0.0.0:宿主端口)。宿主端口同一时间只能被一个进程/容器占用,被占就报上面的错。两大类占用来源:

  1. 宿主机其它进程:你/系统/别的服务(如 python http.server、nginx、VSCode 端口转发)占着该端口——最常见;
  2. 其它 docker 容器:另一个容器的 -p 映射了同一宿主端口(含 compose 里两个服务映射同一端口、或旧容器没删干净)。

解法

  1. 先看是不是 docker 容器占的:docker ps(看 Ports 列有没有该端口)。有就 docker rm -f <旧容器>(或 docker stop + docker rm),确认没有别的服务需要它再删。
  2. 再看宿主机进程:ss -tlnp | grep <端口>(或 lsof -i:<端口> / netstat -tulpn | grep <端口>),看到 PID/进程名就能定位是谁占的——是临时进程就停掉,是长期服务就换端口。
  3. 换宿主端口(最省事):-p 8081:80 换成没被占的端口;compose 里改 ports: 左侧的宿主端口(如 "8081:80"),或把端口写成环境变量统一管理(${LOBE_PORT}:3210 这类)。
  4. 排查 compose 内部冲突:同一个 compose 文件里两个服务映射同一宿主端口会互相打架,逐个服务检查 ports: 左侧值是否唯一。
验证证据
  • 本地实测(2026-08-29,WSL Ubuntu,docker 29.1.3,alpine:3.20):
  • 链 A(宿主进程占用):python3 http.server 占 8080 → docker run -p 8080:80 → failed to bind host port 0.0.0.0:8080/tcp: address already in use(exit 125);ss -tlnp 定位到 python3 进程(pid 可见);停掉后换 -p 8081:80 → 成功,docker port 显示 80/tcp -> 0.0.0.0:8081,docker-proxy 监听 0.0.0.0:8081 与 [::]:8081;
  • 链 B(容器占用):容器 1 -p 8090:80 成功 → 容器 2 抢同一端口 → Bind for :::8090 failed: port is already allocated(exit 125);docker ps Ports 列定位到旧容器;docker rm -f 旧容器后同一端口再起成功。
  • 实测复现日志(2026-08-29)

相关 canonical

按「前置 → 同根 / 同域 / 相关」读:

适用工具 (1)

本问题方案已挂到下列工具的方案页——从工具页也能回到这里,双向可达。

docker · 外部工具

成套方案 (组合包)

这个问题包含在下列成套安装方案中。

来源与证据

收录 验证 ✓ 实测验证适用 1 工具
方案含本地实测或来源可复核的解法;未实测项已在文中如实标注。

素材来源:https://github.com/lobehub/lobehub/issues/5700

← 编码代理与终端 问题域 | 问题货架 | 遇到其它问题?去 问题空间 提交求助卡