Implement Docker network security with custom bridge networks and container isolation

Intermediate 25 min Jun 08, 2026 355 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Secure your Docker deployments by creating isolated custom bridge networks, implementing container segmentation, and configuring network access controls to prevent unauthorized communication between containers.

Prerequisites

  • Docker installed
  • Root or sudo access
  • Basic networking knowledge
  • Understanding of container concepts

What this solves

Docker's default bridge network allows all containers to communicate freely, creating security risks in multi-application environments. Custom bridge networks provide container isolation, network segmentation, and granular access controls to prevent data breaches and lateral movement attacks.

Docker network fundamentals and security risks

Docker's default networking model creates several security vulnerabilities. The default bridge network assigns containers to a shared subnet where they can communicate without restrictions. This means a compromised web application container could access your database container directly.

Custom bridge networks solve this by creating isolated network segments. Each network operates independently with its own subnet, and containers can only communicate within their assigned network unless explicitly configured otherwise.

Key security benefits: Network isolation prevents container-to-container attacks, reduces attack surface, and enables zero-trust networking principles in containerized environments.

Step-by-step implementation

Install Docker and verify network capabilities

First, ensure Docker is installed and check the current network configuration.

sudo apt update
sudo apt install -y docker.io docker-compose
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
sudo dnf install -y docker docker-compose
sudo systemctl enable --now docker
sudo usermod -aG docker $USER

Log out and back in for group changes to take effect, then verify Docker networks:

docker network ls
docker network inspect bridge

Create isolated custom bridge networks

Create separate networks for different application tiers. This example creates networks for web, application, and database layers.

# Create frontend network for web servers
docker network create --driver bridge \
  --subnet=172.20.1.0/24 \
  --gateway=172.20.1.1 \
  --opt com.docker.network.bridge.name=web-bridge \
  frontend-net

# Create backend network for application servers
docker network create --driver bridge \
  --subnet=172.20.2.0/24 \
  --gateway=172.20.2.1 \
  --opt com.docker.network.bridge.name=app-bridge \
  backend-net

# Create database network for data tier
docker network create --driver bridge \
  --subnet=172.20.3.0/24 \
  --gateway=172.20.3.1 \
  --opt com.docker.network.bridge.name=db-bridge \
  --opt com.docker.network.bridge.enable_icc=false \
  database-net

Configure network access policies with iptables

Implement firewall rules to control traffic between network segments. These rules prevent unauthorized cross-network communication.

# Block inter-container communication on database network
sudo iptables -I DOCKER-USER -i db-bridge -o db-bridge -j DROP

# Allow only backend network to access database network
sudo iptables -I DOCKER-USER -s 172.20.2.0/24 -d 172.20.3.0/24 -j ACCEPT

# Allow only frontend to access backend on specific ports
sudo iptables -I DOCKER-USER -s 172.20.1.0/24 -d 172.20.2.0/24 -p tcp --dport 8080 -j ACCEPT

# Block direct frontend to database access
sudo iptables -I DOCKER-USER -s 172.20.1.0/24 -d 172.20.3.0/24 -j DROP

# Save iptables rules
sudo iptables-save > /etc/iptables/rules.v4

Create network policy enforcement script

Automate network security policy application with a reusable script.

#!/bin/bash

# Docker Network Security Policy Script
set -euo pipefail

echo "Applying Docker network security policies..."

# Function to check if rule exists
rule_exists() {
    iptables -C DOCKER-USER "$@" 2>/dev/null
}

# Function to add rule if it doesn't exist
add_rule_if_not_exists() {
    if ! rule_exists "$@"; then
        iptables -I DOCKER-USER "$@"
        echo "Added rule: $@"
    else
        echo "Rule already exists: $@"
    fi
}

# Database network isolation
add_rule_if_not_exists -i db-bridge -o db-bridge -j DROP
add_rule_if_not_exists -s 172.20.2.0/24 -d 172.20.3.0/24 -j ACCEPT

# Frontend to backend communication (port 8080 only)
add_rule_if_not_exists -s 172.20.1.0/24 -d 172.20.2.0/24 -p tcp --dport 8080 -j ACCEPT

# Block direct frontend to database
add_rule_if_not_exists -s 172.20.1.0/24 -d 172.20.3.0/24 -j DROP

