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

Docker Compose配置疑问:仅暴露指定容器端口,阻止其他端口被主机访问

问题分析与解决方案

你遇到的问题核心是对Docker网络模型和expose指令的作用理解有一点偏差,咱们一步步拆解:

1. 先澄清expose和ports的真实作用

你查到的定义基本没错,但有个关键细节被忽略了:

  • ports:主动将容器端口映射到主机的网卡接口(包括主机的本地IP和公网IP),允许外部设备(非Docker网络内的设备)通过主机IP访问容器服务。
  • expose:这本质上是一个文档性的声明,主要作用是告诉其他开发者这个容器服务使用了哪个端口,同时Docker Compose会自动将这些端口信息注入到关联服务的环境变量中(比如APP_PORT_8080_TCP)。它完全不具备网络访问控制的能力——容器的端口是否能被访问,取决于服务的监听地址和网络的连通性。

2. 为什么主机能访问10.0.0.7:8080?

你的custom-net是一个普通的Docker Bridge网络,这种网络的特性是:

  • 主机和容器之间是直接连通的,Docker会自动在主机上配置路由规则,让主机可以直接访问容器的IP。
  • 你的app容器内的服务应该是监听在0.0.0.0:8080(这是大多数应用的默认配置),而不是仅监听容器内部的127.0.0.1。这意味着只要能连通容器IP,就能访问这个端口——而主机刚好能连通10.0.0.7,所以扫描会显示端口开放。

3. 实现需求的解决方案:隔离容器网络

要实现「仅让web_server能访问app的8080端口,主机无法访问」,最优雅的方式是使用内部专用网络:

修改后的docker-compose.yml

version: "3.9"
services:
  app:
    image: sandbox/app
    container_name: app
    volumes:
      - ./src/app:/app/
    restart: unless-stopped
    networks:
      - internal-net  # 仅加入内部专用网络
  web_server:
    image: nginx:latest
    container_name: proxy
    ports:
      - "80:80"
    networks:
      - internal-net  # 和app服务通信
      - external-net  # 对外提供web服务
networks:
  internal-net:
    internal: true  # 标记为内部网络,主机无法直接访问其中的容器
    driver: bridge
  external-net:
    driver: bridge

配置说明

  • internal-net设置了internal: true,这个网络内的容器只能和同网络的容器通信,主机无法直接访问这些容器的IP和端口,彻底隔离了主机对app服务的访问。
  • web_server同时加入两个网络:通过internal-net以服务名(app:8080)访问app的8080端口,通过external-net对外暴露80端口给主机和外部设备。
  • 不需要给容器指定固定IP,Docker会自动分配网络内的IP,且服务名访问更稳定可靠。

这样调整后,你再用nmap扫描主机,就只能看到web_server的80端口开放,app的8080端口会完全不可达。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 19:52:33