Beszel: мониторинг VPS и Docker без Prometheus

Администрирование
Beszel: мониторинг VPS и Docker без Prometheus

Beszel подойдёт, если вы хотите видеть загрузку процессора, памяти, дисков, сети и Docker-контейнеров в одной панели, но пока не готовы собирать полноценный стек Prometheus и Grafana. В этой инструкции мы развернём центральную панель Beszel Hub на VPS, подключим локальный агент через Unix-сокет, закроем внутренний порт от интернета, добавим HTTPS через Nginx и проверим, что метрики и алерты действительно работают.

Оглавление

Что такое Beszel и когда он уместен

Beszel — компактная система мониторинга с веб-панелью и агентами. Она собирает метрики Linux-хоста и, при наличии доступа к Docker API, сведения о контейнерах. Администратор получает графики, историю показателей и уведомления без самостоятельной настройки базы временных рядов, экспортёров и сложных запросов.

Такой подход особенно удобен для небольшой инфраструктуры:

  • одного VPS с несколькими Docker-сервисами;
  • нескольких серверов разработки и продакшена;
  • личных self-hosted приложений;
  • ботов и фоновых задач, которым важны память, диск и доступность;
  • игровых серверов, где нужно заранее заметить рост RAM или заполнение диска;
  • агентств и небольших команд, которым нужна единая обзорная панель.

Beszel не является полной заменой Prometheus, Grafana, Loki или Zabbix. Если нужны произвольные бизнес-метрики приложения, сложные PromQL-запросы, длительное хранение телеметрии по собственной политике, распределённая трассировка или централизованный анализ логов, потребуется более развитый стек. Beszel решает другую задачу: быстро показать состояние ограниченного числа серверов и контейнеров с небольшим объёмом ручной настройки.

На дату подготовки материала актуальная документация Beszel относится к версии 0.18.7. Проект развивается, поэтому перед установкой проверьте страницу релизов и инструкции: названия переменных, схема подключения и рекомендуемый Compose-файл могут измениться.

Как устроены Hub и Agent

Архитектура состоит из двух компонентов:

  1. Beszel Hub хранит настройки и историю, показывает веб-интерфейс, управляет пользователями и алертами.
  2. Beszel Agent собирает сведения о конкретной машине и передаёт их Hub.

Hub и Agent умеют общаться двумя способами.

SSH-подключение от Hub к Agent

Hub инициирует соединение с SSH-сервером агента, обычно на порту 45876. При первом запуске Hub создаёт ключ ED25519, а агент принимает только этот ключ. Согласно документации Beszel, встроенный SSH-сервер агента не предоставляет терминал и не принимает команды: это уменьшает последствия компрометации ключа.

Режим удобен, когда центральный Hub может напрямую достучаться до серверов. Но строгая политика FORWARD DROP в iptables способна незаметно нарушить маршрутизацию пакетов между контейнером Hub и удалённым агентом. В такой ситуации разработчики рекомендуют режим WebSocket.

Исходящее WebSocket-подключение от Agent к Hub

Агент сам соединяется с URL центральной панели. Это полезно для серверов за NAT, в закрытых сетях и в случаях, когда открывать входящий порт агента нежелательно. Для регистрации используются публичный ключ, токен и отпечаток машины. Обратный прокси перед Hub обязан пропускать WebSocket Upgrade.

В этой инструкции локальный агент соединяется с Hub через Unix-сокет. Порт агента не открывается вовсе, а HTTP-порт Hub доступен только на loopback-интерфейсе. Для удалённых серверов мы отдельно разберём исходящий WebSocket и SSH-вариант.

Что понадобится до установки

Подготовьте:

  • VPS с 64-битной Ubuntu, root-доступом или пользователем с sudo;
  • установленный Docker Engine и плагин Docker Compose;
  • домен или поддомен, например monitor.example.ru;
  • DNS-запись типа A, указывающую на выделенный IPv4 VPS;
  • открытые наружу TCP-порты 80 и 443 для Nginx и выпуска сертификата;
  • электронную почту для учётной записи администратора и уведомлений, если вы выберете email-канал.

