DevOps и Docker 14 мин чтения 2026-10-03

Единый дашборд для сервисов и контейнеров на VDS: развертывание Homepage в Docker Compose с автообнаружением и виджетами метрик

Практическая инструкция по развертыванию Homepage в Docker Compose на Linux VDS: безопасная изоляция сокета через docker-socket-proxy, автообнаружение контейнеров через метки, системные виджеты и публикация через Nginx с SSL.

Инженерная редакция SysKit Проверено инженерами SysKit.ru

Для системных администраторов, DevOps-инженеров и вебмастеров серверная инфраструктура на базе Docker со временем превращается в лабиринт из десятков изолированных сервисов. Когда на виртуальном сервере (VDS) одновременно работают хранилище файлов, менеджер паролей, аналитика, легковесный мониторинг, почтовые шлюзы и панели управления, отслеживать их адреса становится серьезной рутиной. Приходится либо сохранять десятки закладок в браузере с нестандартными сетевыми портами вроде :3000, :8080 или :9443, либо регулярно подключаться по SSH и вбивать sudo docker ps, чтобы проверить статус упавшего контейнера.

Старые дашборды вроде Heimdall, Flame или Dashy либо перестали активно развиваться, либо требуют ручного заполнения каждого сервиса через веб-формы без обратной связи о реальном здоровье контейнеров. Настоящим стандартом в сообществе self-hosted стал проект Homepage (разрабатываемый командой gethomepage). Это сверхбыстрый дашборд с современным интерфейсом на TypeScript и Next.js, который не требует базы данных, настраивается через лаконичные YAML-файлы и поддерживает автоматическое обнаружение Docker-контейнеров по меткам (labels), выводя статус их работы, использование CPU и RAM в реальном времени.

В этом руководстве разберем правильную и безопасную архитектуру развертывания Homepage: изолируем сокет Docker через легковесный прокси docker-socket-proxy с правами только на чтение, подготовим production-манифест Docker Compose с жесткими лимитами ресурсов, настроим автоматическое обнаружение сервисов и защитим веб-интерфейс с помощью Nginx Reverse Proxy и SSL-сертификата.

1. Зачем нужен Homepage: сравнение со старыми панелями (Heimdall, Dashy и Flame)

Чтобы оценить преимущества Homepage, сравним ключевые популярные дашборды для персональных серверов и Homelab:

Панель дашборда Потребление RAM Авто-обнаружение Docker Конфигурация Виджеты сервисов
Heimdall 70–120 МБ (PHP/Laravel) Нет (только вручную) SQLite + GUI Базовые Enhanced Apps
Dashy 110–200 МБ (Vue.js/Node) Ограниченно (через API) Тяжелый YAML / GUI Много виджетов, долгий рендер
Flame 40–60 МБ (Node.js) Да (через labels) SQLite / GUI (проект заброшен) Минимальные
Homepage 40–60 МБ (до 80–150 МБ с виджетами) Да (через labels и сокет) Чистый декларативный YAML Более 100 нативных интеграций

Важно отметить реалистичные требования к памяти: «чистый» контейнер Homepage сразу после запуска потребляет около 40–60 МБ оперативной памяти. Однако по мере добавления десятков сервисов с активными виджетами (постоянный опрос API Uptime Kuma, Beszel, погодных сервисов и Docker-статистики) процесс Node.js/Next.js занимает от 80 до 150 МБ RAM. Это по-прежнему в разы легче тяжелых панелей мониторинга, но требует закладывать разумные лимиты памяти в манифесте Compose.

Ключевое инженерное преимущество Homepage — философия «Инфраструктура как код» (IaC). Все настройки хранятся в обычных текстовых файлах формата YAML. Их легко положить в Git-репозиторий, моментально восстановить после переустановки операционной системы или синхронизировать между несколькими серверами с помощью автоматических бэкапов в S3.

2. Архитектура и безопасность: изоляция сокета через docker-socket-proxy

В большинстве любительских инструкций по настройке дашбордов авторы рекомендуют пробросить сокет демона Docker напрямую в контейнер строкой /var/run/docker.sock:/var/run/docker.sock:ro. Однако даже флаг :ro (read-only) в Docker не гарантирует абсолютной защиты: флаг :ro ограничивает права только на уровне монтирования файловой системы Linux, но сам UNIX-сокет остается двунаправленным каналом связи. Потенциальные уязвимости в HTTP-библиотеках приложения могут позволить злоумышленнику отправлять команды к Docker API и считывать переменные окружения соседних контейнеров с паролями и токенами.

