บนเซิร์ฟเวอร์จริง เราไม่โหลดโปรแกรมจากเว็บมั่วๆ มาลง — เราใช้ “ระบบ package” ที่จัดการให้ครบและปลอดภัย บทนี้สอนตั้งแต่ลง/ลบ/อัปเดตโปรแกรมด้วย dnf ไปจนถึงตั้งเวลาและซิงค์นาฬิกาให้ตรงเป๊ะด้วย NTP
ถ้าคุณคุ้นกับ Windows การลงโปรแกรมคือ — เปิดเว็บ โหลดไฟล์ .exe มา ดับเบิลคลิก กด Next Next Next จบ แต่บน RHEL เราไม่ทำแบบนั้น เพราะมันไม่ปลอดภัยและจัดการยาก ลองคิดดูว่าถ้าเซิร์ฟเวอร์มี 100 เครื่อง คุณจะไล่โหลดไฟล์ทีละเครื่องไหวไหม
แทนที่จะทำแบบนั้น Linux มี ระบบ package — เป็นคลังซอฟต์แวร์กลางที่ผ่านการตรวจสอบแล้ว เราแค่บอกชื่อโปรแกรมที่อยากได้ ระบบก็จะไปดึงมาลงให้พร้อม “ของที่จำเป็น” ครบเซ็ต
การโหลด .exe จากเว็บมั่วๆ = ไปซื้อของกินจากแผงข้างทางที่ไม่รู้สะอาดไหม
ระบบ package ของ Linux = สั่งของจาก App Store ที่คัดกรองแล้ว มีลายเซ็นรับรองของแท้ และถ้าแอปต้องใช้แอปอื่นช่วย มันจะลงให้ครบเองโดยไม่ต้องไปตามหา
RHCSA ชอบให้ “ลง package ตัวนี้”, “ลบตัวนั้น”, “เพิ่ม repo จาก URL ที่กำหนด”, หรือ “ตั้ง timezone ให้ถูก” — ทั้งหมดต้องทำด้วยคำสั่งให้คล่อง และต้องเขียนถาวรให้รอดหลังรีบูตด้วย
มีสองคำที่ต้องแยกให้ออก เพราะคนมักสับสน:
.rpm หนึ่งกล่องคือหนึ่งโปรแกรม (เช่น nginx) ข้างในมีไฟล์โปรแกรม + ข้อมูลว่าต้องพึ่งกล่องอื่นไหม.rpm จากคลัง (repository) มาลงให้ และที่เก่งคือมันจัดการ dependency (ของที่จำเป็นต้องมี) ให้เองครบถ้าคุณติดตั้ง .rpm ด้วยมือเปล่า (คำสั่ง rpm -i) มันเหมือน ซื้อชั้นวางหนังสือ IKEA แต่ลืมซื้อน็อต — ประกอบไม่ได้ ต้องวิ่งไปหาน็อตเอง
แต่ถ้าใช้ dnf มันเหมือนสั่งจากร้านที่ แถมน็อต ไขควง และคู่มือมาให้ครบในกล่องเดียว — สั่งโปรแกรมเดียว มันลง dependency ให้หมดอัตโนมัติ
คุณอาจเคยเห็นคำสั่ง yum ในคู่มือเก่าๆ — บน RHEL 9 มันคือ dnf ตัวเดียวกัน (yum ยังพิมพ์ได้อยู่ มันชี้ไปที่ dnf ให้) ในห้องสอบจะใช้ตัวไหนก็ได้ แต่แนะนำให้ชินกับ dnf
คำสั่งที่เปลี่ยนแปลงระบบ (ลง/ลบ/อัปเดต) ต้องใช้สิทธิ์ root ดังนั้นเติม sudo นำหน้า ส่วนคำสั่งแค่ “ดู” (search/info/list) ใช้ user ธรรมดาก็ได้
[student@server1 ~]$ sudo dnf install httpd Dependencies resolved. ================================================================ Package Arch Version Repository Size ================================================================ Installing: httpd x86_64 2.4.57-5.el9 appstream 1.5 M Installing dependencies: apr x86_64 1.7.0-12.el9 appstream 127 k apr-util x86_64 1.6.1-23.el9 appstream 98 k ... Is this ok [y/N]: y Complete!
สังเกตว่าเราสั่งลงแค่ httpd แต่ dnf เห็นว่ามันต้องใช้ apr, apr-util ด้วย เลย ลงให้ครบเอง นี่แหละความฉลาดของ dnf
-yเติมท้ายเพื่อตอบ “yes” อัตโนมัติ ไม่ต้องมานั่งกด y เอง เช่น dnf install -y httpd$ sudo dnf install ชื่อ # ลงโปรแกรม (+ dependency) $ sudo dnf remove ชื่อ # ลบโปรแกรมออก $ sudo dnf upgrade # อัปเดตทุกอย่างให้ใหม่ล่าสุด (= update) $ dnf search คำ # ค้นหา package จากคำ $ dnf info ชื่อ # ดูรายละเอียด: เวอร์ชัน ขนาด คำอธิบาย $ dnf list installed # ลิสต์ทุก package ที่ลงแล้ว $ dnf provides /usr/sbin/httpd # ไฟล์นี้มาจาก package ไหน? $ dnf history # ดูประวัติว่าเคยลง/ลบอะไรไปบ้าง
installลงโปรแกรมใหม่ ลง dependency ให้ครบremoveลบออก (ระวัง: อาจลบ dependency ที่ของอื่นใช้ร่วมตามไปด้วย)upgradeอัปเดตให้เป็นเวอร์ชันล่าสุด — update ก็ความหมายเดียวกันsearchนึกชื่อไม่ออก ลองค้นจากคำใกล้เคียง เช่น dnf search web serverinfoอยากรู้ว่า package นี้คืออะไร เวอร์ชันไหน ก่อนตัดสินใจลงprovidesเจอไฟล์แปลกๆ อยากรู้ว่ามันมาจากโปรแกรมไหน ใช้ตัวนี้historyดูบันทึกย้อนหลัง และยัง dnf history undo เลขที่ เพื่อย้อนกลับได้dnf search = ค้นจาก ชื่อ/คำอธิบาย ของ package (เช่นหาคำว่า "editor")
dnf provides = ค้นจาก ชื่อไฟล์หรือ path ว่ามาจาก package ไหน (เช่น /etc/httpd มาจากตัวไหน)
บางทีเราอยากได้ “ชุดเครื่องมือ” ทั้งชุด ไม่ใช่ทีละตัว เช่นอยากได้เครื่องมือพัฒนาโปรแกรมครบเซ็ต RHEL จึงรวม package หลายตัวไว้เป็น กลุ่ม (group) สั่งทีเดียวได้ทั้งกลุ่ม
package เดี่ยว = สั่งกาแฟแก้วเดียว / group = สั่ง “เซ็ตอาหารเช้า” ที่มาพร้อมกาแฟ ขนมปัง ไข่ ครบจานเดียว
$ dnf group list Available Groups: Development Tools System Tools Container Management $ sudo dnf group install "Development Tools" Complete!
group listดูว่ามีกลุ่มอะไรให้เลือกบ้างgroup install "ชื่อ"ลงทั้งกลุ่ม — ชื่อกลุ่มมีช่องว่าง ต้องครอบด้วยเครื่องหมายคำพูดนี่เป็นของใหม่ของ RHEL 9 (มาจากระบบ AppStream) และ ออกสอบบ่อย — ปัญหาคือบางโปรแกรมมีหลายเวอร์ชันให้เลือก เช่น PHP มีทั้ง 8.1 และ 8.2 แต่บนเครื่องเดียวจะลงพร้อมกันไม่ได้ Module stream คือวิธีให้เรา เลือกว่าจะเอาเวอร์ชันไหน
นึกถึง Netflix ที่มีหนังเรื่องเดียวกันหลาย “ซีซัน” — module = ชื่อหนัง (เช่น php), stream = ซีซัน/เวอร์ชัน (เช่น 8.2) คุณเลือกได้ว่าจะดูซีซันไหน แต่เปิดดูได้ทีละซีซัน
$ dnf module list php Name Stream Profiles Summary php 8.1 [d] common [d], devel PHP scripting language php 8.2 common, devel PHP scripting language [d] = default [e] = enabled [i] = installed $ sudo dnf module install php:8.2 Complete!
module listดูว่ามี module อะไร และแต่ละตัวมี stream (เวอร์ชัน) อะไรบ้างmodule install php:8.2เลือก stream 8.2 แล้วลงเลย — รูปแบบคือ ชื่อ:streammodule enable php:8.2แค่เลือกเวอร์ชัน แต่ยังไม่ลง (เตรียมไว้ให้ลงทีหลัง)module reset phpรีเซ็ตให้ลืมการเลือกทั้งหมด กลับไปเริ่มใหม่module enable แค่ “เปิด” ให้เวอร์ชันนั้นพร้อมเลือก แต่ยังไม่ติดตั้ง ถ้าโจทย์บอกให้ “ติดตั้ง php เวอร์ชัน 8.2” ต้องใช้ module install php:8.2 ไม่ใช่ enable เฉยๆ (หรือ enable ก่อนแล้วค่อย dnf install php ก็ได้)
เผลอ enable เวอร์ชันผิดไปแล้ว แก้ด้วย sudo dnf module reset ชื่อ เพื่อล้างค่า แล้วค่อยเลือกใหม่ ไม่ต้องตกใจ
dnf ไว้ “ลง/ลบ” แต่ rpm เก่งเรื่อง “สืบ/ค้น” ว่าตอนนี้บนเครื่องมีอะไรลงอยู่บ้าง option ที่ใช้คู่กับ -q (query = ถามข้อมูล) จำ 3 ตัวนี้พอ
$ rpm -qa bash-5.1.8-6.el9.x86_64 httpd-2.4.57-5.el9.x86_64 ... (ลิสต์ยาวมาก — มักใช้คู่กับ grep) $ rpm -qf /usr/sbin/httpd httpd-2.4.57-5.el9.x86_64 $ rpm -ql httpd /etc/httpd /usr/sbin/httpd /var/www/html ...
rpm -qaa = all → ลิสต์ทุก package ที่ลงแล้ว (มักทำ rpm -qa | grep httpd)rpm -qf pathf = file → ไฟล์นี้มาจาก package ไหน (เหมือน dnf provides แต่ดูเฉพาะที่ลงแล้ว)rpm -ql ชื่อl = list → package นี้วางไฟล์ไว้ที่ไหนบ้างเวลาจะ เปลี่ยน ระบบ (ลง/ลบ/อัปเดต) → ใช้ dnf เพราะจัดการ dependency ให้ เวลาจะแค่ ดู/ค้น ว่ามีอะไรลงอยู่ → ใช้ rpm -q ได้เลย
Repository (repo) คือ “คลังซอฟต์แวร์” ที่ dnf ไปหยิบของมาลง บางครั้งของที่เราต้องการไม่ได้อยู่ในคลังมาตรฐาน เราจึงต้อง บอก dnf ว่ามีคลังเพิ่มอยู่ตรงไหน — ข้อนี้ออกสอบบ่อย โจทย์มักให้ URL/BaseURL มา แล้วให้เราเพิ่มเข้าไป
repo = รายชื่อ “ร้านค้า” ที่ App Store ของเรารู้จัก ถ้าอยากได้ของจากร้านใหม่ ก็ต้องเพิ่มที่อยู่ร้านนั้นเข้าไปในรายชื่อก่อน มันถึงจะไปสั่งของจากร้านนั้นได้
รายชื่อ repo ทั้งหมดเก็บเป็นไฟล์นามสกุล .repo อยู่ในโฟลเดอร์ /etc/yum.repos.d/ เราสร้างไฟล์ใหม่ใส่ข้อมูลร้านลงไป
[myrepo] name=My Custom Repo baseurl=http://content.example.com/repo/ enabled=1 gpgcheck=0
[myrepo]ชื่อย่อ (ID) ของ repo อยู่ในวงเล็บเหลี่ยม ห้ามมีช่องว่างname=ชื่อยาวๆ ที่อ่านเข้าใจ (จะเป็นอะไรก็ได้)baseurl=ที่อยู่ของคลัง — ตัวสำคัญที่สุด ใส่ผิดเป็นใช้ไม่ได้enabled=1เปิดใช้งาน repo นี้ (0 = ปิดไว้)gpgcheck=ตรวจลายเซ็นของแท้ไหม (1 = ตรวจ ต้องมี key, 0 = ไม่ตรวจ)$ sudo dnf config-manager --add-repo http://content.example.com/repo/ Adding repo from: http://content.example.com/repo/ $ dnf repolist repo id repo name myrepo My Custom Repo
config-manager --add-repo URLสร้างไฟล์ .repo ให้อัตโนมัติจาก URL ที่ให้มาdnf repolistเช็กว่า repo ที่เพิ่มเข้ามาแล้ว dnf มองเห็นจริงไหมไฟล์ .repo เก็บอยู่ในดิสก์ รอดหลังรีบูตอยู่แล้ว ไม่ต้องทำอะไรเพิ่ม แต่ต้องเช็กสองอย่างให้ดี: (1) baseurl ถูกต้องไหม ลองด้วย dnf repolist หรือ dnf install package-ในนั้น (2) ถ้าตั้ง gpgcheck=1 ต้องมี gpgkey= ชี้ไปที่ key จริง ไม่งั้นจะลงไม่ได้
มาถึงครึ่งหลังของบท — เรื่อง เวลา ฟังดูเล็กน้อย แต่สำคัญมากบนเซิร์ฟเวอร์ ถ้านาฬิกาเครื่องเพี้ยน log จะจดเวลาผิด, ใบรับรอง (certificate) อาจใช้ไม่ได้, และระบบที่คุยกันหลายเครื่องจะงงกันหมด
เครื่องมือหลักคือ timedatectl — พิมพ์เฉยๆ ก็เห็นภาพรวมทั้งหมด
$ timedatectl Local time: Mon 2026-06-16 09:00:00 +07 Universal time: Mon 2026-06-16 02:00:00 UTC Time zone: Asia/Bangkok (+07, +0700) System clock synchronized: yes NTP service: active
หน้าจอนี้บอกครบ: เวลาท้องถิ่น, เวลา UTC (เวลากลางโลก), timezone ที่ตั้งไว้, และนาฬิกาซิงค์อยู่ไหม
$ timedatectl list-timezones # ดูรายชื่อ timezone ทั้งหมด $ timedatectl list-timezones | grep Bangkok Asia/Bangkok $ sudo timedatectl set-timezone Asia/Bangkok # ตั้ง timezone $ sudo timedatectl set-time "2026-06-16 09:00:00" # ตั้งเวลามือ
list-timezonesลิสต์ยาวมาก ใช้ | grep ช่วยหา เช่นหาคำว่า Bangkokset-timezoneตั้งเขตเวลา ต้องพิมพ์ชื่อให้ตรงเป๊ะ เช่น Asia/Bangkok (มี / และตัวพิมพ์ใหญ่)set-timeตั้งเวลาด้วยมือ — แต่ จะใช้ได้ต่อเมื่อปิด NTP ก่อน เพราะถ้า NTP เปิด มันจะแย่งตั้งเวลาให้เองtimedatectl set-timezone เปลี่ยนค่าในระบบถาวรเลย (จริงๆ มันไปแก้ลิงก์ /etc/localtime ให้) รอดหลังรีบูต ไม่ต้องตั้งซ้ำ
การตั้งเวลาด้วยมือไม่เวิร์กระยะยาว เพราะนาฬิกาเครื่องจะค่อยๆ เพี้ยน วิธีที่ถูกต้องคือให้เครื่อง ซิงค์เวลากับเซิร์ฟเวอร์เวลากลาง ผ่านระบบที่เรียกว่า NTP (Network Time Protocol) บน RHEL 9 ตัวที่ทำงานนี้คือบริการชื่อ chronyd
NTP เหมือน นาฬิกาบนมือถือที่ตั้งเวลาเองอัตโนมัติ — มันคอยถามเวลาจากเสาสัญญาณ/อินเทอร์เน็ตอยู่เรื่อยๆ คุณไม่ต้องมานั่งหมุนเข็มเอง chrony ก็ทำแบบเดียวกันให้เซิร์ฟเวอร์
ในไฟล์นี้เราระบุว่าจะไปถามเวลาจากเซิร์ฟเวอร์ตัวไหน ผ่านคำว่า server หรือ pool
pool 2.rhel.pool.ntp.org iburst server time.example.com iburst driftfile /var/lib/chrony/drift
serverระบุเซิร์ฟเวอร์เวลา 1 ตัว (โจทย์มักให้ชื่อ server มาเติมตรงนี้)poolระบุ “กลุ่ม” เซิร์ฟเวอร์เวลาหลายตัว เผื่อบางตัวล่มiburstให้ซิงค์เร็วขึ้นตอนเริ่มต้น (ใส่ต่อท้ายตามปกติ)$ sudo systemctl restart chronyd # โหลดค่าใหม่จากไฟล์ $ sudo timedatectl set-ntp true # เปิดการซิงค์เวลาอัตโนมัติ $ chronyc sources MS Name/IP address Stratum Poll Reach LastRx Last sample =========================================================== ^* time.example.com 2 6 377 21 +12us
systemctl restart chronydสำคัญมาก: แก้ไฟล์ chrony.conf แล้วต้อง restart มันถึงจะอ่านค่าใหม่timedatectl set-ntp trueเปิดสวิตช์ให้ระบบซิงค์เวลาอัตโนมัติ (สั่งให้ chronyd ทำงาน)chronyc sourcesตรวจว่ากำลังคุยกับเซิร์ฟเวอร์เวลาตัวไหน เครื่องหมาย ^* หน้าชื่อ = ตัวที่ซิงค์อยู่จริงการแก้ /etc/chrony.conf เขียนลงดิสก์ถาวรแล้ว แต่ให้แน่ใจว่าบริการรันอยู่และเปิดตอนบูตด้วย: sudo systemctl enable --now chronyd — มิฉะนั้นรีบูตแล้วเวลาอาจไม่ซิงค์
dnf install ขึ้น error หาของไม่เจอ — เกือบทุกครั้งคือพิมพ์ baseurl ผิด ตรวจ URL ให้ชัวร์ แล้วทดสอบด้วย dnf repolistgpgkey= ชี้ไปที่ key จริงด้วย ถ้ายังไม่มี key ให้ตั้ง gpgcheck=0 ไปก่อน ไม่งั้นลงไม่ได้enable แค่เลือกเวอร์ชัน ยังไม่ลง! ถ้าโจทย์ให้ “ติดตั้ง” ต้องใช้ module install ชื่อ:stream/etc/chrony.conf เสร็จแต่ไม่ restart บริการ — ค่าใหม่ไม่มีผล ต้อง systemctl restart chronyd ทุกครั้งtimedatectl set-ntp false ก่อน ค่อยตั้งเวลาเองasia/bangkok (พิมพ์เล็ก) ใช้ไม่ได้ ต้อง Asia/Bangkok ตัวพิมพ์ใหญ่ตรงเป๊ะ — ลอกจาก list-timezones มาเลยปลอดภัยสุด| คำสั่ง | ทำอะไร |
|---|---|
dnf install ชื่อ | ลงโปรแกรม (พร้อม dependency) |
dnf remove ชื่อ | ลบโปรแกรม |
dnf upgrade | อัปเดตทุกอย่างให้ล่าสุด |
dnf search คำ | ค้น package จากคำ |
dnf info ชื่อ | ดูรายละเอียด package |
dnf list installed | ลิสต์ package ที่ลงแล้ว |
dnf provides /path | ไฟล์นี้มาจาก package ไหน |
dnf history | ดูประวัติการลง/ลบ |
dnf group install "ชื่อ" | ลง package ทั้งกลุ่ม |
dnf module list | ดู module และ stream ที่มี |
dnf module install ชื่อ:stream | ลง module ตามเวอร์ชันที่เลือก |
dnf module reset ชื่อ | ล้างการเลือก stream |
dnf config-manager --add-repo URL | เพิ่ม repo จาก URL |
dnf repolist | ดูรายชื่อ repo ที่ใช้งานอยู่ |
rpm -qa | ลิสต์ทุก package ที่ลงแล้ว |
rpm -qf /path | ไฟล์นี้มาจาก package ไหน |
rpm -ql ชื่อ | package นี้มีไฟล์อะไรบ้าง |
timedatectl | ดูเวลา/timezone/สถานะ NTP |
timedatectl set-timezone Z | ตั้ง timezone (เช่น Asia/Bangkok) |
timedatectl list-timezones | ดูรายชื่อ timezone |
timedatectl set-ntp true | เปิดซิงค์เวลาอัตโนมัติ |
systemctl restart chronyd | รีสตาร์ทบริการเวลา (หลังแก้ conf) |
chronyc sources | ดูว่าซิงค์กับ server เวลาตัวไหน |
ลง/ลบ/ค้น/อัปเดต package ด้วย dnf → เลือกเวอร์ชันด้วย module stream → เพิ่ม repo จาก URL ที่โจทย์ให้ → สืบว่าไฟล์มาจาก package ไหนด้วย rpm -qf → ตั้ง timezone และเปิดซิงค์เวลา NTP ด้วย chrony ได้อย่างถูกต้องและถาวร