การตั้งค่า ufw ใน Linux: ไฟร์วอลล์บนเซิร์ฟเวอร์และพื้นฐาน nftables
การตั้งค่า ufw มีสามขั้นตอน: ตั้งนโยบายเริ่มต้นด้วย sudo ufw default deny incoming และ allow outgoing, อนุญาต SSH และพอร์ตที่ต้องใช้ เช่น sudo ufw allow 22/tcp และ sudo ufw allow 443/tcp แล้วเปิดไฟร์วอลล์ด้วย sudo ufw enable ตรวจกฎด้วย sudo ufw status numbered โดย ufw ควบคุม netfilter ผ่าน iptables หรือ nftables อีกที
ไฟร์วอลล์ใน Linux ตัดสินว่าแพ็กเก็ตเครือข่ายใดควรเข้าสู่เซิร์ฟเวอร์และใดควรถูกทิ้ง ตัวกรองแพ็กเก็ตจริงอยู่ในเคอร์เนลในชื่อ netfilter ส่วนผู้ใช้ควบคุมผ่านยูทิลิตีอย่าง iptables และ nftables ระดับต่ำ หรือตัวห่อหุ้ม ufw (Uncomplicated Firewall) สำหรับเซิร์ฟเวอร์ Ubuntu และ Debian ส่วนใหญ่ การตั้งค่า ufw ใช้เวลาเพียงห้านาที: ปิดขาเข้าทั้งหมด เปิด SSH และพอร์ตของบริการ แล้วเปิดใช้งาน ด้านล่างเป็นขั้นตอนทีละขั้น ข้อผิดพลาดที่พบบ่อย และพื้นฐาน nftables ให้เข้าใจสิ่งที่เกิดขึ้นเบื้องหลัง
ไฟร์วอลล์ใน Linux ทำงานอย่างไร
การกรองแพ็กเก็ตอยู่ในเคอร์เนล ซึ่งก็คือ netfilter มันมีจุดดักจับ (hooks) ได้แก่ ทราฟฟิกขาเข้าสู่โฮสต์, ขาออก และทราฟฟิกที่ส่งต่อ (forward) ยูทิลิตีที่ผู้ใช้เรียกใช้เพียงเขียนกฎลงในเคอร์เนลสำหรับจุดเหล่านี้
| เครื่องมือ | ระดับ | ใช้เมื่อ |
|---|---|---|
ufw | ตัวห่อหุ้ม ไวยากรณ์เรียบง่าย | เซิร์ฟเวอร์เดี่ยวบน Ubuntu/Debian กับกฎทั่วไป |
firewalld | ตัวห่อหุ้มแบบโซน | RHEL, Rocky, Fedora |
nftables (nft) | ระดับต่ำ ทันสมัย | กฎซับซ้อน NAT ชุดของที่อยู่ |
iptables | ระดับต่ำ กำลังเลิกใช้ | ระบบเก่าและสคริปต์เดิม |
สิ่งสำคัญคือใช้เครื่องมือจัดการเพียงตัวเดียว หากแก้กฎผ่าน ufw และ iptables โดยตรงพร้อมกัน กฎทั้งสองจะเขียนทับกัน และผลลัพธ์จะคาดเดาไม่ได้
การติดตั้งและตรวจสอบ ufw
ใน Ubuntu ufw มักติดตั้งไว้แล้วแต่ปิดอยู่ ส่วน Debian ต้องติดตั้งแยก:
$ sudo apt update
$ sudo apt install ufw
$ sudo ufw status
Status: inactive
สถานะ inactive หมายความว่ากฎของ ufw ยังไม่ถูกบังคับใช้ ยังไม่ควรเปิดไฟร์วอลล์ตอนนี้: อนุญาต SSH ก่อน มิฉะนั้นบนเซิร์ฟเวอร์ระยะไกลคุณจะตัดการเข้าถึงของตัวเอง
ขั้นตอนการตั้งค่า ufw บนเซิร์ฟเวอร์ทีละขั้น
ขั้นที่ 1. นโยบายเริ่มต้น
นโยบายเริ่มต้นคือสิ่งที่ทำกับแพ็กเก็ตเมื่อไม่มีกฎใดตรง รูปแบบที่ปลอดภัยสำหรับเซิร์ฟเวอร์คือ ปฏิเสธขาเข้า และอนุญาตขาออก
$ sudo ufw default deny incoming
Default incoming policy changed to 'deny'
$ sudo ufw default allow outgoing
Default outgoing policy changed to 'allow'
คำตอบของการเชื่อมต่อขาออกที่คุณเริ่มเองผ่านไปได้อัตโนมัติ เพราะ ufw ติดตามสถานะของการเชื่อมต่อ (connection tracking) จึงไม่ต้องเปิดพอร์ตสำหรับคำตอบ
ขั้นที่ 2. อนุญาต SSH
$ sudo ufw allow OpenSSH
Rules updated
Rules updated (v6)
OpenSSH เป็นโปรไฟล์ของแอปพลิเคชัน หาก SSH ฟังบนพอร์ตที่ไม่ใช่ค่าเริ่มต้น ให้อนุญาตพอร์ตนั้นอย่างชัดเจน: sudo ufw allow 2222/tcp ตรวจว่า sshd ฟังพอร์ตใดจริงได้ด้วย sudo ss -tlnp | grep sshd
ขั้นที่ 3. เปิดพอร์ตของบริการ
$ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp
ควรระบุโปรโตคอลเสมอ: หากไม่ใส่ /tcp ufw จะเปิดพอร์ตทั้ง TCP และ UDP ซึ่งประตูที่เปิดเกินจำเป็นไม่มีประโยชน์
ขั้นที่ 4. เปิดใช้งานไฟร์วอลล์
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
ufw จะเริ่มทำงานทันทีและเปิดอัตโนมัติทุกครั้งที่บูต อย่าปิดเซสชัน SSH ปัจจุบัน ให้เปิดอีกหนึ่งเซสชันแล้วตรวจว่าการเชื่อมต่อยังใช้ได้
ขั้นที่ 5. ตรวจสอบกฎ
$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp (OpenSSH) ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
กฎสำหรับ IPv6 ufw สร้างให้เอง หาก /etc/default/ufw มี IPV6=yes (ค่าเริ่มต้น)
วิธีเปิดพอร์ตใน ufw: ไวยากรณ์ทั้งหมด
คำสั่ง ufw allow รับทั้งรูปแบบสั้นและแบบเต็ม รูปแบบสั้นเหมาะกับกรณีทั่วไป ส่วนรูปแบบเต็มใช้เมื่อต้องระบุต้นทาง อินเทอร์เฟซ หรือปลายทาง
| งาน | คำสั่ง |
|---|---|
| พอร์ต TCP | sudo ufw allow 443/tcp |
| พอร์ต UDP | sudo ufw allow 51820/udp |
| ช่วงของพอร์ต | sudo ufw allow 6000:6007/tcp |
| ตามชื่อบริการ | sudo ufw allow https |
| จาก IP เดียว | sudo ufw allow from 203.0.113.10 |
| จากซับเน็ตไปยังพอร์ต | sudo ufw allow from 10.0.0.0/24 to any port 5432 proto tcp |
| บนอินเทอร์เฟซ | sudo ufw allow in on eth1 to any port 3306 proto tcp |
| ปฏิเสธ | sudo ufw deny 23/tcp |
| ปฏิเสธพร้อมคำตอบ | sudo ufw reject 25/tcp |
ความต่างระหว่าง deny กับ reject: deny ทิ้งแพ็กเก็ตเงียบๆ ทำให้ไคลเอนต์รอจน timeout ส่วน reject ส่งคำตอบกลับว่าพอร์ตปิด สำหรับโลกภายนอกมักเลือก deny ส่วนเครือข่ายภายในการใช้ reject สะดวกกว่า เพราะไคลเอนต์เห็นข้อผิดพลาดทันที
เข้าถึงฐานข้อมูลจากเซิร์ฟเวอร์เดียวเท่านั้น
งานที่พบบ่อย: PostgreSQL หรือ MySQL ต้องไม่มองเห็นจากอินเทอร์เน็ต แต่แอปพลิเคชันบนเซิร์ฟเวอร์ข้างเคียงต้องเชื่อมต่อได้
$ sudo ufw allow from 10.0.0.5 to any port 5432 proto tcp
Rule added
พอร์ต 5432 ยังคงปิดสำหรับทุกคนอื่นด้วยนโยบาย deny incoming นอกจากนี้ควรตั้งค่าตัวฐานข้อมูลให้ฟังเฉพาะที่อยู่ภายในด้วย ไฟร์วอลล์และการตั้งค่าของบริการช่วยกันป้องกัน
โปรไฟล์แอปพลิเคชัน
แพ็กเกจสามารถวางคำอธิบายพอร์ตของตนไว้ใน /etc/ufw/applications.d/ ได้ ดูรายการและเนื้อหาของโปรไฟล์:
$ sudo ufw app list
Available applications:
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH
$ sudo ufw app info "Nginx Full"
Profile: Nginx Full
Title: Web Server (Nginx, HTTP + HTTPS)
Description: Small, but very powerful and efficient web server
Ports:
80,443/tcp
อนุญาตโปรไฟล์: sudo ufw allow "Nginx Full" ชื่อที่มีเว้นวรรคต้องใส่เครื่องหมายคำพูด สร้างโปรไฟล์ของตัวเองในรูปแบบ INI ไว้ในไดเรกทอรีเดียวกัน แล้วนำไปใช้ด้วย sudo ufw app update ชื่อ
วิธีลบกฎใน ufw
วิธีที่เชื่อถือได้ที่สุดคือลบตามหมายเลข:
$ sudo ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] OpenSSH ALLOW IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
[ 4] OpenSSH (v6) ALLOW IN Anywhere (v6)
[ 5] 80/tcp (v6) ALLOW IN Anywhere (v6)
[ 6] 443/tcp (v6) ALLOW IN Anywhere (v6)
$ sudo ufw delete 2
Deleting:
allow 80/tcp
Proceed with operation (y|n)? y
Rule deleted
หลังลบ หมายเลขจะเลื่อน ดังนั้นก่อนลบครั้งถัดไปให้รัน status numbered อีกครั้ง วิธีที่สองคือทำซ้ำกฎด้วยคำว่า delete: sudo ufw delete allow 80/tcp วิธีนี้จะลบทั้งเวอร์ชัน IPv4 และ IPv6 พร้อมกัน
ลำดับของกฎและการแทรกไว้ด้านบน
ufw ตรวจกฎจากบนลงล่าง และใช้กฎแรกที่ตรง ดังนั้นการปฏิเสธที่อยู่เฉพาะต้องอยู่เหนือการอนุญาตทั่วไป:
$ sudo ufw insert 1 deny from 198.51.100.23
Rule inserted
หากเพิ่ม deny ด้วยคำสั่งปกติ กฎจะไปอยู่ท้ายรายการหลัง allow 443/tcp และจะไม่มีผลกับพอร์ตนั้น
ป้องกัน SSH จากการเดารหัสผ่าน: ufw limit
กฎ limit อนุญาตการเชื่อมต่อ แต่บล็อกที่อยู่ที่เปิดการเชื่อมต่อ 6 ครั้งขึ้นไปภายใน 30 วินาที:
$ sudo ufw limit OpenSSH
Rule updated
นี่เป็นการป้องกันพื้นฐานจากการเดารหัสผ่านจำนวนมาก สำหรับการป้องกันที่จริงจังควรเพิ่มการล็อกอินด้วยคีย์เท่านั้น และอาจใช้ fail2ban ซึ่งสามารถแบนที่อยู่ผ่าน ufw ได้
ไลน์ล็อกของ ufw
เปิดการบันทึกด้วย sudo ufw logging on ระดับมีให้เลือก: low, medium, high, full ข้อมูลจะถูกเขียนลง /var/log/ufw.log (ผ่าน rsyslog) และลงในล็อกของเคอร์เนล:
$ sudo journalctl -k | grep 'UFW BLOCK' | tail -2
Oct 14 10:12:03 web kernel: [UFW BLOCK] IN=eth0 OUT= SRC=45.155.205.1 DST=192.0.2.10 PROTO=TCP SPT=51544 DPT=3389
Oct 14 10:12:09 web kernel: [UFW BLOCK] IN=eth0 OUT= SRC=89.248.165.7 DST=192.0.2.10 PROTO=TCP SPT=40312 DPT=23
ฟิลด์ SRC และ DPT บอกว่าใครเคาะพอร์ตใด หากบริการไม่ตอบสนอง และในล็อกมี UFW BLOCK ที่พอร์ตของบริการนั้น แสดงว่ายังไม่ได้เพิ่มกฎ
ufw และ Docker: เหตุใดพอร์ตจึงเปิดทั้งที่มีกฎ
นี่คือกับดักที่รู้จักกันดี เมื่อ Docker เผยแพร่พอร์ต (-p 8080:80) มันจะเพิ่มกฎ NAT และเชนชื่อ DOCKER เองเพื่อให้ทราฟฟิกไปยังคอนเทนเนอร์วิ่งผ่าน forward จึงข้ามกฎขาเข้าของ ufw ผลคือ ufw status ไม่แสดงพอร์ต 8080 แต่จากภายนอกก็เข้าถึงได้
ทางแก้ที่เป็นไปได้:
- เผยแพร่พอร์ตเฉพาะ localhost:
-p 127.0.0.1:8080:80แล้วให้ reverse proxy (nginx) รับทราฟฟิกจากภายนอก - เพิ่มกฎของตัวเองในเชน
DOCKER-USERเพราะ Docker จะไม่เขียนทับเชนนี้ - ไม่เผยแพร่พอร์ตของคอนเทนเนอร์ภายในเลย แต่เชื่อมต่อผ่านเครือข่ายของ Docker
รีเซ็ตและปิดการใช้งาน
$ sudo ufw disable # ปิด กฎยังคงอยู่
$ sudo ufw reset # ลบกฎทั้งหมดและปิด
$ sudo ufw reload # โหลดการตั้งค่าใหม่
ก่อน reset ufw จะเก็บสำเนาไฟล์กฎไว้ใน /etc/ufw/ พร้อมวันที่ต่อท้ายชื่อ ตัวกฎเองเก็บไว้ที่ /etc/ufw/user.rules และ user6.rules ไม่ควรแก้ด้วยมือ ให้ใช้คำสั่งเท่านั้น
พื้นฐาน nftables
nftables เป็นตัวแทนสมัยใหม่ของ iptables ในเคอร์เนล Linux ใน Debian 10 ขึ้นไปและ Ubuntu 20.10 ขึ้นไป คำสั่ง iptables ทำงานผ่านชั้นความเข้ากันได้ iptables-nft เป็นค่าเริ่มต้น ดังนั้นกฎของ ufw ก็จะอยู่ใน nftables ด้วย ดูทุกอย่างที่โหลดอยู่ในเคอร์เนล:
$ sudo nft list ruleset
โครงสร้างของ nftables: ตาราง (ตระกูล ip, ip6 หรือ inet สำหรับทั้งสองแบบ) ประกอบด้วย เชน ที่ผูกกับจุดของ netfilter และเชนประกอบด้วย กฎ ไฟร์วอลล์ขั้นต่ำสำหรับเซิร์ฟเวอร์ในไฟล์ /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
iif "lo" accept
ip protocol icmp accept
meta l4proto ipv6-icmp accept
tcp dport { 22, 80, 443 } accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
นำไปใช้และเปิดให้ทำงานตอนบูต:
$ sudo nft -c -f /etc/nftables.conf # ตรวจไวยากรณ์อย่างเดียว
$ sudo systemctl enable --now nftables
เพิ่มกฎขณะทำงานได้ แต่จะหายไปหลังรีบูตหากไม่บันทึกลงไฟล์:
$ sudo nft add rule inet filter input tcp dport 5432 ip saddr 10.0.0.5 accept
$ sudo nft -a list chain inet filter input # -a แสดง handle ของกฎ
$ sudo nft delete rule inet filter input handle 9
จุดแข็งหลักของ nftables คือชุดค่า ({ 22, 80, 443 }) และตาราง inet เดียวสำหรับ IPv4 และ IPv6 อย่ารันบริการ nftables.service ของคุณเองพร้อมกับ ufw: flush ruleset จะลบกฎของ ufw ทิ้ง
ข้อผิดพลาดที่พบบ่อย
- เปิดใช้ ufw โดยไม่มีกฎสำหรับ SSH — การเข้าถึงหาย ทางออกคือคอนโซลของผู้ให้บริการ (VNC/serial):
sudo ufw allow OpenSSHหรือsudo ufw disable - เปิดพอร์ตแล้วแต่บริการเข้าไม่ได้ — บริการฟัง
127.0.0.1ไม่ใช่ที่อยู่ภายนอก ตรวจด้วยss -tlnp - มีไฟร์วอลล์ระดับคลาวด์ด้วย — ผู้ให้บริการหลายรายมี security groups ต้องเปิดพอร์ตที่นั่นด้วย
- deny ไม่ทำงาน — กฎอยู่ต่ำกว่ากฎที่อนุญาต ใช้
insert 1
สรุป
การตั้งค่า ufw พื้นฐานคือ default deny incoming, อนุญาต SSH และพอร์ตของบริการ, ufw enable และตรวจด้วย status numbered สำหรับการเข้าถึงเฉพาะจุดใช้กฎที่มี from และ port สำหรับ SSH ใช้ limit และจำไว้ว่า Docker จะข้าม ufw เมื่อต้องการ NAT หรือชุดกฎที่ซับซ้อน ให้ย้ายไปใช้ nftables การป้องกันเซิร์ฟเวอร์ด้วยไฟร์วอลล์ถูกอธิบายพร้อมตัวอย่างจริงในคอร์ส Linux
คำถามที่พบบ่อย
ufw ต่างจาก iptables อย่างไร?
ufw เป็นตัวห่อหุ้มที่มีไวยากรณ์ง่าย ซึ่งสร้างกฎ iptables หรือ nftables ให้เอง ส่วน iptables และ nftables เป็นเครื่องมือระดับต่ำที่ให้การควบคุมเต็มที่ แต่ต้องมีความรู้มากกว่า
กฎของ ufw ยังอยู่หลังรีบูตหรือไม่?
อยู่ หลังรัน sudo ufw enable ไฟร์วอลล์จะเริ่มตอนบูต และกฎเก็บไว้ที่ /etc/ufw/user.rules และ user6.rules
ต้องเปิดพอร์ตสำหรับการเชื่อมต่อขาออกหรือไม่?
ไม่ต้อง หากนโยบายเป็น allow outgoing คำตอบของการเชื่อมต่อขาออกจะผ่านไปอัตโนมัติ เพราะการติดตามสถานะ
จะอนุญาต ping เมื่อเปิด ufw ได้อย่างไร?
ค่าเริ่มต้น ufw อนุญาต ICMP echo-request ขาเข้าอยู่แล้ว กฎนี้ระบุไว้ใน /etc/ufw/before.rules หากต้องการบล็อก ping ให้เปลี่ยน ACCEPT เป็น DROP ในไฟล์นั้น แล้วรัน sudo ufw reload
CentOS และ Rocky Linux มี ufw หรือไม่?
เครื่องมือมาตรฐานคือ firewalld ผ่านคำสั่ง firewall-cmd ติดตั้ง ufw ได้จาก EPEL แต่ไม่ควรใช้ร่วมกับ firewalld
หัวข้อนี้สอนอย่างละเอียดพร้อมฝึกปฏิบัติในคอร์ส “Linux: с нуля до уверенного администрирования”
ไปที่คอร์ส