SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor

วิธีติดตั้ง 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 บวกกับหน่วยความจำส่วนที่ไม่ใช่ heap ของ JVM และตัวระบบปฏิบัติการเอง มันจะทำงานได้จนกว่าจะถึงวันที่งานหนัก ซึ่ง kernel จะสั่ง out-of-memory killer ให้ยุติการทำงานของ process ใด process หนึ่ง หากมีการรีสตาร์ทโดยไม่ทราบสาเหตุ ให้รัน dmesg -T | grep -i 'killed process' เพื่อตรวจสอบว่าเกิดจากสาเหตุนี้หรือไม่ หากคุณมี RAM เพียง 2 GB ให้เพิ่ม swap file เข้าไป

CPU และดิสก์ไม่ได้ต้องการทรัพยากรสูง vCPU หนึ่งหรือสองตัวสามารถรองรับอุปกรณ์ได้หลายสิบตัว เริ่มต้นที่ดิสก์ 20 GB แล้วคอยเฝ้าระวัง เพราะฐานข้อมูลจะขยายขนาดตามจำนวน client ที่พบและระยะเวลาที่คุณเก็บสถิติไว้ ตัว controller เพียงอย่างเดียวจะทำให้เครื่องขนาด 4 GB ส่วนใหญ่ว่างงาน ดังนั้นหากคุณวางแผนจะให้มีแอปอื่นใช้งานร่วมด้วย ให้คำนวณขนาดตามแอปนั้นเป็นหลัก เพราะ PhotoPrism และ Immich มีความต้องการ RAM ขั้นต่ำที่ต่างกันมาก และทั้งสองแอปต้องการ RAM มากกว่าตัว controller

มีฟีเจอร์ CPU อย่างหนึ่งที่สำคัญและมักถูกมองข้ามในแผนราคาประหยัด:

grep -m1 -o avx /proc/cpuinfo

MongoDB 5.0 ขึ้นไปต้องการ AVX (advanced vector extensions) บนฮาร์ดแวร์ x86_64 หากคำสั่งดังกล่าวไม่แสดงผลลัพธ์ใดๆ mongod จะหยุดทำงานระหว่างเริ่มระบบและ container จะรีสตาร์ทวนไปเรื่อยๆ เนื่องจาก binary พยายามรันคำสั่งที่ CPU ไม่มี โฮสต์รุ่นเก่าอย่าง Intel Celeron และ Pentium มักเป็นสาเหตุ รวมถึง hypervisor ที่ซ่อน CPU flag ไม่ให้ guest เห็น MongoDB 4.4 เป็นรุ่นล่าสุดที่รันได้โดยไม่ต้องใช้ AVX และ image ยังรองรับรุ่นเก่าไปจนถึง 3.6 แต่ 4.4 สิ้นสุดระยะเวลาสนับสนุน (end of life) ไปแล้วในเดือนกุมภาพันธ์ 2024 แม้ว่า MongoDB จะมีการปล่อย build รุ่น 4.4 ออกมาเพื่อแก้ไข CVE-2025-14847 ในเดือนธันวาคม 2025 แต่ก็ไม่มีการรับประกันว่าจะมีการแก้ไขสำหรับช่องโหว่ถัดไป และรุ่นที่เก่ากว่านั้นก็ยิ่งล้าสมัยไปไกลกว่าเดิม การย้ายไปใช้โฮสต์ที่มี CPU ใหม่กว่าจึงเป็นทางออกที่ดีกว่า บน ARM VPS ปัญหานี้จะไม่เกิดขึ้นเนื่องจาก 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 ~/unifi

MongoDB จำเป็นต้องมีผู้ใช้ก่อนที่แอปพลิเคชันจะเข้าสู่ระบบได้ อิมเมจ 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-application