Docker официально поддерживает 64-битные Ubuntu 22.04 LTS, 24.04 LTS, 25.10 и 26.04 LTS на перечисленных в документации архитектурах. Для стабильного сервера разумно выбирать LTS-выпуск, доступный в панели хостинга. Если Docker ещё не установлен, используйте официальный APT-репозиторий, а не случайный скрипт из статьи или устаревший пакет дистрибутива.

Есть важная особенность: опубликованные Docker-порты могут обходить ожидаемые правила UFW. Документация Docker рекомендует учитывать цепочку DOCKER-USER и совместимость с iptables-nft либо iptables-legacy. Поэтому мы привяжем порт Beszel к 127.0.0.1, а не будем надеяться только на запрет UFW.

Перед началом полезно пройти базовую защиту сервера: обновить пакеты, создать отдельного sudo-пользователя, настроить SSH-ключи и файрвол. Для этого используйте опубликованный чек-лист первых шагов после покупки VPS.

Подготовка VPS

Сначала проверьте систему и доступное место:

cat /etc/os-release
uname -m
df -h /
free -h

Обновите индекс пакетов и установленные исправления:

sudo apt update
sudo apt upgrade

Команда обновляет пакеты и может предложить перезапуск служб или системы. На рабочем сервере сначала изучите список изменений, сделайте резервную копию и согласуйте окно обслуживания. Проверить необходимость перезагрузки можно так:

test -f /var/run/reboot-required && cat /var/run/reboot-required || true

Убедитесь, что Docker и Compose доступны:

sudo docker version
sudo docker compose version
sudo systemctl is-active docker

Если Docker отсутствует, следуйте официальной инструкции Docker Engine для Ubuntu. Не добавляйте пользователя в группу docker без понимания последствий: управление Docker daemon практически равнозначно root-доступу к хосту.

Создайте рабочий каталог с ограниченными правами:

sudo install -d -m 0750 -o root -g root /opt/beszel
cd /opt/beszel

Дальнейшие команды изменения файлов выполняйте внимательно. Перед заменой конфигурации сохраняйте её копию, а после изменения Compose или Nginx всегда запускайте встроенную проверку.

Установка Beszel через Docker Compose

Создайте /opt/beszel/compose.yaml:

services:
  beszel:
    image: henrygd/beszel:0.18.7
    container_name: beszel
    restart: unless-stopped
    environment:
      APP_URL: https://monitor.example.ru
    ports:
      - "127.0.0.1:8090:8090"
    volumes:
      - ./beszel_data:/beszel_data
      - ./beszel_socket:/beszel_socket
    healthcheck:
      test: ["CMD", "/beszel", "health", "--url", "http://localhost:8090"]
      interval: 120s
      start_period: 10s
      timeout: 5s

  beszel-agent:
    image: henrygd/beszel-agent:0.18.7
    container_name: beszel-agent
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./beszel_agent_data:/var/lib/beszel-agent
      - ./beszel_socket:/beszel_socket
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      LISTEN: /beszel_socket/beszel.sock
      HUB_URL: http://localhost:8090
      TOKEN: REPLACE_AFTER_FIRST_LOGIN
      KEY: "REPLACE_AFTER_FIRST_LOGIN"
    healthcheck:
      test: ["CMD", "/agent", "health"]
      interval: 120s

Замените monitor.example.ru своим доменом. Здесь версия образов закреплена явно. Это делает обновления предсказуемыми: контейнер не перескочит на новую версию только потому, что тег latest изменился. Перед публикацией статьи и перед фактическим развёртыванием проверьте, остаётся ли 0.18.7 актуальным стабильным релизом.

Пока значения TOKEN и KEY не заполнены, запустите только Hub:

cd /opt/beszel
sudo docker compose config
sudo docker compose up -d beszel
sudo docker compose ps

docker compose config должен завершиться без ошибки. Затем проверьте контейнер и локальный HTTP-ответ:

sudo docker compose logs --tail=100 beszel
curl -I http://127.0.0.1:8090

Не используйте docker compose down -v: параметр -v удаляет именованные тома проекта и может привести к потере данных. В нашей схеме используются bind-каталоги, но привычка запускать разрушительные команды без проверки опасна для других Compose-проектов.

Первый вход и подключение локального сервера

