Docker and UFW: Firewall Configuration Guide
- Introduction
- Technical Explanation
- Solution Methods
- Method Comparison Table
- Scenario Recommendations
- Diagnostics and Debugging
- Security Checklist
- Useful Links
Version 1.6.9 | Updated: August 08, 2026
Introduction
Problem Description
When using Docker on Linux systems with UFW (Uncomplicated Firewall), a critical security issue arises: UFW rules do not apply to ports published by Docker. This means that even if you configure UFW to block all incoming traffic, Docker container ports remain open to the entire internet.
Why This Matters
Many administrators rely on UFW as the primary server protection mechanism. Without understanding Docker’s interaction with iptables, they may inadvertently leave critical services (databases, admin panels, internal APIs) accessible from outside.
Typical Vulnerability Scenario
-
Administrator configures UFW:
ufw default deny incoming
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
-
Starts a container with a database:
docker run -d -p 5432:5432 postgres
-
Expectation: PostgreSQL is only accessible locally
-
Reality: PostgreSQL is accessible from the internet on port 5432
Technical Explanation
iptables Architecture
Linux uses Netfilter/iptables for network traffic filtering. Packets pass through chains in a specific order:
INCOMING PACKET
|
v
PREROUTING
(NAT, destination change)
|
+----------+----------+
| |
For host? For forwarding?
v v
INPUT FORWARD
(UFW works (Docker rules
here) here)
| |
v v
Local POSTROUTING
processes (NAT for containers)
How Docker Manipulates iptables
When starting a container with the -p option, Docker automatically creates iptables rules.
1. DOCKER Chain in nat Table
# View NAT rules
iptables -t nat -L DOCKER -n -v
Example output:
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
15 780 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0
tcp dpt:5432 to:172.17.0.2:5432
2. DOCKER Chain in filter Table
# View filter rules
iptables -L DOCKER -n -v
Example output:
Chain DOCKER (1 references)
pkts bytes target prot opt in out source destination
12 624 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2
tcp dpt:5432
3. Rule Processing Order
Docker inserts a jump rule into the FORWARD chain:
iptables -L FORWARD -n -v
Chain FORWARD (policy DROP)
pkts bytes target prot opt in out source dest
245 15680 DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0
245 15680 DOCKER-ISOLATION-STAGE-1 all -- * * 0.0.0.0/0 0.0.0.0/0
125 7800 ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0
ctstate RELATED,ESTABLISHED
12 624 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0
Why UFW Doesn’t Work
UFW manages ufw-before-input, ufw-after-input and other chains in the INPUT chain. But traffic to Docker containers goes through the FORWARD chain, which UFW does not control.
External traffic -> PREROUTING (DNAT) -> FORWARD (Docker ACCEPT) -> Container
^
UFW doesn't see this traffic!
Solution Methods
Method 1: Disabling iptables in Docker
Description
Completely prevent Docker from managing iptables. Docker will not create any firewall rules.
Configuration
Create or edit the file /etc/docker/daemon.json:
{
"iptables": false
}
Restart Docker:
sudo systemctl restart docker
Verification
# Before change - many Docker rules
sudo iptables -L -n | grep -i docker
# After change - no Docker rules
sudo iptables -L -n | grep -i docker
Consequences
What will stop working:
-
Automatic NAT for containers - containers won’t be able to access the internet
-
Port publishing (-p flag) - won’t work
-
Inter-container communication via bridge networks
What needs manual configuration:
# Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# Or permanently in /etc/sysctl.conf
net.ipv4.ip_forward = 1
# NAT for container internet access
iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -o eth0 -j MASQUERADE
# Allow forwarding for Docker
iptables -A FORWARD -i docker0 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o docker0 -m state \
--state RELATED,ESTABLISHED -j ACCEPT
# Manual port publishing
iptables -t nat -A PREROUTING -p tcp --dport 80 \
-j DNAT --to-destination 172.17.0.2:80
iptables -A FORWARD -p tcp -d 172.17.0.2 --dport 80 -j ACCEPT
Method 2: Binding Ports to localhost
Description
Instead of publishing ports on all interfaces (0.0.0.0), bind them only to localhost (127.0.0.1). Organize external access through a reverse proxy.
Docker CLI
# WRONG - accessible externally
docker run -d -p 5432:5432 postgres
# CORRECT - local only
docker run -d -p 127.0.0.1:5432:5432 postgres
Docker Compose
version: '3.8'
services:
# Database - local only
postgres:
image: postgres:15
ports:
- "127.0.0.1:5432:5432"
environment:
POSTGRES_PASSWORD: secret
volumes:
- postgres_data:/var/lib/postgresql/data
# Redis - local only
redis:
image: redis:7
ports:
- "127.0.0.1:6379:6379"
# Application - local only
app:
image: myapp:latest
ports:
- "127.0.0.1:3000:3000"
depends_on:
- postgres
- redis
# Nginx - the only public port
nginx:
image: nginx:alpine
ports:
- "80:80" # Public HTTP
- "443:443" # Public HTTPS
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app
volumes:
postgres_data:
Nginx Configuration Example
events {
worker_connections 1024;
}
http {
# Upstream for application
upstream app_backend {
server app:3000;
}
# HTTP -> HTTPS redirect
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
# HTTPS server
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Main application
location / {
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
}
Verifying Port Bindings
# Check which addresses ports are listening on
sudo netstat -tlnp | grep docker
# or
sudo ss -tlnp | grep docker
# Expected output for localhost binding:
# tcp LISTEN 0 128 127.0.0.1:5432 0.0.0.0:* users:(("docker-proxy"...))
# Check external accessibility (should be refused)
# From another machine:
nc -zv your-server-ip 5432
# Connection refused - correct!
# Check local accessibility (should work)
nc -zv 127.0.0.1 5432
# Connection succeeded - correct!
Method 3: DOCKER-USER Chain
Description
Docker specifically preserves the DOCKER-USER chain for user rules. Rules in this chain are processed before Docker’s automatic rules, but after connection establishment.
Basic Setup
# View current DOCKER-USER rules
sudo iptables -L DOCKER-USER -n -v --line-numbers
# By default only:
# 1 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
“Deny All, Allow Selectively” Strategy
# IMPORTANT: Identify external interface
# Usually eth0, ens3, enp0s3, etc.
EXTERNAL_IF="eth0"
# 1. Allow established/related connections (important for responses)
sudo iptables -I DOCKER-USER -i $EXTERNAL_IF -m conntrack \
--ctstate ESTABLISHED,RELATED -j ACCEPT
# 2. Allow specific ports
# HTTP
sudo iptables -I DOCKER-USER -i $EXTERNAL_IF -p tcp --dport 80 -j ACCEPT
# HTTPS
sudo iptables -I DOCKER-USER -i $EXTERNAL_IF -p tcp --dport 443 -j ACCEPT
# 3. Allow from specific IPs (e.g., office)
sudo iptables -I DOCKER-USER -i $EXTERNAL_IF -s 203.0.113.0/24 -j ACCEPT
# 4. Block everything else externally to Docker
sudo iptables -I DOCKER-USER -i $EXTERNAL_IF -j DROP
Correct Rule Order
# Clear and reconfigure with correct order
sudo iptables -F DOCKER-USER
# Add rules in processing order (top to bottom):
# 1. Allow established (always first)
sudo iptables -A DOCKER-USER -m conntrack \
--ctstate ESTABLISHED,RELATED -j RETURN
# 2. Allow local traffic
sudo iptables -A DOCKER-USER -i lo -j RETURN
# 3. Allow internal network
sudo iptables -A DOCKER-USER -s 10.0.0.0/8 -j RETURN
sudo iptables -A DOCKER-USER -s 172.16.0.0/12 -j RETURN
sudo iptables -A DOCKER-USER -s 192.168.0.0/16 -j RETURN
# 4. Allow specific public ports
sudo iptables -A DOCKER-USER -p tcp --dport 80 -j RETURN
sudo iptables -A DOCKER-USER -p tcp --dport 443 -j RETURN
# 5. Allow access from trusted IPs to any port
sudo iptables -A DOCKER-USER -s 203.0.113.50 -j RETURN
# 6. Allow SSH to specific container only from specific IP
sudo iptables -A DOCKER-USER -s 203.0.113.100 -p tcp --dport 2222 -j RETURN
# 7. Log blocked attempts (optional)
sudo iptables -A DOCKER-USER -j LOG \
--log-prefix "DOCKER-USER-DROPPED: " --log-level 4
# 8. Block everything else
sudo iptables -A DOCKER-USER -j DROP
Scenario Examples
Scenario 1: Web Server with Database
# Only 80 and 443 public, DB local only
sudo iptables -F DOCKER-USER
sudo iptables -A DOCKER-USER -m conntrack \
--ctstate ESTABLISHED,RELATED -j RETURN
sudo iptables -A DOCKER-USER -i lo -j RETURN
sudo iptables -A DOCKER-USER -s 172.16.0.0/12 -j RETURN
sudo iptables -A DOCKER-USER -p tcp --dport 80 -j RETURN
sudo iptables -A DOCKER-USER -p tcp --dport 443 -j RETURN
sudo iptables -A DOCKER-USER -i eth0 -j DROP
Saving Rules
Verifying Rules
# View rules with line numbers
sudo iptables -L DOCKER-USER -n -v --line-numbers
# Example output:
# Chain DOCKER-USER (1 references)
# num
pkts bytes target prot opt in out source destination
# 1
156 12480 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
#
ctstate RELATED,ESTABLISHED
# 2
0 0 RETURN all -- lo * 0.0.0.0/0 0.0.0.0/0
# 3
23 1380 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
# 4
45 2700 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
# 5
12 624 DROP all -- eth0 * 0.0.0.0/0 0.0.0.0/0
# Testing (from another server)
nmap -p 80,443,5432,6379 your-server-ip
# 80/tcp
open
# 443/tcp open
# 5432/tcp filtered <-- Blocked!
# 6379/tcp filtered <-- Blocked!
Method 4: ufw-docker Utility
Description
The ufw-docker utility is a script that modifies UFW to work correctly with Docker. It adds rules to the DOCKER-USER chain through UFW-like syntax.
Installation
# Clone repository
git clone https://github.com/chaifeng/ufw-docker.git
cd ufw-docker
# Install script
sudo cp ufw-docker /usr/local/bin/
sudo chmod +x /usr/local/bin/ufw-docker
# Install UFW rules for Docker
sudo ufw-docker install
# Restart UFW
sudo systemctl restart ufw
What install Does
The ufw-docker install command adds to /etc/ufw/after.rules:
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp \
--tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp \
--tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp \
--tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 \
-j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP
COMMIT
# END UFW AND DOCKER
Usage
Allow Access to Container
# Syntax: ufw-docker allow <container_name> [port[/protocol]]
# Allow all traffic to nginx container
sudo ufw-docker allow nginx
# Allow only port 80/tcp to nginx container
sudo ufw-docker allow nginx 80/tcp
# Allow port 443
sudo ufw-docker allow nginx 443/tcp
Complete Example
# Initial setup
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enable
# Install ufw-docker
sudo ufw-docker install
sudo systemctl restart ufw
# Start containers
docker run -d --name web -p 80:80 -p 443:443 nginx
docker run -d --name db -p 5432:5432 postgres
docker run -d --name redis -p 6379:6379 redis
# By default all Docker ports are blocked!
# Check: nmap -p 80,443,5432,6379 server-ip
# All ports filtered
# Open only web ports
sudo ufw-docker allow web 80/tcp
sudo ufw-docker allow web 443/tcp
# Check: nmap -p 80,443,5432,6379 server-ip
# 80/tcp
open
# 443/tcp open
# 5432/tcp filtered
# 6379/tcp filtered
# Allow Redis access only from office
sudo ufw-docker allow redis 6379/tcp 203.0.113.0/24
# View all Docker rules
sudo ufw-docker status
Method 5: Host Network Mode
Description
When using network_mode: host, the container uses the host’s network stack directly, without creating a separate network namespace. Docker doesn’t create NAT rules, and UFW works normally.
Docker Compose
version: '3.8'
services:
nginx:
image: nginx:alpine
network_mode: host
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
UFW Configuration
# Now UFW works as usual
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Verify
sudo ufw status verbose
Example: Web Application
version: '3.8'
services:
app:
image: node:18-alpine
network_mode: host
working_dir: /app
volumes:
- ./:/app
command: node server.js
environment:
- PORT=3000
- DB_HOST=localhost
- DB_PORT=5432
postgres:
image: postgres:15
network_mode: host
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
# UFW rules
sudo ufw allow 3000/tcp # Application
# PostgreSQL (5432) not opened - localhost only
Important Features
Method Comparison Table
| Criterion | iptables=false | localhost bind | DOCKER-USER | ufw-docker | host network |
|---|---|---|---|---|---|
Setup complexity |
High |
Low |
Medium |
Low |
Low |
Requires iptables knowledge |
Yes |
No |
Yes |
No |
No |
Container isolation |
Yes |
Yes |
Yes |
Yes |
No |
UFW compatibility |
Yes |
Yes |
Partial |
Yes |
Yes |
Production ready |
No |
Yes |
Yes |
Yes |
Caution |
Needs reverse proxy |
No |
Yes |
No |
No |
No |
Survives reboot |
Manual |
Yes |
Manual |
Yes |
Yes |
Scenario Recommendations
Scenario 1: Simple Web Server
Conditions: Single server, web app + DB, minimal administration
Recommendation: Bind to localhost + Nginx
version: '3.8'
services:
app:
image: myapp:latest
ports:
- "127.0.0.1:3000:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/myapp
depends_on:
- db
db:
image: postgres:15
# No ports published - access only from Docker network
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
volumes:
- db_data:/var/lib/postgresql/data
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- app
volumes:
db_data:
# UFW for host
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Scenario 2: Development Server
Conditions: Access to various ports needed, but only from office network
Recommendation: DOCKER-USER with whitelist
#!/bin/bash
# /usr/local/bin/setup-docker-firewall.sh
OFFICE_NET="203.0.113.0/24"
VPN_NET="10.8.0.0/24"
iptables -F DOCKER-USER
# Established connections
iptables -A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN
# Localhost
iptables -A DOCKER-USER -i lo -j RETURN
# Docker internal
iptables -A DOCKER-USER -s 172.16.0.0/12 -j RETURN
# Office network - full access
iptables -A DOCKER-USER -s $OFFICE_NET -j RETURN
# VPN network - full access
iptables -A DOCKER-USER -s $VPN_NET -j RETURN
# Block everything else
iptables -A DOCKER-USER -j DROP
echo "Docker firewall configured"
Scenario 3: Microservices
Conditions: Many containers, complex network topology
Recommendation: Docker networks + minimal public ports
version: '3.8'
services:
# Public layer
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
networks:
- frontend
# API Gateway
api-gateway:
image: kong:latest
networks:
- frontend
- backend
# Ports NOT published
# Microservices
users-service:
image: users-service:latest
networks:
- backend
- database
orders-service:
image: orders-service:latest
networks:
- backend
- database
- queue
# Infrastructure
postgres:
image: postgres:15
networks:
- database
# Ports NOT published
redis:
image: redis:7
networks:
- backend
# Ports NOT published
rabbitmq:
image: rabbitmq:3-management
networks:
- queue
ports:
- "127.0.0.1:15672:15672" # Management UI local only
networks:
frontend:
backend:
database:
queue:
Diagnostics and Debugging
When the hardening bites back
Both of the following are our own rules working as intended. They are recorded here because each presents as something else entirely, and both cost real time before being recognised.
Containers cannot reach the network — pulls and builds fail
Symptom: docker pull times out or fails to resolve, docker build dies with a
DNS error, and a container cannot even ping its own gateway (172.17.0.1),
while the host itself has perfectly good connectivity.
Cause: Docker routes container traffic through the FORWARD chain. A host
hardened with -P FORWARD DROP and no matching ACCEPT — or with a broad deny in
DOCKER-USER — cuts every container off from the outside. This is exactly what
the hardening in this guide does, and on a monitoring host it is usually correct:
nothing there needs to originate outbound traffic from a container.
iptables -S | grep -E '^-P FORWARD' # DROP means containers are cut off
iptables -S DOCKER-USER # a deny here does the same
docker run --rm debian:12 ping -c1 172.17.0.1 # fails on such a host
What to do about it depends on why you are pulling:
-
Installing or upgrading the stack — pull with the host’s own networking:
docker build --network=hostworks, andmisc/bootstrap.shalready builds that way for this reason. For pulls, run them where the daemon can reach out, or use the offline bundle, which needs no network at all. -
You genuinely need container egress — add a targeted ACCEPT rather than turning the policy back to ACCEPT wholesale:
iptables -I DOCKER-USER -i docker0 -j ACCEPT # all containers, outboundDecide that deliberately: it is the rule the hardening exists to avoid.
SSH says “No route to host” while the host answers ping and HTTPS
Symptom: ssh fails immediately with No route to host, but ICMP and 443 to the
same address work.
Cause: a connection-limit rule rejects the seventh concurrent SSH connection
from one source address, with icmp-port-unreachable — which is precisely what
“No route to host” means to a client. A firewall drop would time out instead, so
the fast, definite failure is the clue.
iptables -S INPUT | grep connlimit
ss -tn state established '( sport = :22 )' | grep -c <your-ip>
It is easy to hit without noticing: one SSH connection per command in a script reaches the limit quickly, and half-open connections linger after the commands finish. Two fixes, in order of preference:
# 1. Reuse one connection for the whole session (client side, no server change)
cat >> ~/.ssh/config <<'EOF'
Host <monitoring-host>
ControlMaster auto
ControlPath ~/.ssh/cm/%r@%h:%p
ControlPersist 10m
EOF
mkdir -p ~/.ssh/cm
# 2. Drop the lingering sockets on the server, if you are already locked out
#
(reach it from an allowlisted host)
ss -K -tn state established '( sport = :22 )' dst <your-ip>
A host exporter cannot reach a container that is healthy
Symptom: an exporter running on the host times out talking to a container by its IP, while the same container answers immediately from another container on the same bridge. The container is healthy either way, so it reads as an exporter fault.
Cause: an OUTPUT rule that drops a private range containing the Docker bridge.
Docker’s default subnets sit inside 172.16.0.0/12, so a rule written to isolate
internal networks catches them without naming Docker at all.
Container-to-container traffic is unaffected because it never passes the host’s
OUTPUT chain — which is why the fault looks selective.
iptables -S OUTPUT | grep -E '\-d (10\.|172\.|192\.168\.)'
ip -4 -o addr show | awk '$2 ~ /^(docker[0-9]+|br-)/ {print $2, $4}'
The check is the second command against the first: only a dropped range that actually contains a bridge on this host explains it. Two fixes:
# 1. Admit the docker bridges
iptables -I OUTPUT -o br+ -j ACCEPT
iptables -I OUTPUT -o docker0 -j ACCEPT
netfilter-persistent save
# 2. Or take the host out of the path: run the exporter inside the application's
#
own network, so the traffic never leaves the bridge. See
#
exporters/postgres/docker-compose.network.yml for a worked example.
Diagnosed live on angular.friendly-tech.com, where a host-networked exporter could not reach a PostgreSQL container that was serving normally. ## Checking Open Ports
iptables Analysis
# All rules with packet counts
sudo iptables -L -n -v
# DOCKER-USER only
sudo iptables -L DOCKER-USER -n -v --line-numbers
# NAT table
sudo iptables -t nat -L -n -v
# Docker rules
sudo iptables -L DOCKER -n -v
sudo iptables -t nat -L DOCKER -n -v
# Trace packet path
sudo iptables -t raw -A PREROUTING -p tcp --dport 5432 -j TRACE
sudo dmesg | grep TRACE
Security Checklist
Before Deployment
-
Check which ports each container publishes
-
Configure one of the Docker port protection methods
-
Verify rules with external port scanner
-
Configure blocked connection logging
Regular Checks
-
Open port scanning:
nmap -p- server-ip -
iptables rules check:
iptables -L DOCKER-USER -n -v -
Audit docker-compose files for public ports
-
Verify new containers before starting
Automation
#!/bin/bash
# /usr/local/bin/docker-security-check.sh
echo "=== Docker Security Check ==="
echo ""
echo "1. Published ports:"
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep -v "127.0.0.1"
echo ""
echo "2. DOCKER-USER rules:"
iptables -L DOCKER-USER -n --line-numbers
echo ""
echo "3. Externally accessible ports:"
ss -tlnp | grep docker-proxy | grep -v "127.0.0.1"
echo ""
echo "4. Port scan from localhost (simulating external):"
for port in 3306 5432 6379 27017 9200 5672; do
timeout 1 bash -c \
"cat < /dev/null > /dev/tcp/$(hostname -I | awk '{print $1}')/$port" \
2>/dev/null && echo "WARNING: Port $port is open!" \
|| echo "OK: Port $port is closed"
done
Useful Links
-
Docker Documentation - Networking: https://docs.docker.com/network/
-
Docker and iptables: https://docs.docker.com/network/iptables/
-
UFW Documentation: https://help.ubuntu.com/community/UFW
-
ufw-docker GitHub: https://github.com/chaifeng/ufw-docker
-
iptables Tutorial: https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html
branch 1.6.9 · commit a862b45d92590285f229f80a6b5d2efabcb3b1b0 · page generated August 08, 2026