Безопасность и Защита 11 мин чтения 2026-09-17

Свой Tailscale на VDS: развертывание Headscale в Docker Compose с веб-панелью для безопасного доступа к серверам и базам данных

Практическое руководство по развертыванию собственного координатора Headscale с веб-панелью в Docker Compose. Объединяем VDS, серверы баз данных, рабочие станции и мобильные устройства в зашифрованную сеть WireGuard без открытия публичных портов наружу.

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

По мере роста инфраструктуры любого веб-проекта количество узлов неизбежно увеличивается: фронтенд на одном сервере, кластер PostgreSQL на втором, тестовый контур на третьем, рабочий ноутбук инженера дома и офисная рабочая станция. Главная дилемма системного администратора при такой архитектуре — как безопасно администрировать эти узлы и настроить защищенную связь между сервисами.

Самое распространенное и опасное решение — «пробросить» порты сервисов наружу, привязав их к публичному адресу 0.0.0.0. Стоит открыть порты PostgreSQL (5432), MySQL (3306), Redis (6379) или веб-панели администрирования в интернет, как в системных журналах начинают фиксироваться тысячи попыток авторизации от автоматических сканеров (Shodan, Censys) и распределенных ботнетов. Любая уязвимость нулевого дня или ошибка в пароле приводит к мгновенной компрометации данных.

Инженерный регламент: защита периметра и корпоративные каналы связи

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

В этом руководстве мы разберем, как построить полностью изолированную приватную сеть (оверлейную Mesh-сеть) на базе протокола WireGuard, используя собственный координатор Headscale с графической веб-панелью Headscale-UI в Docker Compose. Вы сможете объединить все свои VDS и рабочие устройства в единую зашифрованную подсеть и наглухо закрыть все порты баз данных и SSH от внешнего мира.

Совет инженера: разделение плоскости данных и плоскости управления

Координатор Headscale выполняет исключительно функции Control Plane (плоскости управления): он регистрирует устройства, обновляет криптографические открытые ключи и сообщает нодам IP-адреса пиров. Сам трафик баз данных, файлов и SSH передается напрямую между узлами (Data Plane) по протоколу WireGuard без прохождения через координатор, что гарантирует максимальную пропускную способность канала и минимальный RTT.

1. Зачем нужен свой координатор: риски открытых портов и архитектура оверлейной Mesh-сети

Традиционное туннелирование «точка-точка» (Hub and Spoke) строится по топологии «звезда»: все клиенты подключаются к центральному серверу, и весь трафик между двумя серверами прокачивается через него. Это создает единую точку отказа, повышает сетевую задержку и требует аренды дорогого канала с высокой пропускной способностью на центральном узле.

Tailscale предложил современный подход: прямое P2P-соединение (Peer-to-Peer Mesh) на базе WireGuard с автоматическим пробитием сложных NAT через протоколы STUN/ICE. Однако коммерческий облачный сервис Tailscale имеет ряд критических ограничений для корпоративной или чувствительной инфраструктуры:

  • Ограничение на количество пользователей и подключаемых узлов в бесплатном тарифе.
  • Хранение сетевых метаданных (топологии сети, имен хостов, логов подключений) на серверах зарубежной корпорации.
  • Риск внезапной блокировки учетных записей или невозможности оплаты коммерческой подписки российскими банковскими картами.

Headscale — это полностью открытая (Open Source) серверная реализация протокола координации Tailscale, написанная на языке Go. Вы получаете полную суверенность собственной инфраструктуры, отсутствие ограничений на количество машин и поддержку всех официальных клиентов Tailscale для Linux, Windows, macOS, Android и iOS.

Критерий Классический туннель WireGuard Tailscale (SaaS) Headscale (Self-hosted)
Топология передачи данных Звезда (весь трафик через центральный узел) Прямой P2P Mesh Прямой P2P Mesh
Отказоустойчивость при падении сервера Полный обрыв всей сети Установленные туннели продолжают жить Установленные туннели продолжают жить
Приватность сетевых метаданных На личном сервере В зарубежном облаке США 100% на вашем сервере
Лимиты подключенных устройств Ограничены только RAM/CPU Лимиты тарифного плана Без ограничений (0 ₽)
Сложность добавления нового пира Ручная правка wg0.conf на всех узлах Одна команда авторизации Одна команда или клик в UI

2. Требования к серверу-координатору и подготовка ОС