До настройки Nginx веб-интерфейс слушает только 127.0.0.1:8090 на сервере. Это намеренно: панель не должна появиться в интернете без TLS. Для первоначального входа создайте SSH-туннель со своего компьютера:

ssh -L 8090:127.0.0.1:8090 your-user@server-ip

Откройте http://127.0.0.1:8090 в локальном браузере и создайте администратора. Используйте уникальный длинный пароль. Не создавайте очевидные логины вроде admin, если интерфейс позволяет выбрать другое имя или email.

В Hub нажмите Add System. Для версии 0.12.0 и новее документация также описывает универсальные токены в разделе /settings/tokens. Скопируйте выданные публичный ключ и токен, затем подставьте их в compose.yaml вместо заглушек.

Для локального агента укажите в интерфейсе Hub путь Unix-сокета как Host / IP:

/beszel_socket/beszel.sock

Перезапустите агент и проверьте его журнал:

cd /opt/beszel
sudo docker compose up -d beszel-agent
sudo docker compose ps
sudo docker compose logs --tail=100 beszel-agent

Через короткое время система в панели должна стать зелёной. Если этого не произошло, убедитесь, что оба контейнера монтируют один каталог ./beszel_socket, а LISTEN и Host / IP содержат одинаковый путь.

Проверьте также, что порт 8090 не опубликован на внешнем адресе:

sudo ss -lntp | grep ':8090'

Ожидается прослушивание на 127.0.0.1:8090, а не на 0.0.0.0:8090 и не на [::]:8090.

HTTPS и обратный прокси Nginx

Если Nginx ещё не установлен, воспользуйтесь отдельной инструкцией по установке Nginx на Ubuntu 24.04. Убедитесь, что DNS-запись домена уже указывает на сервер:

getent ahostsv4 monitor.example.ru

Создайте конфигурацию виртуального хоста. Перед изменением существующего файла сделайте копию.

server {
    listen 80;
    listen [::]:80;
    server_name monitor.example.ru;

    client_max_body_size 10M;

    location / {
        proxy_read_timeout 360s;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:8090;
    }
}

Заголовки Upgrade и Connection нужны для WebSocket. Без них агенты с универсальным токеном могут не подключиться через прокси. Значение APP_URL в Compose должно совпадать с внешним HTTPS-адресом: Beszel использует его в ссылках уведомлений и при генерации конфигурации агента.

Активируйте сайт способом, принятым в вашей конфигурации Nginx, затем обязательно проверьте синтаксис:

sudo nginx -t
sudo systemctl reload nginx

Для выпуска TLS-сертификата используйте Certbot или другой ACME-клиент по его официальной инструкции. Подробный материал Cheap-Host о Let's Encrypt запланирован на будущую дату, поэтому мы намеренно не ставим на него внутреннюю ссылку. После выпуска сертификата проверьте:

curl -I https://monitor.example.ru
openssl s_client -connect monitor.example.ru:443 -servername monitor.example.ru </dev/null

Не публикуйте внутренний порт 8090 и не открывайте его в UFW. Снаружи должны быть доступны только необходимые сервисы, обычно SSH, HTTP для ACME-проверки и HTTPS. Посмотреть слушающие порты можно командой:

sudo ss -lntup

Подключение удалённых VPS

Для нескольких серверов установите агент на каждом узле, а Hub оставьте один. Выбор способа соединения зависит от сети.

Вариант 1: исходящий WebSocket

Это предпочтительный путь для NAT VPS и закрытых сетей: агент инициирует исходящее соединение к https://monitor.example.ru. В Compose агента используются:

environment:
  LISTEN: 45876
  KEY: "PUBLIC_KEY_FROM_HUB"
  HUB_URL: https://monitor.example.ru
  TOKEN: "REGISTRATION_TOKEN"

network_mode: host нужен агенту для статистики сетевых интерфейсов хоста. Он одновременно делает LISTEN доступным в сетевом пространстве хоста, поэтому не полагайтесь на отсутствие секции ports. Если SSH-режим не используется, ограничьте входящий 45876/tcp сетевым файрволом. В версиях Beszel, поддерживающих соответствующую переменную, можно рассмотреть отключение SSH-функции агента через DISABLE_SSH; перед применением сверьте точное поведение с документацией установленной версии.

