วิธีติดตั้ง UniFi Controller บน VPS แบบละเอียด
เรียนรู้วิธีติดตั้ง UniFi Network Application บน VPS พร้อมเทคนิคการจัดสรร RAM การรัน Docker ร่วมกับ MongoDB และการตั้งค่า Layer 3 Adoption ผ่านคำสั่ง set-inform
หน้าที่จริงของ UniFi controller บน VPS
UniFi controller บน VPS คือเซิร์ฟเวอร์จัดการหนึ่งเครื่องที่ยังคงเข้าถึงได้แม้ไซต์ที่ดูแลอยู่จะล่มไปแล้ว ซอฟต์แวร์ดังกล่าวคือ UniFi Network Application ของ Ubiquiti ซึ่งเป็นโปรแกรม Java ที่ทำงานร่วมกับฐานข้อมูล MongoDB ทำหน้าที่กำหนดค่า access point และ switch ของคุณ จัดเก็บสถิติการใช้งาน และให้บริการอินเทอร์เฟซสำหรับผู้ดูแลระบบ โดยตัวมันเองไม่ได้ทำหน้าที่รับส่งข้อมูล (traffic) ของไคลเอนต์
ประเด็นสุดท้ายนี้เป็นตัวกำหนดว่าควรติดตั้งไว้ที่ใด หากคุณวาง controller ไว้บนเครื่องภายในสำนักงานที่มันดูแลอยู่ คุณจะสูญเสียทั้งเครือข่ายและเครื่องมือสำหรับตรวจสอบเครือข่ายไปในเวลาเดียวกัน แต่หากคุณวางไว้บน VPS ที่มี public address ที่เสถียร มันจะยังคงทำงานต่อไป เก็บข้อมูลได้ต่อเนื่อง และสามารถรับอุปกรณ์ (adopt) จากหลายไซต์มาไว้ที่จุดเดียวได้ สิ่งที่มันต้องการคือ uptime ไม่ใช่พลังประมวลผลสูง
เมื่อ controller ออฟไลน์ access point และ switch ที่ถูก adopt ไว้แล้วจะยังคงส่งข้อมูลต่อไปตามการตั้งค่าที่ได้รับไปก่อนหน้า คุณจะสูญเสียหน้าแดชบอร์ดและสถิติต่างๆ รวมถึงฟีเจอร์ที่จำเป็นต้องใช้ controller ในขณะทำงาน เช่น หน้าล็อกอิน guest portal หรือ RADIUS (remote authentication dial-in user service) หาก controller ทำหน้าที่เป็นเซิร์ฟเวอร์ RADIUS ให้คุณ แต่ไคลเอนต์จะยังคงเชื่อมต่อเครือข่ายได้ตามปกติ
UniFi controller ต้องการ RAM เท่าไร
ขั้นต่ำคือ 2 GB แต่ควรจัดสรรที่ 4 GB จะเหมาะสมกว่า มีส่วนประกอบหลักสองอย่างที่ใช้หน่วยความจำในกล่องเดียวกันคือ Java และ MongoDB ซึ่งต่างฝ่ายต่างจัดสรรขนาดหน่วยความจำของตัวเอง
Java heap ถูกจำกัดด้วย MEM_LIMIT ซึ่ง container image ตั้งค่าเริ่มต้นไว้ที่ 1024 MB ส่วน MongoDB คืออีกครึ่งหนึ่งที่เหลือ โดย storage engine แบบ WiredTiger จะกำหนดขนาด cache ไว้ที่ครึ่งหนึ่งของ RAM ส่วนที่เกินจาก 1 GB หรือ 256 MB แล้วแต่ว่าค่าใดจะมากกว่า ใน VPS ขนาด 2 GB จะมี cache ประมาณ 512 MB รวมกับ heap อีก 1 GB บวกกับ non-heap memory ของ JVM และตัวระบบปฏิบัติการเอง ซึ่งเพียงพอสำหรับการใช้งานทั่วไป แต่หากวันใดที่มีโหลดงานหนัก kernel จะสั่ง out-of-memory killer ให้ยุติการทำงานของ process ใด process หนึ่ง หากเกิดการรีสตาร์ทโดยไม่ทราบสาเหตุ ให้รัน dmesg -T | grep -i 'killed process' เพื่อตรวจสอบว่าเกิดจากกรณีนี้หรือไม่ หากคุณมี RAM เพียง 2 GB ควรเพิ่ม swap file เข้าไปด้วย
CPU และ disk ไม่ได้ต้องการทรัพยากรสูง vCPU หนึ่งหรือสองตัวสามารถรองรับอุปกรณ์ได้หลายสิบตัว เริ่มต้นที่ disk ขนาด 20 GB แล้วคอยเฝ้าดูการใช้งาน เนื่องจากฐานข้อมูลจะขยายขนาดตามจำนวน client ที่พบและระยะเวลาที่คุณเก็บสถิติไว้ ตัว controller เพียงอย่างเดียวจะทำให้เครื่องขนาด 4 GB เหลือทรัพยากรว่างส่วนใหญ่ หากคุณวางแผนจะรันบริการอื่นร่วมด้วย ให้คำนวณขนาดตามบริการนั้นเป็นหลัก เพราะ PhotoPrism และ Immich มีความต้องการ RAM ขั้นต่ำที่ต่างกันมาก และทั้งสองบริการต้องการ RAM มากกว่าตัว controller
มีฟีเจอร์ CPU อย่างหนึ่งที่สำคัญและมักถูกมองข้ามในแผนบริการราคาถูก:
grep -m1 -o avx /proc/cpuinfoMongoDB 5.0 ขึ้นไปต้องการ AVX (advanced vector extensions) บนฮาร์ดแวร์ x86_64 หากคำสั่งดังกล่าวไม่แสดงผลลัพธ์ใดๆ mongod จะหยุดทำงานระหว่างเริ่มระบบและ container จะรีสตาร์ทวนไปเรื่อยๆ เนื่องจาก binary พยายามรันคำสั่งที่ CPU ไม่มี โฮสต์ประเภท Intel Celeron และ Pentium รุ่นเก่ามักเป็นสาเหตุ รวมถึง hypervisor ที่ซ่อน CPU flag ไม่ให้ guest เห็น MongoDB 4.4 ไม่ต้องการ AVX และเป็นทางเลือกเดียวที่เหลืออยู่ แต่เป็นเวอร์ชันฐานข้อมูลที่ต้นทางไม่มีการอัปเดตแพตช์แล้ว การย้ายไปใช้โฮสต์ที่มี CPU ใหม่กว่าเป็นทางออกที่ดีกว่า สำหรับ VPS แบบ ARM จะไม่มีปัญหานี้เนื่องจาก AVX เป็นชุดคำสั่งของ x86 และทั้งสอง image มี build สำหรับ arm64 ให้ใช้งาน หากคุณกำลังตัดสินใจระหว่างสองสถาปัตยกรรมนี้ ความแตกต่างระหว่างแผน VPS แบบ ARM และ x86 มีรายละเอียดมากกว่าแค่เรื่องราคา
การติดตั้ง UniFi Network Application ด้วย Docker Compose
การใช้ Docker เป็นวิธีที่ลดปัญหาได้ดีที่สุด เพราะช่วยให้คุณสามารถกำหนดเวอร์ชันของ MongoDB ให้ตรงกับที่แอปพลิเคชันรองรับ แทนที่จะต้องใช้เวอร์ชันที่มากับ distribution ของคุณ หากยังไม่มี Docker บนเซิร์ฟเวอร์ ให้ ติดตั้ง Docker บน VPS ก่อน
mkdir -p ~/unifi/config ~/unifi/db
cd ~/unifiMongoDB จำเป็นต้องมีผู้ใช้ก่อนที่แอปพลิเคชันจะเข้าสู่ระบบได้ อิมเมจ MongoDB อย่างเป็นทางการจะรันสคริปต์ใดก็ตามที่พบใน /docker-entrypoint-initdb.d ในการเริ่มทำงานครั้งแรก ให้บันทึกไฟล์นี้เป็น ~/unifi/init-mongo.sh:
#!/bin/bash
if which mongosh > /dev/null 2>&1; then
mongo_init_bin='mongosh'
else
mongo_init_bin='mongo'
fi
"${mongo_init_bin}" <<EOF
use ${MONGO_AUTHSOURCE}
db.auth("${MONGO_INITDB_ROOT_USERNAME}", "${MONGO_INITDB_ROOT_PASSWORD}")
db.createUser({
user: "${MONGO_USER}",
pwd: "${MONGO_PASS}",
roles: [
"clusterMonitor",
{ db: "${MONGO_DBNAME}", role: "dbOwner" },
{ db: "${MONGO_DBNAME}_stat", role: "dbOwner" },
{ db: "${MONGO_DBNAME}_audit", role: "dbOwner" },
{ db: "${MONGO_DBNAME}_restore", role: "dbOwner" }
]
})
EOFสคริปต์ดังกล่าวจะทำงาน เฉพาะ เมื่อไดเรกทอรีฐานข้อมูลว่างเปล่าเท่านั้น หากคุณเริ่ม stack ครั้งแรกด้วยรหัสผ่านที่ผิด ผู้ใช้จะถูกสร้างขึ้นด้วยรหัสผ่านที่ผิดนั้น และการแก้ไขไฟล์ compose ในภายหลังจะไม่มีผลใดๆ เพราะสคริปต์จะไม่ถูกรันซ้ำอีก อาการที่พบคือคอนเทนเนอร์ของแอปพลิเคชันจะบันทึก log ว่า MongoDB ปฏิเสธการตรวจสอบสิทธิ์ ในขณะที่หน้าเว็บอินเทอร์เฟซไม่ปรากฏขึ้นมา สำหรับการติดตั้งใหม่ วิธีแก้ไขคือให้หยุด stack, ลบ ~/unifi/db แล้วเริ่มใหม่
จากนั้นให้สร้างไฟล์ ~/unifi/compose.yaml:
services:
unifi-db:
image: docker.io/mongo:8.0
container_name: unifi-db
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=change-this-root-password
- MONGO_USER=unifi
- MONGO_PASS=change-this-unifi-password
- MONGO_DBNAME=unifi
- MONGO_AUTHSOURCE=admin
volumes:
- ./db:/data/db
- ./init-mongo.sh:/docker-entrypoint-initdb.d/init-mongo.sh:ro
restart: unless-stopped
unifi-network-application:
image: lscr.io/linuxserver/unifi-network-application:10.5.67-ls141
container_name: unifi-network-application
depends_on:
- unifi-db
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
- MONGO_USER=unifi
- MONGO_PASS=change-this-unifi-password
- MONGO_HOST=unifi-db
- MONGO_PORT=27017
- MONGO_DBNAME=unifi
- MONGO_AUTHSOURCE=admin
- MEM_LIMIT=1024
- MEM_STARTUP=1024
volumes:
- ./config:/config
ports:
- "8080:8080"
- "3478:3478/udp"
- "127.0.0.1:8443:8443"
restart: unless-stoppedแท็กของอิมเมจทั้งสองถูกกำหนดเวอร์ชันไว้โดยเจตนา 10.5.67-ls141 คือเวอร์ชันของแอปพลิเคชันที่เป็นปัจจุบันในเดือนสิงหาคม 2026 ดังนั้นให้ตรวจสอบรายการ release ของอิมเมจและกำหนดเวอร์ชันที่เป็นปัจจุบันในขณะที่คุณติดตั้ง แท็กของฐานข้อมูลมีความสำคัญมากกว่า MongoDB ไม่สามารถอัปเกรดไฟล์ข้อมูลข้ามเวอร์ชันหลักได้ด้วยตัวเอง ดังนั้น mongo:latest อาจดึงเวอร์ชันหลักใหม่มาในอนาคต ซึ่งจะทำให้มันปฏิเสธการเปิดไฟล์ข้อมูลเดิมและรีสตาร์ทวนลูป ให้กำหนดเวอร์ชันหลักไว้และค่อยอัปเกรดอย่างตั้งใจ UniFi Network 8.1 ขึ้นไปรองรับ MongoDB 3.6 ถึง 7.0 และเวอร์ชัน 9.0 ได้เพิ่มการรองรับ MongoDB 8.0
PUID และ PGID ต้องตรงกับผู้ใช้จริงบนโฮสต์ มิฉะนั้นไฟล์ภายใต้ ./config จะถูกครอบครองโดย identity ที่ไม่มีสิทธิ์เขียนข้อมูล ให้รัน id เพื่อดูค่าของคุณ การทำงานของ PUID และ PGID ในคอนเทนเนอร์ จะอธิบายถึงปัญหาที่เกิดขึ้นเมื่อค่าไม่ตรงกัน
เริ่มการทำงานและตรวจสอบ:
docker compose up -d
docker compose ps
docker compose logs -f unifi-network-applicationdocker compose ps ควรแสดงคอนเทนเนอร์ทั้งสองในสถานะ running หาก unifi-db ค้างอยู่ที่ restarting อาจเกิดจากปัญหา AVX ที่กล่าวถึงข้างต้น หรือปัญหาเรื่องสิทธิ์ใน ./db เมื่อ log นิ่งแล้ว ให้ตรวจสอบ listener ทั้งสอง:
curl -sk -o /dev/null -w '%{http_code}\n' https://127.0.0.1:8443/
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/informหากได้รับ HTTP status code ใดๆ แสดงว่า listener ทำงานและตอบสนองแล้ว Connection refused หมายความว่าแอปพลิเคชันกำลังเริ่มทำงาน ซึ่งอาจใช้เวลาหนึ่งหรือสองนาทีบน VPS ขนาดเล็กในการรันครั้งแรก หรือหมายความว่ามันไม่เคยเริ่มทำงานได้เลย
เข้าถึงอินเทอร์เฟซผู้ดูแลระบบโดยไม่เปิดเผยสู่สาธารณะ
พอร์ต 8443 ถูกเผยแพร่ไว้ที่ 127.0.0.1 ในไฟล์ด้านบน ดังนั้นจึงไม่มีสิ่งใดจากภายนอก VPS ที่สามารถเข้าถึงอินเทอร์เฟซผู้ดูแลระบบได้ ให้ทำการส่งต่อพอร์ตผ่าน SSH เพื่อเรียกใช้งานตัวช่วยตั้งค่า:
ssh -L 8443:127.0.0.1:8443 you@vps.example.comเปิด session นั้นทิ้งไว้แล้วเข้าไปที่ https://127.0.0.1:8443 เนื่องจาก certificate เป็นแบบ self-signed เบราว์เซอร์จะแจ้งเตือนหนึ่งครั้ง ให้สร้างบัญชีผู้ดูแลระบบ ตั้งชื่อไซต์ และข้ามขั้นตอนการเพิ่มอุปกรณ์ไปก่อนในตอนนี้
การใช้ SSH tunnel เหมาะสำหรับผู้ดูแลระบบเพียงคนเดียว หากเป็นทีม ให้กำหนดที่อยู่ private address ให้กับ VPS และผูกอินเทอร์เฟซเข้ากับที่อยู่นั้นแทน การทำ WireGuard VPN บน VPS ของคุณเอง และ การใช้ Tailscale subnet router ต่างก็ช่วยให้คุณมีที่อยู่ที่เฉพาะทีมของคุณเท่านั้นที่สามารถเข้าถึงได้ ให้เปลี่ยนพอร์ตที่เผยแพร่เป็น 10.8.0.1:8443:8443 สำหรับ WireGuard หรือเปลี่ยนเป็นที่อยู่ที่ Tailscale กำหนดให้ ข้อควรระวังคือ Docker ไม่สามารถเผยแพร่พอร์ตบนที่อยู่ที่ยังไม่มีอยู่จริงได้ ดังนั้นอินเทอร์เฟซของ tunnel จะต้องทำงานก่อนที่คอนเทนเนอร์จะเริ่มทำงาน มิฉะนั้นคอนเทนเนอร์จะล้มเหลวด้วยข้อผิดพลาด bind error
เหตุใดอุปกรณ์ UniFi ระยะไกลจึงไม่ยอมรับการเชื่อมต่อ (Adopt)
โดยปกติแล้วอุปกรณ์ UniFi จะค้นหา Controller ของตนเองผ่านการกระจายสัญญาณ (broadcast) บนเครือข่ายท้องถิ่นที่พอร์ต UDP 10001 การกระจายสัญญาณนี้ไม่สามารถข้ามผ่าน LAN ได้ ดังนั้นอุปกรณ์ที่อยู่ในสำนักงานต่างเมืองจึงไม่สามารถค้นหา Controller ที่อยู่บน VPS ได้โดยตรง นี่คือการทำ Layer 3 adoption ซึ่งเป็นจุดที่ผู้ใช้งานส่วนใหญ่มักประสบปัญหา ทั้งตัวอุปกรณ์และ Controller ต่างทำงานได้ปกติ แต่ไม่มีการระบุให้อุปกรณ์ทราบว่าต้องไปค้นหาที่ใด
ขั้นแรก ให้ระบุที่อยู่แก่ Controller ในส่วน Settings ของ Controller ไปที่หัวข้อ System จะพบการตั้งค่า inform host พร้อมตัวเลือก override ให้ตั้งค่าเป็น hostname หรือ IP สาธารณะของ VPS หากไม่ตั้งค่านี้ Controller จะแจ้งที่อยู่ตามที่เห็นบนอินเทอร์เฟซของตนเอง ซึ่งหากอยู่ใน Docker bridge network จะเป็นที่อยู่ภายใน เช่น 172.18.0.3 ทำให้อุปกรณ์ได้รับที่อยู่นั้นแต่ไม่สามารถหาเส้นทางไปถึงได้ จึงกลับไปค้นหาใหม่ตามเดิม
จากนั้นให้ชี้เป้าหมายของอุปกรณ์ไปยังที่อยู่นั้น โดยการ SSH เข้าไปยังอุปกรณ์ที่อยู่ใน LAN ระยะไกล อุปกรณ์ที่ตั้งค่าโรงงานจะใช้ชื่อผู้ใช้ ubnt และรหัสผ่าน ubnt:
ssh ubnt@192.168.1.20
set-inform http://vps.example.com:8080/informเฟิร์มแวร์รุ่นใหม่จะแสดงเมนูแทนการเข้าสู่ shell โดยตรง ให้รันคำสั่งเดียวกันนี้ในรูปแบบคำสั่งเดียว:
ssh ubnt@192.168.1.20 mca-cli-op set-inform http://vps.example.com:8080/informขณะนี้อุปกรณ์จะปรากฏใน Controller ว่าพร้อมสำหรับการเชื่อมต่อ (Ready to Adopt) ให้คลิก Adopt แล้วสถานะจะเปลี่ยนเป็น Adopting นี่คือจุดที่มักสร้างความประหลาดใจให้ผู้ใช้งาน: โดยปกติคุณต้องรันคำสั่ง set-inform เป็นครั้งที่สอง เนื่องจากอุปกรณ์จะรีสตาร์ทเข้าสู่ขั้นตอน provisioning และกลับไปใช้ inform URL ที่บันทึกไว้ในการตั้งค่าเดิม ซึ่ง Controller ยังแทนที่ข้อมูลไม่เสร็จสิ้น การรันคำสั่งซ้ำในขณะที่สถานะเป็น Adopting จะช่วยให้การส่งมอบการควบคุมเสร็จสมบูรณ์ พิมพ์ info บนอุปกรณ์เพื่อตรวจสอบ inform URL และสถานะปัจจุบัน
หากอุปกรณ์เคยถูกเชื่อมต่อกับ Controller อื่นมาก่อน การใช้เพียง set-inform จะไม่สำเร็จเนื่องจากอุปกรณ์ยังคงเก็บข้อมูลรับรอง (credentials) ของ Controller เดิมไว้ ให้รีเซ็ตเป็นค่าโรงงานก่อน โดยใช้ปุ่มรีเซ็ตหรือใช้คำสั่ง set-default ผ่าน SSH โดยใช้ข้อมูลรับรองเดิม
หากมีอุปกรณ์จำนวนมาก ให้ใช้ DHCP แทน DHCP option 43 จะเก็บค่าเฉพาะของผู้ผลิต (vendor-specific) โดยอุปกรณ์ UniFi จะอ่าน inform URL จาก suboption 2 คุณสามารถสร้าง hex string ได้บนเครื่อง Linux ใดก็ได้:
URL="http://vps.example.com:8080/inform"
HEX=$(printf '%s' "$URL" | od -An -tx1 | tr -d ' \n')
printf '02%02x%s\n' "${#URL}" "$HEX"สำหรับ http://192.168.3.10:8080/inform ซึ่งเป็นสตริงขนาด 31 ไบต์ จะได้ผลลัพธ์เป็น 021f687474703a2f2f3139322e3136382e332e31303a383038302f696e666f726d ให้นำผลลัพธ์นี้ไปวางในช่อง DHCP option 43 ของเราเตอร์ในรูปแบบค่า hex อุปกรณ์ทุกตัวที่บูตบนเครือข่ายนั้นจะได้รับที่อยู่ของ Controller จาก DHCP lease โดยไม่ต้องตั้งค่าผ่าน SSH เลย คู่มือรุ่นเก่าอาจระบุให้ใช้ suboption 1 คือ 0104 ตามด้วยเลข IPv4 4 ไบต์ในรูปแบบ hex ซึ่งอุปกรณ์รุ่นปัจจุบันยังคงรองรับรูปแบบนี้อยู่
ยังมีวิธีที่สามหากคุณดูแลระบบ DNS ที่ไซต์งาน อุปกรณ์ UniFi จะพยายาม resolve hostname unifi เมื่อบูตเครื่อง ดังนั้นการสร้าง A record สำหรับ unifi ให้ชี้ไปยังที่อยู่ VPS ของคุณจะทำให้อุปกรณ์เชื่อมต่อได้โดยไม่ต้องตั้งค่าที่ตัวอุปกรณ์ทีละเครื่อง วิธีนี้ใช้ได้ผลเฉพาะในกรณีที่คุณเป็นผู้ควบคุม DNS resolver ที่อุปกรณ์เหล่านั้นใช้งานจริงเท่านั้น
พอร์ตใดของ UniFi ที่ควรเปิด และพอร์ตใดที่ควรเก็บเป็นส่วนตัว
มีเพียงสองพอร์ตเท่านั้นที่จำเป็นต้องเข้าถึงได้จากไซต์ระยะไกล
- TCP 8080 คือช่องทาง inform ซึ่งอุปกรณ์ที่ถูก adopt ทุกตัวจะเชื่อมต่อเข้ามา ข้อมูลภายในถูกเข้ารหัสด้วย AES โดยใช้คีย์ที่ controller มอบให้อุปกรณ์ระหว่างการ adopt นี่คือเหตุผลว่าทำไมการใช้ HTTP แบบปกติจึงเป็นค่าเริ่มต้นในส่วนนี้
- UDP 3478 คือ STUN (session traversal utilities for NAT) ซึ่งอุปกรณ์ใช้เพื่อรักษาเส้นทางกลับไปยัง controller
พอร์ตอื่นๆ ทั้งหมดควรปิดไว้บน VPS
- TCP 8443 คืออินเทอร์เฟซสำหรับผู้ดูแลระบบ พอร์ตนี้ต้องไม่เปิดเป็นสาธารณะโดยเด็ดขาด เนื่องจากเป็นจุดที่เก็บการตั้งค่าของทุกไซต์ที่ controller จัดการไว้ภายใต้รหัสผ่านเดียว
- UDP 10001 และ UDP 1900 คือการค้นหาแบบ broadcast ซึ่งการ broadcast ไม่สามารถข้ามผ่านอินเทอร์เน็ตได้ ดังนั้นการเปิดพอร์ตเหล่านี้จึงไม่มีประโยชน์
- TCP 8880 และ TCP 8843 คือการ redirect ไปยัง guest portal ให้เปิดพอร์ตเหล่านี้ก็ต่อเมื่อคุณใช้งาน guest portal เท่านั้น
- TCP 6789 คือการทดสอบความเร็วผ่านมือถือ และ UDP 5514 คือ remote syslog ให้เพิ่มพอร์ตเหล่านี้เมื่อคุณต้องการใช้งาน
- TCP 27117 คือ MongoDB ในไฟล์ compose ด้านบน ฐานข้อมูลไม่ได้ประกาศพอร์ตใดๆ ออกมา จึงทำงานอยู่เฉพาะบนเครือข่ายภายในของ Docker เท่านั้น โปรดคงสถานะนี้ไว้
หากไซต์ของคุณมีที่อยู่สาธารณะแบบ static ให้เปิดอนุญาตเฉพาะที่อยู่นั้น:
sudo ufw allow OpenSSH
sudo ufw allow proto tcp from 203.0.113.4 to any port 8080
sudo ufw allow proto udp from 203.0.113.4 to any port 3478
sudo ufw enable
sudo ufw status verboseพื้นฐาน ufw สำหรับไฟร์วอลล์ VPS ครอบคลุมการตั้งค่า default deny ที่กฎเหล่านี้อ้างอิงถึง
มีกับดักหนึ่งที่มักทำให้ผู้ใช้งานพลาดเสมอ นั่นคือ พอร์ตที่ Docker ประกาศใช้งานจะข้ามการทำงานของ ufw การประกาศพอร์ตจะเขียนกฎ NAT และ forwarding ลงใน iptables โดยตรง และทราฟฟิกดังกล่าวจะถูกกรองใน chain ของ Docker เอง ไม่ใช่ใน INPUT chain ที่ ufw จัดการ ดังนั้น ufw deny 8443 อาจดูถูกต้องใน ufw status ในขณะที่พอร์ตยังคงเปิดรับการเชื่อมต่อจากภายนอก ให้ทดสอบจากเครื่องอื่นเสมอ ห้ามทดสอบจากตัว VPS เอง:
nc -vz vps.example.com 8443ผลลัพธ์ที่คุณต้องการคือการถูกปฏิเสธการเชื่อมต่อหรือหมดเวลา (timeout) หากสามารถเชื่อมต่อได้ แสดงว่าพอร์ตนั้นเปิดเป็นสาธารณะไม่ว่า ufw จะตั้งค่าไว้อย่างไร วิธีแก้ไขที่เชื่อถือได้คือวิธีที่ระบุไว้ในไฟล์ compose แล้ว นั่นคือการประกาศพอร์ตบน 127.0.0.1 หรือบน tunnel address เพื่อไม่ให้ Docker ผูกพอร์ตเข้ากับอินเทอร์เฟซสาธารณะ การใช้กฎใน chain DOCKER-USER ก็สามารถทำได้เช่นกัน แต่การผูกพอร์ต (binding) นั้นง่ายกว่าและป้องกันความผิดพลาดจากการเรียงลำดับกฎได้ดีกว่า
แล้วตัวติดตั้งของ Ubiquiti เองล่ะ?
Ubiquiti มีการเผยแพร่แพ็กเกจ Debian สำหรับ Network Application ซึ่งใช้งานได้จริง แต่บน Ubuntu เวอร์ชันปัจจุบันจะเกิดปัญหาเรื่อง MongoDB ที่ทางดิสทริบิวชันไม่มีให้แล้ว เนื่องจาก Ubuntu 22.04 และ 24.04 ไม่มีแพ็กเกจ MongoDB server มาให้ ทำให้คุณต้องเพิ่ม repository ของ MongoDB เองและจับคู่เวอร์ชันด้วยตนเอง แต่ container ที่กล่าวถึงข้างต้นได้จัดการการจับคู่เวอร์ชันไว้ใน tag เดียวที่ถูกล็อกไว้แล้ว ซึ่งเป็นเหตุผลว่าทำไมวิธีนั้นจึงเป็นแนวทางที่แนะนำในที่นี้
ผลิตภัณฑ์สำหรับการ self-host ตัวใหม่ของ Ubiquiti คือ UniFi OS Server ซึ่งรันแอปพลิเคชัน UniFi ในรูปแบบ Podman container และมอบประสบการณ์การใช้งาน UniFi OS แบบเดียวกับที่พบในฮาร์ดแวร์คอนโซลของพวกเขา ข้อมูล ณ เดือนสิงหาคม 2026 ระบบต้องการ Ubuntu 22.04 หรือ 24.04 บนสถาปัตยกรรม x86_64, Podman เวอร์ชัน 4.3.1 หรือใหม่กว่าพร้อมด้วย slirp4netns และกำหนดสเปกขั้นต่ำที่ 2 vCPU กับ RAM 4 GB โดยแนะนำที่ 4 vCPU กับ RAM 8 GB ตัวติดตั้งนี้อยู่หลังการล็อกอินบัญชี Ubiquiti ฟรีบนหน้าดาวน์โหลดของพวกเขา จึงไม่มี URL แบบบรรทัดเดียวที่เสถียรสำหรับนำมาวางในคู่มือได้ ตัวติดตั้งจะสร้าง system user ชื่อ uosserver และรัน container ในฐานะผู้ใช้ดังกล่าว ให้เลือกวิธีนี้หากคุณต้องการใช้แพ็กเกจจากผู้ผลิตโดยตรง แต่ให้เลือกใช้ container stack หากคุณต้องการล็อกเวอร์ชันด้วยตนเองและต้องการให้เซิร์ฟเวอร์ยังคงว่างพอสำหรับงานอื่น ๆ
ตำแหน่งที่เก็บไฟล์สำรองข้อมูลของ UniFi และวิธีการคัดลอกออกจากเซิร์ฟเวอร์
Controller จะเขียนไฟล์สำรองข้อมูลตามกำหนดการที่คุณตั้งค่าไว้ในเมนู Settings ในส่วนของ backup พร้อมทั้งกำหนดจำนวนไฟล์ที่จะเก็บไว้ ไฟล์เหล่านี้จะถูกเก็บไว้ที่ /config/data/backup/autobackup ภายในคอนเทนเนอร์ ซึ่งตรงกับตำแหน่ง ~/unifi/config/data/backup/autobackup บนโฮสต์ โดยมีชื่อไฟล์ในรูปแบบ autobackup_10.5.67_20260813_1200_1755086400004.unf
ตรวจสอบให้แน่ใจว่าไฟล์เหล่านั้นถูกสร้างขึ้นจริง:
ls -l ~/unifi/config/data/backup/autobackupหากไดเรกทอรีว่างเปล่าหลังจากตั้งค่ากำหนดการไปแล้วหนึ่งวัน นั่นเป็นปัญหาที่พบได้บ่อยในการติดตั้งคอนเทนเนอร์ใหม่ แอปพลิเคชันคาดหวังว่าไดเรกทอรี autobackup จะมีอยู่จริงแต่ไม่ได้สร้างขึ้นมาให้ ส่งผลให้งานที่ตั้งเวลาไว้ไม่สามารถเขียนไฟล์ใดๆ ได้ ให้คุณสร้างไดเรกทอรีดังกล่าวด้วยตนเองโดยใช้สิทธิ์ผู้ใช้เดียวกับที่คอนเทนเนอร์ใช้งาน จากนั้นรอให้ถึงรอบการทำงานถัดไป:
mkdir -p ~/unifi/config/data/backup/autobackup
docker compose restart unifi-network-applicationไฟล์ .unf จะเก็บการตั้งค่าของไซต์และบัญชีผู้ดูแลระบบไว้ ดังนั้นให้ปฏิบัติต่อไฟล์นี้เสมือนเป็นกุญแจสำคัญ ควรคัดลอกไฟล์เหล่านี้มาเก็บไว้ในเครื่องที่คุณควบคุมและรักษาความเป็นส่วนตัวของไฟล์ไว้:
rsync -av you@vps.example.com:~/unifi/config/data/backup/autobackup/ ~/unifi-backups/การกู้คืนข้อมูลทำได้ในขั้นตอนเดียว หน้าแรกของตัวช่วยติดตั้ง (setup wizard) ในการติดตั้งใหม่จะมีตัวเลือกให้กู้คืนจากไฟล์สำรองข้อมูล และสำหรับ Controller ที่กำลังทำงานอยู่ คุณสามารถกู้คืนได้จากหน้าการตั้งค่าเดียวกัน การกู้คืนข้อมูลควรทำในเวอร์ชันเดียวกันหรือเวอร์ชันที่ใหม่กว่าเท่านั้น ไฟล์สำรองข้อมูลที่สร้างจากแอปพลิเคชันเวอร์ชันที่ใหม่กว่าจะไม่สามารถกู้คืนลงในเวอร์ชันที่เก่ากว่าได้ นี่คือเหตุผลที่คุณควรจดบันทึกหมายเลขเวอร์ชันกำกับไว้คู่กับไฟล์สำรองข้อมูลเสมอ
สิ่งที่อาจเสียหายจากการอัปเกรด controller
ให้สำรองข้อมูลด้วยตนเองและดาวน์โหลดไฟล์เก็บไว้ก่อนการอัปเกรดทุกครั้ง จากนั้น:
docker compose pull
docker compose up -d
docker compose logs -f unifi-network-applicationฐานข้อมูลเป็นสิ่งแรกที่มักเกิดปัญหา การเปลี่ยนแท็ก mongo เป็นเวอร์ชันหลักใหม่ในการแก้ไขครั้งเดียวกับตัวแอปพลิเคชันเป็นวิธีที่เร็วที่สุดที่จะทำให้ controller ไม่สามารถเริ่มทำงานได้ เนื่องจาก MongoDB จะไม่เปิดไฟล์ข้อมูลจากเวอร์ชันหลักที่ต่างกันหากไม่มีการอัปเกรดแบบเป็นขั้นตอน ให้ทำการอัปเกรดแอปพลิเคชันแยกต่างหาก และย้าย MongoDB ทีละเวอร์ชันหลักโดยต้องมีไฟล์สำรองข้อมูลที่ใหม่ล่าสุดอยู่ในมือเสมอ
หน่วยความจำคือสิ่งถัดไป เวอร์ชันที่ใหญ่ขึ้นต้องการ heap ที่ใหญ่ขึ้น หากแอปพลิเคชันเริ่มทำงานได้ ทำงานไปได้ไม่กี่นาทีแล้วหยุดไป ให้เพิ่มค่า MEM_LIMIT และ MEM_STARTUP เป็น 1536 หรือ 2048 แล้วรีสตาร์ทใหม่ การใช้คำสั่ง dmesg -T | grep -i 'killed process' บนโฮสต์จะช่วยยืนยันได้ว่า kernel เป็นตัวสั่งยุติการทำงานหรือไม่
เฟิร์มแวร์ของอุปกรณ์เป็นความเสี่ยงที่คนมักลืม หลังจาก controller อัปเกรดตัวเองแล้ว มันจะเสนอให้อัปเกรดเฟิร์มแวร์สำหรับอุปกรณ์ที่ถูกรับรองไว้ (adopted devices) อย่ากดตอบรับในเซสชันเดียวกัน หากการอัปเกรดอุปกรณ์และการอัปเกรด controller เกิดขึ้นพร้อมกันแล้วการเชื่อมต่อระหว่างกันหลุด อุปกรณ์อาจค้างอยู่ในสถานะที่ถูกตั้งค่าไม่สมบูรณ์ และคุณจะต้องกลับไปใช้ set-inform ผ่าน SSH บนฮาร์ดแวร์ที่อยู่อีกอาคารหนึ่ง
ช่วงเวลาการอัปเกรดนั้นไม่ได้น่ากังวลอย่างที่คิด อุปกรณ์ยังคงส่งต่อ traffic ได้ตามปกติในขณะที่ controller กำลังรีสตาร์ท ดังนั้นผู้ใช้งานจะไม่พบปัญหาใดๆ สิ่งที่จะหยุดทำงานคือ guest portal และ RADIUS หาก controller เป็นผู้ให้บริการส่วนนี้ ดังนั้นควรเลือกเวลาที่ไม่มีการใช้งานบริการดังกล่าว การที่ controller หยุดทำงานเงียบๆ ตอนตี 3 เป็นเรื่องที่ควรทราบ ดังนั้นให้ตั้งค่า Uptime Kuma status monitor ไปที่พอร์ต 8080 เพื่อให้ระบบแจ้งเตือนคุณ
ทางเลือกที่ตรงไปตรงมา: คอนโซลแบบโฮสต์ของ Ubiquiti
Ubiquiti ให้บริการจัดการงานเดียวกันนี้ในรูปแบบบริการ ณ เดือนสิงหาคม 2026 Official UniFi Cloud Console มีราคาเริ่มต้นที่ $29 ต่อเดือน โดยสามารถจัดการอุปกรณ์ UniFi ได้สูงสุด 500 เครื่อง ซึ่ง Ubiquiti จะเป็นผู้ดำเนินการอัปเดตและสำรองข้อมูลให้ ส่วนแอปพลิเคชันแบบ self-hosted ที่คุณเพิ่งติดตั้งไปนั้นไม่มีค่าใช้จ่ายและไม่มีค่าธรรมเนียมรายเดือน
เลือกใช้คอนโซลแบบโฮสต์หากคุณจัดการเพียงไซต์เดียวและต้องการจ่ายเงินเพื่อแลกกับความสะดวกในการดูแลรักษา เลือกใช้ VPS หากคุณจัดการหลายไซต์ หรือหากคุณต้องการให้ controller อยู่ภายในเครือข่ายที่คุณควบคุมและใช้งานร่วมกับบริการอื่นที่คุณรันอยู่ ความแตกต่างของค่าใช้จ่ายในระดับเล็กนั้นมีอยู่จริง แต่ไม่ใช่ปัจจัยเดียวที่ต้องพิจารณา คอนโซลแบบโฮสต์หมายถึงการฝากความพร้อมใช้งานไว้กับผู้อื่น ส่วน VPS นั้นเป็นความรับผิดชอบของคุณ รวมถึงคืนที่ดิสก์เต็มด้วย หากเซิร์ฟเวอร์นี้จะถูกใช้งานอย่างคุ้มค่า สิ่งอื่นที่คุณสามารถรันบน VPS ได้ คือรายการที่คุณควรอ่านต่อไป
FAQ
ทำไมอุปกรณ์ UniFi ของฉันถึงไม่ยอมเชื่อมต่อ (adopt) กับ controller บน VPS?
อุปกรณ์จะค้นหา controller ผ่านการกระจายสัญญาณ (broadcast) บน UDP port 10001 ซึ่งสัญญาณนี้จะไม่หลุดออกจากเครือข่ายท้องถิ่น ทำให้อุปกรณ์ที่อยู่คนละไซต์ไม่สามารถค้นหา controller บนอินเทอร์เน็ตสาธารณะได้ ให้ตั้งค่า inform host override ในการตั้งค่าระบบของ controller ให้เป็น hostname ของ VPS จากนั้นชี้อุปกรณ์ไปที่นั่นด้วย ssh ubnt@<device-ip> ตามด้วย set-inform http://vps.example.com:8080/inform หากอุปกรณ์ค้างอยู่ในสถานะ Adopting ให้รัน set-inform อีกครั้งในขณะที่มันค้างอยู่ หากเคยมี controller อื่นเชื่อมต่ออุปกรณ์นี้มาก่อน ให้รีเซ็ตเป็นค่าเริ่มต้นจากโรงงาน (factory default) ก่อน เพราะอุปกรณ์ยังคงเก็บข้อมูลรับรอง (credentials) ของ controller ตัวเก่าไว้อยู่
UniFi controller ที่โฮสต์เองต้องใช้ RAM เท่าไร?
RAM ขนาด 2 GB คือขั้นต่ำที่ใช้งานได้ และ 4 GB คือระดับที่เหมาะสม แอปพลิเคชันนี้ทำงานบน Java ร่วมกับ MongoDB ซึ่งทั้งสองส่วนจะจัดสรรหน่วยความจำแยกกัน โดย container image จะจำกัด Java heap ไว้ที่ 1024 MB เป็นค่าเริ่มต้น ในขณะที่ WiredTiger cache ของ MongoDB จะใช้ RAM ครึ่งหนึ่งของส่วนที่เกิน 1 GB ขึ้นไป บนสถาปัตยกรรม x86_64 ให้ตรวจสอบด้วยว่า CPU รองรับ AVX ผ่าน grep -m1 -o avx /proc/cpuinfo หรือไม่ เนื่องจาก MongoDB 5.0 ขึ้นไปจะไม่สามารถเริ่มทำงานได้หากไม่มีคำสั่งนี้ และจะทำให้ database container รีสตาร์ทวนซ้ำไปเรื่อยๆ
ฉันควรเปิดพอร์ต 8443 สู่สาธารณะหรือไม่?
ไม่ควร พอร์ต 8443 คืออินเทอร์เฟซสำหรับผู้ดูแลระบบ ซึ่งเก็บการตั้งค่าของทุกไซต์ที่ controller จัดการอยู่ ให้เผยแพร่ผ่าน 127.0.0.1 และเข้าถึงด้วย ssh -L 8443:127.0.0.1:8443 you@vps.example.com หรือผูกไว้กับที่อยู่ของ WireGuard หรือ Tailscale แทน มีเพียง TCP 8080 และ UDP 3478 เท่านั้นที่จำเป็นต้องเข้าถึงได้จากไซต์ของคุณ และคุณสามารถจำกัดการเข้าถึงเฉพาะที่อยู่ IP สาธารณะของไซต์นั้นๆ ได้หากเป็น IP แบบคงที่ โปรดจำไว้ว่าพอร์ตที่เผยแพร่ผ่าน Docker จะไม่ถูกกรองโดย ufw ดังนั้นควรทดสอบจากเครื่องภายนอกแทนการเชื่อถือสถานะของ ufw status
เครือข่ายของฉันจะหยุดทำงานหรือไม่หาก VPS controller ล่ม?
ไม่หยุดทำงาน Access point และ switch ที่เชื่อมต่ออยู่จะยังคงส่งต่อข้อมูล (forward traffic) ตามการตั้งค่าที่ controller ได้ผลักดัน (push) ไว้ก่อนหน้า ทำให้ไคลเอนต์ยังคงเชื่อมต่อและ Wi-Fi ยังคงใช้งานได้ตามปกติ สิ่งที่จะหยุดทำงานคือการจัดการ คุณจะไม่สามารถเข้าถึงแดชบอร์ดและข้อมูลสถิติ รวมถึงฟีเจอร์แบบเรียลไทม์ที่ controller ให้บริการ เช่น การยืนยันตัวตนผ่าน guest portal หรือ RADIUS ในกรณีที่ controller ทำหน้าที่เป็น RADIUS server
UniFi controller เก็บไฟล์สำรองข้อมูลอัตโนมัติไว้ที่ไหน?
ใน container image ที่ใช้ที่นี่ ไฟล์จะถูกเก็บไว้ใน /config/data/backup/autobackup ซึ่งแมปไปยัง path ข้อมูลของคุณบวกกับ data/backup/autobackup บนโฮสต์ โดยจะเป็นไฟล์ .unf ที่ตั้งชื่อตามเวอร์ชันและเวลาที่สำรองข้อมูล ในการติดตั้งใหม่บางครั้งไดเรกทอรี autobackup อาจไม่มีอยู่จริง ทำให้การสำรองข้อมูลตามตารางเวลาไม่ทำงานโดยไม่มีการแจ้งเตือนข้อผิดพลาด ดังนั้นควรตรวจสอบไดเรกทอรีดังกล่าวหนึ่งวันหลังจากตั้งค่าตารางเวลา และสร้างไดเรกทอรีด้วยตนเองหากพบว่าว่างเปล่า ควรคัดลอกไฟล์ออกจาก VPS เพราะไฟล์ .unf ประกอบด้วยการตั้งค่าไซต์และบัญชีผู้ดูแลระบบทั้งหมด