Поскольку координатор Headscale не передает через себя тяжелый поток данных, требования к серверу минимальны. Вам не нужны десятки ядер и терабайты оперативной памяти. Для обслуживания сети из 50–100 серверов и рабочих станций достаточно базового тарифа VDS:

  • Процессор: 1 vCPU.
  • Оперативная память: 1–2 ГБ RAM (потребление всего стека в Docker не превышает 250–350 МБ).
  • Диск: 15–25 ГБ NVMe (база SQLite занимает считанные мегабайты).
  • Сеть: Выделенный публичный IPv4-адрес со статическим маршрутом.
  • Операционная система: Ubuntu 24.04 LTS или Debian 12.
  • Доменное имя: Делегированный поддомен (например, hs.example.com или vpn.company.ru), направленный A-записью на IP-адрес координатора. Протокол Tailscale строго требует валидного HTTPS-сертификата.

Подключитесь к серверу по SSH и выполните базовую подготовку сетевого стека ядра Linux. Включите транзит сетевых пакетов (IP Forwarding), который необходим для корректной маршрутизации подсетей и работы встроенного DERP-сервера:

sudo tee /etc/sysctl.d/99-headscale.conf <<EOF
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
EOF

sudo sysctl -p /etc/sysctl.d/99-headscale.conf

Убедитесь, что на сервере установлены Docker и плагин Docker Compose. Если они отсутствуют, установите их через официальный репозиторий Docker:

curl -fsSL https://get.docker.com | sh
sudo systemctl enable --now docker

3. Готовый стек Docker Compose: Headscale + Headscale-UI + Caddy

Для создания надежного и необслуживаемого сервиса мы развернем связку из трех контейнеров:

  1. Headscale: Ядро координатора сети, обслуживающее запросы клиентов по API на внутреннем порту 8080.
  2. Headscale-UI: Современный графический веб-интерфейс, позволяющий просматривать статус нод, генерировать pre-auth ключи и управлять маршрутами без ввода длинных консольных команд.
  3. Caddy: Высокопроизводительный веб-сервер, который выполняет роль Reverse Proxy и берет на себя автоматический выпуск и продление бесплатных SSL-сертификатов Let's Encrypt.

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

sudo mkdir -p /opt/headscale/config
sudo mkdir -p /opt/headscale/data
cd /opt/headscale

Создайте файл манифеста docker-compose.yml:

services:
  headscale:
    image: headscale/headscale:0.24.2
    container_name: headscale
    restart: unless-stopped
    volumes:
      - ./config:/etc/headscale
      - ./data:/var/lib/headscale
    command: headscale serve
    networks:
      - hs-network

  headscale-ui:
    image: ghcr.io/gurucomputing/headscale-ui:latest
    container_name: headscale-ui
    restart: unless-stopped
    networks:
      - hs-network

  caddy:
    image: caddy:2-alpine
    container_name: headscale-caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - hs-network

networks:
  hs-network:
    name: hs-network

volumes:
  caddy_data:
  caddy_config:

Создайте конфигурационный файл Caddyfile в каталоге /opt/headscale. Замените hs.example.com на ваш реальный поддомен:

hs.example.com {
    # Проксирование панели Headscale-UI
    handle /web* {
        reverse_proxy headscale-ui:8080
    }

    # Проксирование API и протокола координации Headscale
    handle {
        reverse_proxy headscale:8080
    }

    tls admin@example.com
    encode gzip zstd
}

4. Тонкая настройка config.yaml: подсеть 100.64.0.0/10, DNS и безопасность

Скачайте официальный шаблон конфигурации Headscale в папку /opt/headscale/config:

curl -fsSL https://raw.githubusercontent.com/juanfont/headscale/main/config-example.yaml   -o /opt/headscale/config/config.yaml

Откройте файл /opt/headscale/config/config.yaml и настройте ключевые параметры:

# Внешний URL вашего координатора (строго по HTTPS)
server_url: https://hs.example.com

# Внутренний адрес прослушивания в контейнере
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 127.0.0.1:9090

# Пути к базе данных SQLite и сокету
database:
  type: sqlite
  sqlite:
    path: /var/lib/headscale/db.sqlite

# Диапазоны приватных IP-адресов оверлейной сети (RFC 6598 Carrier-Grade NAT)
prefixes:
  v4: 100.64.0.0/10
  v6: fd7a:115c:a1e0::/48

# Настройка встроенного сервера DERP (пробитие симметричных NAT)
derp:
  server:
    enabled: true
    region_id: 999
    region_code: "headscale-derp"
    region_name: "Headscale Embedded DERP"
    stun_listen_addr: "0.0.0.0:3478"
  urls:
    - https://controlplane.tailscale.com/derpmap/default
  auto_update_enabled: true
  update_frequency: 24h

