====== ZeroTier — оверлей-сеть ======
Self-hosted ZeroTier-сеть, через которую обеспечивается удалённый доступ ко всем домашним сервисам, без необходимости публиковать SSH/админ-порты в интернет. Контроллер свой, не ZeroTier Central.
===== TL;DR — самое важное =====
* **Сеть**: ''c53bc939c1ce37d2'' (имя ''melnoff-main-network''), подсеть ''172.25.30.0/24''.
* **Контроллер**: [[https://zt.melnoff.com|zt.melnoff.com]] (ztnet UI), это **не** my.zerotier.com. Авторизация участников делается там.
* **Свой moon**: ''c53bc939c1'' @ ''94.103.86.3:9993'' (это и есть контроллер). Файл moon: ''000000c53bc939c1.moon''.
* **На каждом новом клиенте** — три команды, см. [[#bootstrap_нового_клиента]].
* **Если ZT «полу-работает»** (онлайн, но трафик не ходит) — первым делом проверить ''allowManaged''. См. [[#типичные_проблемы]].
===== Архитектура =====
==== Уровни ====
- **Planets** — публичные корни ZeroTier Inc. Используются для bootstrap. У вас в ''peers'' это адреса с ролью ''PLANET'' (''cafe04eba9'', ''cafe80ed74'' и т.п.).
- **Moon** (свой) — ваш корень, добавленный к planets. Дублирует функцию rendezvous и даёт быстрый relay внутри РФ.
- **Leaves** — обычные клиенты сети. У них роль ''LEAF''.
==== Роли узлов в сети ====
^ Узел / Description ^ ZT addr ^ ZT IP ^ Public/LAN endpoint ^ Заметки ^
| Контроллер + moon (хост ''zt.melnoff.com'') | ''c53bc939c1'' | ''172.25.30.225'' | ''94.103.86.3:9993'' | Linux Oracle 10. ZT крутится в Docker (zyclonite/zerotier:1.16.0). Web UI = ztnet. |
| Этот мак | ''54dcf8821c'' | ''172.25.30.11'' | ''212.74.229.169:9993'' | macOS, ZT 1.16.1, ''feth2340'' интерфейс. |
| Узел "imelnikov" | (см. контроллер) | ''172.25.30.10'' | — | Доступ ''ssh imelnikov@172.25.30.10''. |
| PVE-роутер в LAN | (gateway-узел) | ''172.25.30.1'' | — | Бриджит ZT в ''192.168.0.0/24'' и ''172.16.10.0/24''. |
| Удалённый peer (sym-NAT) | ''cab282198d'' | ''172.25.30.6'' | ''193.35.100.225'' | За симметричным NAT'ом — для доступа из мака требуется relay через moon. |
| Прочие участники | ''31040019d0'', ''35d963a742'', ''73db6c289d'', ''77b9f07f34'', ''7e27e08dd1'', ''c63ddbdfe3'' | — | разное | Разные клиенты сети; точное соответствие ZT-addr↔IP смотреть на ''zt.melnoff.com'' → Members. |
==== Маршруты ====
Контроллер раздаёт клиентам сети (в дополнение к ''172.25.30.0/24''):
^ Target ^ Via ^ Что значит ^
| ''172.25.30.0/24'' | ''(direct)'' | Сама ZT-подсеть |
| ''192.168.0.0/24'' | ''172.25.30.1'' | Через ZT-gateway пробрасывается в физический LAN |
| ''172.16.10.0/24'' | ''172.25.30.1'' | Доступ к Docker-фабрике на PVE (LXC 107 = ''172.16.10.1'') |
==== Push DNS ====
* Зона: ''homepc.zt''
* Резолвер: ''192.168.0.11''
Push DNS применяется только на клиентах с ''allowDNS=1''.
===== Контроллер на zt.melnoff.com =====
==== Стек ====
OpenSSH доступен как ''ssh root@zt.melnoff.com''. На хосте Docker-стек:
^ Контейнер ^ Образ ^ Порт ^ Назначение ^
| ''zerotier'' | ''zyclonite/zerotier:1.16.0'' | UDP 9993 (host network) | Сам ZT-демон в режиме контроллера. ZT-addr ''c53bc939c1''. |
| ''ztnet'' | ''sinamics/ztnet:latest'' | ''3000'' (HTTP) | Современный web UI/API для управления контроллером. |
| ''postgres'' | ''postgres:16-alpine'' | (internal) | БД для ztnet. |
Обновлён до 1.16.0 на 2026-04-27 (in-place recreate с named volume ''ztnet_zerotier''; identity и БД members сохранены). Compose-файл: ''/opt/ztnet/docker-compose.yml''. Бэкап volume оставлен в ''/root/zt-volume-backup-*.tgz''.
==== Полезные команды на контроллере ====
# войти на хост
ssh root@zt.melnoff.com
# на хосте — zerotier-cli работает только через docker exec
docker exec zerotier zerotier-cli info
docker exec zerotier zerotier-cli listnetworks
docker exec zerotier zerotier-cli peers
# проверить достижимость члена сети с самого контроллера (тест L3)
docker exec zerotier ping -c 3 172.25.30.6
# логи
docker logs --tail 100 zerotier
docker logs --tail 100 ztnet
# REST API контроллера (через токен из контейнера)
TOK=$(docker exec zerotier cat /var/lib/zerotier-one/authtoken.secret)
docker exec zerotier curl -s -H "X-ZT1-Auth: $TOK" \
http://localhost:9993/controller/network/c53bc939c1ce37d2/member
==== Web UI (ztnet) ====
* Адрес — на порту ''3000'' хоста (либо за nginx). Логин/пароль — у владельца.
* Авторизация новых member'ов — там.
* Здесь же редактируются: name, ipAssignments, capabilities/tags, routes, dns push, broadcast, multicast limits.
===== Bootstrap нового клиента =====
Минимальный набор шагов на любом новом узле, который должен подключиться к сети:
==== Linux ====
# 1. Установка (Debian/Ubuntu)
curl -s https://install.zerotier.com | sudo bash
# 2. Присоединение к сети
sudo zerotier-cli join c53bc939c1ce37d2
# 3. Подключить свой moon (важно для symmetric-NAT окружений)
sudo zerotier-cli orbit c53bc939c1 c53bc939c1
# 4. Разрешить демону применять выданные IP/маршруты
sudo zerotier-cli set c53bc939c1ce37d2 allowManaged=1
# 5. Авторизовать узел в zt.melnoff.com → Members → ✓ Auth
==== macOS ====
# 1. Установка через Homebrew или из dmg на zerotier.com
brew install --cask zerotier-one
# 2-5: те же команды что на Linux. Бинарник в /usr/local/bin/zerotier-cli
sudo zerotier-cli join c53bc939c1ce37d2
sudo zerotier-cli orbit c53bc939c1 c53bc939c1
sudo zerotier-cli set c53bc939c1ce37d2 allowManaged=1
==== Windows ====
- Поставить ZeroTier One MSI с zerotier.com.
- В трее → Join Network → ввести ''c53bc939c1ce37d2''.
- В админ-cmd: ''zerotier-cli orbit c53bc939c1 c53bc939c1''.
- Авторизовать узел в Members на ''zt.melnoff.com''.
==== Через .moon файл (альтернатива orbit) ====
Положить файл ''000000c53bc939c1.moon'' в:
* Linux: ''/var/lib/zerotier-one/moons.d/''
* macOS: ''/Library/Application Support/ZeroTier/One/moons.d/''
* Windows: ''%PROGRAMDATA%\ZeroTier\One\moons.d\''
После рестарта демона moon будет загружен. ''zerotier-cli listmoons'' должен показать его. Это полезно если узел стартует в условиях, когда planet'ы недоступны.
===== Зачем нужен свой moon =====
Moon — это ваш собственный root-сервер сети ZeroTier (планета ZT-Inc + ваша «луна» = два корня).
==== Решает три задачи ====
- **Скорость rendezvous и relay.** Публичные planet'ы географически далеко (Амстердам, Сингапур, США — latency 150-240 мс). Свой moon в РФ — 8-11 мс. При невозможности hole-punch'а (см. ниже) трафик идёт через корень — на planet'е это медленно.
- **Symmetric-NAT окружения.** Если узел за «строгим» NAT'ом (типа корпоративного или мобильного), p2p-соединения не пробиваются. Без relay через близкий moon связь не работает совсем. Конкретный пример в этой сети — узел ''172.25.30.6'' (''cab282198d'') за симметричным NAT'ом ''193.35.100.225''.
- **Независимость от публичной инфраструктуры ZT-Inc.** Если planet'ы временно недоступны (блокировка провайдером, DDoS, downtime), свой moon продолжает работать.
==== Когда moon **не нужен** ====
* На самом узле-moon (он сам и есть root).
* Если оба пира за обычным cone NAT-ом — hole-punch через planet'ы работает напрямую, moon не используется.
==== Технически ====
Moon — это подписанный JSON-документ:
{
"id": "c53bc939c1",
"roots": [{
"identity": "c53bc939c1:0:b9b6...<публичный ключ>",
"stableEndpoints": ["94.103.86.3/9993"]
}],
"signature": "...",
"timestamp": ...,
"updatesMustBeSignedBy": "..."
}
Создание новой moon: на узле-кандидате ''zerotier-idtool initmoon /var/lib/zerotier-one/identity.public > moon.json'', отредактировать ''stableEndpoints'', потом ''zerotier-idtool genmoon moon.json'' → получится ''.moon''. Распространять на клиентов через ''moons.d/'' или команду ''orbit''.
===== Типичные проблемы =====
==== 1. ''allowManaged=0'' — IP «висит», но реально не на интерфейсе ====
**Симптом.** ''zerotier-cli info'' = ONLINE, ''listnetworks'' = OK с правильным IP, ''peers'' показывает ''DIRECT'' пира — но любой ICMP/TCP до него падает с ''No route to host'' или просто таймаутится. Под капотом: ''ifconfig '' не показывает inet-адрес, в ''netstat -rn'' нет маршрута на ''172.25.30.0/24''. Трафик уходит через default route (например, на параллельный VPN).
**Причина.** Локальная политика клиента запрещает ZT-демону применять IP/маршруты, выданные контроллером.
**Лечение.**
sudo zerotier-cli set c53bc939c1ce37d2 allowManaged=1
⚠️ ''leave'' сети **сбрасывает** этот флаг в 0. После любого ''leave''/''join'' цикла — выставить заново.
==== 2. Moon не подхватывается из ''moons.d/'' ====
**Симптом.** Файл ''.moon'' в каталоге есть, но ''zerotier-cli listmoons'' возвращает ''[]''.
**Причина.** Демон читает ''moons.d/'' только при старте.
**Лечение.** Без рестарта: ''sudo zerotier-cli orbit '' (для нашей сети — ''sudo zerotier-cli orbit c53bc939c1 c53bc939c1''). С рестартом: ''sudo launchctl kickstart -k system/com.zerotier.one'' (macOS) или ''sudo systemctl restart zerotier-one'' (Linux).
==== 3. Узел в Central «онлайн», но ''paths: 0'' и недоступен ====
**Симптом.** На контроллере (''docker exec zerotier zerotier-cli peers'') узел виден как ''DIRECT'' с low latency. На клиенте этот же узел в ''peers'' имеет ''paths: 0, latency: -1''. Пинг не доходит, ARP не resolve'ится.
**Причина.** Кэш member-info на клиенте залип — endpoint от moon не получен.
**Лечение.**
sudo zerotier-cli leave c53bc939c1ce37d2
sudo zerotier-cli join c53bc939c1ce37d2
sleep 5
sudo zerotier-cli set c53bc939c1ce37d2 allowManaged=1 # ← обязательно после join
В ZT 1.16 relay-only пути **не показываются** в массиве ''paths'' — поэтому ''paths: 0'' не означает «недоступен», просто «нет p2p». Всегда пробуйте ping реально.
==== 4. ''ACCESS_DENIED'' в ''listnetworks'' ====
**Причина.** Узел не авторизован контроллером.
**Лечение.** На ''zt.melnoff.com'' → Members → найти узел по ZT-addr (10 hex) → поставить галку Auth.
==== 5. Дублирование ICMP-ответов (''DUP!'') ====
**Симптом.** При ''ping'' появляются строчки с пометкой ''(DUP!)''.
**Причина.** На маке параллельно работает второй TUN-VPN (например, AdGuard на ''utun4'' с ''198.18.0.1'') — он подхватывает копии пакетов.
**Лечение.** Не критично, на функциональность не влияет. Если раздражает — проверить, не тащит ли VPN-клиент broadcast/multicast в свой туннель.
===== Диагностический playbook =====
Делать в этом порядке. Каждый шаг предполагает, что предыдущий вернул «зелёный» результат.
- **Демон ONLINE?** ''sudo zerotier-cli info'' → ''ONLINE''. Если ''OFFLINE'' — UDP 9993 наружу заблокирован, либо демон не запущен.
- **Сеть OK?** ''sudo zerotier-cli listnetworks'' → ''OK'' и осмысленный IP. Если ''ACCESS_DENIED'' — авторизовать в Central. Если ''REQUESTING_CONFIGURATION'' дольше 30 сек — контроллер недоступен.
- **''allowManaged=1''?** ''sudo zerotier-cli get allowManaged''. Если ''0'' — фиксить (см. проблема №1).
- **Путь до пира.** ''sudo zerotier-cli -j peers'' → достать запись по ZT-addr целевого узла. Смотреть массив ''paths''. Если пусто — это **не** обязательно «недоступен» (см. проблема №3), просто нет p2p.
- **Moon загружен?** ''sudo zerotier-cli listmoons'' → должна быть запись с ''id'' = ''000000c53bc939c1''. Если пусто — ''orbit'' (см. проблема №2).
- **Stale member cache?** ''leave/join'' цикл (см. проблема №3).
- **Последняя надежда:** рестарт демона; апгрейд контроллера до ZT 1.16.x.
===== Полезные ссылки =====
* [[https://zt.melnoff.com|Self-hosted controller (ztnet UI)]]
* [[https://docs.zerotier.com/|Официальная документация ZeroTier]]
* [[https://github.com/sinamics/ztnet|ztnet (controller UI)]]
* [[selfhosted:hardware|Где физически живут участники сети]]
===== Резервная копия moon-файла =====
На случай, если контроллер ''zt.melnoff.com'' будет недоступен (катастрофа / блокировка / порт 9993 закрыт), а нужно поднять новый клиент — вот канонический moon-файл в base64.
В файле **нет** приватных ключей — только публичная identity moon-узла, его stable endpoint и подпись world'а. Поэтому хранить его в публичной wiki безопасно.
* **Имя файла:** ''000000c53bc939c1.moon''
* **Размер:** 259 байт
* **SHA-256:** ''76e8a39807413a5b650c61d133d53285492484af0a7d519cf72a86dd3ce76cf6''
* **Извлечён с:** ''zt.melnoff.com:/var/lib/zerotier-one/moons.d/000000c53bc939c1.moon'' (в Docker-контейнере ''zerotier'').
==== Содержимое (base64) ====
fwAAAMU7yTnBAAABnK+hl0TThMZt6mNZ+M7RQUomXAqP14FfhYP31JFStqq/jyPQcZjitqCMpAHybQcKvbtOW+8oLS2CSNAxzpru31jfdZwqwP1gRqQV7UP6nk+nGmCJcToCv+gF4CUe+JiQaLRXpQEPkeSeSREa4W/4DQ/2NmxR0J7qdLPYWmzZhWknkTbrCzr/9qY6M14n+j2IIPrWKO18x06B6Ed1HZ/Z2KIIlcwVAcU7yTnBALm27ZEIiAep3L8bws8Jwp88Q1I52ZzB8iUyNesmZbJ74rWPvgYpHJq5p66QE4l5x3wAkt0LZ3IqD4TSoVcatj0AAQReZ1YDJwkAAA==
==== Восстановление на новом клиенте ====
=== Linux ===
# 1. Декодировать в правильное имя файла
mkdir -p /var/lib/zerotier-one/moons.d
echo 'fwAAAMU7yTnBAAABnK+hl0TThMZt6mNZ+M7RQUomXAqP14FfhYP31JFStqq/jyPQcZjitqCMpAHybQcKvbtOW+8oLS2CSNAxzpru31jfdZwqwP1gRqQV7UP6nk+nGmCJcToCv+gF4CUe+JiQaLRXpQEPkeSeSREa4W/4DQ/2NmxR0J7qdLPYWmzZhWknkTbrCzr/9qY6M14n+j2IIPrWKO18x06B6Ed1HZ/Z2KIIlcwVAcU7yTnBALm27ZEIiAep3L8bws8Jwp88Q1I52ZzB8iUyNesmZbJ74rWPvgYpHJq5p66QE4l5x3wAkt0LZ3IqD4TSoVcatj0AAQReZ1YDJwkAAA==' \
| base64 -d > /var/lib/zerotier-one/moons.d/000000c53bc939c1.moon
# 2. Проверить (sha256 должен совпасть)
sha256sum /var/lib/zerotier-one/moons.d/000000c53bc939c1.moon
# ожидаем: 76e8a39807413a5b650c61d133d53285492484af0a7d519cf72a86dd3ce76cf6
# 3. Перезапустить демон
sudo systemctl restart zerotier-one
# 4. Убедиться что moon подхватился
sudo zerotier-cli listmoons
=== macOS ===
sudo mkdir -p "/Library/Application Support/ZeroTier/One/moons.d"
echo 'fwAAAMU7yTnBAAABnK+hl0TThMZt6mNZ+M7RQUomXAqP14FfhYP31JFStqq/jyPQcZjitqCMpAHybQcKvbtOW+8oLS2CSNAxzpru31jfdZwqwP1gRqQV7UP6nk+nGmCJcToCv+gF4CUe+JiQaLRXpQEPkeSeSREa4W/4DQ/2NmxR0J7qdLPYWmzZhWknkTbrCzr/9qY6M14n+j2IIPrWKO18x06B6Ed1HZ/Z2KIIlcwVAcU7yTnBALm27ZEIiAep3L8bws8Jwp88Q1I52ZzB8iUyNesmZbJ74rWPvgYpHJq5p66QE4l5x3wAkt0LZ3IqD4TSoVcatj0AAQReZ1YDJwkAAA==' \
| base64 -D | sudo tee "/Library/Application Support/ZeroTier/One/moons.d/000000c53bc939c1.moon" > /dev/null
# Перезапуск
sudo launchctl kickstart -k system/com.zerotier.one
sudo zerotier-cli listmoons
=== Windows (PowerShell, admin) ===
$b64 = 'fwAAAMU7yTnBAAABnK+hl0TThMZt6mNZ+M7RQUomXAqP14FfhYP31JFStqq/jyPQcZjitqCMpAHybQcKvbtOW+8oLS2CSNAxzpru31jfdZwqwP1gRqQV7UP6nk+nGmCJcToCv+gF4CUe+JiQaLRXpQEPkeSeSREa4W/4DQ/2NmxR0J7qdLPYWmzZhWknkTbrCzr/9qY6M14n+j2IIPrWKO18x06B6Ed1HZ/Z2KIIlcwVAcU7yTnBALm27ZEIiAep3L8bws8Jwp88Q1I52ZzB8iUyNesmZbJ74rWPvgYpHJq5p66QE4l5x3wAkt0LZ3IqD4TSoVcatj0AAQReZ1YDJwkAAA=='
$dir = 'C:\ProgramData\ZeroTier\One\moons.d'
New-Item -ItemType Directory -Force -Path $dir | Out-Null
[IO.File]::WriteAllBytes("$dir\000000c53bc939c1.moon", [Convert]::FromBase64String($b64))
Restart-Service ZeroTierOneService
& 'C:\Program Files (x86)\ZeroTier\One\zerotier-cli.bat' listmoons
==== Альтернатива — без файла ====
Если узел может достучаться до публичных planet'ов ZT, можно обойтись без файла — одной командой:
sudo zerotier-cli orbit c53bc939c1 c53bc939c1
Демон сам найдёт identity moon-узла через planet'ы. Это проще, но требует, чтобы хотя бы при первом запуске planet'ы были достижимы.