Promo Domain .biz.id hanya Rp2.500 Cek domain →
JowHost
VPS & Server

Docker Bypass UFW: Kenapa Port Container Tetap Terbuka dan Cara Menutupnya

Hasil uji: UFW aktif dan hanya membuka SSH, tetapi port Docker tetap bisa diakses dari internet. Penyebab docker bypass UFW dan dua cara menutupnya.

Tim JowHost 4 menit baca
Terminal menunjukkan port container Docker tetap terbuka walau UFW aktif
Daftar isi
  1. Uji 1: UFW aktif, port Docker tetap terbuka
  2. Kenapa Docker bypass UFW terjadi
  3. Cara 1: publikasikan hanya ke 127.0.0.1
  4. Cara 2: jadikan 127.0.0.1 bawaan untuk semua container
  5. Bagaimana dengan port yang harus publik tapi dibatasi IP?
  6. Cek server Anda sekarang

Kami menyalakan UFW di VPS uji dan hanya mengizinkan SSH. Port 9999 tanpa aturan diblokir seperti seharusnya. Lalu kami menjalankan nginx di Docker dengan -p 8080:80, dan dari internet port 8080 tetap membalas HTTP 200. Inilah yang disebut docker bypass UFW. Kalau Anda menjalankan database, panel admin, atau API di Docker, port-nya bisa terbuka ke internet tanpa Anda sadari.

Diuji 5 November 2026 di Super Cloud Regular 1 vCPU · 2 GB, Ubuntu 24.04.5 LTS, Docker 29.9.3, ufw 0.36.2. Akses "dari luar" diuji dari server lain lewat internet.

Uji 1: UFW aktif, port Docker tetap terbuka

Di image Ubuntu 24.04 yang kami pakai, ufw belum terpasang (ufw: command not found). Pasang dan aktifkan dengan hanya SSH yang diizinkan:

sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verbose
Status: active
Default: deny (incoming), allow (outgoing), deny (routed)

To                         Action      From
--                         ------      ----
22/tcp (OpenSSH)           ALLOW IN    Anywhere
22/tcp (OpenSSH (v6))      ALLOW IN    Anywhere (v6)

Port 8080 tidak ada di daftar. Sekarang jalankan container dan lihat port-nya:

docker run -d --name web -p 8080:80 nginx:alpine
docker ps --format "{{.Names}}  {{.Ports}}"
web  0.0.0.0:8080->80/tcp, [::]:8080->80/tcp

Lalu dari komputer lain:

curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 8 http://IP-VPS:8080/
Port yang dicoba dari internet Hasil
8080 (container nginx, tidak diizinkan UFW) HTTP 200, terbuka
9999 (tanpa container, tidak diizinkan UFW) timeout 6 detik, diblok

UFW bekerja untuk port biasa, tetapi tidak untuk port yang dipublikasikan Docker. Dokumentasi resmi Docker juga mengakui ini: port container yang dipublikasikan melewati aturan ufw dan firewalld.

Kenapa Docker bypass UFW terjadi

default deny (incoming) milik UFW berlaku di chain INPUT, yaitu paket yang ditujukan ke VPS itu sendiri. Docker tidak lewat jalur itu. Saat container dipublikasikan, Docker membuat aturan NAT yang mengubah tujuan paket langsung ke IP container:

sudo iptables -t nat -S DOCKER | grep 8080
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80

Karena tujuannya sudah berubah menjadi 172.17.0.2, paket diteruskan lewat chain FORWARD, bukan INPUT. Di FORWARD, chain milik Docker diperiksa lebih dulu daripada chain UFW:

sudo iptables -S FORWARD | head -5
-P FORWARD DROP
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-FORWARD
-A FORWARD -j ufw-before-logging-forward
-A FORWARD -j ufw-before-forward

Paket ke container sudah diterima di DOCKER-FORWARD sebelum sempat sampai ke aturan UFW.

Cara 1: publikasikan hanya ke 127.0.0.1

Ini cara yang kami sarankan untuk aplikasi yang diakses lewat reverse proxy (Nginx, Caddy) atau cukup dari dalam VPS. Tulis alamat IP sebelum port:

docker rm -f web
docker run -d --name web -p 127.0.0.1:8080:80 nginx:alpine
web  127.0.0.1:8080->80/tcp
Diuji dari Hasil
Dalam VPS (curl http://127.0.0.1:8080) HTTP 200
Internet timeout, tertutup

Di Docker Compose, caranya sama di bagian ports:

services:
  web:
    image: nginx:alpine
    ports:
      - "127.0.0.1:8080:80"

Cara 2: jadikan 127.0.0.1 bawaan untuk semua container

Kalau Anda sering lupa menulis 127.0.0.1:, ubah alamat bawaan Docker di /etc/docker/daemon.json:

{
  "ip": "127.0.0.1"
}
sudo systemctl restart docker
docker run -d --name web -p 8080:80 nginx:alpine
docker ps --format "{{.Names}}  {{.Ports}}"
web  127.0.0.1:8080->80/tcp

Walau perintahnya tetap -p 8080:80, port hanya terbuka di localhost dan dari internet tertutup (sudah kami uji). Binding IPv6 [::]:8080 yang sebelumnya muncul juga hilang.

Dua catatan:

  • systemctl restart docker menghentikan semua container. Yang punya restart: unless-stopped atau always akan menyala lagi; yang tidak punya harus dijalankan ulang.
  • Port yang memang harus publik, misalnya 80 dan 443 untuk reverse proxy, ditulis eksplisit: -p 0.0.0.0:80:80. Di uji kami, port dengan 0.0.0.0 eksplisit kembali bisa diakses dari internet.

Bagaimana dengan port yang harus publik tapi dibatasi IP?

Misalnya port database yang hanya boleh diakses dari IP kantor. Aturan ufw allow from … tidak berlaku untuk port Docker, karena alasan yang sama seperti di atas. Docker menyediakan chain DOCKER-USER untuk aturan seperti ini; penjelasan resminya ada di dokumentasi Docker Packet filtering and firewalls. Untuk kebanyakan kasus, lebih sederhana jika port database tidak dipublikasikan sama sekali, lalu diakses lewat tunnel SSH.

Cek server Anda sekarang

docker ps --format "{{.Names}}\t{{.Ports}}"

Setiap baris yang berisi 0.0.0.0: atau [::]: adalah port yang terbuka ke internet, apa pun aturan UFW-nya. Pastikan dengan mencoba dari komputer lain:

curl -m 5 -s -o /dev/null -w "%{http_code}\n" http://IP-VPS:PORT/

Kalau keluar kode HTTP (200, 401, 404), port itu bisa dijangkau dari internet.

Belum memasang Docker? Ikuti Install Docker di Ubuntu 24.04. Sekalian tutup juga login password SSH lewat SSH key untuk VPS.

VPS & Server

Ditulis oleh

Tim JowHost

Server Specialist.

Artikel lainnya