В этой подробной статье мы будем строить Docker лабораторию для удобного управления проектами Docker Compose с помощью графического интерфейса. И да, под капотом только Open Source 🐧.
Предисловие

Я развернул такую лабораторию на своём домашнем Linux ПК и теперь с удобством управляю своими docker compose сервисами, работающие не только на нём, но и удалённых серверах. Но обо всём по порядку 📝.
🖐️Эй!
Подписывайтесь на наш телеграм @r4ven_me📱, чтобы не пропустить новые публикации на сайте😉. А если есть вопросы или желание пообщаться по тематике — заглядывайте в Вороний чат @r4ven_me_chat🧐.
Наша будущая лаборатория будет строиться вокруг такого замечательного Open Source продукта, как Komodo.
Ниже коротко о составе лаборатории.
- Komodo (как оркестратор Docker) - предназначен для автоматизации развертывания, масштабирования и управления контейнерными приложениями с помощью удобной панели управления. Умеет с помощью агентов управлять сервисами Docker на удалённых машинах.
- Nginx Proxy Manager - это удобный инструмент с веб-интерфейсом, который упрощает настройку Nginx в качестве обратного прокси и управление SSL-сертификатами (например, Let’s Encrypt или самоподписанными).
- Technitium - это функциональный DNS-сервер, также с веб-интерфейсом, позволяющий гибко управлять доменными зонами и разрешением имён, блокировать рекламу и прочее. Может реализовывать резолвинг по TCP, UDP, DoT, DoH и пр.
- И много много разных compose проектов 😉.
Чуть подробнее про Komodo под спойлером
- Подключение неограниченного количества серверов (архитектура Core + Periphery — центральный Core и лёгкие агенты Periphery на узлах);
- Мониторинг ресурсов: CPU, память, диск с алертами;
- Доступ к shell-сессиям серверов через браузер;
- Создание, запуск, остановка, перезапуск и redeploy контейнеров;
- Просмотр статуса, логов в реальном времени;
- Exec в контейнер (подключение к shell внутри контейнера прямо из UI);
- Деплой стеков из UI, с хоста или из Git-репозитория;
- Автоматический redeploy при push в Git (через webhook);
- Поддержка нескольких compose-файлов (docker compose -f … -f …);
- Передача environment variables;
- Импорт существующих compose-проектов;
- Сборка образов из Dockerfile прямо в UI;
- Автоматическая сборка из Git-репозитория (с webhook);
- Поддержка версионирования образов;
- Procedures и Actions - многошаговые автоматизированные workflows;
- Resource Sync - декларативное управление всей конфигурацией через TOML-файлы в Git;
- Поддержка Podman (как альтернативы Docker);
- Полностью self-hosted, open-source (GPLv3).
Схема лаборатории

Так, материала впереди много, поэтому меньше слов, больше дела, пингвины 🐧🐧🐧.
📝 Все действия из данной статьи выполнялись в среде дистрибутива Linux Mint (Ubuntu), редакции Cinnamon, и от имени обычного пользователя с правами sudo.
Во всех остальных дистрибутивах Linux всё будет выглядеть +- аналогично.
Подготовка
Установка Docker

Т.к. мы строим лабораторию для удобного управления Docker ресурсами, устанавливаем Docker Engine и добавляем нашего пользователя в группу docker.
sudo curl https://get.docker.com/ | bash
sudo gpasswd -a $USER docker
newgrp dockerПосле успешной установки и добавления в группу Docker пробуем выполнить команду:
docker run hello-worldВ случае успеха увидим такое:

Установка вспомогательных утилит
Теперь установим утилиты из стандартных репозиториев, которые нам понадобятся в ходе настройки нашей лаборатории:
sudo apt update
sudo apt install -y libnss3-tools dnsutils acl mkcert pwgenlibnss3-tools- утилиты для управления сертификатами и хранилищем NSS;acl- инструменты для работы с расширенными списками контроля доступа (Access Control Lists) в файловых системах;mkcert- простой инструмент для создания локальных доверенных TLS-сертификатов;pwgen- генератор случайных паролей.
Создание рабочей директории и установка прав
Создаём workdir и ограничиваем к ней доступ:
sudo mkdir -vp /opt/komodo/
sudo chmod -v 700 /opt/komodo
Устанавливаем полные права на workdir и будущие файлы для текущего пользователя:
sudo setfacl -R -m m::rwx /opt/komodo
sudo setfacl -R -m d:m::rwx /opt/komodo
sudo setfacl -R -m u:ivan:rwX /opt/komodo
sudo setfacl -R -m d:u:ivan:rwX /opt/komodo
getfacl /opt/komodo
Генерация сертификатов
Т.к. я привожу пример настройки Docker лаборатории на десктопном Linux ПК, то создам самоподписанный “центр сертификации (RootCA)” и сертификаты для доменов.
Для этого воспользуемся ранее установленной утилитой mkcert:
mkcert -install
mkcert -CAROOTПервая команда создаёт локальный центр сертификации и добавляет его корневой сертификат в доверенные сертификаты на нашей системе и в хранилище установленных браузеров, например, Firefox и Chromium:

Теперь создадим директорию для сертификатов и две штуки их самих:
- Для основного локального домена
home.lan; - И wildcard сертификат для поддоменов
*.home.lan.
mkdir -vp /opt/komodo/periphery/stacks/nginx/certs
cd /opt/komodo/periphery/stacks/nginx/certs
mkcert -cert-file ./home.lan.crt -key-file ./home.lan.key "home.lan" "localhost" "127.0.0.1"
mkcert -cert-file ./_wildcard.home.lan.crt -key-file ./_wildcard.home.lan.key "*.home.lan"☝️ Нам важен именно такой путь: /opt/komodo/periphery/stacks/nginx/certs.

(Опционально) Добавление mkcert rootCA в доверенные на другом хосте
Если вы планируете обращаться по HTTPS к вашему локальному хосту с других хостов, например, по защищённой приватной сети, то просто скопируйте корневой сертификат (не ключ!), созданный mkcert, в доверенные на другом хосте и обновите список.
Пример для Debian:
scp ~/.local/share/mkcert/rootCA.pem user@target_host:/tmp/
ssh -t user@target_host sudo cp /tmp/rootCA.pem /usr/local/share/ca-certificates/mkcert-rootCA.crt
ssh -t user@target_host sudo update-ca-certificates
ssh user@target_host trust list | grep mkcertДобавление хостов в /etc/hosts
Теперь нам нужно добавить 3 записи в локальный файл /etc/hosts:
cat << EOF | sudo tee -a /etc/hosts
127.0.0.1 home.lan # Nginx proxy
127.0.0.1 komodo.home.lan # Docker manager
127.0.0.1 technitium.home.lan # DNS
EOFСоздание сети докер
Для нашей инсталляции мы создадим отдельную сеть Docker: komodo_net:
docker network create --opt com.docker.network.bridge.name=br-komodo-net --opt com.docker.network.enable_ipv6=false --driver bridge --subnet 10.51.51.0/24 --gateway 10.51.51.1 komodo_netС подготовкой закончили😌.
Настройка прокси сервера - Nginx Proxy Manager
Приступаем к настройке нашего proxy, который будет управлять сертификатами, проксированием HTTP и TCP.
Запуск nginx-proxy-manager в Docker

Переходим в рабочую директорию nginx и создаём файл docker сервисов:
cd /opt/komodo/periphery/stacks/nginx/
vim ./compose.yamlНаполняем его следующим содержимым:
---
# https://nginxproxymanager.com/setup/
networks:
komodo_net:
external: true
services:
nginx:
image: jc21/nginx-proxy-manager:latest
container_name: nginx
restart: unless-stopped
stop_grace_period: 30s
cpus: 2
mem_limit: 2G
environment:
TZ: Europe/Moscow
DB_SQLITE_FILE: /data/database.sqlite
hostname: nginx
volumes:
- ./data/:/data/
- ./certs/letsencrypt:/etc/letsencrypt/
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- 127.0.0.1:80:80 # HTTP
- 127.0.0.1:81:81 # Web UI
- 127.0.0.1:443:443 # HTTPS
# - 127.0.0.1:53:53 # DNS
dns:
- 10.51.51.50
- 8.8.8.8
networks:
komodo_net:
ipv4_address: 10.51.51.50
aliases:
- home.lan
- nginx-proxy-manager
- nginx-proxy
- nginx📝 Лимиты ресурсов контейнера скорректируйте под ваши потребности. Параметры cpus:, mem_limit:.
Запускаем наш первый сервис и смотрим вывод:
docker compose up -d && docker logs -f nginx
После успешного запуска открываем в веб-браузере адрес http://localhost:81.
Увидим окно приветствия и предложение указать имя/email администратора и задать для него пароль:

💡 Совет
Сгенерировать надёжный пароль можно с помощью установленной на этапе подготовки утилиты pwgen:
pwgen -s 32 1
Добавление сертификатов в Nginx
На данном шаге мы настроим прокси-доступ к Web GUI панелям наших сервисов (в т.ч. nginx-proxy-manager) по HTTPS.
После входа в админ-панель прокси включаем тёмную тему 😉, меняем язык интерфейса на русский и переходим в раздел управления сертификатами:

Нажимаем “Добавить сертификат” –> “Свой сертификат”. Указываем:
- имя -
home.lan; - ключ -
/opt/komodo/periphery/stacks/nginx/certs/home.lan.key; - сертификат -
/opt/komodo/periphery/stacks/nginx/certs/home.lan.crt.