docker 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 ในไฟล์ด้านบน ดังนั้นบน Docker Engine 28.0.0 หรือใหม่กว่า จะไม่มีสิ่งใดภายนอก VPS ที่สามารถเข้าถึงอินเทอร์เฟซผู้ดูแลระบบได้ ในรุ่นที่เก่ากว่า โฮสต์อื่นที่อยู่ใน L2 segment เดียวกัน เช่น เครื่องที่เชื่อมต่ออยู่บน network switch เดียวกัน จะสามารถเข้าถึงพอร์ตที่เผยแพร่ไปยัง localhost ได้ ดังนั้นให้รัน docker version และอัปเกรดก่อนหากเซิร์ฟเวอร์รายงานว่าเป็นรุ่นที่เก่ากว่านั้น ให้ทำการ forward พอร์ตผ่าน SSH เพื่อรันตัวช่วยตั้งค่า (setup wizard):

ssh -L 8443:127.0.0.1:8443 you@vps.example.com

เปิด session นั้นทิ้งไว้แล้วเข้าไปที่ https://127.0.0.1:8443 ในเบราว์เซอร์ ใบรับรองเป็นแบบ self-signed ดังนั้นเบราว์เซอร์จะแจ้งเตือนหนึ่งครั้ง ให้สร้างบัญชีผู้ดูแลระบบ ตั้งชื่อไซต์ และข้ามขั้นตอนการเพิ่มอุปกรณ์ (device adoption) ไปก่อนในขณะนี้

SSH tunnel เหมาะสำหรับการใช้งานโดยผู้ดูแลระบบเพียงคนเดียว หากเป็นทีม ให้กำหนด private address ให้กับ VPS และ bind อินเทอร์เฟซไปยังที่อยู่นั้นแทน ทั้ง WireGuard VPN บน VPS ของคุณเอง และ Tailscale subnet router ต่างก็ให้ที่อยู่ซึ่งเฉพาะทีมของคุณเท่านั้นที่สามารถเข้าถึงได้ ให้เปลี่ยนพอร์ตที่เผยแพร่เป็น 10.8.0.1:8443:8443 สำหรับ WireGuard หรือเปลี่ยนเป็นที่อยู่ที่ Tailscale กำหนดให้ ข้อควรระวังคือ Docker ไม่สามารถเผยแพร่พอร์ตบนที่อยู่ที่ยังไม่มีอยู่จริงได้ ดังนั้นอินเทอร์เฟซของ tunnel จะต้องพร้อมใช้งานก่อนที่คอนเทนเนอร์จะเริ่มทำงาน มิฉะนั้นคอนเทนเนอร์จะล้มเหลวพร้อมข้อผิดพลาดในการ bind

เหตุใดอุปกรณ์ 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 ใดที่ควรเปิด และพอร์ตใดที่ควรเก็บไว้เป็นส่วนตัว

มีสองพอร์ตที่ต้องเข้าถึงได้จากไซต์ระยะไกลเพื่อการทำ adoption และการจัดการในแต่ละวัน

  • TCP 8080 คือช่องทาง inform ซึ่งอุปกรณ์ที่ถูก adopt ทุกตัวจะเชื่อมต่อเข้ามา ข้อมูลภายในถูกเข้ารหัสด้วย AES โดยใช้คีย์ที่ controller มอบให้อุปกรณ์ระหว่างการทำ adoption นี่คือเหตุผลว่าทำไมการใช้ HTTP แบบปกติจึงเป็นค่าเริ่มต้นในส่วนนี้
  • UDP 3478 คือ STUN (session traversal utilities for NAT) ซึ่งอุปกรณ์ใช้เพื่อรักษาเส้นทางกลับไปยัง controller

บางฟีเจอร์ต้องการพอร์ตเพิ่มเติม ข้อมูลอ้างอิงของ Ubiquiti ระบุว่าต้องใช้ TCP 5671 สำหรับการบันทึก Traffic Flow จากเกตเวย์ UXG ที่ถูก adopt บนเครือข่าย L2 หรือ L3 ดังนั้นหากไซต์ของคุณมี UXG ที่รายงานผลมายัง controller นี้และคุณต้องการ log ดังกล่าว ให้เปิดพอร์ต 5671 สำหรับไซต์นั้นด้วย

