September 27, 2026
Firewall dengan UFW.
Mengamankan server Ubuntu dengan UFW: default policy, allow/deny, application profile, rate limiting, logging, dan jebakan Docker yang melewati aturan UFW.
UFW (Uncomplicated Firewall) adalah antarmuka sederhana untuk firewall kernel Linux (netfilter, lewat iptables/nftables). Alih-alih menulis aturan iptables yang panjang, cukup ufw allow 443/tcp. UFW sudah terpasang di Ubuntu tetapi nonaktif secara default.
Prinsip dasarnya: tolak semua koneksi masuk, lalu buka hanya port yang benar-benar dibutuhkan.
1. Urutan Aman Mengaktifkan UFW
Peringatan: Jika kamu mengakses server lewat SSH, izinkan SSH sebelum mengaktifkan UFW. Kalau tidak, koneksimu akan terputus dan kamu harus masuk lewat konsol VPS/provider.
sudo apt install ufw # biasanya sudah ada
# 1. default policy
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 2. izinkan SSH dulu!
sudo ufw allow OpenSSH # atau: sudo ufw allow 22/tcp
# 3. port layanan
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# 4. aktifkan
sudo ufw enable
# 5. cek
sudo ufw status verbose
Contoh output:
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp (OpenSSH) ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
Jika SSH memakai port selain 22, izinkan port itu (misalnya sudo ufw allow 2222/tcp).
2. Default Policy
| Arah | Rekomendasi | Alasan |
|---|---|---|
incoming | deny | Hanya port yang dibuka eksplisit yang bisa diakses |
outgoing | allow | Server tetap bisa apt update, memanggil API, dll. |
routed | deny | Untuk server yang bukan router; relevan untuk Docker/VM |
deny membuang paket diam-diam (klien menunggu sampai timeout), sedangkan reject langsung membalas “ditolak”. Untuk internet publik, deny lebih umum dipakai.
3. Allow dan Deny
# port & protokol
sudo ufw allow 443/tcp
sudo ufw allow 51820/udp # WireGuard
sudo ufw allow 6000:6007/tcp # rentang port (wajib sebut protokol)
# hanya dari IP / subnet tertentu
sudo ufw allow from 203.0.113.10
sudo ufw allow from 192.168.1.0/24 to any port 3306 proto tcp
# hanya di interface tertentu
sudo ufw allow in on eth1 to any port 5432 proto tcp
# blokir IP
sudo ufw deny from 198.51.100.23
# tambahkan keterangan
sudo ufw allow 8080/tcp comment 'app staging'
Urutan aturan itu penting
UFW memeriksa aturan dari atas ke bawah dan berhenti di aturan pertama yang cocok. Jika sudah ada allow 22/tcp dari mana saja, lalu kamu menambah deny from 198.51.100.23, IP itu tetap bisa SSH karena aturan allow ada di atas. Gunakan insert:
sudo ufw insert 1 deny from 198.51.100.23
Melihat dan menghapus aturan
sudo ufw status numbered
sudo ufw delete 3 # hapus berdasarkan nomor
sudo ufw delete allow 8080/tcp # hapus berdasarkan isi aturan
Setelah menghapus satu nomor, penomoran bergeser. Jalankan status numbered lagi sebelum menghapus berikutnya.
Perintah lain
| Perintah | Fungsi |
|---|---|
sudo ufw disable | Matikan firewall (aturan tetap tersimpan) |
sudo ufw reload | Muat ulang aturan |
sudo ufw reset | Hapus semua aturan & nonaktifkan (ada backup otomatis) |
sudo ufw show added | Aturan yang ditambahkan, dalam format perintah |
4. Application Profile
Paket seperti OpenSSH, Nginx, dan Apache memasang profil aplikasi di /etc/ufw/applications.d/, sehingga kamu bisa mengizinkan berdasarkan nama.
sudo ufw app list
sudo ufw app info "Nginx Full"
| Profil (Nginx) | Port |
|---|---|
Nginx HTTP | 80/tcp |
Nginx HTTPS | 443/tcp |
Nginx Full | 80/tcp + 443/tcp |
sudo ufw allow "Nginx Full"
Membuat profil sendiri:
# /etc/ufw/applications.d/myapp
[MyApp]
title=My Application
description=API internal dan metrics
ports=3000/tcp|9100/tcp
sudo ufw app update MyApp
sudo ufw allow from 10.0.0.0/8 to any app MyApp
5. Rate Limiting
UFW punya fitur sederhana untuk melawan brute force: limit. Koneksi dari satu IP akan ditolak jika mencoba 6 kali atau lebih dalam 30 detik.
sudo ufw limit OpenSSH
# atau
sudo ufw limit 22/tcp
Jika sebelumnya sudah ada allow 22/tcp, hapus aturan itu dulu (atau ganti), karena aturan allow di atas akan cocok lebih dulu.
Fitur ini cocok untuk SSH, tetapi tidak cocok untuk HTTP/HTTPS: browser membuka banyak koneksi sekaligus dan pengguna di belakang NAT kantor berbagi satu IP. Untuk web, lakukan rate limiting di Nginx (limit_req) atau di CDN. Untuk perlindungan SSH yang lebih pintar (berbasis log login gagal), gunakan fail2ban, dibahas di catatan SSH Hardening
.
6. Logging
sudo ufw logging on # level low (default)
sudo ufw logging medium # lebih detail
sudo ufw logging off
Log tersimpan di /var/log/ufw.log (atau lewat journalctl -k):
sudo tail -f /var/log/ufw.log
sudo grep "UFW BLOCK" /var/log/ufw.log | tail -20
Level high dan full sangat verbose dan bisa memenuhi disk dengan cepat di server publik.
7. IPv6
Pastikan IPV6=yes di /etc/default/ufw (default Ubuntu sudah yes). Dengan begitu setiap ufw allow otomatis membuat aturan untuk IPv4 dan IPv6 (terlihat sebagai baris (v6) di status). Jika IPv6 dimatikan sementara server punya alamat IPv6, port bisa terbuka lewat IPv6 tanpa kamu sadari.
8. Jebakan Besar: Docker Melewati UFW
Ini jebakan paling sering di VPS. Kamu menjalankan:
docker run -d -p 3306:3306 mysql:8
UFW menolak semua incoming dan tidak ada aturan untuk 3306, tetapi MySQL tetap bisa diakses dari internet.
Penyebabnya: Docker menulis aturan iptables sendiri. Port yang di-publish diarahkan (DNAT) di tabel nat lalu lewat chain FORWARD, sebelum sempat melewati chain INPUT tempat aturan UFW berada. Dokumentasi Docker sendiri menyebut Docker dan UFW tidak kompatibel dalam hal ini.
Solusi
1. Bind port ke localhost (paling sederhana dan paling disarankan):
docker run -d -p 127.0.0.1:3306:3306 mysql:8
# docker-compose.yml
services:
db:
image: mysql:8
ports:
- "127.0.0.1:3306:3306"
Lalu expose hanya lewat reverse proxy (Nginx/Caddy) di port 80/443, atau akses database lewat SSH tunnel:
ssh -L 3306:127.0.0.1:3306 user@server
2. Jangan publish port yang tidak perlu. Container dalam satu network Docker
bisa saling akses lewat nama service tanpa ports: sama sekali.
3. Chain DOCKER-USER. Docker menyediakan chain ini untuk aturan buatan admin yang dievaluasi sebelum aturan Docker. Contoh: hanya izinkan akses dari satu subnet ke container yang dipublish lewat interface publik eth0:
sudo iptables -I DOCKER-USER -i eth0 ! -s 203.0.113.0/24 -j DROP
Aturan iptables manual tidak persisten setelah reboot; simpan di /etc/ufw/after.rules atau gunakan tool seperti ufw-docker yang mengintegrasikan UFW dengan chain tersebut (setelah itu aturannya dikelola dengan ufw route allow ...).
Catatan: Menonaktifkan pengelolaan iptables Docker (
"iptables": falsedidaemon.json) memang membuat UFW berlaku lagi, tetapi merusak networking container (NAT keluar, komunikasi antar-network). Tidak disarankan kecuali kamu paham konsekuensinya.
Verifikasi dari luar server, bukan dari server itu sendiri:
# dari laptop
nc -zv IP_SERVER 3306
nmap -Pn -p 1-10000 IP_SERVER
9. Kesalahan Umum
| Masalah | Penyebab | Solusi |
|---|---|---|
| Terkunci keluar dari SSH | ufw enable sebelum allow SSH | Masuk lewat konsol provider, ufw allow OpenSSH |
| Aturan deny tidak berefek | Ada allow di atasnya | ufw insert 1 deny ... |
| Port container tetap terbuka | Docker mem-bypass UFW | Bind ke 127.0.0.1 / DOCKER-USER |
| Port tetap tertutup padahal sudah di-allow | Firewall di level cloud (Security Group AWS, firewall Hetzner/DO) | Buka juga di panel provider |
| Terbuka lewat IPv6 | IPV6=no padahal ada alamat IPv6 | Set IPV6=yes, ufw reload |
| Membuka port database ke publik “sementara” | Lupa ditutup | Batasi from <IP> atau pakai SSH tunnel |
Referensi

Hey! I’m Fanny, the software engineer tending to this digital garden. You can read more about me, or subscribe by email.