Инженерный стандарт безопасности SysKit — использование специального шлюза docker-socket-proxy (от Tecnativa). Это минималистичный контейнер на базе HAProxy, который монтирует хостовый сокет локально, но выпускает наружу только разрешенные API-эндпоинты и жестко блокирует любые опасные запросы:

  • Разрешено: чтение списка контейнеров (CONTAINERS=1) и базовой информации о демоне (INFO=1).
  • Запрещено: любые модифицирующие запросы POST/DELETE/PUT (POST=0), управление томами, создание сетей, исполнение команд внутри контейнеров (EXEC=0) и запуск новых образов.

💡 Совет инженера по сетевой изоляции сокета

Контейнеры Homepage и docker-socket-proxy объединяются в изолированную внутреннюю сеть Docker homepage_internal. Порт сокета 2375 вообще не публикуется на хост-системе наружу, а обращение к нему происходит по внутреннему DNS-имени службы. Это исключает риск случайного обхода фаервола, подробно разобранного в разборе обхода UFW через Docker iptables.

3. Развертывание Homepage и docker-socket-proxy в Docker Compose с лимитами ресурсов

Подготовим структуру каталогов на сервере. Рекомендуется размещать стек в рабочей директории системных сервисов /opt/homepage:

sudo mkdir -p /opt/homepage/config
cd /opt/homepage
sudo chown -R $USER:$USER /opt/homepage

Создадим файл манифеста docker-compose.yml. Обратите внимание на современные стандарты Docker Compose:

  • Отсутствие директивы version: в современной спецификации Compose Specification (Docker Compose v2) поле version: признано устаревшим (obsolete) и опускается. Запуск выполняется стандартной встроенной командой docker compose (вместо старого Python-пакета docker-compose v1).
  • Лимиты ресурсов (mem_limit и cpus): директивы mem_limit и cpus на верхнем уровне каждого сервиса гарантируют жесткое ограничение потребления RAM даже при пиковых нагрузках, предотвращая аварийное срабатывание ядра OOM-Killer на соседних сервисах VDS согласно шаблону безопасного Docker Compose.
services:
  docker-proxy:
    image: ghcr.io/tecnativa/docker-socket-proxy:latest
    container_name: homepage_socket_proxy
    restart: unless-stopped
    environment:
      - CONTAINERS=1
      - INFO=1
      - POST=0
      - NETWORKS=0
      - VOLUMES=0
      - EXEC=0
      - IMAGES=0
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - homepage_internal
    mem_limit: 64m
    cpus: 0.20

  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage_app
    restart: unless-stopped
    depends_on:
      - docker-proxy
    ports:
      # Служебный порт привязан строго к локальному интерфейсу (защита от сканирования)
      - "127.0.0.1:3000:3000"
    volumes:
      - ./config:/app/config
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    environment:
      # Разрешенные хосты для встроенной защиты от Host Header Injection
      HOMEPAGE_ALLOWED_HOSTS: "dash.example.com,127.0.0.1,localhost"
    networks:
      - homepage_internal
    mem_limit: 256m
    cpus: 0.50

networks:
  homepage_internal:
    driver: bridge

Проверить, что служебный порт 3000 надежно скрыт от внешнего мира и не доступен из интернета, можно с помощью сетевого сканера онлайн-чекера портов SysKit.

4. Базовая конфигурация в YAML: settings.yaml, docker.yaml и widgets.yaml

Конфигурация Homepage разделена на специализированные файлы в каталоге /opt/homepage/config. Создадим ключевые файлы перед первым запуском контейнеров.

Файл settings.yaml — Общий вид и локализация

В файле config/settings.yaml задаются заголовок страницы, язык интерфейса, цветовая тема и структура расположения блоков:

title: "SysAdmin Dashboard"
background:
  image: ""
  opacity: 100
theme: dark
color: slate
language: ru
layout:
  "Мониторинг и Сервер":
    style: row
    columns: 2
  "Сервисы и Приложения":
    style: row
    columns: 3
  "Сетевые Инструменты":
    style: row
    columns: 3

Файл docker.yaml — Связка со шлюзом docker-socket-proxy

