Запуск Unifi Network Application в Docker



Після заміни Raspberry Pi 4 на 5, я почав переносити всі сервіси в Docker контейнери, і Unifi Network Application не виявилося виключенням. В цій статті я опишу покроково, як запустити докер, коректно зробити імпорт та експорт конфігурації, розкажу про особливості роботи контролера в Docker.

Вступ

Docker давно став стандартом де-факто для розгортання сервісів: він спрощує оновлення, ізолює залежності та дозволяє швидко переносити системи між хостами без повторної конфігурації. Для домашніх серверів і Raspberry Pi це особливо актуально – один docker-compose може замінити години ручного налаштування.

Водночас UniFi Network Application досі не має офіційного Docker-образу від Ubiquiti на Docker Hub, що змушує шукати альтернативні, перевірені рішення від спільноти.

У цій статті я розгляну контейнеризоване рішення від команди LinuxServer.io, яке де-факто стало стандартом у спільноті. Покроково покажу, як правильно підняти UniFi Controller у Docker разом із MongoDB, які порти необхідні для коректної роботи пристроїв, як виглядає взаємодія контейнерів між собою та що потрібно врахувати при міграції з класичної сервісної інсталяції.

Схема взаємодії

Я вирішив візуалізувати взаємодію між користувачем, пристроями та контейнерами в простій графічній формі:

Також опишу призначення портів:

  • 8080 inform – основний канал взаємодії між UniFi-пристроєм і контролером
  • 8443 Web UI – панель керування через браузер
  • 3478 STUN – потрібен для визначення зовнішньої адреси пристрою, якщо він за NAT
  • 10001 discovery – механізм автоматичного пошуку контролера в локальній мережі
  • 27017 – це внутрішній порт між контейнерами для MongoDB

Файл докер-конфігурації

Файл конфігурації docker-compose.yml буде містити всю необхідну інформацію для запуску двох докер контейнерів:

  • MongoDB
  • Unifi Network Application

Для того, щоб не публікувати значення змінних та конфіденційну інформацію напряму в docker-compose.yml файлі, ці дані будуть перенесені в окремий файл .env так буде зручніше керувати змінними.

MongoDB

Раніше, коли MongoDB встановлювалась на Raspberry Pi 4 як системний сервіс, я зіткнувся з апаратними обмеженнями – запускалась лише MongoDB 4.4.18, тоді як новіші версії просто не стартували. Причина в тому, що починаючи з MongoDB 5.x проєкт офіційно підвищив вимоги до CPU, зокрема до наявності AVX-інструкцій, які відсутні в процесорах ARMv8, що використовуються в Raspberry Pi.

Docker вирішує цю проблему завдяки використанню архітектурно сумісних образів (arm64) та чітко зафіксованих версій, це значить, що можна запускати саме ту версію MongoDB, яку підтримує конкретний застосунок (у моєму випадку – UniFi), без конфліктів із системними бібліотеками, залежностями або обмеженнями дистрибутива.

Тому буде обрана сучасна версія – MongoDB 8.0.

services:
  unifi-db:
    image: mongo:8.0
    container_name: unifi-db
    environment:
      - MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
      - MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
      - MONGO_USER=${MONGO_USER}
      - MONGO_PASS=${MONGO_PASS}
      - MONGO_DBNAME=${MONGO_DBNAME}
      - MONGO_AUTHSOURCE=${MONGO_AUTHSOURCE}
    volumes:
      - ./mongo/data:/data/db
      - ./init-mongo.sh:/docker-entrypoint-initdb.d/init-mongo.sh:ro
    restart: unless-stopped
...

Unifi Network Application

Схожа ситуація була й з UniFi Controller. При класичному встановленні як сервіс у системі доводилось окремо інсталювати та підтримувати Java Runtime Environment, стежачи за сумісністю версій Java з конкретним релізом контролера.

У Docker-варіанті ця проблема зникає повністю: контейнер UniFi вже містить всі необхідні залежності, включно з Java, підібрані саме під цю версію контролера. Це значно спрощує розгортання застосунку!