📝 Разумеется, вы также можете настроить автоматическое получение и обновление сертификатов от Let’s Encrypt, если создаёте лабораторию на машине с белым IP адресом.
И таким же образом загружаем wildcard сертификат. В итоге у вас должно быть добавлено два сертификата:

Создание прокси-хостов
Теперь переходим в “Хосты” –> “Прокси-хосты” и нажимаем “Добавить Прокси-хост”:

В пункте “Домены” указываем home.lan и нажимаем Enter. Далее в поле “Хост” указываем сетевой алиас нашего прокси nginx, в поле “Порт” - порт, на котором работает админка прокси - 81. После заполнения переходим на вкладку “SSL”:

Тут выбираем сертификат home.lan, включаем принудительный SSL и поддержку HTTP/2. После чего нажимаем “Сохранить”:

Таким же образом добавляем еще два прокси-хоста.
Komodo:
- Домен -
komodo.home.lan - Хост -
komodo-core - Порт -
9120 - Включить - Поддержка Websockets
- SSL сертификат -
_wildcard.home.lan - Включить - Всегда SSL
- Включить - Поддержка HTTP/2
Technitium:
- Домен -
technitium.home.lan - Хост -
technitium - Порт -
5380 - Включить - Поддержка Websockets
- SSL сертификат -
_wildcard.home.lan - Включить - Всегда SSL
- Включить - Поддержка HTTP/2
В итоге у нас получится три прокси-хоста:

Проверяем работу проксирования нажав на запись home.lan в колонке “ИСТОЧНИК”. Откроется новая страница входа в панель nginx, но уже с валидным соединением по HTTPS:


Никаких ругательств на сертификаты и небезопасное соединение😌.
Создание потока (stream) для DNS запросов
Теперь мы создадим один стрим для проксирования DNS запросов в DNS сервер technitium.
Переходим в “Хосты” –> “Потоки” и нажимаем “Добавить Поток”:

Указываем:
- Входящий порт -
53 - Хост перенаправления -
technitium - Порт перенаправления -
53 - Протоколы TCP и UDP
И нажимаем “Сохранить”:

Будет такая запись:

Настройка менеджера Docker - Komodo
Переходим к менеджеру Docker ресурсов - Komodo.
Запуск Komodo в Docker
Идём в рабочую директорию и создаём compose файл:
cd /opt/komodo
vim ./compose.yamlНаполняем его:
---
# https://github.com/moghtech/komodo/blob/main/compose/mongo.compose.yaml
networks:
komodo_net:
external: true
services:
komodo_db:
image: mongo:8.2.7-rc0
container_name: komodo-db
labels:
komodo.skip: # Prevent Komodo from stopping with StopAllContainers
restart: unless-stopped
stop_grace_period: 1m
cpus: 2
mem_limit: 2G
hostname: komodo-db
command: --quiet --wiredTigerCacheSizeGB 0.25
volumes:
- ./db/data/:/data/db/
- ./db/config/:/data/configdb/
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
environment:
TZ: Europe/Moscow
MONGO_INITDB_ROOT_USERNAME: ${KOMODO_DB_USERNAME}
MONGO_INITDB_ROOT_PASSWORD: ${KOMODO_DB_PASSWORD}
expose:
- 27017
dns:
- 10.51.51.50
- 8.8.8.8
networks:
komodo_net:
ipv4_address: 10.51.51.51
aliases:
- komodo-db.home.lan
- komodo-db
komodo_core:
image: ghcr.io/moghtech/komodo-core:${COMPOSE_KOMODO_IMAGE_TAG:-latest}
depends_on:
- komodo_db
container_name: komodo-core
labels:
komodo.skip: # Prevent Komodo from stopping with StopAllContainers
restart: unless-stopped
stop_grace_period: 1m
cpus: 2
mem_limit: 2G
hostname: komodo-core
env_file: ./.env
environment:
TZ: Europe/Moscow
KOMODO_DATABASE_ADDRESS: komodo-db:27017
KOMODO_DATABASE_USERNAME: ${KOMODO_DB_USERNAME}
KOMODO_DATABASE_PASSWORD: ${KOMODO_DB_PASSWORD}
volumes:
- ./core/backups/:/backups/
- ./core/syncs/:/syncs/
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
expose:
- 9120
dns:
- 10.51.51.50
- 8.8.8.8
networks:
komodo_net:
ipv4_address: 10.51.51.52
aliases:
- komodo-core.home.lan
- komodo.home.lan
- komodo-core
- komodo
komodo_periphery:
image: ghcr.io/moghtech/komodo-periphery:${COMPOSE_KOMODO_IMAGE_TAG:-latest}
labels:
komodo.skip: # Prevent Komodo from stopping with StopAllContainers
container_name: komodo-periphery
stop_grace_period: 1m
cpus: 2
mem_limit: 2G
hostname: komodo-periphery
restart: unless-stopped
env_file: ./.env
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /proc:/proc
## Specify the Periphery agent root directory.
## Must be the same inside and outside the container,
## or docker will get confused.
## Default: /etc/komodo.
- ${PERIPHERY_ROOT_DIRECTORY:-/opt/komodo}:${PERIPHERY_ROOT_DIRECTORY:-/opt/komodo}
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
expose:
- 8120
dns:
- 10.51.51.50
- 8.8.8.8
networks:
komodo_net:
ipv4_address: 10.51.51.53
aliases:
- komodo-periphery.home.lan
- komodo-periphery📝 Лимиты ресурсов контейнера скорректируйте под ваши потребности. Параметры cpus:, mem_limit:.
Файл описывает работу и взаимодействие трёх сервисов:
komodo_db- база данных MongoDB;komodo_core- непосредственно сам Komodo (ядро системы);komodo_periphery- агент Komodo, который имеет привилегированный доступ кdocker.sockдля управления Docker на данном хосте.
Теперь создаём файл с переменными окружения сервисов Komodo:
vim ./.envИ наполняем:
# https://github.com/moghtech/komodo/blob/main/compose/compose.env
TZ=Europe/Moscow
COMPOSE_KOMODO_IMAGE_TAG=2.0
KOMODO_INIT_ADMIN_USERNAME=komodo
KOMODO_INIT_ADMIN_PASSWORD=
KOMODO_DB_USERNAME=komodo
KOMODO_DB_PASSWORD=
KOMODO_PASSKEY=
KOMODO_HOST=https://komodo.home.lan
KOMODO_TITLE=Komodo
KOMODO_FIRST_SERVER=https://komodo-periphery:8120
KOMODO_FIRST_SERVER_NAME=komodo.home.lan
KOMODO_DISABLE_CONFIRM_DIALOG=true
KOMODO_MONITORING_INTERVAL="15-sec"
KOMODO_RESOURCE_POLL_INTERVAL="1-hr"
KOMODO_WEBHOOK_SECRET=
KOMODO_JWT_SECRET=
KOMODO_JWT_TTL="1-day"
KOMODO_LOCAL_AUTH=true
KOMODO_DISABLE_USER_REGISTRATION=false
KOMODO_ENABLE_NEW_USERS=false
KOMODO_DISABLE_NON_ADMIN_CREATE=false
KOMODO_TRANSPARENT_MODE=false
KOMODO_LOGGING_PRETTY=false
KOMODO_PRETTY_STARTUP_CONFIG=false
PERIPHERY_ROOT_DIRECTORY=/opt/komodo/periphery
# PERIPHERY_STACK_DIR=/opt/komodo/stacks
PERIPHERY_PASSKEYS=${KOMODO_PASSKEY}
PERIPHERY_DISABLE_TERMINALS=false
PERIPHERY_SSL_ENABLED=true
PERIPHERY_INCLUDE_DISK_MOUNTS=/etc/hostname
PERIPHERY_LOGGING_PRETTY=false
PERIPHERY_PRETTY_STARTUP_CONFIG=falseТут нам необходимо задать свои значения для паролей/секретов. Вновь воспользуемся утилитой pwgen:
sed -iE "s/^KOMODO_INIT_ADMIN_PASSWORD=.*/KOMODO_INIT_ADMIN_PASSWORD=$(pwgen -s 32 1)/" ./.env
sed -iE "s/^KOMODO_DB_PASSWORD=.*/KOMODO_DB_PASSWORD=$(pwgen -s 32 1)/" ./.env
sed -iE "s/^KOMODO_PASSKEY=.*/KOMODO_PASSKEY=$(pwgen -s 64 1)/" ./.env
sed -iE "s/^KOMODO_WEBHOOK_SECRET=.*/KOMODO_WEBHOOK_SECRET=$(pwgen -s 64 1)/" ./.env
sed -iE "s/^KOMODO_JWT_SECRET=.*/KOMODO_JWT_SECRET=$(pwgen -s 64 1)/" ./.envПосле этого можем запускать сервис komodo:
docker compose up -d && docker compose logs -f
После успешного запуска возвращаемся в браузер и переходим на https://komodo.home.lan, где мы видим вход в панель управления Komodo без всякой ругани на TLS сертификаты:

Вводим логин komodo и пароль из переменной KOMODO_INIT_ADMIN_PASSWORD:
grep ADMIN_PASSWORD ./.env
Интерфейс юзерфрендли, с приятным и современным дизайном.
Создание compose stack для nginx - файлы на сервере
Идём в “Stacks” –> “New Stack”:

Указываем имя nginx, а в качестве сервера выбираем наш локальный komodo.home.lan:

☝️ Важно, чтобы имя стека совпадало с названием директории с compose файлами проекта в /opt/komodo/periphery/stacks. По этой причине мы создавали именно такую структуру.
Заходим внутри стека nginx:

И на вкладке “Config” выбираем режим “Files On Server”:

📝 Данный режим позволяет подтянуть существующие файлы проекта в сущность “Stack” Komodo.
Сохраняем изменения:

И т.к. наш nginx уже запущен, стек автоматически перейдёт в статус “RUNNING”:

Если видите что-то подобное:

Значит вы указали неправильное имя стека, либо некорректно примонтировали рабочую директорию periphery контейнера:
☝️ Рабочая директория агента (periphery) указывается в переменной PERIPHERY_ROOT_DIRECTORY и обязательно должна совпадать с указанным в ней путём на самом хосте и в контейнере. В моём примере: /opt/komodo/periphery:/opt/komodo/periphery.
Вы можете изменять параметры стека прямо в веб интерфейсе Komodo на вкладке “Info” (в случае режима “Files On Server”). После изменений, нажмите “Save” и затем “Redeploy”, чтобы применить обновлённые параметры.
Управлять ресурсами сервера можно как внутри самого стека, так и в разделе “Servers” –> “<server_name>”:

Очень наглядно, очень удобно 👍.
Настройка DNS сервера - Technitium

Любая лаборатория считается неполноценной, если в ней отсутствует свой DNS сервер.
Создание compose stack для technitium - файлы на сервере
Возвращаемся в веб-панель “Komodo” –> “Stacks” –> “New Stack”. Указываем название technitium и выбираем наш локальный сервер komodo.home.lan.
После проваливаемся внутрь стека на вкладке “Config” выбираем режим “UI Defined”:

Наполняем поле “Compose File” таким содержимым:
---
# https://github.com/TechnitiumSoftware/DnsServer/blob/master/docker-compose.yml
networks:
komodo_net:
external: true
services:
technitium:
image: technitium/dns-server:${DNS_SERVER_IMAGE_TAG:-latest}
container_name: technitium
restart: unless-stopped
stop_grace_period: 1m
cpus: 2
mem_limit: 2G
hostname: technitium
sysctls:
- net.ipv4.ip_local_port_range=1024 65535
env_file: ./.env
volumes:
- ./data/:/etc/dns/
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
expose:
- 5380/tcp # DNS web console (HTTP)
# - 53443/tcp # DNS web console (HTTPS)
- 53/udp # DNS service
- 53/tcp # DNS service
# - 853/udp # DNS-over-QUIC service
# - 853/tcp # DNS-over-TLS service
# - 443/udp # DNS-over-HTTPS service (HTTP/3)
# - 443/tcp # DNS-over-HTTPS service (HTTP/1.1, HTTP/2)
# - 80/tcp # DNS-over-HTTP service (use with reverse proxy or certbot certificate renewal)
# - 8053/tcp # DNS-over-HTTP service (use with reverse proxy)
# - 67/udp # DHCP service
dns:
- 10.51.51.50
- 8.8.8.8
networks:
komodo_net:
ipv4_address: 10.51.51.54
aliases:
- technitium.home.lan
- technitium-dns
- technitium📝 Лимиты ресурсов контейнера скорректируйте под ваши потребности. Параметры cpus:, mem_limit:.
Прокручиваем вниз до поля “Environment” и наполняем следующим:
# https://github.com/TechnitiumSoftware/DnsServer/blob/master/DockerEnvironmentVariables.md
DNS_SERVER_IMAGE_TAG=14.3.0
DNS_SERVER_ADMIN_PASSWORD=4RyYdGWcpkdGFj6anL64JxtbKwpQheqC
DNS_SERVER_DOMAIN=technitium.home.lan
DNS_SERVER_PREFER_IPV6=false
DNS_SERVER_RECURSION=AllowOnlyForPrivateNetworks
DNS_SERVER_FORWARDERS=8.8.8.8, 9.9.9.9
💡 Совет
Пароль для переменной DNS_SERVER_ADMIN_PASSWORD можно также сгенерировать через pwgen:
pwgen -s 32 1Нажимаем “Save”:

И запускаемся нажатием кнопки “Deploy”:

Перейдите на вкладку “Log”, чтобы видеть вывод контейнера. Если всё ок, должны увидеть следующее:

Вы можете изменять параметры стека прямо в веб интерфейсе Komodo на вкладке “Config” (в случае режима “UI Defined”). После изменений, нажмите “Save” и затем “Redeploy”, чтобы применить обновленные параметры.
☝️ Важно понимать, что при удалении стека в Komodo, файлы с хоста не удаляются.
После успешного запуска идём в браузер и открываем https://technitium.home.lan. Веб интерфейс управления DNS должен также открыться без проблем:

Логин admin, пароль берём из переменной DNS_SERVER_ADMIN_PASSWORD.
После входа сразу же подключаем тёмную тему 🌚:

Данный DNS сервер очень удобен в управлении и имеет достаточно широкий функционал: зоны, кэш, рекурсия и пр.
Создание зоны home.lan и записей для неё
Для удобства работы в нашей лаборатории создадим отдельную зону для домена home.lan.
Переходим на вкладку “Zones” и нажимаем “Add Zone”:

Указываем зону home.lan, оставляем чекбокс “Primary zone (default)” и нажимаем “Add”:

После создания мы попадём в настройки новой зоны. Нажимаем “Add Record” и в качестве имени указываем символ *, а в поле адреса 127.0.0.1 или физический адрес, на котором nginx-proxy-manager слушает 443 порт.

Нажимаем “Save”.
📝 Символ * работает следующим образом: при обращении к любому поддомену в зоне home.lan, DNS сервер будет резолвить его в адрес nginx-proxy-manager (127.0.0.1 в данном примере), который в свою очередь по SNI будет осуществлять проксирование на нужный нам сервис/контейнер. Таким образом мы упрощаем себе работу в зоне home.lan, ограничиваясь лишь добавлением прокси-записи в nginx, без постоянных добавлений A записей. Разумеется, вы вольны настроить DNS, как вам угодно. Это лишь мой пример. Но для того, чтобы всё это работало, необходимо настроить вашего клиента DNS. Об этом смотрите ниже: “Настройка DNS клиента”.
Через минуту-две проверяем работу в терминале хоста с помощью утилиты dig:
dig @10.51.51.50 r4ven.me +noall +answer
dig @10.51.51.50 test.home.lan +noall +answerДолжны увидеть такое:

Данный DNS сервер умеет много чего. Рекомендую поизучать его функционал на досуге 👨💻.
Проверка статуса ресурсов лаборатории
Выполним небольшую проверку, что всё на месте и всё работает, после завершения настройки сервисов compose:
docker ps; docker image ls; docker network ls
Настройка автозапуска ключевых сервисов
Т.к. наша лаборатория зиждется на трёх китах (прокси, docker менеджер и DNS сервер), давайте настроим их автозапуск с помощью Systemd, чтобы они наверняка запускались при старте системы.
Nginx Proxy Manager
Смело вставляем весь блок в терминал (это всё одна here doc команда):
cat << EOF | sudo tee /etc/systemd/system/komodo-proxy.service
[Unit]
Description=Nginx Proxy Manager
Requires=docker.service
After=docker.service
[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=/opt/komodo/periphery/stacks/nginx
ExecStart=/usr/bin/docker compose up
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.target
EOFKomodo
cat << EOF | sudo tee /etc/systemd/system/komodo-core.service
[Unit]
Description=Komodo docker stack services
Requires=docker.service
After=docker.service
[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=/opt/komodo
ExecStart=/usr/bin/docker compose up
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.target
EOFTechnitium
cat << EOF | sudo tee /etc/systemd/system/komodo-dns.service
[Unit]
Description=Technitium DNS server
Requires=docker.service
After=docker.service
[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=/opt/komodo/periphery/stacks/technitium
ExecStart=/usr/bin/docker compose up
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.target
EOFЗапуск и проверка
Обновляем конфигурацию Systemd и пробуем запустить сервисы с включением автозапуска:
sudo systemctl daemon-reload
sudo systemctl enable --now komodo-{proxy,core,dns}
systemctl list-units | grep -E 'komodo.*.service' | column -t
systemctl status komodo-{proxy,core,dns} | grep -B3 'Active:'
Настройка DNS клиента
Для удобства эксплуатации нашей лаборатории, рекомендую настроить отправку локальных DNS запросов на наш сервер Technitium.
Настройка резолвинга зависит от вашей системы и конфигурации сети.
systemd-resolved
Ниже я покажу пример настройки с помощью systemd-resolved.
⚠️ Пожалуйста, подходите к шагу по настройке разрешения имён осознанно. Прежде, чем продолжить, вам необходимо убедиться, кто именно у вас управляет списком серверов для резолвинга. Например, в Linux Mint, адресом сервера, куда нужно слать DNS запросы, может управлять NetworkManager, который может перекрывать настройки других программ.
Делаем бэкап конфигов DNS и создаём новый минимальный конфиг systemd-resolved:
sudo mv -v /etc/resolv.conf{,.backup}
sudo ln -sv /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
sudo mv -v /etc/systemd/resolved.conf{,_backup}
cat << EOF | sudo tee /etc/systemd/resolved.conf
[Resolve]
DNS=10.51.51.50
FallbackDNS=192.168.1.1 8.8.8.8
Domains=~.
EOFПерезапускаем службу:
sudo systemctl restart systemd-resolved
systemctl status systemd-resolved
resolvectl
Проверяем работу DNS уже без явного указания адреса technitium:
dig r4ven.me +noall +answer +identify
dig test.home.lan +noall +answer +identify
Работает!
NetworkManager
Если вашей сетью управляет NetworkManager, то указать свои DNS сервера можно через GUI:



Или через nmcli:
# Смотрим соединения
nmcli connection show
# Задаём DNS
nmcli connection modify "Проводное подключение 1" \
ipv4.dns "10.51.51.50,192.168.1.1,8.8.8.8" \
ipv4.ignore-auto-dns yesПосле применения изменений, желательно перезапустить сервис NetworkManager:
sudo systemctl restart NetworkManagerПроверяем работу DNS уже без явного указания адреса technitium:
dig r4ven.me +noall +answer +identify
dig test.home.lan +noall +answer +identify
На вид всё ок 😌. Но я больше рекомендую вариант с systemd-resolved.
Добавление внешних серверов в Komodo
Одна из ключевых фич Komodo - это возможность оркестрировать контейнерами, которые работают на удалённых серверах.
Далее покажу пример настройки и запуска агента (periphery) на удалённой машине с IP 192.168.122.31.
Установка komodo-periphery на удалённый хост для управления с помощью локального Komodo
Безусловно, на удалённом хосте должен быть установлен Docker Engine:
sudo curl https://get.docker.com/ | bashСоздаём рабочую директорию, выставляем права и создаём compose файл:
sudo mkdir -p /opt/periphery && sudo chmod 700 /opt/periphery
sudo vim /opt/periphery/compose.yamlПосле наполняем его:
---
services:
komodo_periphery:
image: ghcr.io/moghtech/komodo-periphery:2.0
labels:
komodo.skip:
container_name: komodo-periphery
stop_grace_period: 1m
cpus: 1
mem_limit: 1G
hostname: komodo-periphery
restart: on-failure
env_file: ./.env
ports:
- 192.168.122.31:8120:8120
volumes:
- ${PERIPHERY_ROOT_DIRECTORY}:${PERIPHERY_ROOT_DIRECTORY}
- /var/run/docker.sock:/var/run/docker.sock
- /proc:/proc
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro☝️ Обязательно заменить адрес 192.168.122.31 на свой.
Теперь создаём и наполняем переменные окружения:
sudo vim /opt/periphery/.envTZ=Europe/Moscow
PERIPHERY_ROOT_DIRECTORY=/opt/periphery
PERIPHERY_PASSKEYS=
PERIPHERY_DISABLE_TERMINALS=false
PERIPHERY_SSL_ENABLED=true
PERIPHERY_INCLUDE_DISK_MOUNTS=/etc/hostname
PERIPHERY_LOGGING_PRETTY=false
PERIPHERY_PRETTY_STARTUP_CONFIG=false
PERIPHERY_BIND_IP=0.0.0.0☝️Важно
В переменной PERIPHERY_PASSKEYS обязательно указываем тот же ключ, что указан в .env для Komodo сервера. Именно по нему будет происходить авторизация. Подключение и управление выполняется по HTTPS/Websockets.
Теперь создадим юнит Systemd для автозапуска Periphery при загрузке ОС:
sudo vim /etc/systemd/system/komodo-periphery.service[Unit]
Description=Komodo periphery docker stack services
Requires=docker.service
After=docker.service
[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=/opt/periphery
ExecStartPre=/usr/bin/sleep 5
ExecStart=/usr/bin/docker compose up
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.targetПеречитываем конфиг Systemd и запускаем наш сервис:
sudo systemctl daemon-reload
sudo systemctl enable --now komodo-periphery
systemctl status komodo-periphery
sudo docker compose -f /opt/periphery/compose.yaml logs -f komodo_peripheryЕсли видим такое, значит всё ок:

Теперь возвращаемся в интерфейс Komodo: “Servers” –> “New Server”, указываем имя, например, rustfs.home.lan:

Тут активируем сервер “Enabled” и указываем его адрес:порт. В моём случае это https://192.168.122.31:8120:

☝️ Обязательно укажите https:// в адресе.
Нажимаем “Save” и при успешном подключении увидим:

☝️Важно
Удалённый хост:порт должен быть доступен из вашей сети, где обитает контейнер с Komodo.
Создание compose stack - RustFS (S3 storage)
В целом наша лаборатория уже в рабочем состоянии и готова выполнять свои задачи. Давайте для примера добавим еще один стек, например, RustFS - S3-совместимное хранилище, которое выступает альтернативой печально известному MinIO.
Переходим в “Stacks” –> “New Stack”, указываем имя rustfs и выбираем наш удалённый сервер rustfs.home.lan:

Далее выбираем режим UI Defined и аналогичным образом заполняем поля “Compose File”:
---
# https://github.com/rustfs/rustfs/blob/main/docker-compose-simple.yml
# https://github.com/rustfs/rustfs/blob/main/docker-compose.yml
services:
rustfs:
image: rustfs/rustfs:1.0.0-alpha.90
container_name: rustfs
restart: unless-stopped
stop_grace_period: 30s
cpus: 2
mem_limit: 2G
user: "root:root"
env_file: ./.env
healthcheck:
test:
[
"CMD",
"sh", "-c",
"curl -f http://127.0.0.1:9000/health && curl -f http://127.0.0.1:9001/rustfs/console/health"
]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
ports:
- "192.168.122.31:9000:9000" # S3 API port
- "192.168.122.31:9001:9001" # Console port
volumes:
- ./data/storage/:/data/
- ./data/logs/:/app/logs/
- ./data/certs/:/opt/tls/ # TLS configuration, you should create tls directory and put your tls files in it and then specify the path here
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro☝️ Не забудьте указать свой адрес, вместо 192.168.122.31.
и “Environment”:
# https://docs.rustfs.com/installation/docker/#complete-parameter-configuration-example
RUSTFS_UID="root"
RUSTFS_GID="root"
TZ=Europe/Moscow
# RUSTFS_VOLUMES=/data/rustfs{0..3} # Define 4 storage volumes
RUSTFS_ADDRESS=0.0.0.0:9000
RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
RUSTFS_CONSOLE_ENABLE=true
RUSTFS_CORS_ALLOWED_ORIGINS=*
RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS=*
RUSTFS_ACCESS_KEY=ivan
RUSTFS_SECRET_KEY=3QuZHlIh6KDtnX0SBElGa8nI2xZAtSNb
RUSTFS_OBS_LOGGER_LEVEL=info
RUSTFS_TLS_PATH=/opt/tls
# RUSTFS_OBS_ENDPOINT=http://otel-collector:4318В переменной RUSTFS_ACCESS_KEY указываем логин администратора, а в RUSTFS_SECRET_KEY задаём пароль. Можно также сгенерить через pwgen:
pwgen -s 32 1Теперь “Save” и “Deploy”:

Самое время настроить проксирование. Идём в наш Nginx: “Прокси Хосты” –> “Добавить Прокси-хост”.
Создаём запись для админки RustFS:
- Домены:
rustfs.home.lan - IP перенаправления:
192.168.122.31 - Порт перенаправления:
9001 - SSL-сертификат:
_wildcard.home.lan - Всегда SSL - да
- Поддержка HTTP/2 - да
Следом создаём запись для самого S3:
- Домены:
s3.home.lan - IP перенаправления:
192.168.122.31 - Порт перенаправления:
9000 - SSL-сертификат:
_wildcard.home.lan - Всегда SSL - да
- Поддержка HTTP/2 - да

Переходим по https://rustfs.home.lan, вводим логин (RUSTFS_ACCESS_KEY) и пароль (RUSTFS_SECRET_KEY):


Можете создавать бакеты:

И обращаться к ним по адресу s3.home.lan. Например, с помощью утилиты rclone, по которой я недавно делал статью про монтирование удалённых хранилищ:
sudo apt install -y rclone
mkdir -vp ~/.config/rclone
cat << EOF > ~/.config/rclone/rclone.conf
[rustfs]
type = s3
provider = Minio
endpoint = https://s3.home.lan
access_key_id = ivan
secret_access_key = 3QuZHlIh6KDtnX0SBElGa8nI2xZAtSNb
# force_path_style = true
# no_check_bucket = true
EOFПроверяем:
rclone ls rustfs:
rclone mkdir rustfs:doc
rclone copy /usr/share/doc/docker-ce rustfs:doc
rclone ls rustfs:doc

Работает😌
Послесловие
Фух, как обычно, путь был тернист, но мы справились 😉👨💻.
Теперь у нас есть полноценная лаборатория, в которой можно разрабатывать, тестировать и эксплуатировать различные сервисы с большим удобством 😌.
В следующей заметке я покажу, как создавать стеки, используя тертий вариант - через Git репозитории. Покажу как безопасно хранить env файлы в Git и автоматизировать процедуру деплоя при пуше изменений в репо.
Также у меня есть готовый Ansible playbook для развёртывания komodo-periphery на удалённые хосты. Его я также выложу отдельной заметкой. Не пропустите!
Добавляйтесь в наш канал в телеге и Вороний чат там же. У нас там дружелюбное (я слежу за этим) сообществом пингвинов 🐧🐧🐧. Там же можете смело задавать вопросы по материалам блога.
Спасибо, что читаете. До связи! 👋
Полезные материалы
- Оф.сайт Nginx Proxy Manager
- GitHub репозиторий Nginx Proxy Manager
- Оф. документация по установке Nginx Proxy Manager
- Оф. сайт Komodo
- GitHub репозиторий Komodo
- Оф. документация Komodo
- mongo.compose.yaml для Komodo
- compose.env для Komodo
- Komodo Import - Quickstart
- Оф. сайт Technitium DNS
- GitHub репозиторий Technitium DNS
- docker-compose.yml Technitium DNS
- Переменные окружения Docker Technitium DNS


