A typical fresh VPS deployment on Ubuntu or Debian begins with UFW configured to deny incoming traffic by default while allowing only ports 22, 80, and 443. After installing Docker and launching a docker-compose.yml that maps PostgreSQL on 5432 and Redis on 6379 for convenient local access, administrators often assume the firewall still protects the system because ufw status shows no additional rules.
External connection tests with nc immediately reveal that both ports respond from the public IP, because Docker activates IP forwarding and installs DNAT rules in the nat table's PREROUTING chain. These rules rewrite destination addresses to container IPs on the docker0 or custom bridge before packets reach the routing decision, sending them into the FORWARD chain instead of INPUT.
Docker places its DOCKER-FORWARD and DOCKER chains at the top of FORWARD, ahead of ufw-before-forward rules, so the default deny routed policy never evaluates the traffic. The same behavior occurs with IPv6 when Docker 27+ manages ip6tables or when docker-proxy binds to [::] addresses, creating an open path even if IPv4 appears locked down.
Scans of cloud provider ranges by tools such as masscan detect the newly exposed ports within 30–120 seconds. On Redis without authentication, bots issue FLUSHALL, attempt REPLICAOF to load malicious modules, or use CONFIG SET to write cron jobs for persistence. Older Redis versions or those running as root allow full remote code execution through Lua sandbox escapes such as CVE-2022-0543 or direct module loading.
PostgreSQL instances with weak default credentials suffer immediate unauthorized access and data exfiltration or ransomware deployment. Real-world examples include a test Qdrant stack on Hetzner CPX21 compromised in under two minutes and multiple reports against the Spree Commerce starter template that left Redis unprotected.
Effective isolation requires explicit rules in the DOCKER-USER chain, disabling automatic IPv6 exposure, binding containers only to localhost, or adopting nftables inet tables that apply policy before Docker's NAT rules execute.


