วิธีติดตั้ง Asterisk และ FreePBX บน VPS ด้วยตนเอง
เรียนรู้วิธีติดตั้ง Asterisk และ FreePBX บน VPS ของคุณเอง พร้อมตั้งค่า SIP trunk และพอร์ต RTP อย่างถูกต้อง รวมถึงการกำหนดกฎ Firewall เพื่อป้องกันการสแกนและการฉ้อโกงค่าโทร
เซิร์ฟเวอร์ VoIP แบบ self-hosted คืออะไร
เซิร์ฟเวอร์ VoIP แบบ self-hosted คือเซิร์ฟเวอร์ SIP ที่ทำงานบน VPS ภายใต้การควบคุมของคุณ ทำให้การโทรถูกส่งผ่านเครื่องของคุณเองแทนที่จะผ่านบริการโทรศัพท์แบบ hosted โดย VoIP (voice over IP) จะส่งสัญญาณเสียงในรูปแบบแพ็กเก็ต UDP ส่วน SIP (session initiation protocol) คือระบบสัญญาณที่ใช้ในการสร้างและยุติการโทร ข้อมูลเสียงไม่ได้เดินทางผ่าน SIP และข้อเท็จจริงเพียงข้อเดียวนี้คือสาเหตุของปัญหาเกือบทั้งหมดที่ระบุไว้ด้านล่าง
ระบบที่ทำงานได้ประกอบด้วย 4 ส่วนหลัก
- ซอฟต์แวร์ PBX (private branch exchange) โดยปกติจะเลือกใช้ Asterisk ซึ่งทำหน้าที่เก็บข้อมูลส่วนขยาย (extensions) และ dialplan
- ปลายทาง (endpoints) ได้แก่ โทรศัพท์ตั้งโต๊ะหรือซอฟต์โฟนที่ลงทะเบียนกับ PBX โดยใช้ชื่อผู้ใช้และรหัสผ่าน
- SIP trunk คือบัญชีแบบชำระเงินกับผู้ให้บริการที่เชื่อมต่อคุณเข้ากับเครือข่ายโทรศัพท์สาธารณะและให้เช่าหมายเลขโทรศัพท์จริง
- เส้นทางสื่อ (media path) คือกระแสข้อมูล RTP (real-time transport protocol) ที่ทำหน้าที่ส่งสัญญาณเสียงผ่านพอร์ต UDP ของตนเอง
การทำ self-host ระบบ PBX ไม่ได้หมายถึงการเป็นเจ้าของหมายเลขโทรศัพท์ด้วยตนเอง หมายเลขโทรศัพท์ยังคงมาจากผู้ให้บริการ และคุณยังคงต้องชำระค่าบริการรายหมายเลขและรายนาที สิ่งที่คุณเป็นเจ้าของคือการกำหนดเส้นทางการโทร, ระบบฝากข้อความเสียง, การบันทึกเสียง และรายการส่วนขยาย นอกจากนี้คุณยังต้องรับผิดชอบด้านความปลอดภัยของบริการที่มักตกเป็นเป้าหมายการโจมตีเพื่อผลประโยชน์ทางการเงินอีกด้วย
เซิร์ฟเวอร์ VoIP แบบ self-hosted ต้องใช้พอร์ตใดบ้าง
การส่งสัญญาณ SIP ใช้พอร์ต 5060 สำหรับ UDP และ TCP และพอร์ต 5061 สำหรับ SIP ผ่าน TLS (transport layer security) พอร์ตเหล่านี้ทำหน้าที่จัดการการตั้งค่าสายเรียกเข้าเท่านั้น ส่วนเสียงของแต่ละสายจะเป็นการรับส่งข้อมูลแบบ UDP แยกต่างหาก ซึ่งจะถูกส่งไปยังพอร์ตที่อยู่ในช่วง RTP โดย Asterisk มีไฟล์ตัวอย่าง rtp.conf ที่กำหนดค่า rtpstart=10000 และ rtpend=20000 ไว้ ซึ่งค่าเริ่มต้นที่คอมไพล์มาคือ 5000 และ 31000 โดยแต่ละสายจะใช้พอร์ต 2 พอร์ตจากช่วงดังกล่าว พอร์ตหนึ่งสำหรับ RTP และอีกพอร์ตสำหรับ RTCP (RTP control protocol)
การแยกส่วนนี้คือจุดที่ความพยายามครั้งแรกส่วนใหญ่ล้มเหลว สายเรียกเข้าเชื่อมต่อได้ โทรศัพท์ทั้งสองเครื่องแสดงสถานะว่ารับสายแล้ว แต่ทั้งสองฝั่งกลับไม่ได้ยินเสียงใดๆ เนื่องจาก firewall อนุญาตพอร์ต 5060 แต่ทิ้งแพ็กเก็ต RTP ทั้งหมด การส่งสัญญาณและสื่อเป็นข้อมูลคนละชุดกัน จึงต้องมีกฎ firewall แยกกัน หากคุณยังไม่คุ้นเคยกับความแตกต่างนี้ การอ่านเรื่อง วิธีการทำงานของพอร์ตและ listening sockets บน Linux จะเป็นประโยชน์ก่อนที่คุณจะเปิดพอร์ตใดๆ
ควรจำกัดช่วงพอร์ตให้แคบลงก่อนเปิดใช้งาน ช่วงพอร์ต 20,000 พอร์ตนั้นมากเกินความจำเป็นสำหรับระบบขนาดเล็ก การใช้ 2 พอร์ตต่อหนึ่งสายหมายความว่าช่วงพอร์ต 200 พอร์ตก็เพียงพอสำหรับการรองรับสายเรียกเข้าพร้อมกันถึง 100 สาย
[general]
rtpstart=10000
rtpend=10200นำไปปรับใช้ด้วย sudo asterisk -rx "core reload"
คุณควรติดตั้ง Asterisk หรือ FreePBX?
Asterisk คือตัวเครื่องมือหลัก คุณต้องตั้งค่าผ่านไฟล์ข้อความใน /etc/asterisk และเขียน dialplan ด้วยตนเอง ส่วน FreePBX คือเว็บอินเทอร์เฟซที่เขียนด้วย PHP และ JavaScript ซึ่งทำงานอยู่บน Asterisk โดยจะสร้างไฟล์เหล่านั้นให้คุณโดยอัตโนมัติ และเพิ่มโมดูลสำหรับระบบฝากข้อความเสียง (voicemail) และคิวสายเรียกเข้า (call queues)
ความแตกต่างที่สำคัญบน VPS คือการเป็นเจ้าของเครื่อง ณ เดือนสิงหาคม 2026 ตัวติดตั้งอย่างเป็นทางการของ FreePBX 17 ต้องการระบบ Debian 12 แบบมาตรฐาน และจะทำการติดตั้ง Asterisk, เว็บเซิร์ฟเวอร์, ฐานข้อมูล และ PHP หากคุณนำไปติดตั้งบนเครื่องที่มีบริการอื่นรันอยู่แล้ว ผลลัพธ์ที่ได้จะไม่เป็นที่น่าพอใจ ดังนั้นควรจัดสรร VPS แยกต่างหากสำหรับ FreePBX โดยเฉพาะ
wget https://github.com/FreePBX/sng_freepbx_debian_install/raw/master/sng_freepbx_debian_install.sh -O /tmp/sng_freepbx_debian_install.sh
sudo bash /tmp/sng_freepbx_debian_install.shบันทึกการติดตั้งจะถูกเก็บไว้ที่ /var/log/pbx/freepbx17-install.log ซึ่งเป็นจุดแรกที่ควรตรวจสอบเมื่อสคริปต์หยุดทำงานก่อนกำหนด
FreePBX จะเป็นผู้ควบคุมไฟล์ตั้งค่าที่มันสร้างขึ้น หากคุณแก้ไขไฟล์ใน pjsip.conf ด้วยตนเองบนเครื่องที่ใช้ FreePBX การเปลี่ยนแปลงนั้นจะหายไปในครั้งถัดไปที่ GUI เขียนไฟล์ดังกล่าว FreePBX จะอ่านไฟล์แยกต่างหากที่มีชื่อประกอบด้วย _custom สำหรับการตั้งค่าที่เขียนด้วยตนเอง และจะไม่เข้าไปยุ่งกับไฟล์เหล่านั้น
ข้อแลกเปลี่ยนที่ต้องพิจารณาคือ FreePBX มอบ GUI ให้คุณใช้งาน แต่ก็นำหน้าล็อกอินของระบบโทรศัพท์ไปวางไว้บนอินเทอร์เน็ตสาธารณะ ในขณะที่ Asterisk แบบดิบไม่มีหน้าเว็บใดๆ และทุกการตั้งค่าคือคำสั่งที่มีเอกสารกำกับชัดเจน ซึ่งคุณสามารถอ่านในไฟล์และเก็บไว้ใน git ได้ หากคุณติดตั้ง FreePBX ควรจำกัดการเข้าถึงพอร์ตเว็บให้เฉพาะที่อยู่ IP ของคุณเท่านั้น หรือเข้าถึงผ่าน VPN เนื่องจาก GUI สำหรับผู้ดูแลระบบ PBX เป็นเป้าหมายที่มีเส้นทางตรงสู่ผลประโยชน์ทางการเงิน
หมายเหตุเวอร์ชัน ข้อมูล ณ เดือนสิงหาคม 2026: Asterisk 22 คือรุ่นที่รองรับระยะยาว (LTS) ในปัจจุบัน ซึ่งเผยแพร่เมื่อเดือนตุลาคม 2024 และจะได้รับแพตช์ความปลอดภัยจนถึงเดือนตุลาคม 2028 ส่วน Asterisk 23 คือรุ่นมาตรฐาน ทั้งนี้ Ubuntu 24.04 มี Asterisk 20.6.0 อยู่ในคลังซอฟต์แวร์ universe
การติดตั้ง Asterisk บน Ubuntu 24.04
การติดตั้งผ่านแพ็กเกจของ distribution เป็นวิธีที่รวดเร็วที่สุด Ubuntu ได้ทำการแพตช์ซอฟต์แวร์ไว้ให้แล้ว และบริการจะเริ่มทำงานภายใต้ systemd โดยอัตโนมัติ
sudo apt update
sudo apt install -y asterisk
sudo asterisk -rx "core show version"การคอมไพล์จากซอร์สโค้ดจะทำให้คุณได้รับรุ่น long term support ล่าสุดแทน
sudo apt update
sudo apt install -y build-essential wget
cd /usr/local/src
sudo wget https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-22-current.tar.gz
sudo tar -xzf asterisk-22-current.tar.gz
cd asterisk-22.*
sudo contrib/scripts/install_prereq install
sudo ./configure
sudo make menuselect
sudo make -j"$(nproc)"
sudo make install
sudo make samples
sudo make config
sudo ldconfiginstall_prereq install จะดึง dependency สำหรับการ build ที่จำเป็นสำหรับ distribution ของคุณมาให้ ส่วน install_prereq test จะแสดงรายการคำสั่งที่จะถูกเรียกใช้งานโดยไม่มีการเปลี่ยนแปลงใดๆ กับระบบ make menuselect จะเปิดหน้าจอเลือกโมดูล ซึ่งเป็นจุดที่คุณต้องเปิดใช้งาน codec_opus ภายใต้หัวข้อ Codec Translators ให้เรียกใช้ make samples เฉพาะในการติดตั้งใหม่เท่านั้น เนื่องจากคำสั่งนี้จะเขียนไฟล์การตั้งค่าตัวอย่างลงใน /etc/asterisk ส่วน make config จะติดตั้ง init script ไว้ที่ /etc/init.d/asterisk โดย systemd จะควบคุมผ่านเลเยอร์ความเข้ากันได้กับ SysV ดังนั้น sudo systemctl enable --now asterisk จึงสามารถใช้งานได้หลังจากนั้น
ไม่ว่าคุณจะเลือกวิธีใด sudo asterisk -rvvv จะเชื่อมต่อเข้ากับ daemon ที่กำลังทำงานอยู่และแสดง CLI ให้คุณใช้งาน การเรียกใช้ core show version ใน CLI จะแสดงรายละเอียดของซอฟต์แวร์ที่คุณติดตั้งจริง
การตั้งค่า SIP trunk และส่วนขยาย (extension) หนึ่งรายการ
PJSIP คือ SIP channel driver ที่ใช้ใน Asterisk เวอร์ชันปัจจุบัน การตั้งค่าจะอยู่ในไฟล์ /etc/asterisk/pjsip.conf โดยสร้างขึ้นจากส่วนประกอบ (sections) ขนาดเล็กที่อ้างอิงถึงกันด้วยชื่อ ส่วนประกอบต่างประเภทกันสามารถใช้ชื่อเดียวกันได้ นี่คือเหตุผลที่บล็อกด้านล่างทุกบล็อกถูกเรียกว่า mytrunk
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0
[mytrunk]
type=registration
outbound_auth=mytrunk
server_uri=sip:sip.example.com
client_uri=sip:1234567890@sip.example.com
retry_interval=60
[mytrunk]
type=auth
auth_type=userpass
username=1234567890
password=REPLACE_WITH_A_LONG_RANDOM_SECRET
[mytrunk]
type=aor
contact=sip:sip.example.com:5060
[mytrunk]
type=endpoint
context=from-trunk
disallow=all
allow=ulaw
outbound_auth=mytrunk
aors=mytrunk
[mytrunk]
type=identify
endpoint=mytrunk
match=sip.example.comออบเจกต์ registration จะส่งคำสั่ง REGISTER เพื่อแจ้งให้ผู้ให้บริการทราบว่าต้องส่งสายเรียกเข้าของคุณไปที่ใด ส่วนออบเจกต์ identify คือวิธีที่สายเรียกเข้าจากผู้ให้บริการจะถูกจับคู่กับ endpoint นี้โดยดูจาก source address ซึ่งโดยปกติผู้ให้บริการจะประกาศที่อยู่หลายรายการให้ระบุไว้ที่นั่น การลงทะเบียนขาออก (outbound registration) และ endpoint เป็นออบเจกต์ที่แยกจากกันโดยเจตนา เพื่อให้ส่วนหนึ่งทำหน้าที่แจ้งผู้ให้บริการว่าคุณอยู่ที่ไหน และอีกส่วนทำหน้าที่ตัดสินใจว่าจะจัดการกับสายเรียกเข้านั้นอย่างไร
โทรศัพท์ตั้งโต๊ะต้องการออบเจกต์เพิ่มอีกสามรายการ
[6001]
type=endpoint
context=internal
disallow=all
allow=ulaw
auth=auth6001
aors=6001
direct_media=no
[auth6001]
type=auth
auth_type=userpass
username=6001
password=REPLACE_WITH_A_LONG_RANDOM_SECRET
[6001]
type=aor
max_contacts=1direct_media=no ทำหน้าที่คงสถานะ Asterisk ให้อยู่ในเส้นทางสื่อ (media path) หากละเว้นส่วนนี้ Asterisk จะพยายามให้ endpoint ทั้งสองฝั่งส่ง RTP หากันโดยตรง ซึ่งจะล้มเหลวเมื่อโทรศัพท์อยู่หลัง NAT (network address translation) บนเราเตอร์ตามบ้าน ห้ามตั้งรหัสผ่านให้ตรงกับหมายเลขส่วนขยายโดยเด็ดขาด ตัวอย่างต้นฉบับใช้ password=6001 สำหรับส่วนขยาย 6001 เพื่อให้อ่านเข้าใจง่าย แต่โปรแกรมสแกนจะพยายามเจาะระบบด้วยรูปแบบนั้นเป็นอันดับแรก
Dialplan ในไฟล์ /etc/asterisk/extensions.conf จะเป็นตัวกำหนดว่าแต่ละ context สามารถทำอะไรได้บ้าง
[internal]
exten => 6001,1,Dial(PJSIP/6001,20)
exten => _9X.,1,Dial(PJSIP/${EXTEN:1}@mytrunk,60)
[from-trunk]
exten => 1234567890,1,Dial(PJSIP/6001,20)
same => n,Hangup()context ทั้งสองนี้ถือเป็นขอบเขตความปลอดภัย from-trunk จัดการสายที่เข้ามาจากผู้ให้บริการและทำได้เพียงเรียกไปยังส่วนขยาย 6001 เท่านั้น มันไม่สามารถเข้าถึงรูปแบบ _9X. ได้ ดังนั้นสายจากภายนอกจึงไม่สามารถโทรออกผ่าน trunk ของคุณได้ หากคุณรวม context เข้าด้วยกัน คุณจะสร้างช่องทางสำหรับการฉ้อโกงค่าโทร (toll fraud) แบบคลาสสิกขึ้นมาทันที คือคนแปลกหน้าโทรเข้าเบอร์คุณ แล้ว dialplan ของคุณก็โทรออกโดยใช้บัญชีของคุณ ซึ่งคุณจะต้องเป็นผู้รับผิดชอบค่าใช้จ่ายนั้น
นำการตั้งค่าไปใช้งานและตรวจสอบผลลัพธ์
sudo asterisk -rx "pjsip reload"
sudo asterisk -rx "pjsip show registrations"
sudo asterisk -rx "pjsip show endpoints"pjsip show registrations ควรแสดงรายการ mytrunk พร้อมสถานะ Registered หากขึ้นสถานะ Rejected หมายความว่าผู้ให้บริการปฏิเสธข้อมูลรับรองของคุณ หากขึ้นสถานะ Unregistered หมายความว่าคำสั่ง REGISTER ของคุณไม่ได้รับการตอบกลับ ให้ตรวจสอบ firewall เป็นลำดับถัดไป
กฎไฟร์วอลล์สำหรับ SIP และ RTP
การส่งสัญญาณ (Signalling) และสื่อ (Media) ควรได้รับการจัดการที่แตกต่างกันเนื่องจากมีความเสี่ยงไม่เท่ากัน ให้จำกัดพอร์ต 5060 เฉพาะที่อยู่ IP ที่ผู้ให้บริการของคุณใช้งานจริง และเครือข่ายที่โทรศัพท์ของคุณเชื่อมต่ออยู่เท่านั้น
sudo ufw allow proto udp from 203.0.113.10 to any port 5060
sudo ufw allow proto tcp from 203.0.113.10 to any port 5060
sudo ufw allow 10000:10200/udp
sudo ufw status verboseช่วงพอร์ต RTP เป็นส่วนที่คุณไม่สามารถจำกัดให้แคบได้มากนัก เนื่องจากสื่อมักจะส่งมาจากที่อยู่ IP ที่ต่างจากส่วนของการส่งสัญญาณ หากผู้ให้บริการของคุณมีการประกาศช่วงเครือข่ายย่อย (subnets) สำหรับสื่อ ให้ขอข้อมูลดังกล่าวและจำกัดการเข้าถึงเฉพาะเครือข่ายเหล่านั้น ให้กำหนดขนาดช่วงพอร์ตเท่าที่จำเป็นต่อการใช้งานในช่วงเวลาที่มีการใช้งานสูงสุดเท่านั้น สำหรับนโยบายเริ่มต้น ลำดับของกฎ และรายละเอียดอื่นๆ ของโมเดล ufw สามารถดูได้ที่ คู่มือพื้นฐานการใช้งาน ufw firewall สำหรับ VPS
ตรวจสอบ IPv6 ด้วยเช่นกัน หากมีการตั้งค่า IPV6=no ไว้ใน /etc/default/ufw ตัว ufw จะไม่กรองทราฟฟิก IPv6 เลย ส่งผลให้ daemon ที่ผูกอยู่กับ :: สามารถเข้าถึงได้ผ่าน IPv6 โดยไม่มีกฎข้างต้นบังคับใช้ การเปิดพอร์ตสำหรับ IPv6 ด้วย ufw อธิบายถึงความแตกต่างระหว่างเครือข่ายทั้งสองประเภท ผู้ให้บริการส่วนใหญ่มักมีไฟร์วอลล์เครือข่ายแยกต่างหากในแผงควบคุม ซึ่งจะถูกบังคับใช้ก่อนที่แพ็กเก็ตจะมาถึง VPS ของคุณ ดังนั้นคุณจึงจำเป็นต้องเปิดพอร์ตในทั้งสองจุด
การโจมตีแบบ brute force และการฉ้อโกงค่าโทรศัพท์ผ่าน SIP ไม่ใช่ปัญหาที่เลือกป้องกันได้
หากคุณเปิดพอร์ต 5060 บน public address การสแกนจะเริ่มต้นขึ้นทันที รูปแบบการโจมตีมีความสม่ำเสมอ คือมีการส่งคำขอ REGISTER และ INVITE จากหลาย source address โดยพยายามสุ่มเลขหมายต่อพ่วง (extension) ด้วยรหัสผ่านที่คาดเดาง่าย Asterisk จะบันทึกทุกความล้มเหลวไว้ และบรรทัดใน log จะมีลักษณะดังนี้
Request 'REGISTER' from '<sip:1000@198.51.100.20>' failed for '198.51.100.20:5060' (callid: 5f1a5c0d) - No matching endpoint foundเหตุผลที่เรื่องนี้ต้องให้ความสำคัญอย่างจริงจังคือเรื่องเงิน หาก extension ถูกขโมยไป ผู้โจมตีจะใช้โทรออกต่างประเทศในราคาแพง มักจะเป็นหมายเลข premium rate ที่ผู้โจมตีได้รับส่วนแบ่งจากค่าโทร และคุณจะเป็นผู้รับผิดชอบค่าใช้จ่ายนั้นเนื่องจากการโทรดังกล่าวใช้ข้อมูลยืนยันตัวตนของคุณ การโจมตีนี้ทำงานด้วยความเร็วระดับเครื่องจักรและมักเกิดขึ้นในช่วงกลางคืน
มาตรการควบคุม 6 ประการต่อไปนี้ถือเป็นสิ่งที่จำเป็นสำหรับการเสริมความปลอดภัย ไม่ใช่ทางเลือก
- ห้ามสร้าง extension ที่มีรหัสผ่านเป็นเลขหมายของตัวเองหรือคำสั้นๆ ให้สร้างรหัสผ่านด้วย
openssl rand -base64 24แล้วคัดลอกมาวาง - ปิดการรับสายเรียกเข้าแบบไม่ระบุตัวตน (anonymous inbound calls) โดยปกติ PJSIP จะปฏิเสธสายที่ไม่ระบุตัวตนอยู่แล้ว และจะยอมรับก็ต่อเมื่อคุณสร้าง endpoint ที่ชื่อ
anonymousเท่านั้น ดังนั้นห้ามสร้าง endpoint ดังกล่าว - แยก context ของ trunk ออกจาก context ใดก็ตามที่สามารถโทรออกได้ ดังที่แสดงไว้ข้างต้น
- จำกัดการส่งสัญญาณ (signalling) ตาม source address ทั้งใน ufw และใน firewall ของผู้ให้บริการเครือข่ายของคุณ
- กำหนดเพดานการใช้จ่าย (spending cap) กับผู้ให้บริการ SIP trunk ของคุณ และปิดการใช้งานปลายทางต่างประเทศที่คุณไม่เคยโทร นี่เป็นมาตรการเดียวที่จะจำกัดความเสียหายเมื่อมาตรการอื่นล้มเหลว
- ใช้ fail2ban ร่วมกับ log ของ Asterisk
นอกจากนี้ Asterisk ยังสามารถแจ้งเตือนเหตุการณ์ด้านความปลอดภัยหลังจากได้รับคำขอที่ไม่ตรงกันซ้ำๆ จาก address เดียวกัน ส่วน [global] ในไฟล์ pjsip.conf จะใช้ค่า unidentified_request_count ซึ่งมีค่าเริ่มต้นเป็น 5 และ unidentified_request_period ซึ่งมีค่าเริ่มต้นเป็น 5 วินาที ทั้งสองค่านี้รวมกันหมายความว่า หากมีการส่งคำขอที่ไม่ตรงกัน 5 ครั้งจาก address เดียวกันภายใน 5 วินาที จะเกิดเหตุการณ์ด้านความปลอดภัยที่ fail2ban สามารถดำเนินการจัดการได้
การแบนสแกนเนอร์ด้วย fail2ban
fail2ban มี jail ที่เขียนไว้ให้แล้วใน asterisk ซึ่งครอบคลุมพอร์ต 5060 และ 5061 โดยอ่านจาก /var/log/asterisk/messages และมีค่าเริ่มต้นเป็น maxretry = 10 jail ดังกล่าวจะยังไม่ทำงานจนกว่าคุณจะเปิดใช้งานใน /etc/fail2ban/jail.local
[asterisk]
enabled = true
maxretry = 5
findtime = 600
bantime = 86400sudo systemctl restart fail2ban
sudo fail2ban-client status asteriskผลลัพธ์ที่ถูกต้องจะแสดงไฟล์ log ของ jail และจำนวนที่อยู่ IP ที่ถูกแบนอยู่ในขณะนี้ หากเปิดพอร์ต 5060 สู่สาธารณะ จำนวนดังกล่าวจะไม่เป็นศูนย์ภายในเวลาหนึ่งวัน ตัวกรองที่มาพร้อมกับโปรแกรมจะจับคู่กับประกาศ No matching endpoint found ด้านบน และยังจับคู่กับบรรทัด SecurityEvent ที่มีโครงสร้างของ Asterisk ได้ด้วย เหตุการณ์เหล่านั้นจะถูกส่งไปยังช่องทาง log แยกต่างหากซึ่งถูก comment ไว้ใน /etc/asterisk/logger.conf ดังนั้นให้เปิดใช้งานในไฟล์นั้นและเพิ่มไฟล์ดังกล่าวลงใน logpath ของ jail หากคุณต้องการใช้งาน
[logfiles]
console => notice,warning,error
messages.log => notice,warning,error
security.log => securityโหลดตัวบันทึก log ใหม่ด้วย sudo asterisk -rx "logger reload" ตัวกรองนี้ยังมี journalmatch สำหรับ asterisk.service ดังนั้นคุณจึงสามารถใช้ backend ของ journal ได้หากไม่ต้องการเก็บไฟล์ log ไว้ การติดตั้ง โครงสร้างของ jail.local และการปลดแบนที่อยู่ IP ที่คุณล็อกไว้ มีอธิบายไว้ใน คู่มือการใช้งาน fail2ban สำหรับ Ubuntu 24.04
ความหน่วงและการเลือกใช้ Codec บน VPS ที่อยู่ห่างไกล
ความล่าช้าถูกกำหนดโดยปัจจัยทางภูมิศาสตร์และไม่สามารถแก้ไขได้ด้วยการตั้งค่า ITU-T G.114 แนะนำให้รักษาความล่าช้าทางเดียว (one-way delay) ไว้ไม่เกิน 150 ms สำหรับการสนทนาปกติ และถือว่าค่าที่สูงถึง 400 ms ยังคงอยู่ในระดับที่ใช้งานได้ เสียงจากโทรศัพท์จะถูกส่งไปยัง VPS ของคุณแล้วจึงส่งต่อไปยังผู้ให้บริการ Trunk ดังนั้นการเลือก VPS ในภูมิภาคที่ไม่เหมาะสมจะทำให้เกิดการเดินทางของข้อมูลซ้ำซ้อนเป็นสองเท่า ควรวาง VPS ไว้ใกล้กับโทรศัพท์หรือใกล้กับผู้ให้บริการ และหากต้องเลือกระหว่างสองจุดนี้ ให้เลือกใกล้กับโทรศัพท์เป็นอันดับแรก เนื่องจากเส้นทางดังกล่าวส่วนใหญ่มักผ่านอินเทอร์เน็ตของผู้ใช้งานทั่วไปซึ่งมีปัญหาเรื่อง jitter รุนแรงที่สุด
การเลือก Codec จะเป็นตัวกำหนดแบนด์วิดท์ต่อการโทรแต่ละครั้ง Codec แต่ละตัวในที่นี้จะส่งแพ็กเก็ตทุกๆ 20 ms ซึ่งเท่ากับ 50 แพ็กเก็ตต่อวินาที โดยแต่ละแพ็กเก็ตจะมีส่วนของ IP, UDP และ RTP header เพิ่มเข้ามาอีก 40 bytes นอกเหนือจากข้อมูลเสียง (audio payload)
The data behind this chart
[
{
"label": "G.711 ulaw",
"payload_kbps": 64,
"ip_kbps": 80
},
{
"label": "G.722",
"payload_kbps": 64,
"ip_kbps": 80
},
{
"label": "Opus at 24 kbps",
"payload_kbps": 24,
"ip_kbps": 40
},
{
"label": "G.729",
"payload_kbps": 8,
"ip_kbps": 24
}
]G.711 ulaw เป็นค่าเริ่มต้นบน Trunk ส่วนใหญ่ โดยมี payload อยู่ที่ 64 kbps และเมื่อรวมกับ header แล้ว การโทรหนึ่งครั้งจะมีค่าใช้จ่ายอยู่ที่ 80 kbps ในแต่ละทิศทาง ส่วน Opus ที่ 24 kbps จะอยู่ที่ 40 kbps และ G.729 จะลดลงเหลือ 24 kbps โดยแลกกับคุณภาพเสียงและภาระการประมวลผลของ CPU ตัวเลขเหล่านี้เป็นการคำนวณจาก header ไม่ใช่การวัดผลจริง ซึ่งคิดจากอัตรา payload บวกกับ 40 bytes ต่อแพ็กเก็ตที่ 50 แพ็กเก็ตต่อวินาที ทั้งนี้การทำ Ethernet หรือ VLAN framing จะเพิ่มปริมาณข้อมูลบนสายอีกเล็กน้อย
การแปลงรหัส (transcoding) ต้องใช้ทรัพยากร CPU หากโทรศัพท์และ Trunk ของคุณรองรับ ulaw ทั้งคู่ ให้ตั้งค่าอนุญาตเฉพาะ ulaw เพื่อให้ Asterisk ส่งผ่านสัญญาณเสียงไปโดยไม่ต้องประมวลผลเพิ่มเติม Opus มีประสิทธิภาพดีบนลิงก์ที่มีการสูญเสียข้อมูลสูง แต่การแปลงรหัสระหว่าง Opus และ G.711 จำเป็นต้องใช้โมดูลภายนอก codec_opus ซึ่งคุณต้องเลือกใน make menuselect และโมดูลนี้ไม่ได้ถูกติดตั้งมาเป็นค่าเริ่มต้น
สิ่งที่มักเกิดปัญหาและข้อความที่คุณจะพบ
การเชื่อมต่อสำเร็จแต่ไม่มีเสียงใดๆ ข้อมูล RTP ไม่ถูกส่งมา ให้ตรวจสอบว่าช่วงพอร์ตใน rtp.conf ตรงกับช่วงพอร์ตที่คุณเปิดไว้ในไฟร์วอลล์ จากนั้นให้ตรวจสอบแพ็กเก็ตด้วย sudo tcpdump -ni any udp portrange 10000-10200 ในขณะที่ทำการโทร หากไม่มีแพ็กเก็ตปรากฏขึ้นเลย แสดงว่าไฟร์วอลล์ของคุณหรือไฟร์วอลล์เครือข่ายของผู้ให้บริการกำลังบล็อกแพ็กเก็ตเหล่านั้นอยู่
มีเสียงเพียงฝั่งเดียว ฝั่งหนึ่งกำลังส่ง RTP ไปยังที่อยู่ที่รับข้อมูลไม่ได้ ซึ่งเป็นปัญหาเรื่องที่อยู่มากกว่าเรื่องพอร์ต หาก VPS ของคุณมีที่อยู่สาธารณะอยู่บนอินเทอร์เฟซโดยตรง ก็ไม่จำเป็นต้องจัดการเรื่อง NAT แต่หากผู้ให้บริการกำหนดที่อยู่ส่วนตัวให้กับ VPS โดยมีการแมปแบบหนึ่งต่อหนึ่งกับที่อยู่สาธารณะ ให้ตั้งค่าที่อยู่สาธารณะในส่วน transport และระบุช่วงที่อยู่ส่วนตัวของคุณไว้ใน local_net
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0
local_net=10.0.0.0/8
external_media_address=198.51.100.5
external_signaling_address=198.51.100.5No matching endpoint found ปรากฏใน log คำขอไม่ตรงกับ endpoint ใดๆ ทั้งในส่วนของที่อยู่ IP หรือชื่อผู้ใช้ หากมาจากเครื่องสแกนถือเป็นเรื่องปกติและ fail2ban จะจัดการเอง แต่หากมาจากผู้ให้บริการของคุณเอง แสดงว่าส่วน identify ไม่ได้ระบุที่อยู่ที่พวกเขาใช้ติดต่อคุณเข้ามา
สถานะการลงทะเบียนคือ Rejected ผู้ให้บริการปฏิเสธข้อมูลรับรองในส่วน auth ของคุณ ให้รันคำสั่ง pjsip set logger on ที่ CLI สังเกตการทำงานของ REGISTER หนึ่งรายการและการตอบกลับ จากนั้นเปรียบเทียบค่า client_uri และ username กับข้อมูลที่ผู้ให้บริการมอบให้คุณ
ไม่มีข้อมูลที่เป็นประโยชน์ใน log เลย โดยปกติ Asterisk จะบันทึกข้อมูลระดับ notice ขึ้นไปไว้ที่ messages.log ให้เพิ่มระดับการบันทึกด้วย core set verbose 4 และ pjsip set logger on ในขณะที่คุณจำลองปัญหา จากนั้นให้ปิดทั้งสองค่านี้ เพราะตัวบันทึก SIP จะเขียนข้อมูลทุกแพ็กเก็ตลงใน log
ก่อนที่คุณจะเปิดใช้งานสู่สาธารณะ
PBX ไม่เหมือนกับบริการอื่นที่คุณโฮสต์ด้วยตนเอง หากเว็บแอปพลิเคชันเสียหาย คุณอาจแค่เสียหน้าเว็บไป แต่หาก PBX เสียหาย คุณอาจต้องเสียค่าโทรศัพท์มหาศาลภายในเวลาไม่กี่ชั่วโมงขณะที่คุณกำลังหลับ ควรใช้งานบน VPS ที่ไม่มีบริการอื่นรันอยู่ จำกัดการเข้าถึงพอร์ต 5060 ให้เฉพาะหมายเลข IP ที่รู้จักเท่านั้น กำหนดรหัสผ่านแบบสุ่มให้กับทุก extension และตั้งค่าเพดานการใช้จ่ายในบัญชี trunk สำหรับส่วนอื่นของเซิร์ฟเวอร์ ควรใช้มาตรฐานความปลอดภัยพื้นฐานเช่นเดียวกับเซิร์ฟเวอร์ที่เปิดสู่สาธารณะทั่วไป ซึ่งได้อธิบายไว้ใน บทวิเคราะห์ความปลอดภัยของ VPS นี้
FAQ
ฉันต้องเปิดพอร์ตใดบ้างสำหรับเซิร์ฟเวอร์ VoIP ที่โฮสต์เอง?
เปิดพอร์ต 5060 สำหรับ SIP signalling ผ่านโปรโตคอล UDP และ TCP, พอร์ต 5061 หากคุณใช้ SIP ผ่าน TLS และช่วงพอร์ต UDP สำหรับสื่อ RTP ตัวอย่าง rtp.conf ของ Asterisk ใช้ช่วง 10000 ถึง 20000 และค่าเริ่มต้นที่คอมไพล์มาคือ 5000 ถึง 31000 การโทรแต่ละครั้งจะใช้พอร์ตสองพอร์ตจากช่วงดังกล่าว ดังนั้นช่วงพอร์ตสองร้อยพอร์ตจะรองรับการโทรพร้อมกันได้หนึ่งร้อยสาย ให้เปิดช่วง RTP เป็น UDP และจำกัดพอร์ต 5060 ให้เข้าถึงได้เฉพาะที่อยู่ของผู้ให้บริการและเครือข่ายของคุณเอง แทนที่จะเปิดให้ทุกคนเข้าถึงได้
ฉันควรติดตั้ง Asterisk แบบปกติหรือใช้ FreePBX?
ติดตั้ง Asterisk แบบดิบเมื่อคุณต้องการลดพื้นที่การโจมตี (attack surface) และต้องการเก็บไฟล์คอนฟิกูเรชันไว้ใน git รวมถึงเมื่อคุณยินดีที่จะเขียน dialplan ด้วยตนเอง ติดตั้ง FreePBX เมื่อคุณต้องการ GUI สำหรับจัดการส่วนขยาย (extensions), ข้อความเสียง (voicemail) และคิวการโทร ณ เดือนสิงหาคม 2026 ตัวติดตั้ง FreePBX 17 ต้องการเครื่อง Debian 12 ที่สะอาดและจะติดตั้ง Asterisk, เว็บเซิร์ฟเวอร์, ฐานข้อมูล และ PHP ดังนั้นควรเตรียม VPS แยกต่างหากสำหรับงานนี้ FreePBX จะสร้างไฟล์คอนฟิกูเรชันที่จัดการโดยระบบขึ้นใหม่เสมอ ดังนั้นการแก้ไขด้วยมือควรทำในไฟล์ _custom เท่านั้น
ทำไมถึงไม่มีเสียงหลังจากเชื่อมต่อสายแล้ว?
การส่งสัญญาณ (signalling) ทำงานได้ปกติแต่สื่อ (media) ไม่ทำงาน SIP ทำการตั้งค่าการโทรบนพอร์ต 5060 ส่วนเสียงจะเป็นการไหลของข้อมูล UDP แยกต่างหากไปยังพอร์ตในช่วง RTP ซึ่งอาจถูกบล็อกโดยบางอย่าง ตรวจสอบว่าช่วงพอร์ตใน rtp.conf ตรงกับช่วงที่เปิดในไฟร์วอลล์ของคุณ และตรวจสอบไฟร์วอลล์เครือข่ายของผู้ให้บริการรวมถึงไฟร์วอลล์บนเซิร์ฟเวอร์ด้วย ลองรัน sudo tcpdump -ni any udp portrange 10000-10200 ระหว่างการโทร หากไม่มีแพ็กเก็ตแสดงว่าแพ็กเก็ตถูกบล็อกก่อนที่จะมาถึง
ฉันจะหยุดการโจมตีแบบ SIP brute force และการฉ้อโกงค่าโทรได้อย่างไร?
กำหนดรหัสผ่านที่ยาวและสุ่มให้กับทุกส่วนขยาย ห้ามใช้รหัสผ่านที่ตรงกับหมายเลขส่วนขยายเด็ดขาด แยก context ที่ใช้โดย trunk ออกจาก context ใดๆ ที่สามารถโทรออกได้ เพื่อป้องกันไม่ให้สายเรียกเข้าสามารถโทรออกผ่านบัญชีของคุณได้ จำกัดพอร์ต 5060 ให้เข้าถึงได้เฉพาะที่อยู่ของผู้ให้บริการของคุณเท่านั้น เปิดใช้งาน jail asterisk ใน fail2ban ซึ่งจะอ่านค่าจาก /var/log/asterisk/messages และแบนที่อยู่ที่มีความพยายามล็อกอินล้มเหลว No matching endpoint found จากนั้นให้ตั้งค่าเพดานการใช้จ่ายและบล็อกปลายทางระหว่างประเทศที่ไม่ได้ใช้งานกับผู้ให้บริการของคุณ เพราะนั่นเป็นวิธีเดียวที่จะจำกัดความเสียหายหากมาตรการอื่นล้มเหลว
การใช้ VPS ในภูมิภาคที่ห่างไกลส่งผลต่อคุณภาพการโทรหรือไม่?
ส่งผล เพราะเสียงต้องเดินทางสองช่วง คือจากโทรศัพท์ไปยัง VPS และจาก VPS ไปยังผู้ให้บริการ trunk มาตรฐาน ITU-T G.114 แนะนำให้ความหน่วงทางเดียว (one-way delay) ต่ำกว่า 150 ms และ VPS ที่วางตำแหน่งไม่เหมาะสมอาจใช้เวลาส่วนใหญ่ไปกับระยะทางเพียงอย่างเดียว ให้เลือกภูมิภาคที่ใกล้กับโทรศัพท์ เนื่องจากช่วงนั้นมักวิ่งผ่านอินเทอร์เน็ตของผู้บริโภคซึ่งมีค่า jitter สูงที่สุด การเลือก codec ไม่ช่วยแก้ปัญหาความหน่วง แต่จะเปลี่ยนเพียงการใช้แบนด์วิดท์เท่านั้น ดังนั้น G.729 ช่วยประหยัดข้อมูลได้แต่ไม่สามารถกู้คืนเส้นทางที่มีความหน่วง 200 ms ได้