When running services in Docker containers, you'll often find that all incoming connections appear to originate from Docker's internal gateway IP (typically 172.17.0.1) rather than showing the actual client IP. This happens because Docker's NAT mechanism modifies the packet headers during port forwarding.
By default, Docker creates three network types:
1. Bridge network (docker0)
2. Host network
3. None network
The bridge network is where the IP masking occurs. When using -p 8080:8080
, Docker:
- Creates iptables rules for port forwarding
- Performs source NAT (SNAT) on incoming packets
- Routes traffic through the docker0 bridge
Solution 1: Use Host Networking (Not Recommended)
While --net=host
works, it eliminates container network isolation:
docker run --rm --net=host -p 8080:8080 your_image
Solution 2: Use PROXY Protocol
For HTTP services, configure your reverse proxy to pass the original IP:
Nginx example:
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://container_ip:port;
}
Solution 3: Docker MACVLAN Network
Create a dedicated network that bypasses NAT:
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
macvlan_net
docker run --network=macvlan_net --ip=192.168.1.100 your_image
Solution 4: Transparent Proxy with iptables
Preserve original IPs by modifying Docker's iptables rules:
iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
iptables -t nat -A DOCKER -i docker0 -j RETURN
- Check Docker's NAT rules:
iptables -t nat -L -n -v
- Inspect container networking:
docker inspect container_id | grep IPAddress
- Test connectivity from host:
curl --interface docker0 http://container_ip
When exposing real client IPs:
- Implement proper rate limiting
- Use Web Application Firewalls
- Consider IP whitelisting for sensitive endpoints
When running services in Docker containers, you'll often notice that incoming connections appear to originate from internal Docker network IPs (like 172.17.0.1) rather than the actual client IP addresses. This occurs because Docker's default networking mode uses NAT (Network Address Translation) for port forwarding.
In the default bridge network mode, Docker creates a virtual network where:
# Typical Docker network inspection
$ docker network inspect bridge
[
{
"Name": "bridge",
"IPAM": {
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
}
}
]
The Docker daemon acts as a middleman, receiving connections on the host's public interface and forwarding them to containers through this internal network.
1. Using PROXY Protocol
For TCP services, the PROXY protocol preserves original connection information:
# Nginx configuration example to accept PROXY protocol
server {
listen 8080 proxy_protocol;
real_ip_header proxy_protocol;
set_real_ip_from 172.17.0.0/16;
}
2. Configuring X-Forwarded-For Headers
For HTTP services, configure your reverse proxy to forward headers:
# Traefik example in docker-compose.yml
services:
reverse-proxy:
image: traefik
command:
- --entrypoints.web.address=:80
- --entrypoints.web.forwardedHeaders.insecure
3. IP Transparency with IPVS
For advanced setups, enable IPVS in Docker:
# Enable IPVS in Docker daemon.json
{
"ipv6": true,
"ip-forward": true,
"iptables": true,
"ip-masq": true,
"experimental": true,
"ipv6": true,
"ipvs": true
}
For Node.js Applications
// Middleware to check real IP
app.use((req, res, next) => {
const realIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
console.log('Client IP:', realIp);
next();
});
For Python Flask
from flask import request
@app.route('/')
def index():
client_ip = request.headers.get('X-Forwarded-For', request.remote_addr)
return f"Your IP is: {client_ip}"
Use these commands to inspect network traffic:
# Check Docker network routes
$ ip route show
$ iptables -t nat -L -n -v
# Monitor incoming connections
$ tcpdump -i eth0 port 8080 -nn -v
Remember to consider security implications when exposing client IP information. Always validate and sanitize IP addresses before using them in authentication or logging systems.