# Allow container health checks
add_rule_if_not_exists -p icmp --icmp-type echo-request -j ACCEPT

echo "Network security policies applied successfully"

# Log current rules for audit
iptables -L DOCKER-USER -n --line-numbers > /var/log/docker-network-rules.log
echo "Rules logged to /var/log/docker-network-rules.log"
sudo chmod +x /opt/docker-network-security.sh
sudo /opt/docker-network-security.sh

Deploy containers to isolated networks

Launch containers in their designated network segments to test isolation.

version: '3.8'

services:
  web:
    image: nginx:alpine
    container_name: frontend-web
    networks:
      - frontend-net
    ports:
      - "80:80"
    environment:
      - NGINX_ENVSUBST_OUTPUT_DIR=/etc/nginx/conf.d
    restart: unless-stopped

  app:
    image: node:alpine
    container_name: backend-app
    networks:
      - frontend-net
      - backend-net
    ports:
      - "8080:8080"
    working_dir: /app
    command: sh -c "echo 'const express = require(\"express\"); const app = express(); app.get(\"/health\", (req, res) => res.json({status: \"healthy\"})); app.listen(8080);' > server.js && npm init -y && npm install express && node server.js"
    restart: unless-stopped

  database:
    image: postgres:alpine
    container_name: backend-db
    networks:
      - database-net
      - backend-net
    environment:
      - POSTGRES_DB=appdb
      - POSTGRES_USER=appuser
      - POSTGRES_PASSWORD=securepassword123
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

networks:
  frontend-net:
    external: true
  backend-net:
    external: true
  database-net:
    external: true

volumes:
  postgres_data:
docker-compose up -d

Configure container-level security policies

Add additional security constraints using Docker's built-in security options.

version: '3.8'

services:
  secure-web:
    image: nginx:alpine
    container_name: secure-frontend
    networks:
      - frontend-net
    security_opt:
      - no-new-privileges:true
      - apparmor:docker-default
    cap_drop:
      - ALL
    cap_add:
      - CHOWN
      - SETGID
      - SETUID
    read_only: true
    tmpfs:
      - /tmp:size=100M,noexec,nosuid,nodev
      - /var/cache/nginx:size=50M,noexec,nosuid,nodev
      - /var/run:size=10M,noexec,nosuid,nodev
    user: "101:101"
    restart: unless-stopped

  secure-app:
    image: node:alpine
    container_name: secure-backend
    networks:
      - backend-net
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - SETGID
      - SETUID
    user: "1001:1001"
    restart: unless-stopped

networks:
  frontend-net:
    external: true
  backend-net:
    external: true

Set up network monitoring and audit logging

Configure logging to monitor network traffic and detect security violations.

# Docker network security logging
:msg, contains, "DOCKER-USER" /var/log/docker-network-security.log
& stop
sudo systemctl restart rsyslog

# Add logging to iptables rules
sudo iptables -I DOCKER-USER -s 172.20.1.0/24 -d 172.20.3.0/24 -j LOG --log-prefix "DOCKER-SECURITY-VIOLATION: "
sudo iptables -I DOCKER-USER -s 172.20.1.0/24 -d 172.20.3.0/24 -j DROP

Create network security monitoring script

Implement automated monitoring to detect and alert on security policy violations.

#!/bin/bash

# Docker Network Security Monitor
SECURITY_LOG="/var/log/docker-network-security.log"
ALERT_EMAIL="admin@example.com"
LOGFILE="/var/log/docker-security-monitor.log"

log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOGFILE"
}

check_violations() {
    local violations
    violations=$(grep -c "DOCKER-SECURITY-VIOLATION" "$SECURITY_LOG" 2>/dev/null || echo 0)
    
    if [ "$violations" -gt 0 ]; then
        log_message "ALERT: $violations network security violations detected"
        
        # Get recent violations
        tail -n 20 "$SECURITY_LOG" | grep "DOCKER-SECURITY-VIOLATION" > /tmp/recent_violations.txt
        
        # Send alert email if mail is configured
        if command -v mail >/dev/null 2>&1; then
            mail -s "Docker Network Security Alert" "$ALERT_EMAIL" < /tmp/recent_violations.txt
        fi
        
        return 1
    fi
    return 0
}