...
  unifi-network-application:
    image: lscr.io/linuxserver/unifi-network-application:arm64v8-9.3.45
    container_name: unifi
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - MONGO_USER=${MONGO_USER}
      - MONGO_PASS=${MONGO_PASS}
      - MONGO_HOST=${MONGO_HOST}
      - MONGO_PORT=${MONGO_PORT}
      - MONGO_DBNAME=${MONGO_DBNAME}
      - MONGO_AUTHSOURCE=${MONGO_AUTHSOURCE}
    volumes:
      - ./unifi:/config
    ports:
      - 8443:8443
      - 3478:3478/udp
      - 10001:10001/udp
      - 8080:8080
    restart: unless-stopped

Змінні оточення

Окрему увагу варто приділити винесенню змінних середовища в файл .env. Такий підхід дозволяє чітко відокремити конфігурацію від коду: паролі, імена баз даних, користувачі та інші чутливі параметри зберігаються в одному місці й не містяться безпосередньо в docker-compose.yml.

Це підвищує безпеку, спрощує міграцію між пристроями або середовищами та робить конфігурацію значно читабельнішою. Крім того, .env-файл зручно виключати з репозиторію, що зменшує ризик випадкового витоку облікових даних.

Для зручності я розділив змінні по категоріям коментарями:

# ===== System =====
PUID=1000
PGID=1000
TZ=Europe/Kyiv

# ===== MongoDB root =====
MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=<strong password>

# ===== UniFi Mongo user =====
MONGO_USER=unifi
MONGO_PASS=<strong password>
MONGO_DBNAME=unifi
MONGO_AUTHSOURCE=admin

# ===== Mongo connection =====
MONGO_HOST=unifi-db
MONGO_PORT=27017

Експорт конфігурації Unifi

Оскільки в мене на хості встановлено версію контролера 9.3.45, я буду запускати докер використовуючи таку саму версію, щоб не було конфлікту при майбутньому імпорті конфігурації. Згодом я цю версію оновлю до актуальної.

Для експорту конфігурації необхідно залогінитися на діючому контролері, перейти в меню “Settings” вибрати підменю “System” та перейти на вкладку “Backups“. Завантажити конфігурацію натиснувши на кнопку “Download” та вибрати із списку окрім конфігурації додатково дані, якщо в цьому є необхідність.

Після того, як файл конфігурації успішно завантажено, необхідно зупинити та деактивувати сервіс Unifi на хості, щоб перед запуском докера, жодної версії контролера не було запущено.

Перший запуск

Для запуску Network Application достатньо виконати просту команду із домашньої директорії:

docker compose up -d

В результаті буде створено та запущено два докер контейнери. Перевірити це можна командою:

docker compose ps

unifi lscr.io/linuxserver/unifi-network-application:arm64v8-9.3.45 "/init" unifi-network-application   5 hours ago Up 5 hours 0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp, 8843/tcp, 0.0.0.0:3478->3478/udp, [::]:3478->3478/udp, 0.0.0.0:10001->10001/udp, [::]:10001->10001/udp, 0.0.0.0:8443->8443/tcp, [::]:8443->8443/tcp, 8880/tcp

unifi-db mongo:8.0 "docker-entrypoint.s…" unifi-db 5 hours ago Up 5 hours 27017/tcp

Після цього можна сміливо переходити за адресою: https://<IP>:8443/ відкриється вікно із пропозицією налаштувати контролер, або імпортувати дані з резервної копії. На жаль я не встиг зробити актуальний скріншот, проте суть зрозуміла, не потрібно вносити будь які дані, а достатньо відновити налаштування з бекапу.

Після успішного відновлення конфігурації користувач буде перенаправлений на стартову сторінку контролера, де треба ввести логін та пароль які використовувались під час авторизації на хості.

Зміна Inform Host

Після restore конфігурації UniFi-контролера пристрої можуть з’явитися у статусі Adopting / Pending Adoption або Offline. Це нормально, оскільки в бекапі збережена стара IP-адреса контролера (inform address), і точки доступу, свічі чи шлюзи продовжують звертатися саме до неї.

Щоб пристрої коректно підключилися до нового контролера, необхідно змінити Inform Host (IP-адресу або DNS-ім’я) на актуальну адресу нового сервера – після цього пристрої автоматично перепідключаться та завершать процес adoption.

