Проект Headscale реализует открытый серверный компонент виртуальной сети Tailscale, который позволяет создавать сети, схожие с Tailscale, без привязки к сторонним сервисам. Код Headscale написан на языке Go и распространяется под лицензией BSD.
Tailscale позволяет объединить любое количество территориально разнесённых хостов в одну сеть, построенную по образу mesh-сети, в которой каждый узел взаимодействует с другими узлами напрямую (P2P) или через соседние узлы, без передачи трафика через централизованные внешние серверы VPN-провайдера. Поддерживается управление доступом и маршрутами на основе ACL. Для установки каналов связи в условиях применения трансляторов адресов (NAT) предоставляется поддержка механизмов STUN, ICE и DERP (аналог TURN, но на базе HTTPS). В случае блокировки канала связи между определёнными узлами сеть может перестраивать маршрутизацию для направления трафика через другие узлы.
Список задач которые я хочу закрыть с помощью Headscale и Caddy:
- Объединение нескольких локальных сетей в разных городах и возможность подключения к виртуальной сети из интернета
- Подключение “Exit Node” позволяет перенаправлять трафик клиента через этот узел, что дает возможность получить доступ к заблокированным ресурсам, таким как YouTube, сайты торрентов и другие
- С помощью Caddy будет возможность публиковать свои сервисы из локальной сети в интернет
- …
Для установки Headscale нам понадобится сервер с белым IP (я использую бесплатный сервер от Cloud.ru тариф Free tier, бесплатный с оговоркой :grin: за белый IP нужно будет платить 150р/м) и доменное имя (в моём случае test-headscale.31bel.ru).
Сервер с белым IP нам нужен для построения связей между нодами в разных (локальных) сетях как показано на схеме работы Tailscale(Headscale) выше :point_up:
Пишем файл Docker Compose
Первым делом необходимо проверить установлен у нас Docker
и Docker Compose
командами:
docker --version
docker compose version
Если не установлен то его необходимо установить. Docker желательно устанавливать всегда по официальной документации из Docker.Docs. Так же устанавливаем Docker Compose командой:
sudo apt install docker-compose
И не забываем после установки настроить управление Docker от имени пользователя без полномочий root.
Нам нужно создать каталог, в котором будут храниться конфигурации и данные Headscale и Caddy.
mkdir -p docker/caddy/config docker/headscale/config
Переходим в наш каталог docker и создаём новый файл с именем docker-compose.yml
cd docker
nano docker-compose.yml
Вставляем и сохраняем приведенное ниже содержимое:
services:
caddy:
image: caddy:latest
container_name: caddy
restart: always
stdin_open: true
tty: true
volumes:
- ./caddy/data:/data
- ./caddy/config:/config
- /etc/localtime:/etc/localtime:ro
ports:
- 80:80
- 443:443
entrypoint: /usr/bin/caddy run --adapter caddyfile --config /config/Caddyfile
networks:
- headscale-nw
headscale:
image: headscale/headscale:latest
restart: unless-stopped
container_name: headscale
volumes:
- ./headscale/config:/etc/headscale
- ./headscale/data:/var/lib/headscale
command: serve
depends_on:
- caddy
networks:
- headscale-nw
headscale-admin:
image: goodieshq/headscale-admin:latest
container_name: headscale-admin
restart: unless-stopped
depends_on:
- caddy
networks:
- headscale-nw
networks:
headscale-nw:
external: true
В файле docker-compose.yml мы определили сеть в docker, внутри которой будут доступны друг для друга наши контейнеры, и для её создания необходимо выполнить команду
docker network create headscale-nw
название сети headscale-nw и проверить что она создалась
docker network create ls
Давайте создадим файлы с настройками для каждого из контейнеров.
Caddy
На данный момент мы находимся в каталоге ~/docker/ и нам нужно создать файл Caddyfile в каталоге ./caddy/config
nano ./caddy/config/Caddyfile
Вставляем и сохраняем приведенное ниже содержимое:
https://test-headscale.31bel.ru {
reverse_proxy /admin* headscale-admin:80
reverse_proxy * headscale:8080
}
- Первая строка файла это адрес нашего доменного имени.
Для того что бы наш домен третьего уровня (в нашем случае) понимал на какой сервер ему нужно ссылаться нам необходимо добавить A-запись в DNS у регистратора нашего домена, нужно выполнить следующие шаги:
- Войдите в панель управления вашим регистратором доменов.
- Найдите раздел “DNS” или “Домены”.
- Выберите домен, для которого вы хотите добавить A-запись.
- Нажмите на кнопку “Добавить запись”.
- Введите тип записи “A” и введите IP-адрес сервера, который вы хотите связать с этим доменным именем.
- Введите имя для этой записи (например, “@”, “www”, “mail” и т.д.).
- Нажмите на кнопку “Сохранить” или “Применить”. После выполнения этих шагов, ваша A-запись будет добавлена в DNS вашего регистратора доменов.
Пример как это выглядит у меня:
- Вторая строка будет редиректить все запросы test-headscale.31bel.ru/admin* в наш контейнер с панелью управления по адресу headscale-admin:80
- Третья строка так де как и вторая редиректит все запросы test-headscale.31bel.ru/* в наш контейнер с приложение headscale по адресу headscale:8080
Настройку Caddy закончили. В Caddy можно ещё настроить basic_auth как дополнительную защиту для панель управления.
Пример Caddyfile c basic_auth:
https://test-headscale.31bel.ru {
reverse_proxy /admin* headscale-admin:80
basic_auth /admin/* {
# Username "Bob", password "hiccup"
Bob $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG
}
reverse_proxy * headscale:8080
}
Пример был взят с официальной документации Caddy. В комьюнити находил информацию что можно привязать двухфакторную аутентификацию (two-factor, 2FA), если у меня получится то обязательно опишу как это сделать.
Headscale
Нам понадобится шаблон конфигурационного файла Headscale который мы скачаем с официального репозитория
wget https://raw.githubusercontent.com/juanfont/headscale/main/config-example.yaml -O headscale/config/config.yaml
Теперь нам необходимо его отредактировать:
nano headscale/config/config.yaml
Для базовой настройки и запуска нам необходимо привести несколько строк к виду:
- В параметр server_url вписать адрес нашего доменного имени
#server_url: http://127.0.0.1:8080
server_url: https://test-headscale.31bel.ru
- Параметр listen_addr отвечает на то с каких адресов будет доступ за пределами контейнера (0.0.0.0 это все IP-адреса)
# For production:
listen_addr: 0.0.0.0:8080
#listen_addr: 127.0.0.1:8080
Headscale готов к работе, настроек для headscale-admin делать не нужно.
Запускаем файл Docker Compose
С помощью pwd проверяем что мы находимся в каталоге ~/docker и запускает
docker compose up -d
Ключ -d в команде отвечает за запуск контейнеров в фоновом режиме.
Проверяем состояние созданных контейнеров:
docker compose ps
Если STATUS равен UP на всех контейнерах то всё хорошо. Так же можно посмотреть логи по каждому контейнеру в реальном времени с помощью команды:
docker logs --follow headscale
docker logs --follow caddy
Для проверки работоспособности можно в браузере открыть страницу https://test-headscale.31bel.ru/windows
Ну или сразу открыть панель управления по адресу https://test-headscale.31bel.ru/admin/
Страница открывается по https с действующим сертификатом от Let’s Encrypt благодаря Caddy.
Работа с Headscale-admin
Для входа в панель управления нам нужен API ключ, возвращаемся в консоль и вводим команду:
docker exec headscale headscale apikeys create
Но желательно использовать команду :point_up: с дополнительным ключом –expiration 30d который ограничит действие ключа по времени (для безопасности).
Получаем ключ копируем его и вводим в поле API Key нашей панели управления и кнопку Save.
Теперь нам необходимо создать пользователя, переходим в раздел Users, нажимаем кнопку Create, вводим имя пользователя user1 и нажимаем Enter.
Но все это можно сделать через консоль с помощью команды:
docker exec headscale headscale users create user2
Пользователь у нас есть теперь нам нужно сгенерировать ключ для регистрации новых нод, в разделе Users нажимаем на нашего пользователя и в поле PreAuth Keys нажимаем кнопку Create, ставим галки Ephemeral и Reusable, в поле с датой выбираем сколько наш ключ будет действовать и нажимаем на кнопку галки в кружке.
Это так же можно сделать командой:
docker exec headscale headscale --user user1 preauthkeys create --reusable --expiration 24h
Теперь нам нужно собрать команду для регистрации новой ноды, переходим в раздел Deploy, ставил галку на PreAuth Key, выбираем пользователя user1 и выбираем созданный ранее ключ и получаем команду
tailscale up --login-server=https://test-headscale.31bel.ru --authkey=cfffb6dcc4e16ed6a5c41946c25ba1f9b65da15e5fbcbeb9 --accept-dns=false
Переходим к установки и настройке клиента.
Установка клиента Tailscale на MacOS
Скачиваем клиент с сайта Tailscale, устанавливаем, запускаем и в настройках даём разрешения для приложения в системе. В трее появилась иконка приложения Tailscale нажимаем на неё правой кнопкой и выбираем Settings… переходим в раздел Settings, находим пункт CLI integration, нажимаем на кнопку Show me how и нажимаем кнопку Install.
Далее открываем терминал и вводим нашу заготовленную команду.
Готово.
Установка клиента Tailscale на Android
Приложение устанавливаем через Google Play название Tailscale, запускаем, в верхнем правом углу нажимаем на шестеренку, выбираем Accounts, в верхнем правом углу нажимаем три точки, выбираем пункт Use an alternate server, вводим на адрес сервера Headscale и нажимаем кнопку Add account.
Открывается страница с командой для регистрации.
Набираем эту команду в консоли сервера Headscale:
docker exec headscale headscale nodes register --user user1 --key mkey:b3e480a96dc88d2fe3a765514535eaf4df6ee31e633c1839613fc635c6c47977
Exit Node
Имеется VPS за пределами, на нём Ubuntu, для установки клиента Tailscale на VPS вводим команды:
curl -fsSL https://tailscale.com/install.sh | sh
После установки нужно включить IP forwarding.
Если в вашей системе Linux есть /etc/sysctl.d каталог, используйте:
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf
В противном случае используйте:
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf
В панели управления headscale подготавливаем команду для регистрации нового клиента. Выбираем пункты: PreAuth Key (Пользователя, Ключ), Advertise Exit Node (Говорим что этот клиент будет выступать в роли Exit Node), Accept DNS(Применять настройки DNS, предоставленные headscale).
Копируем получившеюся команду на наш VPS:
tailscale up --login-server=https://test-headscale.31bel.ru --authkey=362fefafd382f2f0b9d5f752f8dc110ef88062034c95124f --advertise-exit-node --accept-dns
Теперь нам нужно вернуться в консоль нашего сервера где установлен headscale и включить Exit Node, необходимо посмотреть routes list командой:
docker exec headscale headscale routes list
Видим что зарегистрированный VPS появился в списке но Enabled = false, нужно это исправить.
docker exec headscale headscale routes enable -r 1
docker exec headscale headscale routes enable -r 2
Теперь возвращаемся в клиент который на Android или Mac, в списке Exit node видим наш VPS, если мы его выберем то наш трафик пойдет через VPS, наш ip сменится и заработаю нужные сайты.
Готово.
DNS
Из последних скриншотов в macos и android видим домен example.com, это внутренний домен который можно изменить на свой например home.local в конфигурационном файле (headscale/config/config.yaml) headscale, параметр base_domain в разделе DNS.
Так же в разделе DNS есть параметр extra_records с помощью которого можно записывать свои записи A для использовании их внутри сети, пример:
Изучайте официальную документацию на сайте headscale и создавайте свою виртуальную сеть, удачи.