Docker Nginx本地请求被识别为子网IP的原因排查
问题解答:本地请求被Nginx识别为Docker网络网关IP的原因
背景与场景
- 已查阅《Restrict access by IP in docker nginx container》《Restricting access to a Docker container》等相关问题
- 本地部署15个Laravel微服务,每个配独立Nginx容器,核心需求:
- 所有Nginx容器之间可互联互通
- 仅接受来自其他容器的请求(仅指定API网关可接受任意IP请求)
- 创建自定义Docker网络:
docker network create --subnet 120.120.130.0/26 common_network
现有配置
Nginx容器docker-compose片段
foodlist_nginx: build: context: ./dockerfiles dockerfile: nginx.Dockerfile container_name: nginx image: nginx restart: unless-stopped tty: true ports: - "${MICROSERVICE_A_NGINX_PORT}:80" networks: common_network: ipv4_address: 120.120.130.x volumes: - .:/var/www/html
注:ipv4_address中的x取值范围为3-62
Nginx default.conf配置
location / { try_files $uri $uri/ /index.php?$query_string; allow 120.120.130.0/26; deny all; }
问题现象
通过localhost:port从本地电脑向Nginx容器发送请求时,请求被正常接受,且Nginx将本地电脑的IP识别为120.120.130.1
更新:完整docker-compose文件
version: '3' networks: common_network: external: true foodlist_network: name: foodlist_network driver: bridge services: foodlist_php: build: context: ./dockerfiles dockerfile: php8.1.Dockerfile container_name: "foodlist_php" image: foodlist_php restart: unless-stopped tty: true networks: - foodlist_network volumes: - .:/var/www/html ports: - "${FOOD_LIST_PHP_PORT}:9000" foodlist_redis: image: redis:latest container_name: "foodlist_redis" command: redis-server --appendonly yes restart: unless-stopped volumes: - redisdata:/dataF ports: - "${FOOD_LIST_REDIS_PORT}:6379" networks: - foodlist_network foodlist_nginx: build: context: ./dockerfiles dockerfile: nginx.Dockerfile container_name: foodlist_nginx image: foodlist_nginx restart: unless-stopped tty: true ports: - "${FOOD_LIST_NGINX_PORT}:80" networks: foodlist_network: common_network: ipv4_address: 120.120.130.6 volumes: - .:/var/www/html depends_on: - foodlist_php foodlist_mysql: image: mysql:8.0.0 container_name: foodlist_mysql restart: unless-stopped tty: true volumes: - mysqldata:/var/lib/mysql ports: - "${FOOD_LIST_MYSQL_PORT}:3306" environment: MYSQL_USER: ${DB_USERNAME} MYSQL_PASSWORD: ${DB_PASSWORD} MYSQL_DATABASE: ${DB_DATABASE} MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} MYSQL_ROOT_HOST: '%' SERVICE_TAGS: "foodlist" command: ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] networks: - foodlist_network volumes: mysqldata: driver: local redisdata: driver: local
原因分析
- Docker端口映射的NAT机制:当你通过
localhost:port访问容器时,请求先经过宿主机的端口转发。Docker会通过NAT(网络地址转换)将宿主机的请求转发到容器内部,此时容器接收到的源IP是common_network子网的默认网关IP——也就是120.120.130.1,这个IP属于你配置的120.120.130.0/26网段,因此被Nginx的allow规则放行。 - 多网络连接的流量路径:你的Nginx容器同时连接了
common_network和foodlist_network,但端口映射是绑定到宿主机所有网卡的。本地请求通过端口映射进入容器时,流量会走Docker网关的转发路径,容器自然将网关IP识别为请求来源。
可选解决方案
如果需要阻止本地请求,可调整Nginx的访问规则:
- 直接拒绝网关IP:在
allow规则后添加deny 120.120.130.1; - 仅允许容器IP段(排除网关):比如根据你的容器IP范围设置
allow 120.120.130.3/32;(或多个容器IP),再执行deny all;
内容的提问来源于stack exchange,提问作者M a m a D
相关产品推荐
相关产品推荐

