# Установка и миграция Инструкция рассчитана на Debian 13 внутри `vpn-egress-gw`. ## 1. Резервная копия До установки сохранить: ```bash install -d -m 0700 /root/vpn-egress-migration cp -a /etc/sing-box/config.json /root/vpn-egress-migration/config.json.before cp -a /root/render-singbox-hy2.sh /root/vpn-egress-migration/ cp -a /usr/local/sbin/vpn-egress-guard.sh /root/vpn-egress-migration/ nft list ruleset > /root/vpn-egress-migration/nft.before.rules ip -4 rule show > /root/vpn-egress-migration/ip-rule.before.txt ip -4 route show table all > /root/vpn-egress-migration/ip-route.before.txt ``` ## 2. Обновление sing-box Пакет имеет строгую зависимость `sing-box (= 1.13.19)`. ```bash apt-get update apt-get install sing-box=1.13.19 sing-box version ``` Если репозиторий SagerNet ещё не публикует 1.13.19, миграцию не продолжать и не обходить dependency/version gate. ## 3. Установка пакета ```bash dpkg -i vpn-egressctl_0.1.0_all.deb install -m 0600 -o root -g root \ /usr/share/vpn-egressctl/policy.json \ /etc/vpn-egress/policy.json systemctl daemon-reload ``` Проверить локальные значения policy до первого применения. ## 4. Guard до VPN Старый unit находится в `/etc/systemd/system` и перекрывает package unit из `/usr/lib`. Сначала обратимо убрать старое определение: ```bash systemctl stop vpn-egress-guard.service mv /etc/systemd/system/vpn-egress-guard.service \ /root/vpn-egress-migration/vpn-egress-guard.service.disabled systemctl daemon-reload systemctl enable --now vpn-egress-guard.service systemctl status vpn-egress-guard.service --no-pager nft list table inet vpn_egress_guard ``` Новый unit имеет `Before=sing-box.service`, а package-managed drop-in для `sing-box.service` добавляет `Requires=` и `After=` от guard. Это закрывает boot window и блокирует запуск sing-box, если совместно запущенный guard завершился с ошибкой. Зависимость не является watchdog для ручного удаления nftables-таблицы; текущее runtime-состояние проверяет `vpn-egressctl doctor`. ## 5. Dry run и первый import Для первого `check` URI ещё должен существовать. Создать файл без попадания secret в argv: ```bash install -m 0600 -o root -g root /dev/null /etc/vpn-egress/hysteria2.uri read -r -s URI printf '%s\n' "$URI" > /etc/vpn-egress/hysteria2.uri unset URI vpn-egressctl check vpn-egressctl diff vpn-egressctl sync ``` Более простой вариант для интерактивного применения: ```bash vpn-egressctl import --stdin ``` Команда сама запросит URI без echo, выполнит check/apply/healthcheck и при неуспехе восстановит старые URI и config. ## 6. Включение watcher ```bash systemctl enable --now vpn-egress-sync.path vpn-egressctl doctor ``` ## 7. Вывод старого renderer из эксплуатации После успешного canary и rollback-теста: ```bash mv /root/render-singbox-hy2.sh \ /root/vpn-egress-migration/render-singbox-hy2.sh.disabled ``` Удалять старый файл в день миграции не нужно: перемещение остаётся обратимым. Старый `/usr/local/sbin/vpn-egress-guard.sh` можно архивировать после проверки, что package-managed unit использует `vpn-egressctl guard-apply`. ## 8. Acceptance Обязательные проверки: ```bash vpn-egressctl status vpn-egressctl doctor sing-box check -c /etc/sing-box/config.json ip -4 rule show ip -4 route show table 2022 nft list table inet vpn_egress_guard nft list table inet sing-box systemctl show sing-box.service -p Requires -p After ``` В `config.json` и nftables не должно быть ни старого `185.156.108.141`, ни текущего `85.208.119.160`. С настоящего workload в `10.30.0.0/24` обязательно проверить: 1. DNS через шлюз; 2. TCP и UDP через VPN; 3. HTTPS-запрос к контролируемому endpoint или Cloudflare trace; 4. соответствие наблюдаемого public IP ожидаемому VPN egress; 5. повтор тех же проверок после restart sing-box. Anti-leak проверяется только из консоли canary/staging, чтобы не потерять удалённый доступ к production: ```bash # На шлюзе: systemctl stop sing-box.service # На workload за eth1: запрос наружу должен завершиться ошибкой, а не пойти напрямую. curl --fail --connect-timeout 5 https://www.cloudflare.com/cdn-cgi/trace # На шлюзе: systemctl start sing-box.service vpn-egressctl doctor ```