You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu+Docker环境下ufw无法拦截容器端口流量的问题排查

问题描述

我有一台运行Ubuntu 20的服务器,已安装Docker并运行多个容器。其中名为reverseproxy的Nginx容器负责接收80、443端口的流量,并将其路由至其他容器,该功能运行正常。现在我希望通过ufw拦截除80、443及SSH(22端口)外的所有入站流量,但发现容器发布的3000、3001、8081、15672端口仍能被外部访问。请问这是什么原因?如何通过ufw实现全流量拦截?

当前ufw配置

www@broowqh:~$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
9000                       ALLOW IN    Anywhere
3001                       DENY IN     Anywhere
3001/tcp                   DENY IN     Anywhere
3001/udp                   DENY IN     Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)
9000 (v6)                  ALLOW IN    Anywhere (v6)
3001 (v6)                  DENY IN     Anywhere (v6)
3001/tcp (v6)              DENY IN     Anywhere (v6)
3001/udp (v6)              DENY IN     Anywhere (v6)

Docker容器状态

CONTAINER ID   IMAGE                               COMMAND                  CREATED        STATUS         PORTS                                                                     NAMES
48709042d67f   nginx:1.23-alpine                   "/docker-entrypoint.…"   10 hours ago   Up 10 hours.   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp. reverseproxy
401d6576b3e0   adminer:4.8.1                       "entrypoint.sh docke…"   10 hours ago   Up 10 hours.   0.0.0.0:8081->8080/tcp, :::8081->8080/tcp                                 adminer
c47966cae717   postgres:14.1-alpine                "docker-entrypoint.s…"   10 hours ago   Up 10 hours.   5432/tcp                                                                  db                                                                                                                                                    
1c3709a07fb0   www:current                         "docker-entrypoint.s…"   15 hours ago   Up 10 hours.   0.0.0.0:3001->3001/tcp, :::3001->3001/tcp                                 www
db252e2833bc   postgrest/postgrest:v10.0.0         "/bin/postgrest"         18 hours ago   Up 10 hours.   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp                                 api
68396bebcaa8   rabbitmq:3.9.13-management-alpine   "docker-entrypoint.s…"   19 hours ago   Up 10 hours.   0.0.0.0:5672->5672/tcp, 0.0.0.0:15672->15672/tcp                          broker

Nginx反向代理配置

upstream www {
    server www:3001;
}

upstream api {
    server api:3000;
}

upstream adminer {
    server adminer:8080;
}

upstream rabbit {
    server broker:15672;
}

server {
    listen 80;
    listen [::]:80;

    server_name example.com

    location / {
        return 301 https://example.com$request_uri;
    }
}

server {
    listen 443 default_server ssl http2;
    listen [::]:443 ssl http2;

    server_name example.com;

    ssl_certificate /etc/nginx/ssl/live/smartplaylist.me/example.crt;
    ssl_certificate_key /etc/nginx/ssl/live/smartplaylist.me/example.key;

    location /adminer/ {
        proxy_pass http://adminer/;
    }

    location /rabbit/ {
        proxy_pass http://rabbit/;
    }

    location /api/ {
        proxy_pass http://api/;
    }

    location / {
        proxy_pass http://www/;
    }
}
原因分析

Docker在启动容器并进行端口映射(0.0.0.0:端口->容器端口)时,会直接修改系统的iptables规则,添加允许这些端口入站流量的规则,且这些规则优先级高于ufw规则。这导致即使在ufw中配置了拒绝规则,外部仍能访问这些端口——iptables会先处理Docker添加的规则,直接放行流量。

另外,从容器状态可见,除reverseproxy外,adminer、www、api、broker都直接将端口映射到主机的0.0.0.0地址,等于直接向外部暴露端口,完全绕开了Nginx反向代理的设计。

解决方案

步骤1:移除不必要的容器端口映射

既然已通过Nginx反向代理路由所有外部流量,其他容器无需向主机暴露端口——Docker容器可通过内部网络直接通信(只需处于同一个Docker网络)。

  1. 停止并删除现有容器(注意备份postgres等容器的关键数据):
docker stop adminer www api broker db
docker rm adminer www api broker db
  1. 创建Docker自定义网络,让所有容器加入实现内部通信:
docker network create app-network
  1. 重新启动容器,仅保留reverseproxy的80、443端口映射,其他容器不添加端口映射:
    • 启动postgres:
    docker run -d --name db --network app-network postgres:14.1-alpine
    
    • 启动adminer:
    docker run -d --name adminer --network app-network adminer:4.8.1
    
    • 启动www:
    docker run -d --name www --network app-network www:current
    
    • 启动api:
    docker run -d --name api --network app-network postgrest/postgrest:v10.0.0
    
    • 启动broker:
    docker run -d --name broker --network app-network rabbitmq:3.9.13-management-alpine
    
    • 将reverseproxy加入自定义网络(若未加入):
    docker stop reverseproxy
    docker network connect app-network reverseproxy
    docker start reverseproxy
    

步骤2:修复ufw配置

当前ufw配置中存在冗余规则,需清理并仅保留必要的允许规则:

  1. 删除不必要的规则:
sudo ufw delete allow 9000
sudo ufw delete deny 3001
sudo ufw delete deny 3001/tcp
sudo ufw delete deny 3001/udp
# 删除对应的IPv6规则
sudo ufw delete allow 9000 (v6)
sudo ufw delete deny 3001 (v6)
sudo ufw delete deny 3001/tcp (v6)
sudo ufw delete deny 3001/udp (v6)
  1. 添加80、443端口的允许规则:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
  1. 重新加载ufw:
sudo ufw reload

步骤3:配置Docker尊重ufw规则(可选)

若担心未来误映射端口导致暴露,可修改Docker配置,禁止其自动修改iptables规则:

  1. 编辑Docker守护进程配置文件:
sudo nano /etc/docker/daemon.json
  1. 添加以下内容:
{
  "iptables": false
}
  1. 重启Docker服务:
sudo systemctl restart docker

注:此设置会让Docker不再自动管理iptables规则,需确保所有容器均通过反向代理访问,不直接映射端口,或手动管理容器网络流量。


内容的提问来源于stack exchange,提问作者jkulak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 22:40:48