# Qeli — установка и начало работы (пошагово) > **Документация описывает 0.7.13** — последний выпущенный релиз. Что именно установлено > у вас, покажет `qeli --version`. Полное руководство «с нуля»: от поднятия сервера до заведения пользователей с маршрутами и подключения первого клиента — **и через CLI, и через веб-панель**. Рассчитано на чистый **Linux-сервер** (Debian/Ubuntu) с root-доступом. Все команды сервера — от root (или через `sudo`). > Справочники, на которые опирается этот гайд: > [CONFIG.md](CONFIG.md) — все ключи конфига · [PANEL.md](PANEL.md) — веб-панель · > примеры конфигов: [`server.conf`](../../qeli/config/server.conf) · > [`users.conf`](../../qeli/config/users.conf) · [`client.conf`](../../qeli/config/client.conf). ## Содержание 1. [Что понадобится](#1-что-понадобится) 2. [Установка сервера](#2-установка-сервера) 3. [Первичная настройка сервера (CLI)](#3-первичная-настройка-сервера-cli) 4. [Запуск и проверка](#4-запуск-и-проверка) 5. [Full-tunnel: NAT (настраивается автоматически)](#5-full-tunnel-nat-настраивается-автоматически) 6. [Заведение пользователей (CLI)](#6-заведение-пользователей-cli) 7. [Маршруты: split/full-tunnel, pushed-маршруты, ACL, статический IP](#7-маршруты) 8. [Подключение клиента](#8-подключение-клиента) 9. [То же самое через веб-панель](#9-то-же-самое-через-веб-панель) 10. [Справочник CLI и диагностика](#10-справочник-cli-и-диагностика) 11. [Wire-режимы — какой выбрать](#11-wire-режимы--какой-выбрать) 12. [Частые проблемы](#12-частые-проблемы) 13. [Полное удаление qeli](#13-полное-удаление-qeli) --- ## 1. Что понадобится - **Сервер** Linux x86-64 (**Debian 11+ / Ubuntu 20.04+**), root, публичный IP. `.deb` — портируемая сборка (`make deb-portable`, gate `check-abi`); зависимости пакета: `libc6 >= 2.28`, `libgcc-s1`, `iptables`, `iproute2`, `libcap2-bin`. Ставится «из коробки» на Debian 11/12 и Ubuntu 20.04/22.04/24.04. **Debian 10 (Buster) не подходит**: там пакет называется `libgcc1`, а `libgcc-s1` появился только в Debian 11, поэтому `apt` откажет по зависимости. Для Buster и систем с glibc < 2.28 остаются вариант B (сборка из исходников на самой машине) или вариант C (Docker — рантайм внутри образа). - **Открытый порт** под VPN (по умолчанию TCP `443`) и, если включаете панель, её порт (по умолчанию `8080`). В облачном файрволе/Security Group откройте их. - Ядро с поддержкой **TUN** (`/dev/net/tun` — есть почти везде; на некоторых VPS включается в панели провайдера). - Пакеты `iproute2`, `iptables`, `libcap2-bin` (тянутся зависимостью .deb). - **Клиент**: телефон (Android), десктоп (Windows/macOS) или Linux-CLI. Один бинарь `qeli` совмещает обе роли: `qeli server` и `qeli client`. --- ## 2. Установка сервера > ⚡ **Самый быстрый путь (всё за одну команду).** В корне репозитория есть готовый > установщик [`install-qeli-server.sh`](../../install-qeli-server.sh): ставит qeli и его > зависимости, **спрашивает профиль** — `reality-tls` (по умолчанию; настоящий TLS 1.3 на > TCP:443, держит активный пробинг), `fake-tls` (дешевле по CPU, хватает против пассивного > DPI) или **`udp-quic`** (UDP-путь с датаграммами под QUIC — берите там, где TCP:443 > режут, сбрасывают или он иначе деградирует) — > **и порт** (по умолчанию :443), поднимает его с full-tunnel NAT и заводит > **5 пользователей** с готовыми `qeli://`-строками в `/etc/qeli/client-links/`. > Запуск от root: `./install-qeli-server.sh <публичный-IP-или-домен>` (или > `sudo …`, если `sudo` установлен — он не обязателен и не ставится). Скачивайте скрипт > отдельно и запускайте вторым шагом — `curl … | bash` не используем: скрипт работает от > root и его стоит прочитать до запуска, а `curl -fsSL` на HTTP-ошибке молчит, и `bash` с > пустым stdin выходит с кодом 0 (сорвавшаяся загрузка выглядит как успешная установка). > Для неинтерактивной установки (автоматизация) задайте выбор заранее: > `QELI_PROFILE=udp-quic QELI_PORT=443 ./install-qeli-server.sh `. Дальше > остаётся только вставить строку подключения в приложение. Ручная установка по шагам — > ниже. > > **Что он делает, по порядку:** ① ставит зависимости (`curl`, `jq`, `iptables`, > `iproute2`, `openssl`) → ② заносит qeli на машину **и настраивает ровно то же, что > `.deb`** (системный пользователь `qeli`, `/etc/qeli` + каталоги состояния, > `*.conf.example`, systemd-юнит, polkit-правило) → ③ пишет `/etc/qeli/server.conf` с > выбранным профилем на выбранном порту + full-tunnel NAT (для reality-tls — свежий > `short_id`) → ④ генерирует identity-ключ профиля → ⑤ заводит 5 пользователей и > сохраняет их `qeli://`-ссылки → ⑥ применяет тюнинг ОС под mobile/LTE (BBR + PMTU, плюс > внешний MSS-clamp на TCP-профилях) → ⑦ включает веб-панель по HTTPS со сгенерированным > паролем → ⑧ `systemctl enable --now qeli`. > > **От какого пользователя работает служба** — `QELI_RUN_AS=qeli` (по умолчанию, без привилегий) > или `QELI_RUN_AS=root`. Установщик применяет выбор через `qeli set-service-user` (§10.4) > прямо перед первым стартом, поэтому служба сразу поднимается от нужного пользователя: > ```bash > sudo QELI_RUN_AS=root ./install-qeli-server.sh # без разделения привилегий — см. §10.4 > ``` > Без явной причины оставляйте значение по умолчанию; предупреждение из §10.4 в силе. > > **Две ветки установки (шаг ②) — обе дают идентичную систему:** > - **По умолчанию — скачать `.deb`** из GitHub Releases, проверить его SHA256 и > `apt install`. Обычный путь, ничего дополнительно передавать не нужно. > - **Из готового бинаря — `QELI_BIN=<путь>`:** вместо скачивания ставит этот бинарь и > **сам воспроизводит раскладку .deb** (пользователь, каталоги, `*.conf.example`, > `qeli.service`, polkit-правило `49-qeli.rules`). Для **сборки из исходников** или > **air-gapped**. Добавьте `QELI_SRC=<чекаут репо>`, чтобы копировать юнит и примеры > прямо из исходников (полностью офлайн); без него они тянутся с GitHub. Пример: > ```bash > sudo QELI_BIN=qeli/target/release/qeli QELI_SRC=. ./install-qeli-server.sh > ``` > > **Что ещё он меняет на хосте** (это не побочные мелочи — знайте о них заранее): > - **Тюнинг сети всей системы**: пишет `/etc/sysctl.d/99-qeli-perf.conf` и переключает > congestion control на **BBR** — это влияет на **весь** TCP хоста, не только на qeli. > Там же поднимаются буферы сокетов по умолчанию (`net.core.rmem_default`/`wmem_default` > до 4 МБ) — без этого UDP-профили теряют пакеты, потому что у UDP нет автотюнинга и он > остаётся на 208 КБ. Это тоже общесистемные значения. > - **Загружает модуль `tcp_bbr` при каждой загрузке** через `/etc/modules-load.d/qeli-bbr.conf`. > - **Ставит MSS-правило** (только TCP-профили — udp-quic его пропускает) в > `mangle/OUTPUT` и пытается **сохранить firewall**. Если > `netfilter-persistent` нет — делает снимок в `/etc/iptables/rules.v4`, причём > **всего текущего ruleset хоста**, а не только своего правила. > **Сохранение — best-effort, а не гарантия.** Все шаги идут с `|| true`, то есть > молча продолжают при неудаче. И сам по себе файл `/etc/iptables/rules.v4` ничего не > восстанавливает: его читает при загрузке пакет `iptables-persistent` > (`netfilter-persistent`), и **без него после ребута MSS-правила не будет**. Проверьте > после первой перезагрузки: `iptables -t mangle -S OUTPUT | grep TCPMSS` — если пусто, > поставьте `iptables-persistent` или повесьте правило своим unit'ом. > Симптом отсутствия клэмпа — загрузки, встающие «намертво» у мобильных клиентов. > - **Включает веб-панель по HTTPS и открывает её на `0.0.0.0:8080`**, сгенерировав > пароль и показав его **один раз** в конце вывода. Это единственный момент, когда > пароль виден — сохраните его сразу. Если панель вам не нужна, выключите её после > установки (`[web] enabled = false`) или не открывайте 8080 в облачном файрволе. > - Кладёт `/etc/qeli/client-links/CONNECTION-STRINGS.txt` — там **пароли пяти > пользователей открытым текстом** (каталог `0700`, файлы `0600`). > - Если публичный адрес не задан аргументом — определяет его, обратившись к внешним > сервисам (`api.ipify.org`, `ifconfig.me`, `icanhazip.com`). > > Всё это снимается — см. §13 «Полное удаление». ### Вариант A — .deb-пакет (рекомендуется) #### A.1. Скачать пакет **в `/tmp`** Качайте `.deb` именно в `/tmp` (или другой каталог, читаемый всеми), а **не** в `/root` и не в домашний каталог: ```bash cd /tmp curl -fLO https://github.com/litvinovtd/qeli/releases/download/v0.7.13/qeli_0.7.13_amd64.deb # или scp с рабочей машины: scp qeli_0.7.13_amd64.deb root@server:/tmp/ ``` > **Почему `/tmp`.** `apt` скачивает и распаковывает от имени служебного пользователя > `_apt`, а `/root` и домашние каталоги ему недоступны. Из `/root` установка проходит, но > с предупреждением: > ``` > N: Download is performed unsandboxed as root as file '/root/qeli_0.7.13_amd64.deb' > couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied) > ``` > Это именно предупреждение (apt откатывается на работу от root), но из `/tmp` его > просто не будет. #### A.2. Установить ```bash sudo apt install /tmp/qeli_0.7.13_amd64.deb # ставит и подтягивает зависимости ``` Указывайте **полный путь** (или `./имя.deb`) — без слэша apt будет искать пакет с таким именем в репозиториях. Альтернатива, если apt по какой-то причине недоступен: ```bash sudo dpkg -i /tmp/qeli_0.7.13_amd64.deb sudo apt-get -f install -y # доустановить зависимости (iproute2, iptables, libcap2-bin) ``` Что делает пакет: - кладёт бинарь в `/usr/bin/qeli` (`0755 root:root`, **без** file-capabilities — с 0.7.12 `setcap` намеренно снимается: права даёт systemd-юнит через `AmbientCapabilities` `CAP_NET_ADMIN`/`CAP_NET_RAW`/`CAP_NET_BIND_SERVICE`, а с `NoNewPrivileges=true` ядро file-caps всё равно игнорирует); - создаёт системного пользователя **`qeli`** и каталоги `/etc/qeli`, `/var/log/qeli`, `/var/lib/qeli`, затем делает им `chown -R qeli:qeli`; - создаёт пустой `/etc/qeli/users.conf` (пример с известным хешем НЕ подкладывается); - ставит **примеры** `/etc/qeli/{server,server-multiprofile,users,client,client-reality}.conf.example` (рабочие конфиги вы создаёте сами — шаг 3); - ставит systemd-юнит `qeli.service` (`ExecStart=/usr/bin/qeli server --config /etc/qeli/server.conf`) и polkit-правило `/etc/polkit-1/rules.d/49-qeli.rules`; - **спрашивает, от какого ОС-пользователя работать службе** (вопрос debconf `qeli/run-as`: `qeli` — по умолчанию, без привилегий — или `root`) и применяет ответ через `qeli set-service-user`. Неинтерактивно (автоматизация / preseed): ```bash echo "qeli qeli/run-as select root" | sudo debconf-set-selections sudo apt install /tmp/qeli_0.7.13_amd64.deb ``` Изменить можно в любой момент позже — `sudo qeli set-service-user root|qeli` (§10.4), там же расписаны размены варианта `root`. #### A.3. Права на `/etc/qeli` — обязательный шаг после настройки **Это самая частая причина «установил, а ничего не работает».** Служба работает под `User=qeli` (см. `qeli.service`) и **пишет внутрь `/etc/qeli`** — там генерируются identity-ключи профилей (`/etc/qeli/identity/.key`), туда сохраняет пользователей `add-client` и веб-панель, там же `usage.json`. Под это в юните специально разрешён `ReadWritePaths=/etc/qeli`. `postinst` выставляет владельца **в момент установки**, но всё, что вы **создадите** после — под root, — останется root-овым: ```bash sudo cp /etc/qeli/server-multiprofile.conf.example /etc/qeli/server.conf # → root:root sudo qeli show-identity --config /etc/qeli/server.conf # создаёт identity/ от root ``` > **Что изменилось в 0.7.13.** Раньше под ловушку попадала и **перезапись существующего** > файла: атомарная запись делает `rename`, а он подставляет новый inode, принадлежащий тому, > кто пишет, — поэтому один `sudo qeli add-client` переводил уже правильный > `users.conf` из `qeli:qeli` в `root:root`, и следом ломалась панель (файл блокировки > создаётся с владельцем охраняемого файла). Теперь запись сохраняет владельца заменяемого > файла, так что этот сценарий закрыт. **Создание новых файлов и каталогов от root ловушкой > быть не перестало** — всё, что ниже, по-прежнему нужно. После этого служба под `qeli` не сможет писать в эти файлы. Поэтому **после создания конфига и любых CLI-команд под root** приведите права в порядок: ```bash sudo chown -R qeli:qeli /etc/qeli sudo chmod 755 /etc/qeli sudo chmod 640 /etc/qeli/server.conf /etc/qeli/users.conf # в них хеши паролей и ключи [ -d /etc/qeli/identity ] && sudo chmod 700 /etc/qeli/identity && sudo chmod 600 /etc/qeli/identity/*.key sudo systemctl restart qeli ``` > **Как не наступать на это вовсе** — запускайте CLI сразу от имени `qeli`: > ```bash > sudo -u qeli qeli add-client alice --config /etc/qeli/server.conf > ``` > Тогда всё создаётся с правильным владельцем и `chown` не нужен. Каталоги `/var/lib/qeli`, `/var/log/qeli` и `/run/qeli` (control-сокет) systemd создаёт и раздаёт сам через `StateDirectory`/`LogsDirectory`/`RuntimeDirectory` — их трогать не нужно. **Признаки, что права всё-таки не те** (проверять `journalctl -u qeli -n 50 --no-pager`): - `Permission denied` / `EROFS` при генерации identity — профиль не поднимается на свежей установке; - `add-client` отработал, но пользователь «пропал» после рестарта — запись в users-файл не сохранилась; - панель сохраняет настройки без ошибки, но после рестарта они прежние; - служба уходит в рестарт-петлю (`systemctl status qeli` → `NRestarts` растёт). #### A.4. Проверить установку ```bash qeli --version systemctl status qeli --no-pager ls -la /etc/qeli # владелец всего — qeli:qeli journalctl -u qeli -n 30 --no-pager # ошибок прав быть не должно ``` ### Вариант B — сборка из исходников Нужен Rust (stable). В корне репозитория: ```bash cd qeli cargo build --release --features jemalloc # бинарь → qeli/target/release/qeli # --features jemalloc обязателен для СЕРВЕРНОГО бинаря: без него RSS воркера # упирается в ~180 МБ под churn'ом хендшейков (glibc держит освобождённые арены) # вместо ~40–60 МБ с jemalloc. Клиенту это не нужно. # (опц.) собрать свой .deb из свежего бинаря (Makefile уже включает jemalloc): make -C debian deb # → qeli/debian/qeli_<версия>_amd64.deb ``` Без пакета можно запускать бинарь напрямую (см. шаг 4), но тогда systemd-юнит, пользователя и каталоги создаёте вручную — **или поручите это установщику**: он из свежесобранного бинаря воспроизведёт точную раскладку `.deb` (пользователь `qeli`, `/etc/qeli` + каталоги состояния, `*.conf.example`, `qeli.service`, polkit-правило) без всякого скачивания. Из корня репо: ```bash sudo QELI_BIN=qeli/target/release/qeli QELI_SRC=. ./install-qeli-server.sh <публичный-IP> ``` `QELI_BIN` выбирает ветку установки из бинаря; `QELI_SRC=.` копирует юнит и примеры прямо из этого чекаута (полностью офлайн). См. §2 **«Две ветки установки»**. Заодно ставит и polkit-правило, поэтому кнопка панели `Apply & Restart` работает без отдельного шага ниже. > ⚠️ **Установка не из .deb + веб-панель:** кнопка панели **`Apply & Restart`** выполняет > `systemctl restart` сервиса. **Non-root** сервис `User=qeli` может это делать только с > polkit-правилом. `.deb` (Вариант A) ставит его сам; при ручной/бинарной установке добавьте > его один раз, под root: > ```bash > sudo qeli install-polkit # → /etc/polkit-1/rules.d/49-qeli.rules (см. §10.4) > ``` > Без этого `Apply & Restart` сообщит, что правила нет (молча больше не падает). В > **контейнере** systemctl недоступен вовсе — панель применяет изменения профилей через > перезапуск воркера в процессе, а изменения сокета панели (`web.bind`/`port`/`tls`) > требуют пересоздания контейнера (`docker restart`). ### Вариант C — Docker **Мульти-арч** образ (`linux/amd64`, `linux/arm64`, `linux/arm/v7`) несёт **обе роли** (`qeli server` и `qeli client`) со всеми рантайм-зависимостями внутри (`iproute2`, `iptables`, CA-сертификаты) — работает на любом Linux-хосте и в контейнерных рантаймах роутеров (MikroTik RouterOS v7, OpenWrt). Контейнеру нужны `/dev/net/tun` и три capability — `NET_ADMIN` (TUN, маршруты, iptables), `NET_RAW` и `NET_BIND_SERVICE` (привязка к портам < 1024); готовый `docker-compose.yml` (сервер + опц. gateway-клиент) в комплекте. Сборка/запуск, пример compose и нюансы: > 🐳 **[release/docker/README.md](../../release/docker/README.md)** С Docker остальные шаги установки/systemd из этого гайда можно пропустить; управление профилями и пользователями ниже (CLI или веб-панель) внутри контейнера работает так же. > **Права в контейнере устроены иначе — и §A.3 к нему не относится.** В образе нет > директивы `USER` и сброса привилегий в entrypoint, поэтому **процесс внутри контейнера > работает от root**. Отсюда три следствия: > - Разделения привилегий, ради которого на хосте существует пользователь `qeli`, здесь > **нет**: компрометация демона — это root внутри контейнера (не на хосте, но с выданными > `NET_ADMIN`/`NET_RAW` граница тоньше, чем кажется). Не выставляйте панель наружу без > пароля и `web.allowed_ips`. > - Ловушки с владельцем `/etc/qeli` **не возникает** — всё внутри и так пишется от root. > Но файлы в примонтированном томе появятся на хосте с uid 0; если тот же каталог потом > отдать хостовой службе под `User=qeli`, права придётся привести в порядок вручную. > - Хуки `post_up`/`post_down` в контейнере действительно исполняются **от root** (в отличие > от `.deb`-установки, где это `qeli`). > > Перезапуск службы из панели в контейнере **не работает** и не пытается: systemd внутри > нет. Профили/пользователи/DNS/NAT применяются рестартом worker'а автоматически, а > изменения сокета панели (`web.bind`/`web.port`/`web.tls*`/`web.enabled`) требуют > пересоздания контейнера снаружи — см. §6.11 в > [TROUBLESHOOTING.md](TROUBLESHOOTING.md). --- ## 3. Первичная настройка сервера (CLI) ### 3.1. Создать рабочий конфиг из примера ```bash sudo cp /etc/qeli/server.conf.example /etc/qeli/server.conf sudo nano /etc/qeli/server.conf ``` Формат — **flat-INI**. Файл-пример **исчерпывающий**: каждый ключ перечислен со значением по умолчанию и пояснением; любой удалённый ключ берёт дефолт. Для старта достаточно проверить несколько полей в секции `[profile:tcp]`. ### 3.2. Минимально нужные поля профиля ```ini [profile:tcp] enabled = true # на чём слушаем (порт должен быть открыт в файрволе) bind.address = 0.0.0.0 bind.port = 443 # tcp | udp bind.transport = tcp # виртуальная сеть туннеля # адрес сервера внутри туннеля (шлюз) tun.address = 10.9.0.1 tun.netmask = 255.255.255.0 # пушится клиентам; для прод-TCP см. §12 и CONFIG.md tun.mtu = 1400 # пул адресов, которые раздаются клиентам pool.cidr = 10.9.0.0/24 # никогда не выдавать шлюз pool.exclude = 10.9.0.1 # режим маскировки на проводе (см. §11) obf.mode = fake-tls ``` Остальное (DNS-прокси, padding, heartbeat, лимиты) уже задано разумными дефолтами в примере. Полное описание каждого ключа — [CONFIG.md](CONFIG.md). > **Несколько профилей.** Можно держать рядом второй интерфейс, например UDP на > `:1443` — добавьте секцию `[profile:udp]` (свой `tun.name`/`tun.address`/`pool.cidr`/ > `bind.port`/`bind.transport = udp`). У каждого профиля — свой identity-ключ и свой пул. > Готовый шаблон **со всеми 10 режимами сразу** (reality-tls на :443, остальные на > 8443–8451) — `/etc/qeli/server-multiprofile.conf.example` (его ставит .deb; > в исходниках — [`config/server-multiprofile.conf`](../../qeli/config/server-multiprofile.conf)): > скопируйте его в `server.conf`, оставьте нужные профили, замените `CHANGEME`-ключи. ### 3.3. Пользователи: где они живут По умолчанию пользователи живут в **отдельном файле** — `auth.users_file` (по умолчанию `/etc/qeli/users.conf`). Примеры конфигов идут **без** инлайн-юзеров; заводите их командой `qeli add-client` (шаг 6) — она допишет их в этот файл. Больше ничего делать не нужно. > Можно вместо этого держать пользователей инлайн в `server.conf` секциями `[user:*]`, > но тогда `auth.users_file` **игнорируется целиком** (инлайн имеет приоритет) — так что > не задавайте оба, иначе сервер выдаёт предупреждение, а файл молча отбрасывается. > Рекомендуемый вариант по умолчанию — отдельный файл; `[user:*]` в `server.conf` не держите. --- ## 4. Запуск и проверка **Сначала проверьте конфиг** — это ловит опечатки в ключах (о которых предупреждают §3.1 и §12: неверный ключ молча остаётся с дефолтом) и ключи, убранные в 0.7.12: ```bash sudo qeli check-config --config /etc/qeli/server.conf # сервер (rc≠0 = не запускать) qeli check-config --config ~/qeli-client.conf --client # клиентский конфиг ``` Затем запуск: ```bash sudo systemctl enable --now qeli # запустить + автозапуск при бутe systemctl status qeli # должно быть active (running) journalctl -u qeli -f # живой лог (Ctrl-C — выйти) ``` В логе при старте должны появиться `Profile 'tcp': TUN vpn0 is up`, `listening on 0.0.0.0:443`, и строка с публичным ключом профиля. ### Получить identity-ключ сервера (для пиннинга на клиенте) ```bash sudo qeli show-identity --config /etc/qeli/server.conf ``` ``` PROFILE BIND SERVER PUBLIC KEY (pin on client) tcp tcp://0.0.0.0:443 33f399e6d9b8a31a41e5ffa8b1e1ce457f10d8bbf07c145377fcb7917d532450 ``` Этот hex-ключ клиент **пинит** (`key = …`). Команда создаёт ключи профилей, если их ещё нет (`/etc/qeli/identity/.key`). > **Почему пиннинг обязателен.** По умолчанию включён **H-1** > (`auth.bind_static_to_session = true`): сессионные ключи привязаны к статической > личности сервера, поэтому клиент **обязан** пинить реальный ключ (иначе сервер его > отвергнет). Ссылка `qeli://`, выданная командой `add-client --link` (шаг 6), уже > содержит этот ключ — пользователю ничего вручную вписывать не нужно. После изменения конфига примените его: `sudo systemctl restart qeli`. --- ## 5. Full-tunnel: NAT (настраивается автоматически) Нужно, только если хотите гнать **весь интернет-трафик клиента** через сервер (full-tunnel / «выходная нода»). Для split-tunnel (доступ лишь к подсети туннеля и ресурсам за сервером) — пропустите. Достаточно включить один тумблер в профиле — сервер **сам** через `iptables` включит IP-форвардинг и поставит MASQUERADE + FORWARD + MSS-clamp, а при остановке снимет правила: ```ini # в [profile:tcp] routing.nat.enabled = true # WAN-интерфейс наружу. Оставьте пустым/по умолчанию — определится автоматически # (ip route get 1.1.1.1); либо задайте явно, напр. ens3. routing.nat.interface = ``` ```bash sudo systemctl restart qeli # сервер применит NAT при старте профиля journalctl -u qeli | grep NAT # "NAT masquerade active via iptables (10.9.0.0/24 -> ens3)" sudo iptables-save | grep qeli-nat # увидеть установленные правила ``` Что именно ставит сервер (правила помечены comment'ом `qeli-nat:<профиль>`, чтобы снять ровно их при выключении/остановке): `net.ipv4.ip_forward=1`; `-t nat POSTROUTING -s -o -j MASQUERADE`; две `FORWARD … ACCEPT` (tun↔wan); две `-t mangle FORWARD … TCPMSS --set-mss (tun.mtu−40)` (защита от PMTU-чёрной дыры). > ⚠️ **Требуется `iptables`** (пакет `iptables`). У .deb он в зависимостях, так что при > установке пакетом уже стоит. Если `iptables` **не установлен**, NAT применить нельзя: > в логе сервера будет `ERROR … routing.nat.enabled is set but NAT was NOT applied`, а в **веб-панели** > (Dashboard) — жёлтый баннер с подсказкой. Поставить: `sudo apt install iptables`. > Используется только классический `iptables` (не `nft`/`ufw`). > Прод-тюнинг (BBR, буферы, MTU-probing — заметно ускоряет TCP на мобильных) описан в > [CONFIG.md → «Тюнинг ОС сервера»](CONFIG.md). Для full-tunnel настоятельно примените. > Чтобы правила NAT пережили перезагрузку без сервиса qeli, можно дополнительно > сохранить их (`apt install iptables-persistent`), но обычно qeli ставит их сам при > старте. --- ## 6. Заведение пользователей (CLI) ### 6.1. Простой пользователь ```bash sudo qeli add-client alice --password 's3cret' sudo systemctl restart qeli # перечитать пользователей ``` Команда Argon2id-хеширует пароль и дописывает секцию `[user:alice]` в users-файл. Без `--password` сгенерирует случайный и **напечатает его один раз**. ### 6.2. С опциями ```bash sudo qeli add-client bob \ --password 'pass123' \ --static-ip 10.9.0.50 \ # фиксированный IP в туннеле --max-sessions 3 \ # сколько устройств одновременно (0 = без лимита) --profiles tcp # доступ только к профилю tcp (изоляция интерфейсов) ``` | Опция | Назначение | |---|---| | `--password