Для цього необхідно перейти в меню “Devices” і клацнути на кнопку “Device Updates and Settings” яка розташована вгорі праворуч. У відкритій бічній панелі буде розділ “Device Settings” де потрібно поставити галочку “Inform override Host“. З’явиться попередження:

Override Inform Host
Please ensure that all adopted UniFi Network devices can reach the configured Host for Inform before enabling the override setting. Entering a hostname or IP address that is either incorrect or unreachable will cause your UniFi Network devices to disconnect and may require you to physically reset them.

Підтверджуємо натиснувши на кнопку “Confirm”

Після цього треба буде ввести IP адресу нового уніфай контролера та застосувати зміни. Через декілька хвилин всі пристрої автоматично переключаться на новий контролер і змінять статус на активний.

Продуктивність

Оскільки в мене є однакова версія контролера, встановленого як сервіс, і докер, то я вирішив порівняти використання ресурсів. Це не стосується швидкодії, а саме використання процесора та пам’яті.

Для визначення які ресурси бере на себе докер існує команда docker compose stats і ось її результат:

Якщо описати словами, то Unifi контролер бере 700-750 Мб оперативної памяті, а MongoDB 100-150 Мб, що в сумі може споживати 1Гб, як на мене то це забагато. З процесором трошки простіше – в середньому значення коливаються від 1 до 2%, що на мою думку допустимо.

Для визначення сервісів, я буду використовувати звичайну утиліту htop та фільтрувати навантаження по назві процесу:

У випадку із сервісами, то Java + Unifi візуально беруть менше оперативної пам’яті, приблизно 550-600 Мбайт, а MongoDB приблизно так само як і в Докері, але все-ж таки трошки менше. Проте це перше таке враження.

В дійсності Docker не споживає більше ресурсів, ніж сервіси, запущені напряму в системі. Різниця полягає в тому, що Docker відображає реальне використання памʼяті з урахуванням JVM, кешів і cgroups, тоді як при запуску як сервіс частина споживання прихована на рівні системного кешу. Фактично Docker дає більш чесну та прогнозовану картину використання ресурсів.

Оновлення контролера

Попередніх кроків достатньо для роботи із пристроями використовуючи Unifi Network Application в Docker але на момент виходу статті версія контролера 9.3.45 виглядає вже трошки застарілою.

Для актуалізації останньої офіційної версії необхідно відвідати сайт https://ui.com/download/software/uxg-lite. Наразі остання версія на офіційному сайті 10.0.160 for Debian/Ubuntu, тому саме її можна пошукати і на докер хабі LinuxServer. В розділі Latest була версія 10.0.162 що є бетою, тому краще не використовувати тег latest а користуватися перевіреними версіями.

Для оновлення версії, достатньо змінити версію в рядку image: в файлі docker-compose.yml на актуальну:

image: lscr.io/linuxserver/unifi-network-application:arm64v8-10.0.160

і виконати команду для завантаження нової версії контейнера

docker compose pull

та після завантаження, як і минулого разу достатньо просто запустити його

docker compose up -d

Вже буде запущено нову версію UniFi Network Application!

Висновки

Перенесення UniFi-контролера в Docker – це практичне та надійне рішення, особливо для Raspberry Pi та інших ARM-платформ. Контейнеризація знімає обмеження, пов’язані з версіями MongoDB, залежностями Java та оновленнями операційної системи, дозволяючи використовувати актуальні й підтримувані версії компонентів без ручної підгонки середовища.

Використання готового образу від спільноти linuxserver.io суттєво спрощує розгортання, оновлення та резервне копіювання контролера. Винесення змінних у .env файл підвищує безпеку, читабельність конфігурації та робить інфраструктуру відтворюваною – сервіс можна швидко підняти з нуля на іншому хості.

Процес backup / restore дозволяє безболісно мігрувати між серверами, а розуміння механізму inform address дає змогу коректно «переадоптити» всі пристрої після відновлення. У підсумку Docker-підхід забезпечує стабільність, контроль і масштабованість, яких складно досягти при класичній установці UniFi-контролера як системного сервісу.