พอร์ตอื่นๆ ทั้งหมดควรปิดไว้บน VPS

  • TCP 8443 คืออินเทอร์เฟซสำหรับผู้ดูแลระบบ พอร์ตนี้ต้องไม่เปิดเป็นสาธารณะโดยเด็ดขาด เนื่องจากเก็บการตั้งค่าของทุกไซต์ที่ controller จัดการไว้ภายใต้รหัสผ่านเดียว
  • UDP 10001 และ UDP 1900 คือการค้นหาแบบ broadcast ซึ่ง broadcast ไม่สามารถข้ามอินเทอร์เน็ตได้ ดังนั้นการเปิดพอร์ตเหล่านี้จึงไม่มีประโยชน์
  • TCP 8880 และ TCP 8843 คือการเปลี่ยนเส้นทางไปยัง 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 package สำหรับ Network Application และนับตั้งแต่เดือนตุลาคม 2026 ศูนย์ช่วยเหลือของบริษัทได้ระบุว่าวิธีการดังกล่าวเป็นแบบ legacy และเรียก UniFi OS Server ว่าเป็นมาตรฐานใหม่สำหรับการทำ self-hosting แม้ตัวแพ็กเกจจะใช้งานได้ แต่บน Ubuntu เวอร์ชันปัจจุบันจะเกิดปัญหาเรื่อง MongoDB ที่ทาง distribution ไม่ได้มีให้ใช้งานอีกต่อไป เนื่องจาก Ubuntu 22.04 และ 24.04 ไม่มีแพ็กเกจ MongoDB server มาให้ ทำให้คุณต้องเพิ่ม repository ของ MongoDB เองและจับคู่เวอร์ชันด้วยตนเอง ในขณะที่ container ที่กล่าวถึงข้างต้นได้จัดการการจับคู่เวอร์ชันไว้ใน tag เดียวที่ถูกล็อกไว้แล้ว ซึ่งเป็นเหตุผลว่าทำไมวิธีนั้นจึงเป็นแนวทางที่แนะนำในที่นี้

ผลิตภัณฑ์สำหรับการทำ self-hosted รุ่นใหม่ของ Ubiquiti คือ UniFi OS Server ซึ่งรันแอปพลิเคชัน UniFi ใน Podman containers และมอบประสบการณ์ UniFi OS แบบเดียวกับที่พบในฮาร์ดแวร์คอนโซลของพวกเขา ณ เดือนตุลาคม 2026 Ubiquiti ระบุความต้องการขั้นต่ำไว้ที่ CPU สถาปัตยกรรม x86-64, Ubuntu 24.04 ขึ้นไป หรือ Debian 13 ขึ้นไป, Podman 4.9.3 หรือใหม่กว่า พร้อมด้วย slirp4netns 1.2 หรือใหม่กว่า, RAM อย่างน้อย 2 GB และพื้นที่จัดเก็บข้อมูลว่าง 10 GB ลิงก์ตัวติดตั้งในหน้า Releases หรือ Download ของ Ubiquiti จะระบุเวอร์ชันไว้โดยเฉพาะ: ให้คลิกขวาที่ไฟล์ดาวน์โหลด คัดลอกที่อยู่ลิงก์ แล้วดึงไฟล์ด้วย curl -O หรือ wget แต่ละรุ่นจะมี URL ของตัวเอง ดังนั้นคู่มืออาจระบุเวอร์ชันที่แน่นอนได้ แต่ไม่สามารถให้ลิงก์ที่ชี้ไปยังเวอร์ชันล่าสุดได้ตลอดเวลา ตัวติดตั้งจะตั้งค่า systemd service ที่ชื่อว่า uosserver ซึ่งคุณสามารถหยุดและเริ่มการทำงานได้ด้วย systemctl ให้เลือกวิธีนี้หากคุณต้องการใช้แพ็กเกจจากผู้ผลิตโดยตรง และเลือกใช้ 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 ร้านค้าของ Ubiquiti ในสหรัฐฯ จำหน่ายบริการนี้ในชื่อ Official UniFi Hosting โดยมีราคาเริ่มต้นที่ 29 ดอลลาร์ต่อเดือน ซึ่งสามารถจัดการอุปกรณ์ UniFi Network ได้สูงสุด 1,000 เครื่องบนเซิร์ฟเวอร์ที่ Ubiquiti ดูแล ส่วนแอปพลิเคชันแบบ self-hosted ที่คุณเพิ่งติดตั้งไปนั้นไม่มีค่าใช้จ่ายและไม่มีค่าธรรมเนียมรายเดือน