` | пароль (иначе случайный, печатается один раз) | | `--static-ip ` | постоянный адрес в туннеле (иначе из пула) | | `--max-sessions ` | лимит одновременных **устройств** (0 = наследовать группу/без лимита) | | `--profiles a,b` | разрешённые профили (пусто = все) | | `--link --host ` | сразу напечатать `qeli://`-ссылку + QR (см. ниже) | | `--link-profile

` | для какого профиля строить ссылку (по умолчанию первый) | ### 6.3. Сразу выдать `qeli://`-ссылку / QR ```bash sudo qeli add-client carol --password 'pw' --link --host vpn.example.com:443 --link-profile tcp ``` Печатает готовую `qeli://…`-ссылку (с уже **вшитым ключом сервера**, режимом, SNI) и QR-код в терминале — пользователь сканирует его в мобильном клиенте и подключается в один тап. Ничего вручную вписывать не нужно. ### 6.4. Тонкая настройка вручную (опционально) Любые поля можно дописать прямо в секцию `[user:*]` (см. комментарии в [`users.conf`](../../qeli/config/users.conf)): ```ini [user:bob] # ставит add-client password_hash = $argon2id$v=19$m=...$... enabled = true static_ip = 10.9.0.50 max_sessions = 3 profiles = tcp # ACL: куда этому юзеру можно (пусто = куда угодно) allowed_networks = 10.9.0.0/24, 192.168.1.0/24 # лимит скорости (0 = без лимита) bandwidth.limit_mbps = 50 bandwidth.burst_mbps = 100 # персональный pushed-маршрут (повторяемо) route = 10.20.0.0/16 gateway=10.9.0.1 metric=100 # унаследовать из [group:premium] group = premium ``` Группы — шаблоны для повторяющихся настроек: ```ini [group:premium] bandwidth_limit_mbps = 100 max_sessions = 5 allowed_networks = 0.0.0.0/0 ``` После правок users-файла — `sudo systemctl restart qeli` (или примените живой командой, §10, без перезапуска). --- ## 7. Маршруты ### 7.1. Split-tunnel (по умолчанию) Клиент по умолчанию заворачивает в туннель только **подсеть туннеля** (`pool.cidr`). Остальной трафик идёт мимо VPN. Ничего настраивать на сервере не нужно. ### 7.2. Full-tunnel (весь трафик через сервер) Включается **на клиенте** (`gateway = true` в `client.conf` / тумблер в приложении), а на сервере требует NAT+форвардинг из **§5**. Тогда весь интернет клиента выходит с IP сервера. ### 7.3. Pushed-маршруты на уровне профиля (всем клиентам профиля) Чтобы открыть клиентам доступ к сети **за сервером** (напр. офисной `192.168.50.0/24`), сервер «пушит» маршрут — клиент сам добавит его в таблицу при подключении: ```ini # в [profile:tcp] — повторяемо route = 192.168.50.0/24 gateway=10.9.0.1 metric=100 ``` `gateway` — адрес сервера в туннеле (`tun.address`). `metric` — приоритет (опц.). Форвардинг RFC1918-сетей за сервером (`routing.forward_private`) **включён по умолчанию**; поставьте `false`, чтобы запретить. ### 7.4. Персональные маршруты (конкретному пользователю) Тот же синтаксис, но в секции `[user:*]` — пушится только этому пользователю: ```ini [user:bob] route = 10.20.0.0/16 gateway=10.9.0.1 metric=100 ``` ### 7.5. ACL назначения (`allowed_networks`) Ограничивает, **куда** пользователю можно ходить через туннель (whitelist dst-CIDR). Пусто/нет ключа = без ограничений: ```ini [user:bob] allowed_networks = 10.9.0.0/24, 192.168.1.0/24 ``` ### 7.6. Клиент-клиент и статические адреса ```ini # в [profile:tcp] # разрешить клиентам видеть друг друга в туннеле routing.client_to_client = true # закрепить IP за юзером (альтернатива user.static_ip) pool.reservation.alice = 10.9.0.100 ``` ### 7.7. DNS-через-туннель Важно различать **два разных механизма** — это частый источник путаницы: 1. **Встроенный DNS-прокси** (`dns.enabled` / `dns.listen` / `dns.upstream`) — сервер поднимает резолвер на `tun.address:53` (кэш, блоклист) и форвардит запросы на upstream. 2. **Какой DNS выдаётся клиентам** (`dns.push_servers`) — адрес(а), которые клиент пропишет себе. Это **отдельный** ключ. Что сервер реально пушит клиенту (`server/handler.rs`): | `dns.push_servers` | `dns.enabled` | Клиент получает | Итог | |---|---|---|---| | задан (напр. `1.1.1.1`) | — | первый адрес из списка | клиент ходит на него **напрямую**, мимо прокси (кэш/блоклист не действуют) | | пусто | `true` | `dns.listen` (адрес прокси) | клиент → прокси на сервере → upstream. **Так по умолчанию.** | | пусто | `false` | ничего | клиент оставляет свои резолверы | ```ini # в [profile:tcp] — вариант «клиенты через мой прокси» (рекомендуется) dns.enabled = true dns.upstream = 1.1.1.1, 8.8.8.8 # dns.blocklist = ads.example.com, track.example.com # отдавать 0.0.0.0 (блок рекламы) dns.push_servers = "" # пусто → клиентам выдаётся адрес прокси (tun.address) # ...или «раздать клиентам готовый резолвер напрямую» (LAN / AdGuard / NextDNS): # dns.push_servers = 192.168.50.10 # прокси при этом можно и не включать ``` > Если в панели видите в поле «Передавать DNS клиентам» непустое значение, но клиент всё > равно получает `tun.address` — проверьте, что правка **сохранена и применена** > (перезапуск сервиса): пуш-DNS берётся из конфига на диске, а не из несохранённой формы. --- ## 8. Подключение клиента ### 8.1. Мобильный (Android) и десктоп (Windows/macOS) 1. На сервере выдайте ссылку: `qeli add-client --link --host <публичный-host:порт>` (§6.3) — получите `qeli://…` + QR. 2. В приложении: **Add profile → Scan QR** (или **Paste qeli:// link**) → профиль появится со всеми параметрами и **запиненным ключом сервера**. 3. Нажмите кольцо подключения. Готово. Full-tunnel и «маршрутизировать локальные сети» переключаются тумблерами в приложении. Форма метки времени в окне лога — **Настройки → Время в логе** (те же пять вариантов, что и у `[logging] time_format` на сервере: дата и время / RFC 3339 в UTC / только время / Unix / без метки). Если собираетесь сверять лог приложения с серверным, поставьте `RFC 3339` с обеих сторон. Применяется сразу, к уже написанным строкам — нет. > **iOS.** Клиент для iPhone/iPad лежит в [`qeli-ios/`](../../qeli-ios/README.md) и по > возможностям повторяет Android: те же профили, `qeli://`-ссылки и QR, те же режимы обмена, > русский/английский интерфейс, виджет и переключатель в Пункте управления. Он **собирается > из исходников на macOS** (Xcode 16+, см. README) — готовой сборки в релизах нет, и на > живом устройстве он ещё не проверялся. Отличия, продиктованные платформой: маршрутизация > «по приложениям» доступна только через MDM, а вместо автоподключения при загрузке > используется VPN On Demand — подробности в [`qeli-ios/PARITY.md`](../../qeli-ios/PARITY.md). > ⚠️ **macOS — первый запуск.** Приложение подписано **ad-hoc** (не нотаризовано Apple), > поэтому Gatekeeper его блокирует и оно **не откроется** двойным кликом. Один раз снимите > карантин в Терминале: > ```bash > xattr -cr /Applications/Qeli.app > ``` > (см. [qeli-mac/README.md](../../qeli-mac/README.md)). ### 8.2. Linux CLI-клиент ```bash sudo cp /etc/qeli/client.conf.example /etc/qeli/client.conf sudo nano /etc/qeli/client.conf ``` Минимум (см. [`client.conf`](../../qeli/config/client.conf) — описан каждый ключ): ```ini [qeli] server = vpn.example.com:443 proto = tcp user = alice pass = s3cret # из `qeli show-identity` (ОБЯЗАТЕЛЕН при H-1) key = 33f399e6…d532450 # должен совпадать с obf.mode профиля mode = fake-tls sni = www.cloudflare.com # локальная маршрутизация (в qeli://-ссылке НЕ передаётся — только в файле): # true = full-tunnel (весь трафик через VPN) gateway = false # также заворачивать приватные сети + server-pushed route_local = false # блокировать утечки, пока туннель не поднят (full-tunnel) kill_switch = false # tunnel = управлять /etc/resolv.conf; off = не трогать dns = tunnel ``` ```bash sudo qeli client --config /etc/qeli/client.conf ``` > При H-1 (дефолт) `key` обязателен и должен быть **реальным** (не нулевым). Если на > сервере `bind_static_to_session = false`, можно работать по TOFU (нулевой `key`). --- ## 9. То же самое через веб-панель Полный гайд — [PANEL.md](PANEL.md). Краткий старт: ### 9.1. Включить панель ```bash # задать админ-пароль (генерирует/хеширует, прописывает в [web], включает панель) sudo qeli set-web-password # случайный пароль, печатается один раз # или свой: sudo qeli set-web-password --password 'PANELPASS' ``` Добейте секцию `[web]` для доступа по внешнему IP и перезапустите: ```ini [web] enabled = true # или 127.0.0.1 для доступа только по SSH-туннелю bind = 0.0.0.0 port = 8080 # встроенный HTTPS (self-signed авто; браузер предупредит 1 раз) tls = true # (рекоменд.) свой IP в белый список # allowed_ips = 203.0.113.4 # дефолтный хост для share-ссылок # public_host = vpn.example.com ``` ```bash sudo systemctl restart qeli ``` > **Fail-closed:** с пустым `password_hash` панель не стартует ни на каком `bind`, > включая loopback (с 0.7.12 — раньше loopback был исключением и отдавал открытую панель). > VPN `:443` при этом работает — это отдельный процесс. Хеш задаётся через > `qeli set-web-password`; осознанный отказ — `web.insecure_no_auth = true`. > Откройте порт `8080` в файрволе. ### 9.2. Пользоваться Откройте `https://:8080`, войдите как `admin`. - **Quick start** — **отдельный пункт левого меню** (не вкладка Dashboard). Таблица всех **10** режимов маскировки: `reality-tls`, `reality`, `fake-tls`, `obfs-ws`, `obfs-none`, `plain`, `udp-fake-tls`, `udp-quic`, `udp-obfs`, `obfs-awg`. Кнопка **Launch** в строке собирает готовый профиль (TUN/NAT/DNS/пул/обфускация), сохраняет его и перезапускает сервер. - **Config** — все поля профиля одной страницей (Bind/TUN/Pool/Routing/DNS/Obfuscation/ Performance), вкл. pushed-маршруты и NAT; вкладка **Global** — identity-ключи (показ + **Rotate**), Web UI, H-1. Кнопки: **Save** — записать конфиг на диск; **Apply & Restart** — сохранить и сделать полный `systemctl restart` (применяет всё, включая сокет панели); **Reload** — перечитать конфиг с диска, отбросив несохранённые правки. - **Users** — создать пользователя (пароль **открытым текстом** — хешируется сервером), задать bandwidth/static-IP/группу/max-sessions/**разрешённые профили**/allowed-networks/ **персональные маршруты**. Группы — шаблоны. - **Share / QR** у пользователя — выдаёт `qeli://`-ссылку + QR **без ввода пароля** (сервер хранит обратимо-зашифрованную копию; пароль не меняется). ### 9.3. Подключение К другим серверам (вкладка Client) Панель умеет не только **раздавать** VPN, но и **сама подключаться** к другим qeli-серверам (этот бокс становится клиентом — релеем, или просто управляемым клиентом). Вкладка **Client**: - **Добавить профиль** — тремя способами: - **Import qeli:// link** — вставить `qeli://`-строку, которую вам дал админ сервера; - **Add manually** — форма (server/user/pass/key/mode/sni/rsid/obfs_key, QUIC для UDP, split/full-tunnel); - **Paste INI config** / переключатель **Raw INI** — полный клиентский INI (любой ключ: `dev`/`mtu`/`dns`/`kill_switch`/`bind_static`/`[logging]`…). - **Каждый профиль управляется НЕЗАВИСИМО.** Создание профиля его **не подключает** — он лежит в статусе *Disconnected*. У каждого своя кнопка **Connect** / **Disconnect**; жмёте только на нужные. Статус (подключён + хвост лога) обновляется сам. - **Несколько подключений одновременно** — поднимайте сколько нужно: каждому профилю **автоматически выдаётся свой TUN-интерфейс** (`vpn0`/`vpn1`/…, виден в списке), так что туннели не конфликтуют. К одному серверу — заведите несколько профилей (один тоннель на профиль). Любой режим, не только reality-tls. - ⚠️ **Full-tunnel и несколько туннелей.** Маршрут по умолчанию в системе один, поэтому **несколько одновременных full-tunnel конфликтуют** — для мульти-релея используйте split-tunnel (и разные пул-подсети на серверах), либо держите full-tunnel по одному. Полный заворот на сервере-боксе может отрезать саму панель/SSH — включайте осознанно. - **Хранилище:** профили лежат в `/etc/qeli/clients/.conf` (тот же flat-INI). Это значит, то же самое можно сделать и **файлами**: положить конфиги туда и запускать `qeli client --config /etc/qeli/clients/.conf` (для нескольких — разный `dev` в каждом файле). Готовый пример клиента — [`client-reality.conf`](../../qeli/config/client-reality.conf) и [`client.conf`](../../qeli/config/client.conf) (все режимы и ключи). - **Автозапуск при загрузке.** У каждого профиля есть флаг **autostart**: помеченные профили `qeli` (supervisor + панель) поднимает сам при старте сервиса — после `reboot`/`systemctl restart qeli` нужные тоннели встают без ручного Connect. Задаётся **двумя способами, равнозначно**: - в панели — галочка **«Auto-connect this profile when the server/panel starts»** в форме профиля (в списке такой профиль помечен значком `↻ autostart`); - в файле — строкой `autostart = true` в секции `[qeli]` файла `/etc/qeli/clients/.conf` (правьте руками — эффект тот же, что и галочка). Флаг **независим для каждого профиля** — автозапускаются только помеченные, остальные остаются *Disconnected* до явного Connect. Снять автозапуск — снять галочку (или убрать строку из файла). --- ## 10. Справочник CLI и диагностика `qeli` — один бинарь с подкомандами; есть ещё тонкий клиентский бинарь `qeli-client`. Команды делятся по тому, **как** они общаются с сервером: правят конфиг на диске (нужен рестарт) или идут через control-сокет (применяются на лету). `qeli --help` и `qeli <команда> --help` печатают то же самое. ### 10.1. Режимы запуска (`-c/--config`) ```bash qeli server [-c /etc/qeli/server.conf] # сервер (супервайзер + data-plane worker) qeli client [-c /etc/qeli/client.conf] # клиент qeli check-config [-c <путь>] [--client] # проверить конфиг и выйти (см. §4); --client = как [qeli] qeli-client [-c /opt/etc/qeli/client.conf] # тонкий клиент для роутеров/headless (Entware), только --config ``` > Скрытая `qeli _worker` — внутренний data-plane потомок, порождается `server`. Руками не запускать. ### 10.2. Пользователи и идентичность Правят **файл конфига/ключей** на диске (`-c/--config`, дефолт `/etc/qeli/server.conf`), а **не** сокет — где меняется конфиг или ключ, нужен рестарт сервиса: ```bash # добавить пользователя (Argon2-хеш пароля) в users-файл: sudo qeli add-client alice \ -p 'секрет' \ # --password; без него сгенерит и покажет ОДИН раз --profiles tcp,reality \ # ограничить профилями (пусто = все) --static-ip 10.9.0.100 \ # закрепить туннельный IP (опц.) --max-sessions 2 \ # 0 = дефолт группы --link --host vpn.example.com:443 --link-profile reality # напечатать qeli://-ссылку (+QR) # ПОВТОРНО выдать ссылку УЖЕ существующему пользователю (пароль вводить не нужно): sudo qeli share-link alice \ --host vpn.example.com:443 \ # без него берётся web.public_host --profile reality \ # по умолчанию — первый профиль --label 'Мой VPN' # по умолчанию <профиль>-<порт> sudo qeli set-web-password --username admin [-p 'пароль'] [--no-enable] # логин панели (Argon2id); §9.1 sudo qeli show-identity # pubkey каждого профиля (клиент пинит key=); создаёт ключи, если их нет sudo qeli rotate-identity reality # перегенерировать ключ профиля → клиентам обновить key=, рестарт ``` #### 10.2.1. `share-link` — переслать конфиг существующему пользователю Отвечает на вопрос «клиент потерял настройки / сменил телефон — как выдать ему конфиг заново». `add-client` для этого не годится: он **создаёт** пользователя и на существующем имени падает с ошибкой. ``` qeli share-link [--host <адрес[:порт]>] [--profile <имя>] [--label <текст>] [--reset] [-c <конфиг>] ``` | Флаг | По умолчанию | Что делает | |---|---|---| | `` | — | **обязателен**: существующий пользователь из users-файла | | `--host` | `web.public_host` из конфига | публичный адрес сервера для ссылки; `host:port` переопределяет порт профиля | | `--profile` | первый профиль в конфиге | для какого профиля собрать ссылку (у каждого свой порт, режим, ключ) | | `--label` | `<профиль>-<порт>` | подпись профиля в приложении клиента | | `--reset` | выкл | сгенерировать НОВЫЙ пароль, если старый не восстанавливается (**разрушающее**, см. ниже) | | `-c`, `--config` | `/etc/qeli/server.conf` | путь к конфигу сервера | **Как это работает.** Пароль вводить не нужно и невозможно восстановить из хеша — он необратим. Поэтому при заведении пользователя рядом с Argon2-хешем сохраняется ещё и обратимо зашифрованная копия пароля; `share-link` расшифровывает её и подставляет в ссылку. Остальное берётся из конфига профиля автоматически: порт, транспорт, wire-режим, SNI, obfs-ключ, reality short_id, параметры awg и закреплённый публичный ключ сервера (`show-identity`). Это тот же механизм и тот же код, что за кнопкой share/QR в панели, — ссылки из CLI и из панели совпадают. ```bash # типовой случай: адрес уже задан в web.public_host sudo qeli share-link alice # явный адрес и конкретный профиль sudo qeli share-link alice --host vpn.example.com:443 --profile reality --label 'Мой VPN' ``` Вывод — строка `qeli://…`: её можно отправить клиенту, показать как QR или вставить в приложение. **Когда копии пароля нет** (пользователь заведён до появления этой возможности либо сменился ключ шифрования) — команда **откажется** и укажет на `--reset`: ```bash sudo qeli share-link alice --reset # печатает НОВЫЙ пароль один раз sudo systemctl reload qeli # обязательно: иначе сервер проверяет старый пароль ``` > ⚠️ `--reset` **разрушающий**: конфиг, которым пользователь пользуется сейчас, перестаёт > работать — ему нужно передать новую ссылку. И, в отличие от панели, у CLI нет канала к > работающему воркеру, поэтому перечитать пользователей нужно вручную (`reload`); команда > сама об этом напоминает в выводе. ### 10.3. Живое управление (control-сокет, БЕЗ рестарта) Идут через `--socket` (дефолт `/var/run/qeli/control.sock`) — применяются немедленно: ```bash sudo qeli list-clients # кто сейчас подключён + выданные IP sudo qeli kick alice # оборвать сессии пользователя sudo qeli disable-user bob # заблокировать (кик + запрет реконнекта) sudo qeli enable-user bob # снова разрешить sudo qeli set-bandwidth alice 50 # лимит Мбит/с (0 = без лимита) sudo qeli show-routes alice # маршруты пользователя sudo qeli list-blocked # IP, залоченные брутфорс-защитой (неверный пароль) sudo qeli unblock 1.2.3.4 # снять блок с адреса (--all — со всех) ``` ### 10.4. Прочее ```bash qeli version # версия qeli version --check # спросить у GitHub Releases, есть ли новее (opt-in, только уведомляет, ничего не качает) # Разрешить non-root сервисному пользователю перезапускать свой юнит из кнопки панели # «Apply & Restart». Нужно ТОЛЬКО при установке НЕ из .deb (.deb ставит правило сам) — # панель сама сообщит, когда правила нет. Пишет /etc/polkit-1/rules.d/49-qeli.rules; root. sudo qeli install-polkit # по умолчанию: user=qeli, unit=qeli.service sudo qeli install-polkit --unit qeli-server.service --user vpn # нестандартный юнит/пользователь sudo qeli install-polkit --dry-run # напечатать правило, ничего не писать # Выбрать ОС-пользователя, от которого работает СЛУЖБА: `qeli` (по умолчанию, без привилегий) или `root`. sudo qeli set-service-user root # переключить на root (см. предупреждение ниже) sudo qeli set-service-user qeli # вернуть непривилегированный вариант по умолчанию sudo qeli set-service-user root --dry-run # показать, что изменится sudo qeli set-service-user root --unit qeli-server.service # нестандартный юнит sudo systemctl restart qeli # нужен, чтобы изменение вступило в силу ``` **Что именно делает `set-service-user`.** Он **не** правит поставляемый юнит (`/lib/systemd/system/qeli.service`): dpkg перезапишет его при каждом обновлении, и правка молча потеряется. Вместо этого он управляет **systemd drop-in override**: | аргумент | что делает | |---|---| | `root` | пишет `/etc/systemd/system/qeli.service.d/run-as.conf` с `[Service] User=root / Group=root` — он приоритетнее поставляемого `User=qeli`. Лежит в `/etc`, поэтому переживает обновления пакета. | | `qeli` | удаляет этот drop-in (в поставляемом юните уже `User=qeli`) **и** выполняет `chown -R qeli:qeli /etc/qeli`: файлы, созданные пока служба работала от root, принадлежат root, и непривилегированная служба не смогла бы их писать. | Оба варианта затем выполняют `systemctl daemon-reload`; для применения перезапустите службу. Команда идемпотентна (повторный запуск безопасен), требует root и отвергает любые значения, кроме `qeli`/`root`. Закалка юнита — `ProtectSystem=full`, `NoNewPrivileges=true`, ограниченный `CapabilityBoundingSet` — **действует в обоих случаях**; `root` меняет только то, *от кого* работает процесс. > ⚠️ **Когда запускать от root — и почему обычно не стоит.** > Пользователь `qeli` по умолчанию нужен для разделения привилегий: если демон скомпрометируют, > атакующий получит учётку, которой не принадлежит ничего, кроме `/etc/qeli`, — **а не машину**. > Запуск от root это убирает: компрометация VPN-демона становится **полным root на хосте**. > Демон доступен из интернета, так что различие не теоретическое. > > Законные причины выбрать `root`: > - ядро или контейнер, не уважающие `AmbientCapabilities`, — непривилегированная служба вообще > не может создать TUN или занять :443 (симптом: профиль не поднимается с > `Operation not permitted`, хотя юнит выдаёт нужные capabilities); > - ограниченное окружение, где нельзя поставить polkit-правило, а кнопка панели > `Apply & Restart` нужна (root управляет своим юнитом напрямую); > - вы постоянно наступаете на ловушку с владельцем `/etc/qeli` (§A.3) и осознанно принимаете размен. > > Если всё же работаете от root — компенсируйте в другом месте: не выставляйте панель в интернет > (`web.allowed_ips` либо bind на loopback + SSH-туннель) и вернитесь на > `sudo qeli set-service-user qeli`, как только причина отпадёт. ### 10.5. Диагностика ```bash journalctl -u qeli -f # лог сервера sudo qeli list-clients # активные сессии + выданные IP ping 10.9.0.2 # пинг клиента из туннеля (с сервера) ss -tulnp | grep qeli # слушает ли :443 / :8080 ``` На клиенте проверьте, что появился интерфейс `vpn0` и маршруты (`ip a`, `ip route`). > **Глубокая диагностика обфускации.** Если DPI режет туннель и надо понять, что реально > уходит в провод, включите таймлайн форм пакетов: `QELI_TRACE=<файл> qeli client …` > (opt-in, пишет только размеры/тайминги, не содержимое; дамп по SIGUSR1). Подробности и > разбор — в [TROUBLESHOOTING.md](TROUBLESHOOTING.md). --- ## 11. Wire-режимы — какой выбрать Задаётся `obf.mode` на сервере и `mode` на клиенте (должны совпадать): | Режим | Когда | |---|---| | `fake-tls` | **по умолчанию.** Мимикрия под TLS 1.3, против пассивного/сигнатурного DPI. Хороший баланс. | | `reality-tls` | максимальная маскировка: туннель **внутри настоящего TLS 1.3** с одолженным сертом реального сайта (паритет Xray-REALITY). Держит и активное зондирование. Требует `key` + `reality_sid` + `sni`; чуть медленнее. | | `obfs` | ChaCha20-обфускация всего потока; WS-fronting опционален (`front = websocket` / `none`). Нужен общий `obfs_key`. Работает и по TCP, и по UDP. | | `plain` | без маскировки — голый шифрованный туннель (макс. скорость). Для доверенных сетей. | | QUIC-masking | для **UDP**-профилей (`obf.quic.enabled = true`), маскирует под QUIC. | Подробное сравнение, REALITY-настройка (short_ids, handrolled), multipath-бондинг — в [CONFIG.md](CONFIG.md). Бенчмарки всех режимов — [BENCHMARK.md](BENCHMARK.md). --- ## 12. Частые проблемы - **Сервер отказывается стартовать: «pool.cidr … contains this host's DEFAULT GATEWAY» / «overlaps the existing route …».** Это предстартовая проверка, и она спасает вас от потери доступа к машине. Подсеть туннеля пересекается с сетью, которую хост уже использует. Худший случай — когда `tun.address` совпадает с адресом шлюза: при подъёме TUN шлюз становится локальным адресом, весь исходящий трафик умирает в туннеле, и сервер пропадает из сети целиком, вместе с SSH и пингом; вернуться можно только через консоль хостера. Лечение — увести туннель в свободный диапазон (`tun.address = 10.9.0.1`, `pool.cidr = 10.9.0.0/24`, `pool.exclude = 10.9.0.1`). Свои сети смотрите через `ip route` и `ip -4 addr`, а проверить конфиг **до** запуска можно командой `qeli check-config --config /etc/qeli/server.conf` — она выполняет ту же проверку против текущего хоста. - **Поставил из .deb — «ничего не работает»: профиль не поднимается, пользователи и настройки панели не сохраняются, служба в рестарт-петле.** Почти всегда это права: служба работает под `User=qeli` и пишет в `/etc/qeli` (identity-ключи, users-файл, сохранения панели), а конфиг и файлы, созданные вами под root **после** установки, остались root-овыми. Лечится `sudo chown -R qeli:qeli /etc/qeli` + рестарт — подробно с симптомами и модами в §2, «A.3. Права на `/etc/qeli`». - **Клиент проходит «identity verified», но сразу отваливается / `AUTH FAIL … not found`.** Пользователь не там, где сервер его ищет: в `server.conf` есть инлайн `[user:*]` → `users_file` игнорируется (см. §3.3). Держите пользователей в одном месте. - **Подключается, но интернета нет (full-tunnel).** Проверьте, что в профиле `routing.nat.enabled = true` и что на сервере установлен **`iptables`** (`apt install iptables`) — без него сервер не сможет поставить MASQUERADE (в логе `NAT requested but NOT applied`, в панели — жёлтый баннер). Проверка: `iptables-save | grep qeli-nat` должно показывать правила; `journalctl -u qeli | grep NAT` — строку «NAT masquerade active». Если WAN-интерфейс определился неверно — задайте `routing.nat.interface` явно. - **Загрузка зависает / рвётся под нагрузкой (TCP).** Не сделан MSS-clamp под MTU туннеля (PMTU-чёрная дыра) — правило `TCPMSS` из §5; для прода ещё BBR (CONFIG.md). - **Сервер отвергает клиента без понятной причины.** Включён H-1 (дефолт), а клиент не пинит ключ. Впишите реальный `key` (из `qeli show-identity`) — проще всего выдать профиль ссылкой `add-client --link` (§6.3). - **Не пускает после нескольких неверных паролей.** Сработал анти-брутфорс по source-IP. Политик **две, и они независимы**: `[auth] brute_force` — вход **VPN-пользователей**, снимается `qeli unblock ` (или `--all`); `[web] brute_force` — вход **в панель**, снимается только на её странице **Blocked IPs** (CLI туда не достаёт: control-сокет живёт в воркере, а панель — в супервизоре). Дефолты у обеих: 5 попыток / окно 300 с / блокировка 900 с. Либо дождитесь конца блокировки, либо `systemctl restart qeli` — счётчики хранятся в памяти и сбрасываются. - **Веб-панель не стартует.** Fail-closed: пуст `password_hash` — панель не поднимается **ни на каком `bind`, включая loopback** — задайте `qeli set-web-password` (§9.1). VPN `:443` при этом не страдает (это отдельный процесс). - **403 на любое сохранение в панели за доменом/прокси.** Добавьте домен в `web.allowed_origins` (CSRF same-origin); свой IP — в `web.allowed_ips`, иначе заблокируете сами себя. --- ## 13. Полное удаление qeli По ролям — удаляйте только то, что ставили. `<ПОРТ>` ниже = порт вашего профиля (напр. `443`). ### 13.1. Сервер (Linux) ```bash # 1. Остановить и отключить сервис sudo systemctl disable --now qeli # 2a. Ставили из .deb → снять пакет (удалит сервис, /usr/bin/qeli, polkit-правило). # purge удалит и conffiles (примеры конфигов): sudo apt purge qeli # 2b. Ставили вручную/бинарём → снять руками: sudo rm -f /usr/bin/qeli /usr/local/bin/qeli sudo rm -f /etc/systemd/system/qeli.service /lib/systemd/system/qeli.service && sudo systemctl daemon-reload # 3. Конфиги, ключи идентичности, пользователи, выданные ссылки. # ⚠️ identity-ключ пропадёт → клиентам с пиннингом (reality-tls / H-1) придётся # ПЕРЕВЫДАТЬ конфиги. Хотите сохранить: sudo cp -a /etc/qeli /root/qeli-backup sudo rm -rf /etc/qeli # 4. Состояние, логи, runtime sudo rm -rf /var/lib/qeli /var/log/qeli /run/qeli # 5. Системный пользователь сервиса sudo deluser --system qeli 2>/dev/null; sudo delgroup qeli 2>/dev/null; true ``` Дополнительно — **если ставили через `install-qeli-server.sh`** (он трогает ОС): ```bash # sysctl-тюнинг (BBR / буферы / PMTU) sudo rm -f /etc/sysctl.d/99-qeli-perf.conf && sudo sysctl --system >/dev/null # BBR-модуль: установщик прописывает его в автозагрузку — иначе tcp_bbr грузится вечно sudo rm -f /etc/modules-load.d/qeli-bbr.conf # iptables: СВОИ NAT/MASQUERADE-правила qeli снимает сам при чистой остановке (шаг 1). # Установщик дополнительно ставит MSS-clamp — на ИСХОДЯЩИЙ порт (--sport): SYN-ACK летит # ОТ порта сервера, поэтому правило матчит именно --sport. Сначала посмотреть остатки: sudo iptables-save | grep -iE 'qeli-nat|MASQUERADE|TCPMSS' sudo iptables -t mangle -D OUTPUT -p tcp --sport <ПОРТ> --tcp-flags SYN,RST SYN \ -j TCPMSS --set-mss 1340 2>/dev/null; true # И только ПОСЛЕ удаления пере-сохранить — иначе save законсервирует то, что вы # только что пытались снять. Проверьте, что grep выше больше ничего не находит. sudo netfilter-persistent save 2>/dev/null; true ``` > **Проверьте `--sport`, а не `--dport`.** Установщик ставит правило с `--sport`; команда с > `--dport` не совпадёт ни с чем, тихо провалится (из-за `2>/dev/null; true`), и следующий > `netfilter-persistent save` закрепит правило навсегда. > Если у вас **нет** `netfilter-persistent`, установщик сохранил снимок в > `/etc/iptables/rules.v4` — причём **весь** текущий ruleset хоста, не только правило qeli. > Проверьте этот файл перед удалением: `sudo iptables-save > /etc/iptables/rules.v4`. > Если правила НЕ сохранялись в `netfilter-persistent` / `/etc/iptables/rules.v4` — они > исчезнут сами после перезагрузки. ### 13.2. Клиент — Linux (Rust CLI) Чистая остановка (Ctrl+C) **сама** восстанавливает `/etc/resolv.conf`, снимает kill-switch / NAT и удаляет tun. Руками — только если клиент **упал**: ```bash sudo pkill -f 'qeli client' # прибить, если висит # DNS: оригинал лежит в /var/lib/qeli/dns-backup.json — проще всего запустить и ЧИСТО # остановить клиент (он восстановит resolv.conf сам), либо вернуть из бэкапа вручную. # Kill-switch (если был kill_switch = true). Правила живут в ОТДЕЛЬНОЙ цепочке # QELI_KS_<интерфейс> — имя привязано к `dev = …`, чтобы несколько экземпляров клиента # не затирали правила друг друга. Снимается точечно: сначала убрать переход из OUTPUT # (иначе цепочку не удалить), потом очистить и удалить саму цепочку. В режиме шлюза # добавляется ещё и переход из FORWARD. То же самое для IPv6 — engage() программирует # обе таблицы, и без ip6tables-части v6-трафик останется заблокированным. # # Точное имя цепочки клиент печатает в лог при включении kill-switch; ниже пример для # `dev = vpn0`. CH=QELI_KS_vpn0 sudo iptables -D OUTPUT -j $CH 2>/dev/null; true sudo iptables -D FORWARD -j $CH 2>/dev/null; true sudo iptables -F $CH 2>/dev/null; true sudo iptables -X $CH 2>/dev/null; true sudo ip6tables -D OUTPUT -j $CH 2>/dev/null; true sudo ip6tables -D FORWARD -j $CH 2>/dev/null; true sudo ip6tables -F $CH 2>/dev/null; true sudo ip6tables -X $CH 2>/dev/null; true # Exit-узел / шлюз (если был exit_node = true или gateway_nat = true). Эти правила тоже # снимаются только на ЧИСТОЙ остановке, а краш их оставляет — и тогда хост продолжает # маскарадить и форвардить уже после того, как туннель умер. Каждое правило помечено # комментарием: qeli-exit-node (exit_node) или qeli-gw-nat (gateway_nat) — по нему и ищем. sudo iptables -t mangle -S | grep -e qeli-exit-node -e qeli-gw-nat sudo iptables -t nat -S | grep -e qeli-exit-node -e qeli-gw-nat sudo iptables -S | grep -e qeli-exit-node -e qeli-gw-nat # Удалять построчно: в найденной строке заменить -A на -D и выполнить как есть, например: # sudo iptables -t nat -D POSTROUTING -o eth0 -m mark --mark 0x51/0x51 -j MASQUERADE \ # -m comment --comment qeli-exit-node # ip_forward и rp_filter клиент менял на лету — вернуть, если они были выключены: # sudo sysctl -w net.ipv4.ip_forward=0 # sudo sysctl -w net.ipv4.conf.eth0.rp_filter=1 # eth0 = ваш WAN sudo ip link del vpn0 2>/dev/null; true # tun — имя из `dev = …` # Удалить бинарь, конфиг, состояние: sudo rm -f /usr/local/bin/qeli rm -f ~/qeli-client.conf # ваш путь к клиентскому конфигу sudo rm -rf /var/lib/qeli # device-id + dns-backup ``` > **Никогда не снимайте kill-switch через `iptables -F`.** Без имени цепочки эта команда > очищает **всю** таблицу `filter` — вместе с правилами SSH, ufw/fail2ban, Docker и всем, > что настроил администратор. qeli держит свои правила в собственной цепочке > `QELI_KS_<интерфейс>` именно для того, чтобы её можно было снять точечно. При включении > клиент печатает в лог снятие перехода из **OUTPUT**; в режиме шлюза дополнительно > уберите переход из **FORWARD** и ip6tables-копии — как в примере выше. > На **совмещённом** хосте (сервер + клиент рядом) `/var/lib/qeli` общий — не удаляйте > его, пока не снесли сервер. ### 13.3. Десктоп — Windows / macOS (GUI) - **Windows:** закрыть приложение → удалить `QeliWin` (папку portable-сборки или через «Приложения и возможности»). Wintun-адаптер эфемерный — создаётся и удаляется на каждый сеанс, после «Отключить» в системе не остаётся; маршруты/DNS восстанавливаются там же. Данные (профили / настройки / device-id) — удалить папки: `%AppData%\QeliWin`, `%LocalAppData%\qeli`, `%ProgramData%\QeliWin`. - **macOS:** закрыть → удалить `QeliMac.app`. `utun` управляется ядром — исчезает при отключении. Данные — удалить `~/.local/share/qeli`; если включали автозапуск — снять LaunchAgent из `~/Library/LaunchAgents` (файл с `qeli` в имени). ### 13.4. Android Настройки → Приложения → **qeli** → Удалить. Сносит всё: профили (в шифрованном хранилище), device-id, виджет, QS-плитку, автозапуск на буте. Для полной чистоты — отозвать VPN-согласие и выключить Always-on VPN (если включали): Настройки → Сеть/Подключения → VPN → qeli. ### 13.5. Роутеры **OpenWrt:** ```sh /etc/init.d/qeli stop; /etc/init.d/qeli disable opkg remove luci-app-qeli qeli rm -f /etc/config/qeli /etc/init.d/qeli /usr/bin/qeli-client # удалить firewall-зону qeli, которую создавал uci-default при установке: sec=$(uci show firewall | awk -F. "/\.name='qeli'/{print \$2; exit}") [ -n "$sec" ] && uci delete firewall.$sec && uci commit firewall && /etc/init.d/firewall restart ``` **Keenetic:** остановить и удалить init-скрипт, бинарь и конфиг — обратно шагам установки (см. `docs/*/KEENETIC-DEPLOY.md`). ### 13.6. Docker ```bash docker compose -f release/docker/docker-compose.yml down # остановить и снести контейнер # (-v тут бесполезен: в compose нет именованных volume, только bind-mount ./data — # данные удаляет команда rm -rf ./data ниже) docker rmi qeli:latest # образ rm -rf ./data # смонтированный /etc/qeli (конфиги + ключи) ``` --- > Нашли неточность или есть вопрос по настройке — заводите issue/discussion в > репозитории. Полная карта документации — в [README](README.md).