Self-hosted ZeroTier-сеть, через которую обеспечивается удалённый доступ ко всем домашним сервисам, без необходимости публиковать SSH/админ-порты в интернет. Контроллер свой, не ZeroTier Central.
c53bc939c1ce37d2 (имя melnoff-main-network), подсеть 172.25.30.0/24.c53bc939c1 @ 94.103.86.3:9993 (это и есть контроллер). Файл moon: 000000c53bc939c1.moon.allowManaged. См. типичные_проблемы.peers это адреса с ролью PLANET (cafe04eba9, cafe80ed74 и т.п.).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) |
homepc.zt192.168.0.11
Push DNS применяется только на клиентах с allowDNS=1.
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
3000 хоста (либо за nginx). Логин/пароль — у владельца.Минимальный набор шагов на любом новом узле, который должен подключиться к сети:
# 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
# 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
c53bc939c1ce37d2.zerotier-cli orbit c53bc939c1 c53bc939c1.zt.melnoff.com.
Положить файл 000000c53bc939c1.moon в:
/var/lib/zerotier-one/moons.d//Library/Application Support/ZeroTier/One/moons.d/%PROGRAMDATA%\ZeroTier\One\moons.d\
После рестарта демона moon будет загружен. zerotier-cli listmoons должен показать его. Это полезно если узел стартует в условиях, когда planet'ы недоступны.
Moon — это ваш собственный root-сервер сети ZeroTier (планета ZT-Inc + ваша «луна» = два корня).
172.25.30.6 (cab282198d) за симметричным NAT'ом 193.35.100.225.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.
Симптом. zerotier-cli info = ONLINE, listnetworks = OK с правильным IP, peers показывает DIRECT пира — но любой ICMP/TCP до него падает с No route to host или просто таймаутится. Под капотом: ifconfig <ZT iface> не показывает inet-адрес, в netstat -rn нет маршрута на 172.25.30.0/24. Трафик уходит через default route (например, на параллельный VPN).
Причина. Локальная политика клиента запрещает ZT-демону применять IP/маршруты, выданные контроллером.
Лечение.
sudo zerotier-cli set c53bc939c1ce37d2 allowManaged=1
⚠️ leave сети сбрасывает этот флаг в 0. После любого leave/join цикла — выставить заново.
Симптом. Файл .moon в каталоге есть, но zerotier-cli listmoons возвращает [].
Причина. Демон читает moons.d/ только при старте.
Лечение. Без рестарта: sudo zerotier-cli orbit <moonId> <moonId> (для нашей сети — sudo zerotier-cli orbit c53bc939c1 c53bc939c1). С рестартом: sudo launchctl kickstart -k system/com.zerotier.one (macOS) или sudo systemctl restart zerotier-one (Linux).
Симптом. На контроллере (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 реально.
Причина. Узел не авторизован контроллером.
Лечение. На zt.melnoff.com → Members → найти узел по ZT-addr (10 hex) → поставить галку Auth.
Симптом. При ping появляются строчки с пометкой (DUP!).
Причина. На маке параллельно работает второй TUN-VPN (например, AdGuard на utun4 с 198.18.0.1) — он подхватывает копии пакетов.
Лечение. Не критично, на функциональность не влияет. Если раздражает — проверить, не тащит ли VPN-клиент broadcast/multicast в свой туннель.
Делать в этом порядке. Каждый шаг предполагает, что предыдущий вернул «зелёный» результат.
sudo zerotier-cli info → ONLINE. Если OFFLINE — UDP 9993 наружу заблокирован, либо демон не запущен.sudo zerotier-cli listnetworks → OK и осмысленный IP. Если ACCESS_DENIED — авторизовать в Central. Если REQUESTING_CONFIGURATION дольше 30 сек — контроллер недоступен.allowManaged=1? sudo zerotier-cli get <nwid> allowManaged. Если 0 — фиксить (см. проблема №1).sudo zerotier-cli -j peers → достать запись по ZT-addr целевого узла. Смотреть массив paths. Если пусто — это не обязательно «недоступен» (см. проблема №3), просто нет p2p.sudo zerotier-cli listmoons → должна быть запись с id = 000000c53bc939c1. Если пусто — orbit (см. проблема №2).leave/join цикл (см. проблема №3).
На случай, если контроллер zt.melnoff.com будет недоступен (катастрофа / блокировка / порт 9993 закрыт), а нужно поднять новый клиент — вот канонический moon-файл в base64.
В файле нет приватных ключей — только публичная identity moon-узла, его stable endpoint и подпись world'а. Поэтому хранить его в публичной wiki безопасно.
000000c53bc939c1.moon76e8a39807413a5b650c61d133d53285492484af0a7d519cf72a86dd3ce76cf6zt.melnoff.com:/var/lib/zerotier-one/moons.d/000000c53bc939c1.moon (в Docker-контейнере zerotier).fwAAAMU7yTnBAAABnK+hl0TThMZt6mNZ+M7RQUomXAqP14FfhYP31JFStqq/jyPQcZjitqCMpAHybQcKvbtOW+8oLS2CSNAxzpru31jfdZwqwP1gRqQV7UP6nk+nGmCJcToCv+gF4CUe+JiQaLRXpQEPkeSeSREa4W/4DQ/2NmxR0J7qdLPYWmzZhWknkTbrCzr/9qY6M14n+j2IIPrWKO18x06B6Ed1HZ/Z2KIIlcwVAcU7yTnBALm27ZEIiAep3L8bws8Jwp88Q1I52ZzB8iUyNesmZbJ74rWPvgYpHJq5p66QE4l5x3wAkt0LZ3IqD4TSoVcatj0AAQReZ1YDJwkAAA==
# 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
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
$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'ы были достижимы.