คำตอบสั้น ๆ: เขียนกฎ Firewall ด้วย nftables ตั้งแต่โครงสร้าง table และ chain การเปิดพอร์ต การจำกัดต้นทาง ไปจนถึงการบันทึกกฎให้อยู่ถาวรหลังรีบูต
คู่มือนี้อธิบาย nftables ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย
nftables คือระบบ Firewall ที่มาแทน iptables ในเคอร์เนล Linux รุ่นใหม่ ทั้ง Ubuntu 22.04 ขึ้นไปและ Debian 11 ขึ้นไปใช้ nftables เป็นค่าเริ่มต้นแล้ว แม้คำสั่ง iptables จะยังพิมพ์ได้อยู่ แต่เบื้องหลังก็ถูกแปลไปเป็น nftables ให้อีกที
ข้อดีของการเขียนกฎด้วย nftables ตรง ๆ คือไวยากรณ์อ่านง่ายกว่า รวมกฎ IPv4 และ IPv6 ไว้ในชุดเดียวกันได้ และดูกฎทั้งหมดได้ในคำสั่งเดียว คู่มือนี้เขียนกฎชุดพื้นฐานสำหรับเซิร์ฟเวอร์ที่เปิดสู่อินเทอร์เน็ต ตั้งแต่ศูนย์จนถึงบันทึกให้อยู่ถาวร
สิ่งที่ต้องเตรียม
- Ubuntu 22.04/24.04 หรือ Debian 11/12 และสิทธิ์
sudo - ช่องทางสำรองเข้าเครื่องกรณีถูกตัดขาดจาก SSH เช่น Console ผ่านหน้าเว็บของผู้ให้บริการ
- รายการพอร์ตที่ต้องเปิดจริง เช่น 22 (SSH), 80 และ 443 (เว็บ)
หากเครื่องใช้ UFW อยู่แล้ว ให้เลือกอย่างใดอย่างหนึ่ง อย่าใช้พร้อมกัน เพราะกฎจะทับซ้อนกันจนไล่ปัญหาไม่ออก ปิด UFW ก่อนด้วย sudo ufw disable
ขั้นตอนที่ 1: ติดตั้งและดูสถานะปัจจุบัน
sudo apt update
sudo apt install -y nftables
sudo systemctl enable --now nftables
ดูกฎที่มีอยู่ตอนนี้ทั้งหมด ถ้าเพิ่งติดตั้งจะยังว่างเปล่าหรือมีเพียงโครงว่าง
sudo nft list ruleset
ขั้นตอนที่ 2: ทำความเข้าใจโครงสร้าง table, chain และ rule
nftables จัดกฎเป็นสามชั้น เข้าใจสามคำนี้แล้วที่เหลือจะง่ายขึ้นมาก
- table คือกล่องใหญ่ที่รวมกฎของตระกูลโพรโทคอลหนึ่ง ๆ ใช้
inetเพื่อคุมทั้ง IPv4 และ IPv6 พร้อมกัน - chain คือจุดที่แพ็กเก็ตวิ่งผ่าน เช่น
inputสำหรับแพ็กเก็ตที่เข้ามาหาเครื่องนี้forwardสำหรับที่วิ่งผ่านไปเครื่องอื่น และoutputสำหรับที่ออกจากเครื่อง - rule คือเงื่อนไขและการกระทำ เช่น "ถ้าปลายทางเป็นพอร์ต 443 ให้ accept"
ขั้นตอนที่ 3: เขียนไฟล์กฎ
วิธีที่ดูแลง่ายที่สุดคือเขียนกฎทั้งชุดลงไฟล์เดียว แล้วโหลดทีเดียว เปิดไฟล์
sudo nano /etc/nftables.conf
แทนที่เนื้อหาทั้งหมดด้วยชุดนี้ แล้วค่อยปรับพอร์ตให้ตรงกับงานจริงของคุณ
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# อนุญาตการเชื่อมต่อที่สร้างไว้แล้ว ต้องมาเป็นกฎแรกเสมอ
ct state established,related accept
ct state invalid drop
# loopback ภายในเครื่อง
iif lo accept
# ping (ใช้ตรวจสอบเครื่องจากภายนอก)
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
# SSH
tcp dport 22 accept
# เว็บ
tcp dport { 80, 443 } accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
จุดสำคัญคือ policy drop ใน chain input หมายความว่าอะไรที่ไม่มีกฎอนุญาตไว้จะถูกทิ้งทั้งหมด นี่คือแนวทางที่ถูกต้องสำหรับเซิร์ฟเวอร์ที่เปิดสู่อินเทอร์เน็ต และเป็นเหตุผลที่กฎ tcp dport 22 accept ต้องมีก่อนโหลด ไม่เช่นนั้นคุณจะหลุดจาก SSH ทันที
ขั้นตอนที่ 4: ทดสอบก่อนใช้จริง
ตรวจไวยากรณ์ก่อน โดยยังไม่โหลดเข้าเคอร์เนล
sudo nft -c -f /etc/nftables.conf
ถ้าไม่มีข้อความใดแสดงขึ้นมาแปลว่าไวยากรณ์ถูกต้อง ต่อไปตั้งตัวช่วยกันล็อกตัวเองออก โดยสั่งให้ระบบล้างกฎทิ้งอัตโนมัติในอีก 5 นาที หากคุณยังเชื่อมต่อได้ตามปกติค่อยยกเลิกคำสั่งนี้
sudo sh -c 'sleep 300 && nft flush ruleset' &
echo $!
จดเลข Process ID ที่ได้ไว้ แล้วค่อยโหลดกฎจริง
sudo nft -f /etc/nftables.conf
เปิด Terminal อีกหน้าต่างหนึ่งแล้วลอง SSH เข้าเครื่องใหม่ ถ้าเข้าได้แปลว่ากฎถูกต้อง ให้ยกเลิกตัวช่วยด้วย sudo kill <PID>