В файле config/docker.yaml указывается подключение к изолированному шлюзу сокета. Поскольку оба сервиса находятся в общей Docker-сети homepage_internal, в качестве хоста используется имя службы docker-proxy:

local-docker:
  host: docker-proxy
  port: 2375

Файл widgets.yaml — Системные ресурсы хоста и поиск

В файле config/widgets.yaml настраивается верхняя панель дашборда: мониторинг загрузки процессора, оперативной памяти, свободного места на накопителе и времени непрерывной работы (Uptime):

- search:
    provider: duckduckgo
    target: _blank

- resources:
    cpu: true
    memory: true
    uptime: true
    disk:
      - /

5. Добавление сервисов и автообнаружение через Docker Labels

Homepage поддерживает два удобных способа наполнения дашборда: классический статический реестр через services.yaml и динамическое автообнаружение контейнеров с помощью меток (Docker Labels).

Способ А: Статический реестр в services.yaml

Если сервис работает на другом сервере, запущен вне Docker или имеет сложную структуру виджетов, он описывается в файле config/services.yaml. Все популярные иконки из библиотеки Dashboard Icons уже встроены в Homepage:

- Мониторинг и Сервер:
    - Beszel Hub:
        icon: beszel.png
        href: https://beszel.example.com
        description: "Легковесный мониторинг ресурсов VDS"
        server: local-docker
        container: beszel_hub
    - Uptime Kuma:
        icon: uptime-kuma.png
        href: https://status.example.com
        description: "Мониторинг доступности сайтов и SSL"
        server: local-docker
        container: uptime_kuma

- Сервисы и Приложения:
    - Vaultwarden:
        icon: vaultwarden.png
        href: https://passwords.example.com
        description: "Безопасное хранилище паролей и 2FA"
        server: local-docker
        container: vaultwarden_app
    - Gitea:
        icon: gitea.png
        href: https://git.example.com
        description: "Приватный Git-сервер и CI/CD"
        server: local-docker
        container: gitea_app
    - Shlink:
        icon: shlink.png
        href: https://s.example.com
        description: "Сервис коротких ссылок со статистикой"
        server: local-docker
        container: shlink_app

Способ Б: Динамическое автообнаружение через метки (Docker Labels)

Вместо ручного редактирования файлов конфигурации при каждом новом деплое можно просто добавить метки с префиксом homepage. в секцию labels файла docker-compose.yml любого стороннего проекта. Когда контейнер стартует, Homepage мгновенно добавляет его в нужную категорию на дашборде:

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden_app
    restart: unless-stopped
    labels:
      - "homepage.group=Сервисы и Приложения"
      - "homepage.name=Vaultwarden"
      - "homepage.icon=vaultwarden.png"
      - "homepage.href=https://passwords.example.com"
      - "homepage.description=Хранилище учетных записей"

💡 Совет инженера по использованию Docker Labels

При использовании автообнаружения Homepage автоматически связывает карточку сервиса с контейнером, отображая аккуратный зеленый или красный индикатор его реального рабочего состояния. Если контейнер перезагружается или аварийно падает, индикатор на дашборде мгновенно информирует администратора без задержек.

6. Подключение виджетов сервисов: Uptime Kuma, Beszel и Vaultwarden

Главная сила Homepage — возможность встраивать живые виджеты из API сервисов прямо в их карточки на дашборде. Например, для Uptime Kuma можно выводить общий процент аптайма, а для мониторинга Beszel или Git-сервера — счетчики активности.

Пример расширенной конфигурации виджета Uptime Kuma в services.yaml:

- Мониторинг и Сервер:
    - Статус сайтов:
        icon: uptime-kuma.png
        href: https://status.example.com
        description: "Контроль доступности сервисов"
        widget:
          type: uptimekuma
          url: http://127.0.0.1:3001
          slug: default

Для генерации надежных криптостойких паролей и секретных токенов доступа к API интегрируемых сервисов воспользуйтесь бесплатным генератором в онлайн-генераторе надежных паролей SysKit.

7. Публикация в интернет: Nginx Reverse Proxy с WebSocket, авторизация и SSL

Поскольку дашборд предоставляет быстрый доступ ко всем внутренним узлам инфраструктуры, открывать его в интернет без шифрования и ограничения доступа категорически небезопасно. Настроим публикацию через Nginx с получением бесплатного SSL-сертификата Let's Encrypt и заголовками безопасности.