После запуска проверяйте не только зелёный статус в Hub, но и логи агента:

sudo docker compose logs --tail=100 beszel-agent

Вариант 2: SSH от Hub к Agent

В этом режиме Hub должен достигать порта агента, по умолчанию 45876/tcp. Не открывайте его всему интернету. Разрешите соединение только с IP центрального Hub на внешнем файрволе и в локальной политике. Если Hub находится за меняющимся IP или NAT, WebSocket обычно проще и безопаснее в эксплуатации.

При проблемах проверьте маршрут и фильтрацию, но не отключайте файрвол целиком:

nc -vz agent-ip 45876
sudo iptables -S FORWARD
sudo iptables -S DOCKER-USER

Команда nc лишь проверяет TCP-доступность. Она не подтверждает аутентификацию и корректность метрик.

Метрики контейнеров и риск Docker Socket

Для отображения контейнеров официальный пример Beszel монтирует Docker socket в агент в режиме read-only:

volumes:
  - /var/run/docker.sock:/var/run/docker.sock:ro

Суффикс :ro ограничивает файловое монтирование, но сам Docker API остаётся мощным интерфейсом. Docker предупреждает: доступ к daemon нужно давать только доверенным пользователям и программам, потому что через API можно создавать контейнеры с монтированием корневой файловой системы хоста. Компрометация контейнера, имеющего доступ к socket, потенциально может привести к захвату всей машины.

Практические меры:

  • используйте только официальный образ из указанного репозитория;
  • закрепляйте проверенную версию вместо бесконтрольного latest;
  • своевременно устанавливайте исправления Beszel и Docker;
  • не публикуйте Docker API по TCP без обязательных TLS-сертификатов и сетевого ограничения;
  • не помещайте посторонние процессы в контейнер агента;
  • ограничьте доступ к /opt/beszel и файлам конфигурации;
  • удалите монтирование socket, если мониторинг контейнеров не нужен;
  • рассмотрите Docker Socket Proxy с точечным разрешением API, но проверяйте совместимость с вашей версией Beszel.

Посмотрите фактические монтирования и режим контейнера:

sudo docker inspect beszel-agent --format '{{json .Mounts}}'
sudo docker inspect beszel-agent --format '{{.HostConfig.NetworkMode}}'

Не вставляйте токены, ключи и полный вывод docker inspect в публичные тикеты: в конфигурации контейнера могут находиться секреты.

Алерты и проверка мониторинга

В Beszel каналы уведомлений настраиваются в Settings → Notifications, а правила включаются для систем в таблице. Проект использует URL-схемы библиотеки Shoutrrr и поддерживает, среди прочего, Telegram, Discord, Gotify, ntfy, Slack, Matrix, Signal, MQTT, универсальный webhook и другие сервисы.

Не пытайтесь включить сразу десятки уведомлений. Начните с событий, на которые действительно будете реагировать:

  • сервер перестал отвечать;
  • свободное место приближается к критическому уровню;
  • память долго остаётся высокой;
  • CPU постоянно загружен, а не кратковременно занят обновлением;
  • контейнер остановился или стал нездоров;
  • сетевой трафик неожиданно вырос.

Порог зависит от задачи. Универсальное значение вроде «CPU выше 80% — авария» часто создаёт шум: архивирование или сборка образа закономерно загружает процессор. Для диска важен запас времени до заполнения; для памяти — наличие swap, характер приложения и повторяемость события. Сначала наблюдайте нормальный профиль несколько дней, затем выставляйте пороги.

Как проверить, что мониторинг не декоративный

  1. Убедитесь, что система зелёная и новые точки появляются на графике.
  2. Сравните основные показатели с локальными командами:
uptime
free -h
df -h /
docker stats --no-stream

Значения не обязаны совпадать до последнего байта: интервалы и методика агрегации различаются. Но порядок величин и направление изменения должны быть согласованы.

  1. Используйте встроенную тестовую отправку выбранного канала, если она доступна в вашей версии интерфейса.
  2. Создайте безопасный временный тестовый порог, который можно достигнуть без нагрузки на систему.
  3. После получения сообщения верните рабочий порог и зафиксируйте, кто реагирует на алерт.