check_network_health() {
    local networks
    networks=("frontend-net" "backend-net" "database-net")
    
    for network in "${networks[@]}"; do
        if ! docker network inspect "$network" >/dev/null 2>&1; then
            log_message "ERROR: Network $network is missing"
            return 1
        fi
    done
    
    log_message "All networks are healthy"
    return 0
}

# Main monitoring loop
log_message "Starting Docker network security monitoring"

while true; do
    check_violations
    check_network_health
    
    # Check every 5 minutes
    sleep 300
done
sudo chmod +x /opt/monitor-docker-security.sh

# Create systemd service for monitoring
sudo tee /etc/systemd/system/docker-security-monitor.service > /dev/null << 'EOF'
[Unit]
Description=Docker Network Security Monitor
After=docker.service
Requires=docker.service

[Service]
Type=simple
ExecStart=/opt/monitor-docker-security.sh
Restart=always
RestartSec=30
User=root

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now docker-security-monitor

Monitor and audit network security

Set up Prometheus monitoring integration

Configure metrics collection for network security monitoring using Docker's built-in metrics and custom exporters.

version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: docker-prometheus
    networks:
      - monitoring-net
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.enable-lifecycle'
    restart: unless-stopped

  node-exporter:
    image: prom/node-exporter:latest
    container_name: docker-node-exporter
    networks:
      - monitoring-net
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    restart: unless-stopped

networks:
  monitoring-net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.4.0/24

volumes:
  prometheus_data:
global:
  scrape_interval: 30s
  evaluation_interval: 30s

scrape_configs:
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']
    metrics_path: /metrics
    scrape_interval: 30s
    
  - job_name: 'docker-security'
    static_configs:
      - targets: ['host.docker.internal:9323']
    metrics_path: /metrics
# Create monitoring network
docker network create --driver bridge --subnet=172.20.4.0/24 monitoring-net

# Deploy monitoring stack
docker-compose -f docker-monitoring.yml up -d

For more advanced monitoring setups, check out our guide on monitoring Docker containers with Prometheus and Grafana.

Verify your setup

Test network isolation and security policies to ensure proper configuration.

# Check network isolation
docker exec frontend-web ping -c 3 backend-db
# Should fail - no route to database network

# Test allowed communication
docker exec frontend-web curl -f http://backend-app:8080/health
# Should succeed - frontend can reach backend

# Verify iptables rules
sudo iptables -L DOCKER-USER -n --line-numbers

# Check security violations log
sudo tail -f /var/log/docker-network-security.log

# Verify network configuration
docker network ls
docker network inspect frontend-net backend-net database-net

# Check container security settings
docker inspect secure-frontend | grep -A 10 "SecurityOpt"

# Monitor network traffic
sudo netstat -i
sudo ss -tulpn | grep docker
Testing tip: Use docker exec -it container_name /bin/sh to get shell access and test network connectivity between containers manually.

Common issues

Symptom Cause Fix
Containers can't communicate Not on same network Add container to required network with docker network connect
iptables rules not applied Docker daemon restart cleared rules Add rules to startup script or use iptables-persistent
Network creation fails Subnet conflict with existing networks Choose different subnet range with docker network ls
Container health checks fail ICMP blocked by iptables Add rule: iptables -I DOCKER-USER -p icmp -j ACCEPT
Web app can't reach database App container not on backend network Connect to both frontend and backend networks
Security violations not logged Rsyslog not configured Restart rsyslog: sudo systemctl restart rsyslog
Never use --network=host in production. This bypasses all Docker networking security and exposes containers directly to the host network, eliminating isolation benefits.

Advanced security configurations

For production environments, consider implementing additional security layers:

  • Use Docker Secrets for sensitive data instead of environment variables
  • Implement container runtime security with Falco for threat detection
  • Configure image security scanning with vulnerability assessment tools
  • Set up network policies in Kubernetes for orchestrated environments
  • Implement zero-trust networking with service mesh technologies

For Kubernetes environments, explore implementing Kubernetes network policies for similar security benefits at the orchestration layer.

Next steps

Running this in production?

Want this handled for you? Setting this up once is straightforward. Keeping it patched, monitored, backed up and performant across environments is the harder part. See how we run infrastructure like this for European teams.

Automated install script

Run this to automate the entire setup

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. Fully managed, with one fixed contact who knows your setup.

You get one fixed contact who knows your setup

Rotterdam 07:30 · reachable in a message, no ticket form