# Настройка внутреннего MagicDNS
dns:
  magic_dns: true
  base_domain: mesh.internal
  nameservers:
    split: {}
    global:
      - 1.1.1.1
      - 8.8.8.8

Совет инженера: почему используется префикс 100.64.0.0/10

Диапазон 100.64.0.0/10 зарезервирован стандартом RFC 6598 для Carrier-Grade NAT (провайдерских сетей). Использование этого пространства адресов гарантирует, что IP-адреса внутри вашей mesh-сети никогда не пересекутся с локальными подсетями домашнего роутера (192.168.0.0/16) или корпоративными сетями офисов и дата-центров (10.0.0.0/8 и 172.16.0.0/12). Рассчитать доступные диапазоны можно с помощью нашего Калькулятора подсетей IPv4 CIDR.

Инициализируйте пустой файл базы данных SQLite с правильными правами доступа:

sudo touch /opt/headscale/data/db.sqlite
sudo chmod 644 /opt/headscale/data/db.sqlite

Запустите стек сервисов в фоновом режиме:

docker compose up -d

Проверьте логи контейнеров командой docker compose logs -f. Caddy в течение 5–10 секунд автоматически выпустит SSL-сертификат Let's Encrypt через ACME-челлендж.

Для подключения веб-панели сгенерируйте API-ключ с длительным сроком действия:

docker exec -it headscale headscale apikeys create --expiration 90d

Скопируйте сгенерированный ключ в буфер обмена. Откройте в браузере адрес https://hs.example.com/web, перейдите в раздел Settings и вставьте API-ключ. Веб-интерфейс подключится к координатору и отобразит пустой список нод.

5. Рекомендуемые надежные VDS-провайдеры для координатора

Для стабильной координации P2P-соединений критически важен чистый белый IPv4-адрес, высокая доступность дата-центра (SLA 99.98%) и отсутствие задержек на магистральных каналах. Ниже представлены проверенные хостинг-провайдеры для размещения узла Headscale:

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

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

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

Timeweb Cloud

Идеально подходит для развертывания координатора Headscale: мгновенный запуск чистой Ubuntu 24.04 LTS, выделенный статический IPv4-адрес, быстрые NVMe-диски со скоростью до 3500 МБ/с и низкие сетевые задержки по всей РФ.

Конфигурация
от 1–2 vCPU / 1–2 GB RAM / 25–40 GB NVMe
Highload & Надежность
🔷

Selectel

Серверы в дата-центрах уровня Tier III с гарантированной доступностью 99.98% и аппаратной защитой от L3/L4 DDoS-атак. Высокая пропускная способность сети до 1 Гбит/с и гибкое конфигурирование под узлы с интенсивным трафиком.

Конфигурация
от 1–2 vCPU / 2 GB RAM / 30 GB NVMe
Удобство и автобэкапы
🟠

Beget

Интуитивная панель управления VDS, бесплатные автоматические снапшоты состояния диска, встроенный мониторинг системных ресурсов и отзывчивая круглосуточная инженерная поддержка 24/7.

Конфигурация
от 1–2 vCPU / 1–2 GB RAM / 20–30 GB NVMe

6. Подключение клиентов: Linux-серверы, Windows, macOS и мобильные устройства

Перед подключением первых устройств к сети создадим в Headscale изолированное пространство имен (User):

docker exec -it headscale headscale users create sysadmin

Для автоматического подключения серверов без интерактивного перехода по ссылкам в браузере создайте многоразовый Pre-Auth ключ (Pre-authentication key):

docker exec -it headscale headscale preauthkeys create -u sysadmin --reusable --expiration 24h

1. Подключение Linux VDS (сервер базы данных или веб-приложения):

Установите официальный клиент Tailscale на целевом сервере в одну строчку:

curl -fsSL https://tailscale.com/install.sh | sh

Запустите демон, указав URL вашего собственного координатора Headscale и pre-auth ключ:

sudo tailscale up --login-server=https://hs.example.com --authkey=<СКОПИРОВАННЫЙ_PREAUTH_KEY> --hostname=db-cluster-01

Сервер мгновенно получит виртуальный IP-адрес из диапазона 100.64.0.0/10. Проверьте статус подключения:

tailscale status
tailscale ip -4

2. Подключение Windows и macOS:

Скачайте официальный клиент Tailscale. Зажмите клавишу Shift (в Windows) или Option (в macOS) и кликните правой кнопкой мыши по значку Tailscale в трее. В появившемся меню выберите пункт Change Server... и введите адрес https://hs.example.com. После этого нажмите кнопку Log in и скопируйте команду регистрации машины в консоли координатора:

docker exec -it headscale headscale nodes register --user sysadmin --key <МАШИННЫЙ_КЛЮЧ>

3. Подключение смартфонов на iOS и Android:

Установите официальное приложение Tailscale. Не нажимая кнопку входа, коснитесь трех точек в правом верхнем углу (или трижды тапните по логотипу) и выберите пункт Use alternate server. Введите адрес вашего координатора https://hs.example.com и завершите регистрацию устройства.

7. Блокировка внешнего периметра: закрываем SSH, PostgreSQL и MySQL от интернета

Теперь, когда все серверы и рабочие станции объединены в приватную зашифрованную сеть, мы реализуем ключевую задачу безопасности: полное закрытие служебных портов от внешнего интернета.

Клиент Tailscale создает в операционной системе виртуальный сетевой интерфейс tailscale0. Настроим фаервол UFW на сервере с базой данных так, чтобы порты PostgreSQL (5432) и SSH (22) были доступны строго через этот интерфейс, а любые внешние пакеты из публичной сети сбрасывались:

# Запрещаем весь входящий трафик по умолчанию
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Разрешаем SSH и PostgreSQL исключительно через интерфейс mesh-сети tailscale0
sudo ufw allow in on tailscale0 to any port 22 proto tcp comment "SSH strictly via Tailscale"
sudo ufw allow in on tailscale0 to any port 5432 proto tcp comment "PostgreSQL strictly via Tailscale"

# Если на сервере работает публичный веб-сайт, открываем только HTTP/HTTPS снаружи
sudo ufw allow 80/tcp comment "Public HTTP"
sudo ufw allow 443/tcp comment "Public HTTPS"

# Активируем фаервол
sudo ufw enable

Важное предупреждение: проверьте доступ перед разрывом текущей сессии

Перед тем как отключаться от текущей публичной SSH-сессии, откройте второе окно терминала и подключитесь к серверу по его приватному адресу Tailscale: ssh user@100.64.0.2. Убедитесь, что сессия успешно открывается. Только после этого закрывайте резервный публичный терминал.

Для максимальной защиты привяжите демон PostgreSQL к приватному интерфейсу. В файле /etc/postgresql/16/main/postgresql.conf установите:

listen_addresses = 'localhost, 100.64.0.2'

А в файле pg_hba.conf разрешите авторизацию только узлам из вашей приватной сети Headscale:

# Разрешаем подключения к базам только хостам из пула Headscale
host    all             all             100.64.0.0/10            scram-sha-256

После перезагрузки сервисов протестируйте внешний IP-адрес сервера с помощью нашего инструмента Сканер открытых портов онлайн. Порты 22 и 5432 для внешних сканеров теперь будут иметь статус Closed или Filtered. Злоумышленники и ботнеты не смогут даже обнаружить наличие работающей базы данных.

8. Маршрутизация изолированных подсетей и тестовых стендов (Subnet Router)

Функция маршрутизатора подсетей (Subnet Router) в Headscale позволяет предоставить доступ всей mesh-сети к изолированным сетевым сегментам без необходимости устанавливать клиент Tailscale на каждое отдельное устройство. Это актуально в двух ключевых инженерных сценариях:

1. Доступ к корпоративным офисным стендам и локальным серверам:

Если в офисе или локальной лаборатории развернуты аппаратные тестовые стенды, внутренние NAS или сборочные узлы в подсети 192.168.1.0/24, достаточно запустить Tailscale с объявлением маршрута на одном сервере-шлюзе:

sudo tailscale up --advertise-routes=192.168.1.0/24

Затем активируйте предложенный маршрут на стороне координатора Headscale через консоль или веб-панель:

docker exec -it headscale headscale routes list
docker exec -it headscale headscale routes enable -r 1

После активации все подключенные к Headscale инженеры получают прямой защищенный доступ к офисным ресурсам 192.168.1.x без проброса портов наружу.

2. Доступ к закрытым Docker-сетям без публикации портов на хосте:

Часто в микросервисной архитектуре требуется подключиться к вспомогательным контейнерам (Redis, RabbitMQ, стенды тестирования), которые работают во внутренней сети Docker (например, 172.20.0.0/16) и намеренно не имеют директивы ports: в docker-compose.yml. Объявив эту подсеть через шлюзовой контейнер или хост:

sudo tailscale up --advertise-routes=172.20.0.0/16

Вы получаете возможность подключаться к внутренним IP-адресам контейнеров напрямую из IDE или консоли разработчика, сохраняя периметр сервера на 100% герметичным.

9. Резервное копирование базы данных и регламент обновления

