คู่มือ

การตั้งค่า ufw ใน Linux: ไฟร์วอลล์บนเซิร์ฟเวอร์และพื้นฐาน nftables

อัปเดต: · Skillaria.Top

การตั้งค่า 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 รับทั้งรูปแบบสั้นและแบบเต็ม รูปแบบสั้นเหมาะกับกรณีทั่วไป ส่วนรูปแบบเต็มใช้เมื่อต้องระบุต้นทาง อินเทอร์เฟซ หรือปลายทาง

งานคำสั่ง
พอร์ต TCPsudo ufw allow 443/tcp
พอร์ต UDPsudo 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: с нуля до уверенного администрирования”

ไปที่คอร์ส