Шаг 1: Проверка DNS-записи поддомена

Перед выпуском сертификата убедитесь, что A-запись поддомена (например, dash.example.com) указывает на публичный IP-адрес вашего сервера. Проверить корректность делегирования можно через инструмент онлайн-проверки DNS-записей SysKit.

Шаг 2: Базовая конфигурация Nginx для проксирования

Создадим конфигурационный файл виртуального хоста Nginx /etc/nginx/sites-available/homepage.conf:

server {
    listen 80;
    listen [::]:80;
    server_name dash.example.com;

    client_max_body_size 10M;

    # Заголовки безопасности
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;

        # Поддержка WebSocket для мгновенного обновления статусов
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Передача реальных IP-адресов клиента
        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;

        # Оптимальный таймаут для длительных WebSocket-соединений (1 час)
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

💡 Хостовый Nginx против Nginx в Docker-контейнере

Приведенная выше конфигурация рассчитана на веб-сервер Nginx, установленный непосредственно на хостовой ОС Linux (Ubuntu 24.04). Если ваш обратный прокси сам работает в Docker (например, Nginx Proxy Manager или Traefik), привязка к 127.0.0.1 не сработает: в этом случае Homepage и реверс-прокси подключаются к единой внешней пользовательской сети Docker, а директива проксирования указывает на имя контейнера http://homepage_app:3000.

Активируем конфигурацию символической ссылкой и проверим синтаксис веб-сервера:

sudo ln -s /etc/nginx/sites-available/homepage.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Шаг 3: Автоматический выпуск SSL-сертификата через Certbot

Выпустим доверенный SSL-сертификат и настроим автоматическое перенаправление трафика с HTTP на безопасный HTTPS с помощью Certbot:

sudo apt update && sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d dash.example.com --redirect

После завершения установки сертификата убедитесь в его валидности и корректности шифрования TLS в онлайн-чезере SSL-сертификатов SysKit.

Шаг 4: Защита доступа (Встроенная авторизация и 2FA)

В Homepage v2.0+ встроена система аутентификации. Чтобы посторонние пользователи не могли просматривать список сервисов и статус оборудования, достаточно активировать переменные в docker-compose.yml:

    environment:
      HOMEPAGE_ALLOWED_HOSTS: "dash.example.com,127.0.0.1,localhost"
      HOMEPAGE_AUTH_ENABLED: "true"
      HOMEPAGE_AUTH_PASSWORD: "ВашСложныйПароль2026"
      HOMEPAGE_AUTH_SECRET: "9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a"
      HOMEPAGE_EXTERNAL_URL: "https://dash.example.com"

Секретный ключ HOMEPAGE_AUTH_SECRET длиной от 32 символов генерируется стандартной утилитой OpenSSL:

openssl rand -hex 32

⚠️ Ограничение встроенной аутентификации и переход на 2FA

Встроенная авторизация Homepage защищает интерфейс логином и паролем, однако не поддерживает двухфакторную аутентификацию (2FA / TOTP). Для корпоративной инфраструктуры и максимальной защиты рекомендуется организовать единую точку входа через связку Authelia и Nginx Forward Auth либо настроить протокол OpenID Connect (OIDC).

8. Выбор надежного VDS для хостинга личных сервисов и дашборда

Дашборд Homepage потребляет от 40 до 150 МБ оперативной памяти в зависимости от количества активных виджетов и минимально нагружает процессор. Однако сами отслеживаемые сервисы (менеджер паролей, аналитика, CI/CD, Git, базы данных) требуют стабильной виртуальной инфраструктуры с быстрыми накопителями NVMe и достаточным запасом RAM.

Для комфортной работы стека из 5–10 контейнеров оптимально подходят виртуальные серверы (VDS) конфигурации от 1–2 ядер vCPU и 2–4 ГБ оперативной памяти у проверенных провайдеров:

Рекомендуемые VDS-провайдеры

Отказоустойчивые сервера с быстрыми NVMe и каналом до 1 Гбит/с

Выбор редакции
⚡

Timeweb Cloud — Быстрые NVMe VDS

Идеальная площадка для размещения дашборда и десятка Docker-контейнеров: скоростные NVMe-диски, дата-центры в РФ и Европе, порт до 1 Гбит/с.

Конфигурация
1 vCPU 3.3 ГГц • 1 ГБ RAM • 15 ГБ NVMe • Трафик без ограничений
Премиум Tier III
🔷

Selectel — Надежность Tier III

Отказоустойчивая инфраструктура с SLA 99.98% и защитой от DDoS-атак. Оптимальное решение для центрального сервера с рабочими сервисами и базой данных.

Конфигурация
от 1–2 vCPU • 2–4 ГБ RAM • 30 ГБ NVMe • Доступность SLA 99.98%
KVM / Авто-бэкапы
🟠

Beget — Простой старт

Стабильные виртуальные серверы с мгновенным стартом Ubuntu 24.04 LTS, автоматическими ежедневными бэкапами и круглосуточной техподдержкой.

Конфигурация
1 vCPU • 1 ГБ RAM • 20 ГБ NVMe • Выделенный статический IPv4

9. Решение типовых проблем: сбои сокета, кэш конфигов и ошибки Allowed Hosts

В процессе первоначальной настройки и эксплуатации Homepage администраторы могут сталкиваться с несколькими распространенными проблемами:

1. Ошибка «Error connecting to docker daemon» в интерфейсе

Если в карточках контейнеров отображается ошибка соединения с Docker:

  • Убедитесь, что контейнер homepage_socket_proxy запущен: выполните sudo docker ps.
  • Проверьте, что в docker-compose.yml оба сервиса подключены к общей сети homepage_internal.
  • В config/docker.yaml хост должен быть указан строго как docker-proxy (имя службы), а не localhost или 127.0.0.1, так как внутри контейнера localhost указывает на сам контейнер Homepage.

2. Ошибка «403 Forbidden: Invalid Host Header»

В современных версиях Homepage встроен строгий фильтр входящих заголовков Host для защиты от атак типа Host Header Poisoning. Если при открытии дашборда через Nginx возвращается белый экран или 403 ошибка, убедитесь, что ваш публичный домен указан в переменной окружения HOMEPAGE_ALLOWED_HOSTS в docker-compose.yml через запятую:

HOMEPAGE_ALLOWED_HOSTS: "dash.example.com,127.0.0.1,localhost"

3. Изменения в YAML-файлах не отображаются на дашборде

По умолчанию Homepage кэширует статическую структуру в оперативной памяти. Если вы отредактировали services.yaml или widgets.yaml, достаточно нажать кнопку обновления в правом нижнем углу интерфейса или перезапустить контейнер командой sudo docker compose restart homepage.

4. Изоляция сети через флаг internal: true

Для параноидальной безопасности можно полностью запретить контейнерам доступ в интернет, добавив директиву internal: true в описание сети homepage_internal в docker-compose.yml. Шлюз сокета и связь между контейнерами продолжат работать штатно. Однако помните: при таком режиме Homepage потеряет возможность опрашивать внешние API (прогноз погоды, проверку удаленных серверов или публичных сайтов).

Готовы объединить все сервисы сервера в единый красивый пульт?

Арендуйте быстрый VDS с накопителями NVMe, разверните стек Docker Compose с изолированным docker-socket-proxy по нашей инструкции и управляйте десятками контейнеров из одного удобного интерфейса без путаницы с портами.

Вопросы и ответы (FAQ)

Популярные вопросы вебмастеров и сисадминов по данной теме

Как добавить новый сервис на дашборд без перезапуска Homepage?
При использовании автообнаружения через Docker Labels достаточно прописать метки homepage.* в docker-compose.yml целевого приложения и запустить его. Homepage автоматически обновляет список сервисов по событиям Docker. Если сервис описан в services.yaml, достаточно нажать кнопку обновления в правом нижнем углу интерфейса.
Безопасно ли использовать docker-socket-proxy?
Да, это отраслевой стандарт безопасности. В отличие от прямого проброса сокета /var/run/docker.sock, прокси блокирует любые команды изменения состояния (POST, DELETE) и запрещает доступ к томам и исполнению команд в контейнерах. Homepage получает строго read-only доступ к списку запущенных контейнеров.
Сколько оперативной памяти потребляет стек Homepage на сервере?
Стек из контейнеров Homepage и docker-socket-proxy суммарно потребляет от 40 до 70 МБ оперативной памяти. Это делает его идеальным решением для недорогих VDS с 1–2 ГБ RAM, где тяжелые альтернативы вроде Grafana или Portainer создают избыточную нагрузку.

Читайте также в блоге SysKit

Смежные руководства и полезные технические статьи