ให้เลือกใช้คอนโซลแบบโฮสต์หากคุณจัดการเพียงไซต์เดียวและต้องการจ่ายเงินเพื่อแลกกับความสะดวกในการดูแลระบบ ให้เลือกใช้ VPS หากคุณจัดการหลายไซต์ หรือหากคุณต้องการให้ controller อยู่ภายในเครือข่ายที่คุณควบคุมและใช้งานร่วมกับบริการอื่นที่คุณรันอยู่ ความแตกต่างของค่าใช้จ่ายในระดับเล็กน้อยนั้นมีอยู่จริง แต่ไม่ใช่ปัจจัยเดียวที่ต้องพิจารณา คอนโซลแบบโฮสต์หมายถึงการฝากความพร้อมใช้งานไว้กับผู้อื่น ส่วน VPS คือความรับผิดชอบของคุณเอง รวมถึงคืนที่ดิสก์เต็มด้วย หากเซิร์ฟเวอร์นี้ต้องสร้างประโยชน์ในทั้งสองกรณี สิ่งอื่นที่คุณสามารถรันบน VPS ได้ คือรายการที่คุณควรอ่านต่อไป

FAQ

ทำไมอุปกรณ์ UniFi ของฉันถึงไม่ยอมเชื่อมต่อ (adopt) กับ controller บน VPS?

อุปกรณ์จะค้นหา controller ผ่านการกระจายสัญญาณ (broadcast) บน UDP port 10001 ซึ่งสัญญาณ broadcast จะไม่หลุดออกจากเครือข่ายภายใน ทำให้อุปกรณ์ที่อยู่คนละไซต์ไม่สามารถค้นหา controller บนอินเทอร์เน็ตสาธารณะได้ ให้ตั้งค่า inform host override ในการตั้งค่าระบบของ controller ให้เป็น hostname ของ VPS จากนั้นชี้อุปกรณ์ไปยัง host ดังกล่าวด้วย ssh ubnt@<device-ip> ตามด้วย set-inform http://vps.example.com:8080/inform หากอุปกรณ์ค้างอยู่ที่สถานะ Adopting ให้รันคำสั่ง set-inform อีกครั้งในขณะที่อุปกรณ์อยู่ในสถานะนั้น หากอุปกรณ์เคยถูก controller อื่นเชื่อมต่อมาก่อน ให้รีเซ็ตเป็นค่าโรงงานก่อนเสมอ เนื่องจากอุปกรณ์ยังคงเก็บข้อมูลรับรอง (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 คือหน้าจัดการระบบ (admin interface) ซึ่งเก็บการตั้งค่าของทุกไซต์ที่ controller ดูแลอยู่ ให้เผยแพร่พอร์ตนี้ผ่าน 127.0.0.1 โดยใช้ Docker Engine 28.0.0 ขึ้นไป แล้วเข้าใช้งานผ่าน ssh -L 8443:127.0.0.1:8443 you@vps.example.com หรือผูกพอร์ตไว้กับที่อยู่ IP ของ WireGuard หรือ Tailscale เท่านั้น สำหรับการเชื่อมต่อและจัดการอุปกรณ์ ไซต์ของคุณจำเป็นต้องเข้าถึง TCP 8080 และ UDP 3478 ได้ รวมถึง TCP 5671 หากมีการใช้ UXG gateway เพื่อส่ง Traffic Flow logs ไปยัง controller โดยคุณสามารถจำกัดการเข้าถึงพอร์ตเหล่านี้ให้เฉพาะ IP สาธารณะของไซต์นั้นๆ ได้หากเป็น IP แบบ static โปรดจำไว้ว่าพอร์ตที่เผยแพร่ผ่าน 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 ประกอบด้วยการตั้งค่าของไซต์และบัญชีผู้ดูแลระบบทั้งหมด

#unifi#ubiquiti#network-management#docker#self-hosting