# OxidProxy — развёртывание с помощью ИИ-агента Этот файл написан **для агента**, а не для человека. Человек отдаёт агенту эту инструкцию и отвечает на вопросы; всё остальное агент делает сам. **Инструкция написана для OxidProxy 2.4.x.** После установки сверь с тем, что покажет `oxidproxy -V`. - **Совпали первые две цифры** (2.4.0, 2.4.9 — неважно) — конфигурация точно совместима, иди дальше не задумываясь. - **Разошлась вторая цифра** — гарантии нет. Формат конфигурации *мог* измениться, а мог и нет: вторая цифра поднимается и по другим причинам. Это не повод останавливаться, но повод сверить разделы 5 и 7 с документацией и сказать человеку, что инструкция старше программы. **Документация:** https://oxidproxy.com/ru/user_guide.html — там разобрано каждое поле конфигурации. Загляни туда, если чего-то не понимаешь. Но **эта инструкция главнее**: где они расходятся, делай как здесь. Документация написана для человека и описывает намного больше, чем нужно при первой установке. --- ## 0. Правила для агента Прочитай их до начала работы. 1. **Ничего не выдумывай.** Если значения нет — либо спроси у человека, либо возьми умолчание, которое явно указано ниже. Не подставляй «примерное» или «похожее». 2. **Спроси всё сразу**, одним списком (раздел 2), а не по одному вопросу на каждом шаге. 3. **Проверяй результат каждого шага.** Команда завершилась без ошибки — это не то же самое, что «получилось». В инструкции для каждого шага указано, что именно проверить. 4. **Секреты не печатай без нужды.** Токен и пароли показываются один раз, в самом конце (раздел 11). В промежуточных сообщениях их не выводи. 5. **Нужен root** и **прямой доступ по SSH** к серверу. 6. Если шаг не удался — не переходи к следующему. Смотри раздел 12. 7. **Обязательное поле нельзя пропустить.** Если человек не ответил на какой-то из обязательных вопросов (раздел 2, пункты 1–3) или ответил невнятно — спроси **отдельным сообщением, про это одно поле**, и жди ответа. Не подставляй ничего вместо него и не иди дальше. 8. **Человек может сказать, что остальное настроит сам.** Тогда прекрати задавать вопросы: поставь программу, впиши только то, что он назвал, и переходи к разделу 11.1 — там сказано, что ему передать. Службу в этом случае **не запускай**. --- ## 1. Что должно быть у клиента Проверь до начала и скажи человеку, если чего-то нет. | Требование | Как проверить | |---|---| | Debian 12 (bookworm), архитектура x86_64 | `. /etc/os-release; echo $VERSION_ID $(uname -m)` | | Права root | `id -u` должно дать `0` | | Своя подсеть IPv6, маршрутизированная на этот сервер | спросить у человека | | Лицензионный ключ OxidProxy | спросить у человека | Если IPv6-подсети нет — **дальше идти нельзя**. Программа выпускает исходящий трафик только по IPv6; без подсети она бесполезна. Скажи об этом прямо и остановись. ### 1.1. Сервер должен быть исправен ДО начала работ Это не формальность. Если сервер сломан заранее, виноватой будет выглядеть программа, и разбираться придётся с нуля. Прогони четыре проверки и покажи результат человеку: ```bash curl -6 -s --max-time 10 https://ipv6.icanhazip.com/ ; echo "код возврата: $?" getent hosts oxidproxy.com timedatectl | grep -E 'System clock|NTP' df -h / | tail -1 ``` - **IPv6-связность.** Пустой ответ означает, что у сервера нет собственного выхода в IPv6. Это не всегда тупик — бывает, что подсеть выдана «на сегмент» (см. раздел 12, «Подсеть выдана, но не маршрутизирована»), — но запомни этот результат и скажи о нём человеку сразу. Окончательную проверку сделаешь в разделе 10. - **DNS.** Если имя не разрешается, установщик не скачает пакеты. - **Часы.** Разъехавшееся время ломает проверку лицензии: она идёт по TLS, а тот отвергает сертификаты «из будущего». Чинится так: `timedatectl set-ntp true`. - **Место на диске.** Ядро и пакет вместе занимают около гигабайта, плюс место под журнал. Меньше 5 ГБ свободных — предупреди. --- ## 2. Вопросы человеку — задай их одним сообщением Спроси всё перечисленное сразу. В скобках указано, что делать, если человек не знает ответа или у него ничего нет. **Обязательные — умолчаний нет.** Если на любой из них не ответили, переспроси отдельно про это одно поле и жди ответа (правило 7). 1. **Лицензионный ключ.** 2. **Внешний IPv4-адрес сервера** — тот, по которому к прокси будут подключаться клиенты. *(Если человек не знает: выполни `curl -4 -s ifconfig.me` и покажи результат ему на подтверждение. Не бери молча: сервер может быть за NAT, и тогда автоматически определённый адрес будет неверным.)* 3. **Подсети IPv6** в формате CIDR, например `2a01:1234::/32`. **Подсетей может быть несколько — спроси прямо: «одна или несколько?»** Собери полный список, не останавливайся на первой. У каждой свой вес: чем больше число, тем чаще из неё берутся адреса. *(Если веса не назвали — поставь всем одинаковый, 100.)* Каждая подсеть потребует **своей строки** в `rc.local` (раздел 6) и **своей записи** в `ipv6_subnets` (раздел 5.2). Пропустишь одну — она просто не будет использоваться, и никакой ошибки не появится. **Необязательные — есть умолчания:** 4. **Токен для API и панели управления.** *(Нет — сгенерируй сам, см. раздел 5.)* 5. **DNS-серверы с весами.** *(Нет — оставь те, что в шаблоне. Посмотри `/etc/resolv.conf` и покажи найденное человеку, но предлагай добавить не всё подряд, а только локальный резолвер: адрес из `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `100.64.0.0/10`, `fc00::/7` или адрес шлюза. Такой почти всегда быстрее публичного — предложи добавить его с весом 1000. Если же там публичный резолвер (`8.8.8.8`, `1.1.1.1`, `9.9.9.9` и подобные), добавлять нечего: они и так в шаблонном пуле, а второй экземпляр того же сервера только исказит веса.)* 6. **Количество учётных записей.** *(Нет — поставь `10000`.)* 7. **Брендирование панели: надпись и адрес сайта.** *(Нет — не добавляй секцию `brand` вовсе, тогда в панели остаётся наша надпись. Спроси прямо: «Показывать в панели ваше название или наше?» Надпись делится на две части, вторая красится акцентным цветом — например `Acme` + `Proxy`.)* 8. **Порты для прокси.** *(Нет — оставь порты из шаблона: 1080 linux, 1081 android, 1082 windows, 1083 ios, 1084 macos.)* 9. **Нужен ли MITM-порт** — подмена отпечатка браузера, а не только ОС. *(Нет ответа — не включай. Если да — раздел 7.)* **Генерируются всегда, не спрашивай:** - `account_seed` — чтобы логины и пароли не менялись при перезапуске; - пароль сервисной учётной записи (для чекеров и мониторинга). --- ## 3. Установка ### 3.1. Подготовка: обновить систему и снять снимок настроек **Сначала обнови систему.** Установщик ставит пакеты через `dpkg`, а зависимости доразрешает через `apt-get install -f` — на сервере с устаревшим индексом это спотыкается. ```bash apt-get update apt-get -y full-upgrade ``` Если обновление принесло ядро новее текущего (сравни `uname -r` с выводом `dpkg -l 'linux-image-*'`) — **перезагрузись прямо сейчас**, до установки. Иначе выйдет наоборот: наше ядро встанет, а загрузится стоковое. > **Скажи об этом человеку, и запомни сам.** После установки OxidProxy > `apt full-upgrade` перестаёт быть безобидным: если Debian выпустит ядро с > номером выше нашего, GRUB загрузит его, и подмена отпечатка ОС молча > перестанет работать. Правило простое — **после каждого обновления > системы проверять `uname -r` на суффикс `oxidproxy-p0f`**. **Потом сними снимок того, что будешь менять.** Не «запомни» — сохрани на диск: разговор может оборваться или обрезаться, файл на сервере — нет. ```bash BK=/root/oxidproxy-preinstall-$(date +%F-%H%M) mkdir -p "$BK" cp -a /etc/rc.local /etc/default/grub /etc/sysctl.conf "$BK"/ 2>/dev/null cp -a /etc/sysctl.d "$BK"/ 2>/dev/null { uname -r ip -6 addr show scope global ip -6 route show ip -6 route show table local sysctl net.ipv4.ip_local_port_range dpkg -l | grep linux-image } > "$BK"/before.txt 2>&1 echo "$BK" ``` Назови человеку получившийся каталог. Если что-то пойдёт не так, из него видно, каким сервер был до нас. ### 3.2. Установка Одной командой. Она поставит ядро с патчем, сам пакет и предложит баннер при входе. ```bash curl -fsSL --http1.1 https://oxidproxy.com/downloads/install.sh | bash ``` Установщик задаст **два вопроса**: 1. `Install the login banner? (y/N)` — **отвечай `y`**. Это баннер при входе по SSH: показывает состояние службы, загруженное ядро, подсети и адрес панели. Заодно ставит команду `dashboard-url`. 2. `Reboot the server now? (y/N)` — **отвечай `n`**. Перезагрузимся позже, после настройки (раздел 9). Если у тебя нет возможности отвечать интерактивно, подай ответы на вход: ```bash printf 'y\nn\n' | curl -fsSL --http1.1 https://oxidproxy.com/downloads/install.sh | bash ``` **Проверь:** ```bash oxidproxy -V dpkg -l | grep -c linux-image-.*oxidproxy-p0f ``` Первая команда должна назвать версию, вторая — вывести `1`. **Сверь версию с той, для которой написана инструкция** — `2.4.x`, см. начало файла. Совпали первые две цифры — иди дальше. Разошлись — сверься с документацией, прежде чем править `config.yaml`, и скажи человеку, что инструкция старше программы. --- ## 4. Генерация секретов Выполни и сохрани значения — они понадобятся в разделе 6. ```bash openssl rand -hex 24 ``` → это **master_token** (токен API и панели). ```bash openssl rand -base64 18 | tr -d '/+=' ``` → это **пароль сервисной учётной записи**. ```bash od -An -N8 -tu8 /dev/urandom | tr -d ' ' ``` → это **account_seed**. Если `openssl` не установлен: `apt-get install -y openssl`. --- ## 5. Правка конфигурации Файл: `/etc/oxidproxy/config.yaml`. Он уже лежит на месте — это шаблон с подставными значениями. Меняй **только перечисленные ниже поля**, остальное не трогай. ### 5.1. Обязательные замены | Поле | Было в шаблоне | Ставим | |---|---|---| | `license_key` | `"PUT_YOUR_KEY_HERE"` | ключ клиента | | `public_ip` | `"YOUR_EXTERNAL_IPV4"` | внешний IPv4 | | `master_token` | `"change_me_to_secure_token"` | сгенерированный токен | | `max_accounts` | `100000` | ответ клиента или `10000` | | `account_seed` | `123456789` | сгенерированное число | | `service_account.password` | `"strong_password"` | сгенерированный пароль | **Ни одно из значений слева не должно остаться в файле.** Проверь это в разделе 8. ### 5.2. Подсети IPv6 Замени весь блок `ipv6_subnets` на подсети клиента: ```yaml ipv6_subnets: - cidr: "2a01:1234::/32" weight: 100 - cidr: "2a02:5678:9abc::/48" weight: 50 ``` Строку-пример `2a01:xxxx::/32` из шаблона **удали** — с ней сервер запустится, но выходить будет в никуда. ### 5.3. DNS Если клиент назвал свои серверы — замени список. Если нет — оставь как есть, но добавь DNS хостера первым, с большим весом: ```yaml servers: - address: "10.0.0.53:53" # DNS хостера из /etc/resolv.conf weight: 1000 - address: "[2606:4700:4700::1111]:53" weight: 58 - address: "1.1.1.1:53" weight: 7 # серверы ниже — резервные, без веса - address: "[2620:fe::fe]:53" - address: "9.9.9.9:53" ``` Правило: у основных серверов есть `weight`, у резервных его нет. Резервные используются, только когда основные недоступны. ### 5.4. Брендирование Если клиент хочет своё название — добавь секцию (в шаблоне она закомментирована): ```yaml brand: name: "Acme" accent: "Proxy" url: "https://acme.example" ``` `name` + `accent` — две половины надписи, вторая красится акцентным цветом. `url` — куда ведёт логотип, только `http://` или `https://`. Если своего названия нет — **секцию не добавляй вовсе**. Эта же надпись попадёт в баннер при входе по SSH. То есть клиент клиента, подключившись к серверу, увидит его бренд, а не наш. ### 5.5. Что оставить как есть `listen_ip`, `accounts_file`, `rotation_interval`, `shaping`, `timeouts`, `log`, `blocked_file`, порты `api_port` и `api_port_https` — не трогай, если человек не попросил отдельно. --- ## 6. Маршрутизация подсети — `/etc/rc.local` Без этого шага сервер не сможет брать адреса из подсети. Установщик уже добавил в `/etc/rc.local` закомментированную строку-образец после метки `# --- oxidproxy-ipv6-setup ---`. Замени её на **по одной строке для каждой подсети клиента**: ```sh # --- oxidproxy-ipv6-setup --- ip -6 route add local 2a01:1234::/32 dev lo ip -6 route add local 2a02:5678:9abc::/48 dev lo ``` Строка должна стоять **до** `exit 0`. Файл должен быть исполняемым: ```bash chmod +x /etc/rc.local ``` Применить немедленно, не дожидаясь перезагрузки — выполни те же команды руками: ```bash ip -6 route add local 2a01:1234::/32 dev lo ``` **Проверь — по каждой подсети отдельно:** ```bash for net in 2a01:1234::/32 2a02:5678:9abc::/48; do printf '%-28s %s\n' "$net" "$(ip -6 route show table local | grep -c "$net")" done ``` Напротив каждой подсети должно стоять число больше нуля. Ноль означает, что эта подсеть не заработает, а сервер об этом не сообщит. --- ## 7. MITM-порт (только если клиент попросил) Раскомментируй в конфиге секцию `mitm_listeners` и поставь свободный порт: ```yaml mitm_listeners: - port: 9443 profiles: - "windows-chrome" - "windows-firefox" - "macos-safari" - "android-chrome" - "ios-safari" default: "windows-chrome" ``` Предупреди человека о двух вещах: - клиенту MITM-порта нужно **один раз установить наш корневой сертификат**, иначе браузер будет ругаться. Сертификат отдаётся по адресу `http://<внешний IP>:8080/ca`; - через MITM-порт **не пойдут** curl, скрипты и прочее без браузерного `User-Agent` — они получат страницу с объяснением. Если это нужно, добавь в листенер `allow_unknown_ua: true`. --- ## 8. Проверка конфигурации до запуска ```bash oxidproxy -t /etc/oxidproxy/config.yaml ``` Команда должна сказать, что конфигурация принята. Если нет — читай, на что она ругается, и исправляй; не запускай службу с непринятым конфигом. Отдельно убедись, что ни одно подставное значение не осталось: ```bash grep -nE "PUT_YOUR_KEY_HERE|YOUR_EXTERNAL_IPV4|change_me_to_secure_token|strong_password|2a01:xxxx" /etc/oxidproxy/config.yaml ``` Вывод должен быть **пустым**. Если что-то нашлось — вернись к разделу 5. --- ## 9. Перезагрузка Ядро с патчем подмены отпечатка ОС начинает работать только после перезагрузки. Предупреди человека, что связь прервётся на минуту. ```bash reboot ``` После возвращения **проверь**: ```bash uname -r ``` В ответе должно быть `oxidproxy-p0f`. Если суффикса нет — подмена отпечатка ОС **не работает**, см. раздел 12. --- ## 10. Запуск и проверка, что всё живо ```bash systemctl start oxidproxy ``` Подожди 15 секунд и посмотри журнал — это обязательный шаг, не пропускай: ```bash sleep 15 journalctl -u oxidproxy -n 30 --no-pager ``` **Что должно быть в журнале:** - `License Activated via ...` — лицензия принята; - `API Listening (HTTPS) on ...`; - `System Ready. Starting parallel listeners...`. **Чего быть не должно:** строк со словом `rejected` или `FATAL`. Служба может числиться «работающей», не подняв при этом ни одного порта, — этим она и обманчива. **Проверь, что порты действительно слушаются:** ```bash ss -tlnp | grep oxidproxy ``` Должны быть видны все порты из конфигурации. **Проверь, что трафик действительно выходит.** Возьми первую учётную запись и сходи через неё наружу: ```bash CRED=$(head -1 /var/lib/oxidproxy/accounts_*_1080.txt | sed 's|socks5://||') curl -s --max-time 20 -x "socks5h://$CRED" https://ipv6.icanhazip.com/ ``` Ответом должен быть адрес **из подсети клиента**. Если ответа нет — раздел 12. **Открой порты в межсетевом экране**, если он включён. Проверь: ```bash ufw status 2>/dev/null || iptables -L -n | head -20 ``` Нужны порты прокси (1080–1084 или свои), `api_port_https` (8443) и, если включён MITM, его порт. --- ## 11. Что выдать человеку в конце ### 11.1. Если человек решил донастроить сам Программа установлена, но **не запущена**. Передай ему: - что осталось заполнить в `/etc/oxidproxy/config.yaml` — перечисли конкретные поля из раздела 5.1, которые ты не заполнил; - нужно ли ему ещё прописать подсети в `/etc/rc.local` (раздел 6); - сгенерированные тобой значения, если ты успел их вписать; - команды из списка ниже. Предупреди: пока в конфиге остаются подставные значения из шаблона, служба либо не запустится, либо запустится вхолостую. ### 11.2. Если развёртывание доведено до конца **Проверь ссылку прежде, чем отдавать.** Строка должна не просто собираться из кусков, а действительно открывать панель: ```bash curl -sk -o /dev/null -w '%{http_code}\n' \ "https://:8443/dashboard?token=" ``` Должно быть `200`. Если код другой — ссылку не отдавай, иди в раздел 12. Затем выдай одним сообщением: **Панель управления** ``` https://:8443/dashboard?token= ``` Сертификат самоподписанный — браузер один раз покажет предупреждение, с ним надо согласиться. Токен даёт полный доступ к API и панели, храните его как пароль. **Полезные команды на сервере** ```bash # полная ссылка на панель, если потерялась dashboard-url # журнал: последние события journalctl -u oxidproxy -n 50 --no-pager # журнал в реальном времени journalctl -u oxidproxy -f # только ошибки за сутки journalctl -u oxidproxy --since -1d -p err --no-pager # состояние службы systemctl status oxidproxy # перезапуск после правки конфигурации oxidproxy -t /etc/oxidproxy/config.yaml && systemctl restart oxidproxy # какие порты слушаются ss -tlnp | grep oxidproxy # проверить, из какого адреса выходит трафик curl -s -x "socks5h://ЛОГИН:ПАРОЛЬ@:1080" https://ipv6.icanhazip.com/ ``` Отдельно скажи: **при входе по SSH под root показывается баннер** — состояние службы, загруженное ядро, подсети и адрес панели. Это самый быстрый способ понять, жив ли сервер. Учётные записи создаются и выдаются **через панель управления** — файлы в `/var/lib/oxidproxy/` руками открывать не нужно. Логин и пароль сервисной учётной записи для чекеров и мониторинга: `checker` и сгенерированный тобой пароль; ей доступен только домен `ifconfig.me`. --- ## 12. Если что-то не получилось | Признак | Причина и что делать | |---|---| | В журнале `rejected (hwid_mismatch)` | Ключ привязан к другой машине. Пусть клиент обратится в поддержку за перепривязкой. Сам не чини. | | В журнале `rejected` с другой причиной | Ключ неверный или истёк. Проверь, что ключ скопирован целиком, без пробелов. | | `uname -r` без `oxidproxy-p0f` | Загрузилось не то ядро. Проверь `ls /boot/vmlinuz-*` и `GRUB_DEFAULT=0` в `/etc/default/grub`, затем `update-grub` и перезагрузка. | | Служба «работает», портов нет | Почти всегда лицензия. Смотри журнал, раздел 10. | | Запрос через прокси не проходит | Проверь маршрут: `ip -6 route show table local`. Если подсети там нет — раздел 6. Затем проверь, что сервер вообще имеет IPv6-связность: `curl -6 -s https://ipv6.icanhazip.com/`. | | `oxidproxy -t` ругается на `accounts_file` | Если файлов будет несколько, в имени обязаны присутствовать все три переменные: `[os]`, `[mode]`, `[port]`. | | Панель не открывается снаружи | Порт `8443` закрыт межсетевым экраном или у хостера. | ### Подсеть выдана, но не маршрутизирована на сервер Отдельный случай. Выглядит как поломка программы, но ею не является. Признаки складываются так: - маршрут добавлен, `ip -6 route show table local` подсеть показывает; - порты слушаются, в журнале ошибок нет; - запрос через прокси (раздел 10) молча не проходит; - и главное: **у самой машины нет собственного адреса IPv6** — `ip -6 addr show scope global` пусто либо там только `fe80::`. Значит, хостер выдал подсеть «на сегмент», а не маршрутом на сервер: пакеты доходят до соседнего маршрутизатора, тот спрашивает по соседству «чей это адрес?» — а отвечать некому. Настройками программы это не чинится. Два выхода, оба вне её. **1. Правильный — попросить хостера маршрутизировать подсеть на сервер** (routed, а не on-link). Многие делают это по запросу, и тогда ничего дополнительно ставить не нужно. **2. Обходной — поднять демон NDP-прокси**, чтобы он отвечал на соседские запросы вместо нас. ```bash apt-get install -y ndppd ``` `/etc/ndppd.conf` — подставь свой интерфейс и свою подсеть: ``` route-ttl 30000 proxy eth0 { router no timeout 500 ttl 30000 rule 2a05:fb42:28e::/48 { static } } ``` ```bash systemctl enable --now ndppd ``` Две вещи, которые нельзя брать наугад: - **`eth0` — это имя внешнего интерфейса**, и оно часто другое. Посмотри `ip -6 route show default` либо `ip -o link`. Ошибёшься — демон запустится и будет молчать. - **`router no`, а не `yes`.** Наш сервер не маршрутизатор, он лишь отзывается за адреса подсети. С `yes` он начнёт объявлять себя маршрутизатором в чужой сети. Каждую подсеть клиента прописывай **отдельным блоком `rule`**. **Агент: сам не ставь — сначала спроси.** Покажи человеку вывод `ip -6 addr show scope global` и `ip -6 route show`, назови диагноз и оба варианта. Второй трогает сетевую конфигурацию сервера и может быть запрещён правилами хостера, поэтому делай его только по прямому согласию. --- Если ничего не помогло — собери вывод `journalctl -u oxidproxy -n 100 --no-pager` и `oxidproxy -V` и передай в поддержку: support@oxidproxy.com --- ## Чего делать НЕ надо - Не включай `mitm_accept_invalid_certs` — это отладочный флаг, он снимает проверку подлинности сервера. - Не меняй `tcp_congestion`, `tcp_window_size`, `latency_base_ms` и `tos` в листенерах. Это тонкая настройка сетевого поведения; наугад её менять вредно. - Не вписывай `jitter_ms`. С версии 2.2.0 он не применяется вовсе: ключ принимается ради совместимости старых конфигов, но при запуске служба пишет о нём предупреждение в журнал. Если увидишь его в чужом конфиге — это не ошибка, трогать не надо. - Не оставляй `master_token` из шаблона. - Не публикуй содержимое `config.yaml` — там лицензионный ключ и токен.