Вся конфигурация подключенных устройств, выданные IP-адреса и открытые ключи хранятся в единственном файле SQLite /opt/headscale/data/db.sqlite. Для организации надежного резервного копирования создайте ежедневное задание в cron:

sudo crontab -e

Добавьте команду горячего бэкапа SQLite с использованием встроенной утилиты safe-backup:

0 3 * * * sqlite3 /opt/headscale/data/db.sqlite ".backup /opt/headscale/data/backup_$(date +\%Y\%m\%d).sqlite" && find /opt/headscale/data/ -name "backup_*.sqlite" -mtime +14 -delete

Обновление стека Headscale:

Обновление выполняется без простоя уже работающих P2P-туннелей. Узлы кратковременно теряют связь с координатором, но продолжают передавать трафик между собой напрямую:

cd /opt/headscale
docker compose pull
docker compose up -d

10. Резюме и итоговый чек-лист безопасности

Развертывание собственного координатора Headscale в Docker Compose полностью решает проблему небезопасного периметра. Вы перестаете открывать порты баз данных, админок и SSH наружу, объединяя инфраструктуру в устойчивую зашифрованную mesh-сеть WireGuard с централизованным управлением.

✅ Чек-лист готовности и защиты:

  • В ядре Linux активирован net.ipv4.ip_forward = 1.
  • Headscale, Headscale-UI и Caddy запущены в изолированной сети Docker.
  • Выпущен валидный HTTPS-сертификат на поддомен координатора.
  • Устройства объединены в подсеть 100.64.0.0/10 без конфликта локальных IP.
  • Порты SSH (22) и СУБД (5432/3306) в UFW разрешены только через tailscale0.
  • Служебные порты проверены внешним сетевым сканером на отсутствие утечек.
  • Настроен автоматический ежедневный бэкап файла db.sqlite.

⚠️ Типичные ошибки при настройке:

  • Отсутствие HTTPS на координаторе: Официальный клиент Tailscale отказывается работать с чистым HTTP без валидного SSL-сертификата.
  • Блокировка UDP-порта 3478 (STUN): Если закрыть порт STUN в фаерволе VDS-координатора, клиенты не смогут пробивать NAT и установят медленное ретранслируемое соединение.
  • Разрыв SSH-доступа до проверки: Всегда держите активную сессию открытой, пока не проверите успешный вход через IP-адрес интерфейса tailscale0.
  • Забытый роутинг подсетей: При настройке Subnet Router необходимо убедиться, что на сервере включен net.ipv4.ip_forward = 1 и разрешен форвардинг пакетов между сетевыми интерфейсами.

Нужен надежный сервер под координатор Mesh-сети?

Разверните производительный VDS с выделенным статическим IPv4, защитой от сетевых атак и быстрым NVMe-диском для координатора Headscale на Selectel всего от 200 ₽ в месяц.

Развернуть VDS для Headscale на Selectel

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

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

В чем ключевое отличие Headscale от классического WireGuard и облачного Tailscale?
В классическом WireGuard топология строится вручную «точка-точка»: для каждого нового сервера необходимо вручную генерировать пары ключей, настраивать файлы wg0.conf и управлять таблицами маршрутизации. Облачный сервис Tailscale автоматизирует эти процессы, но работает через проприетарные серверы координации с лимитами бесплатного тарифа. Headscale — это полностью открытая и независимая серверная реализация координатора Tailscale, развертываемая на собственном VDS. При этом пользовательский трафик не проходит через сервер Headscale, а передается напрямую между узлами по зашифрованному протоколу WireGuard.
Нужен ли статический белый IP-адрес для каждого подключаемого к сети сервера?
Нет, статический публичный IPv4-адрес необходим только одному узлу — самому координатору Headscale (для резолва DNS и работы службы DERP). Все подключаемые клиенты (серверы баз данных, офисные шлюзы, домашние ПК, смартфоны) могут находиться за любым количеством NAT, иметь динамические адреса или работать через сотовые сети провайдеров (CGNAT). Благодаря протоколам STUN и ICE клиенты автоматически устанавливают прямое P2P-соединение в обход NAT.
Влияет ли координатор Headscale на пропускную способность и скорость передачи данных между серверами?
Практически не влияет. Headscale выступает исключительно плоскостью управления (Control Plane): он участвует только в момент установления соединения для проверки аутентификации, обмена публичными ключами и передачи сетевой карты пиров. Сам трафик данных передается напрямую от узла к узлу (Data Plane) через ядро WireGuard на полной скорости канала с минимальным оверхедом шифрования ChaCha20-Poly1305.

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

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