Не создавайте искусственную нехватку памяти, заполнение диска или CPU-шторм на production-сервере ради проверки. Для нагрузочных экспериментов используйте отдельный стенд.

Обновление и резервное копирование

Данные Hub хранятся в смонтированном каталоге /opt/beszel/beszel_data. Агент использует /opt/beszel/beszel_agent_data, а Unix-сокет находится в beszel_socket и не является самостоятельной резервной копией.

Перед обновлением:

  1. прочитайте заметки о релизе и возможные несовместимости;
  2. сохраните Compose-файл и данные Hub во внешнее хранилище;
  3. убедитесь, что копия действительно читается;
  4. измените закреплённый тег образа;
  5. скачайте образ и пересоздайте контейнер;
  6. проверьте логи, healthcheck, графики и алерты.

Пример локальной согласованной копии с краткой остановкой Hub:

cd /opt/beszel
sudo docker compose stop beszel
sudo tar -C /opt/beszel -czf /var/backups/beszel-$(date +%F).tar.gz compose.yaml beszel_data
sudo docker compose start beszel
sudo tar -tzf /var/backups/beszel-$(date +%F).tar.gz >/dev/null

Остановка создаёт короткий разрыв мониторинга, зато снижает риск получить несогласованное состояние встроенной базы. Команда не заменяет внешнюю резервную копию: архив на том же VPS будет потерян вместе с диском. Перенесите его в отдельное хранилище по защищённому каналу и настройте ротацию. Не храните архивы бесконечно на системном разделе.

Обновление закреплённой версии выглядит так:

cd /opt/beszel
sudo docker compose config
sudo docker compose pull
sudo docker compose up -d
sudo docker compose ps
sudo docker compose logs --tail=100 beszel

Для отката верните прежний тег в compose.yaml, восстановите совместимую резервную копию и пересоздайте контейнер. Не рассчитывайте, что старая версия всегда прочитает данные, уже мигрированные новой версией.

Как выбрать тариф Cheap-Host

У Beszel нет универсального требования к VPS, которое гарантировало бы работу для любого числа узлов и срока хранения. Нагрузка зависит от количества агентов, контейнеров, истории и одновременных пользователей. Поэтому выбирать тариф только по фразе «лёгкий мониторинг» неправильно: учитывайте и приложения, которые уже работают на сервере.

На дату подготовки статьи в основном каталоге Cheap-Host доступны обычные VPS в Москве:

  • Start — 450 ₽/мес: 6 vCPU, 8 ГБ RAM, 96 ГБ NVMe, 1 выделенный IPv4, сеть 100 Mbit/s;
  • Pro — 750 ₽/мес: 12 vCPU, 16 ГБ RAM, 128 ГБ NVMe, 1 выделенный IPv4, сеть 100 Mbit/s;
  • Ultra — 1500 ₽/мес: 20 vCPU, 32 ГБ RAM, 192 ГБ NVMe, 1 выделенный IPv4, сеть 100 Mbit/s.

Для отдельной публичной панели на домене удобен обычный VPS с выделенным IPv4: проще использовать стандартные порты 80/443, Nginx и ACME-сертификат. Тариф Start можно рассматривать как стартовую конфигурацию, если на узле размещаются Beszel и умеренный набор сервисов. Это не обещание конкретной производительности: следите за фактическими графиками и увеличивайте ресурсы, когда появляется устойчивый дефицит.

NAT VPS в Германии стоят от 59 ₽/мес. и используют общий IPv4 с 999 выделенными TCP/UDP-портами плюс SSH. SMTP-порт 25 закрыт. Такой сервер может подойти для удалённого агента с исходящим WebSocket или для непубличного стенда. Для центральной панели на обычном домене NAT менее удобен, потому что стандартные публичные 80/443 могут быть недоступны напрямую. Подробное сравнение сценариев есть в статье NAT VPS или обычный VPS.

Перед заказом перепроверьте актуальный каталог VPS: цены и конфигурации меняются. Не переносите в расчёт характеристики со старых посадочных страниц, если они расходятся с основным каталогом.

Типовые проблемы

Hub открывается по IP, но не по домену

Проверьте A-запись, server_name, сертификат и доступность 80/443. Команды:

getent ahostsv4 monitor.example.ru
sudo nginx -t
sudo ss -lntp | grep -E ':(80|443)\b'
curl -vkI https://monitor.example.ru

Ключ -k в последней команде отключает проверку сертификата и годится только для диагностики. Не используйте его как постоянное решение.

Удалённый агент не подключается через WebSocket

Убедитесь, что HUB_URL начинается с https://, токен и ключ скопированы без лишних переносов, а Nginx передаёт заголовки Upgrade. Проверьте логи обеих сторон:

sudo docker compose logs --tail=200 beszel-agent
sudo docker compose logs --tail=200 beszel
sudo journalctl -u nginx --since "15 minutes ago"

Не публикуйте вывод, пока не удалите секреты и персональные данные.

После включения UFW контейнерный порт всё равно доступен

Это ожидаемый класс проблем Docker: опубликованные порты могут обходить привычные правила UFW. Привязывайте внутренние сервисы к 127.0.0.1, используйте DOCKER-USER для фильтрации и проверяйте доступ с другой машины. Не исправляйте проблему остановкой Docker на production без окна обслуживания.

Контейнеры не отображаются

Проверьте монтирование /var/run/docker.sock, права процесса и логи агента. Если используется Podman или socket proxy, следуйте отдельной официальной инструкции для вашей схемы. Не выдавайте контейнеру privileged: true только ради устранения ошибки: это чрезмерное расширение прав.

Панель работает, но история пропала после пересоздания

Скорее всего, потеряно или неверно смонтировано хранилище /beszel_data. Проверьте путь на хосте и раздел Mounts в docker inspect. Перед любыми исправлениями сделайте копию существующих каталогов, даже если они кажутся пустыми.

FAQ

Можно ли установить Hub и Agent на одном VPS?

Да. Официальный пример Beszel поддерживает совместный запуск и рекомендует для локальной связи Unix-сокет. Это позволяет не открывать порт агента и избежать проблемы с localhost между контейнерными сетями.

Нужен ли Prometheus для Beszel?

Нет. Beszel работает самостоятельно. Prometheus нужен, если ваша задача выходит за рамки готовых метрик и алертов Beszel: например, требуются собственные экспортёры, сложные запросы, федерация или интеграция с существующей наблюдаемостью.

Можно ли поставить Beszel на NAT VPS?

Агент — да, особенно с исходящим WebSocket. Центральный Hub тоже технически можно разместить на выделенном NAT-порту или за дополнительным туннелем, но публичный HTTPS на стандартных 80/443 организовать сложнее. Для обычного домена проще VPS с выделенным IPv4.

Безопасно ли монтировать Docker socket как read-only?

Это снижает риск случайной записи в файл сокета, но не превращает Docker API в безопасный интерфейс. Доступ к daemon потенциально даёт широкие привилегии на хосте. Монтируйте socket только доверенному агенту, обновляйте образ и удалите монтирование, если метрики контейнеров не нужны.

Нужно ли открывать порт 45876?

Только для SSH-соединения от Hub к Agent. При исходящем WebSocket агент подключается к HTTPS-адресу Hub, и входящий порт агента можно закрыть. При network_mode: host проверьте фактическое прослушивание порта и правила файрвола.

Как понять, что пора увеличить тариф?

Смотрите не на единичный пик, а на устойчивую нехватку ресурсов: повторяющийся swap и OOM, длительную загрузку CPU, рост дисковой задержки, заполнение NVMe и ухудшение работы приложений. Сначала найдите причину, затем оптимизируйте или масштабируйте VPS.

Итоги

Beszel закрывает понятный разрыв между ручной проверкой htop и тяжёлой системой наблюдаемости. Для безопасного развёртывания важно не просто запустить два контейнера, а изолировать порт Hub на loopback, подключить локальный агент через Unix-сокет, настроить Nginx с WebSocket и HTTPS, осознанно выдать доступ к Docker socket, проверить реальные метрики и организовать внешнюю резервную копию.

Если вам нужен центральный мониторинг на домене и стандартных портах, выберите VPS Cheap-Host с выделенным IPv4, разверните стенд по инструкции и только после проверки алертов подключайте production-серверы. Начинайте с минимально необходимого доступа и расширяйте схему по мере роста инфраструктуры.

Источники

Читайте также