Документация описывает 0.7.15 — последний выпущенный релиз. Что именно установлено у вас, покажет
qeli --version.
Полное руководство «с нуля»: от поднятия сервера до заведения пользователей с маршрутами и подключения первого клиента — и через CLI, и через веб-панель.
Рассчитано на чистый Linux-сервер (Debian/Ubuntu) с root-доступом. Все команды
сервера — от root (или через sudo).
Справочники, на которые опирается этот гайд: CONFIG.md — все ключи конфига · PANEL.md — веб-панель · примеры конфигов:
server.conf·users.conf·client.conf.
- Что понадобится
- Установка сервера
- Первичная настройка сервера (CLI)
- Запуск и проверка
- Full-tunnel: NAT (настраивается автоматически)
- Заведение пользователей (CLI)
- Маршруты: split/full-tunnel, pushed-маршруты, ACL, статический IP
- Подключение клиента
- То же самое через веб-панель
- Справочник CLI и диагностика
- Wire-режимы — какой выбрать
- Частые проблемы
- Полное удаление qeli
- Сервер Linux x86-64 (Debian 11+ / Ubuntu 20.04+), root, публичный IP.
.deb— портируемая сборка (make deb-portable, gatecheck-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.
⚡ Самый быстрый путь (всё за одну команду). В корне репозитория есть готовый установщик
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 <IP>. Дальше остаётся только вставить строку подключения в приложение. Ручная установка по шагам — ниже.Что он делает, по порядку: ① ставит зависимости (
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) прямо перед первым стартом, поэтому служба сразу поднимается от нужного пользователя:sudo QELI_RUN_AS=root ./install-qeli-server.sh <IP> # без разделения привилегий — см. §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. Пример:sudo QELI_BIN=qeli/target/release/qeli QELI_SRC=. ./install-qeli-server.sh <IP>Что ещё он меняет на хосте (это не побочные мелочи — знайте о них заранее):
- Тюнинг сети всей системы: пишет
/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 на
127.0.0.1:8080(только loopback), сгенерировав пароль и показав его один раз в конце вывода. Это единственный момент, когда пароль виден — сохраните его сразу. Доступ — через SSH-форвард:ssh -L 8080:127.0.0.1:8080 root@<сервер>, затемhttps://127.0.0.1:8080. Публикация наружу — осознанное действие и требует ОБОИХQELI_PANEL_PUBLIC=1иQELI_PANEL_ALLOWED_IPS=<ip[,ip…]>; публичный bind без списка источников инсталлятор ОТКЛОНЯЕТ. Если панель не нужна вовсе — выключите её после установки ([web] enabled = false).- Кладёт
/etc/qeli/client-links/CONNECTION-STRINGS.txt— там пароли пяти пользователей открытым текстом (каталог0700, файлы0600).- Если публичный адрес не задан аргументом — определяет его, обратившись к внешним сервисам (
api.ipify.org,ifconfig.me,icanhazip.com).Всё это снимается — см. §13 «Полное удаление».
Качайте .deb именно в /tmp (или другой каталог, читаемый всеми), а не в /root
и не в домашний каталог:
cd /tmp
curl -fLO https://github.com/litvinovtd/qeli/releases/download/v0.7.15/qeli_0.7.15_amd64.deb
# или scp с рабочей машины: scp qeli_0.7.15_amd64.deb root@server:/tmp/Почему
/tmp.aptскачивает и распаковывает от имени служебного пользователя_apt, а/rootи домашние каталоги ему недоступны. Из/rootустановка проходит, но с предупреждением:N: Download is performed unsandboxed as root as file '/root/qeli_0.7.15_amd64.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)Это именно предупреждение (apt откатывается на работу от root), но из
/tmpего просто не будет.
sudo apt install /tmp/qeli_0.7.15_amd64.deb # ставит и подтягивает зависимостиУказывайте полный путь (или ./имя.deb) — без слэша apt будет искать пакет с таким
именем в репозиториях. Альтернатива, если apt по какой-то причине недоступен:
sudo dpkg -i /tmp/qeli_0.7.15_amd64.deb
sudo apt-get -f install -y # доустановить зависимости (iproute2, iptables, libcap2-bin)Что делает пакет:
- кладёт бинарь в
/usr/bin/qeli(0755 root:root, без file-capabilities — с 0.7.12setcapнамеренно снимается: права даёт systemd-юнит черезAmbientCapabilitiesCAP_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):Изменить можно в любой момент позже —echo "qeli qeli/run-as select root" | sudo debconf-set-selections sudo apt install /tmp/qeli_0.7.15_amd64.deb
sudo qeli set-service-user root|qeli(§10.4), там же расписаны размены вариантаroot.
Это самая частая причина «установил, а ничего не работает». Служба работает под
User=qeli (см. qeli.service) и пишет внутрь /etc/qeli — там генерируются
identity-ключи профилей (/etc/qeli/identity/<profile>.key), туда сохраняет
пользователей add-client и веб-панель, там же usage.json. Под это в юните специально
разрешён ReadWritePaths=/etc/qeli.
postinst выставляет владельца в момент установки, но всё, что вы создадите после —
под root, — останется root-овым:
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 приведите права в порядок:
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: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растёт).
qeli --version
systemctl status qeli --no-pager
ls -la /etc/qeli # владелец всего — qeli:qeli
journalctl -u qeli -n 30 --no-pager # ошибок прав быть не должноНужен Rust (stable). В корне репозитория:
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-правило) без всякого скачивания. Из корня репо:
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:sudo qeli install-polkit # → /etc/polkit-1/rules.d/49-qeli.rules (см. §10.4)Без этого
Apply & Restartсообщит, что правила нет (молча больше не падает). В контейнере systemctl недоступен вовсе — панель применяет изменения профилей через перезапуск воркера в процессе, а изменения сокета панели (web.bind/port/tls) требуют пересоздания контейнера (docker restart).
Мульти-арч образ (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 и нюансы:
С 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.
sudo cp /etc/qeli/server.conf.example /etc/qeli/server.conf
sudo nano /etc/qeli/server.confФормат — flat-INI. Файл-пример исчерпывающий: каждый ключ перечислен со
значением по умолчанию и пояснением; любой удалённый ключ берёт дефолт. Для старта
достаточно проверить несколько полей в секции [profile:tcp].
[profile:tcp]
enabled = true
# на чём слушаем (порт должен быть открыт в файрволе)
bind.address = 0.0.0.0
bind.port = 443
# tcp | udp
bind.transport = tcp
# виртуальная сеть туннеля
# адрес сервера внутри туннеля (шлюз)
tun.address = 10.9.0.1
# пушится клиентам; для прод-TCP см. §12 и CONFIG.md
tun.mtu = 1400
# подсеть VPN и пул; её префикс также настраивает сервер и клиентов
pool.cidr = 10.9.0.0/24
# режим маскировки на проводе (см. §11)
obf.mode = fake-tlsОстальное (DNS-прокси, padding, heartbeat, лимиты) уже задано разумными дефолтами в примере. Полное описание каждого ключа — 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): скопируйте его вserver.conf, оставьте нужные профили, заменитеCHANGEME-ключи.
По умолчанию пользователи живут в отдельном файле — auth.users_file (по умолчанию
/etc/qeli/users.conf). Примеры конфигов идут без инлайн-юзеров; заводите их командой
qeli add-client (шаг 6) — она допишет их в этот файл. Больше ничего делать не нужно.
Можно вместо этого держать пользователей инлайн в
server.confсекциями[user:*], но тогдаauth.users_fileигнорируется целиком (инлайн имеет приоритет) — так что не задавайте оба, иначе сервер выдаёт предупреждение, а файл молча отбрасывается. Рекомендуемый вариант по умолчанию — отдельный файл;[user:*]вserver.confне держите.
Сначала проверьте конфиг — это ловит опечатки в ключах (о которых предупреждают §3.1 и §12: неверный ключ молча остаётся с дефолтом) и ключи, убранные в 0.7.12:
sudo qeli check-config --config /etc/qeli/server.conf # сервер (rc≠0 = не запускать)
qeli check-config --config ~/qeli-client.conf --client # клиентский конфигЗатем запуск:
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, и строка с публичным ключом профиля.
sudo qeli show-identity --config /etc/qeli/server.confPROFILE BIND SERVER PUBLIC KEY (pin on client)
tcp tcp://0.0.0.0:443 33f399e6d9b8a31a41e5ffa8b1e1ce457f10d8bbf07c145377fcb7917d532450
Этот hex-ключ клиент пинит (key = …). Команда создаёт ключи профилей, если их
ещё нет (/etc/qeli/identity/<profile>.key).
Почему пиннинг обязателен. По умолчанию включён H-1 (
auth.bind_static_to_session = true): сессионные ключи привязаны к статической личности сервера, поэтому клиент обязан пинить реальный ключ (иначе сервер его отвергнет). Ссылкаqeli://, выданная командойadd-client --link(шаг 6), уже содержит этот ключ — пользователю ничего вручную вписывать не нужно.
После изменения конфига примените его: sudo systemctl restart qeli.
Нужно, только если хотите гнать весь интернет-трафик клиента через сервер (full-tunnel / «выходная нода»). Для split-tunnel (доступ лишь к подсети туннеля и ресурсам за сервером) — пропустите.
Достаточно включить один тумблер в профиле — сервер сам через iptables
включит IP-форвардинг и поставит MASQUERADE + FORWARD + MSS-clamp, а при остановке
снимет правила:
# в [profile:tcp]
routing.nat.enabled = true
# WAN-интерфейс наружу. Оставьте пустым/по умолчанию — определится автоматически
# (ip route get 1.1.1.1); либо задайте явно, напр. ens3.
routing.nat.interface =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 <pool.cidr> -o <wan> -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 → «Тюнинг ОС сервера». Для full-tunnel настоятельно примените. Чтобы правила NAT пережили перезагрузку без сервиса qeli, можно дополнительно сохранить их (
apt install iptables-persistent), но обычно qeli ставит их сам при старте.
sudo qeli add-client alice --password 's3cret'
sudo systemctl restart qeli # перечитать пользователейКоманда Argon2id-хеширует пароль и дописывает секцию [user:alice] в users-файл.
Без --password сгенерирует случайный и напечатает его один раз.
sudo qeli add-client bob \
--password 'pass123' \
--static-ip 10.9.0.50 \ # фиксированный IP в туннеле
--max-sessions 3 \ # сколько устройств одновременно (0 = без лимита)
--profiles tcp # доступ только к профилю tcp (изоляция интерфейсов)| Опция | Назначение |
|---|---|
--password <P> |
пароль (иначе случайный, печатается один раз) |
--static-ip <IP> |
постоянный адрес в туннеле (иначе из пула) |
--max-sessions <N> |
лимит одновременных устройств (0 = наследовать группу/без лимита) |
--profiles a,b |
разрешённые профили (пусто = все) |
--link --host <H[:port]> |
сразу напечатать qeli://-ссылку + QR (см. ниже) |
--link-profile <P> |
для какого профиля строить ссылку (по умолчанию первый) |
sudo qeli add-client carol --password 'pw' --link --host vpn.example.com:443 --link-profile tcpПечатает готовую qeli://…-ссылку (с уже вшитым ключом сервера, режимом, SNI) и
QR-код в терминале — пользователь сканирует его в мобильном клиенте и подключается в
один тап. Ничего вручную вписывать не нужно.
Любые поля можно дописать прямо в секцию [user:*] (см. комментарии в
users.conf):
[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Группы — шаблоны для повторяющихся настроек:
[group:premium]
bandwidth_limit_mbps = 100
max_sessions = 5
allowed_networks = 0.0.0.0/0После правок users-файла — sudo systemctl restart qeli (или примените живой командой,
§10, без перезапуска).
Клиент по умолчанию заворачивает в туннель только подсеть туннеля (pool.cidr).
Остальной трафик идёт мимо VPN. Ничего настраивать на сервере не нужно.
Включается на клиенте (gateway = true в client.conf / тумблер в приложении), а
на сервере требует NAT+форвардинг из §5. Тогда весь интернет клиента выходит с IP
сервера.
Чтобы открыть клиентам доступ к сети за сервером (напр. офисной 192.168.50.0/24),
сервер «пушит» маршрут — клиент сам добавит его в таблицу при подключении:
# в [profile:tcp] — повторяемо
route = 192.168.50.0/24 gateway=10.9.0.1 metric=100gateway — адрес сервера в туннеле (tun.address). metric — приоритет (опц.).
Форвардинг RFC1918-сетей за сервером (routing.forward_private) включён по
умолчанию; поставьте false, чтобы запретить.
Тот же синтаксис, но в секции [user:*] — пушится только этому пользователю:
[user:bob]
route = 10.20.0.0/16 gateway=10.9.0.1 metric=100Ограничивает, куда пользователю можно ходить через туннель (whitelist dst-CIDR). Пусто/нет ключа = без ограничений:
[user:bob]
allowed_networks = 10.9.0.0/24, 192.168.1.0/24# в [profile:tcp]
# разрешить клиентам видеть друг друга в туннеле
routing.client_to_client = true
# закрепить IP за юзером (альтернатива user.static_ip)
pool.reservation.alice = 10.9.0.100Важно различать два разных механизма — это частый источник путаницы:
- Встроенный DNS-прокси (
dns.enabled/dns.listen/dns.upstream) — сервер поднимает резолвер наtun.address:53(кэш, блоклист) и форвардит запросы на upstream. - Какой DNS выдаётся клиентам (
dns.push_servers) — адрес(а), которые клиент пропишет себе. Это отдельный ключ.
Что сервер реально пушит клиенту (server/handler.rs):
dns.push_servers |
dns.enabled |
Клиент получает | Итог |
|---|---|---|---|
задан (напр. 1.1.1.1) |
— | первый адрес из списка | клиент ходит на него напрямую, мимо прокси (кэш/блоклист не действуют) |
| пусто | true |
dns.listen (адрес прокси) |
клиент → прокси на сервере → upstream. Так по умолчанию. |
| пусто | false |
ничего | клиент оставляет свои резолверы |
# в [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 берётся из конфига на диске, а не из несохранённой формы.
- На сервере выдайте ссылку:
qeli add-client <user> --link --host <публичный-host:порт>(§6.3) — получитеqeli://…+ QR. - В приложении: Add profile → Scan QR (или Paste qeli:// link) → профиль появится со всеми параметрами и запиненным ключом сервера.
- Нажмите кольцо подключения. Готово.
Full-tunnel и «маршрутизировать локальные сети» переключаются тумблерами в приложении.
Форма метки времени в окне лога — Настройки → Время в логе (те же пять вариантов, что и
у [logging] time_format на сервере: дата и время / RFC 3339 в UTC / только время / Unix /
без метки). Если собираетесь сверять лог приложения с серверным, поставьте RFC 3339 с обеих
сторон. Применяется сразу, к уже написанным строкам — нет.
iOS. Клиент для iPhone/iPad лежит в
qeli-ios/и по возможностям повторяет Android: те же профили,qeli://-ссылки и QR, те же режимы обмена, русский/английский интерфейс, виджет и переключатель в Пункте управления. Он собирается из исходников на macOS (Xcode 16+, см. README) — готовой сборки в релизах нет, и на живом устройстве он ещё не проверялся. Отличия, продиктованные платформой: маршрутизация «по приложениям» доступна только через MDM, а вместо автоподключения при загрузке используется VPN On Demand — подробности вqeli-ios/PARITY.md.
⚠️ macOS — первый запуск. Приложение подписано ad-hoc (не нотаризовано Apple), поэтому Gatekeeper его блокирует и оно не откроется двойным кликом. Один раз снимите карантин в Терминале:xattr -cr /Applications/Qeli.app(см. qeli-mac/README.md).
sudo cp /etc/qeli/client.conf.example /etc/qeli/client.conf
sudo nano /etc/qeli/client.confМинимум (см. client.conf — описан каждый ключ):
[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 = per-link DNS через systemd-resolved; off = DNS управляет платформа
dns = tunnelsudo qeli client --config /etc/qeli/client.confПри H-1 (дефолт)
keyобязателен и должен быть реальным (не нулевым). Если на сервереbind_static_to_session = false, можно работать по TOFU (нулевойkey).
Полный гайд — PANEL.md. Краткий старт:
# задать админ-пароль (генерирует/хеширует, прописывает в [web], включает панель)
sudo qeli set-web-password # случайный пароль, печатается один раз
# или свой: sudo qeli set-web-password --password 'PANELPASS'Добейте секцию [web] и перезапустите. Начните с loopback — это значение по
умолчанию, и для него не нужно ничего открывать в файрволе:
[web]
enabled = true
bind = 127.0.0.1
port = 8080
# встроенный HTTPS (self-signed авто; браузер предупредит 1 раз)
tls = true
# хост по умолчанию для share-ссылок
# public_host = vpn.example.comДоступ со своей машины — через SSH-форвард:
ssh -L 8080:127.0.0.1:8080 root@<сервер> # затем откройте https://127.0.0.1:8080Если панель действительно нужна на внешнем адресе — публикуйте её со списком
источников, а не без него. Кроме пароля, allowed_ips — единственное, что отделяет
открытый интернет от интерфейса, который управляет пользователями, переписывает конфиг,
ротирует identity-ключи и восстанавливает бэкапы:
[web]
enabled = true
bind = 0.0.0.0
port = 8080
tls = true
allowed_ips = 203.0.113.4 # ЗДЕСЬ ОБЯЗАТЕЛЕН — ваш адрес (адреса)
# public_host = vpn.example.com
# дефолтный хост для share-ссылок
# public_host = vpn.example.comsudo systemctl restart qeliFail-closed: с пустым
password_hashпанель не стартует ни на какомbind, включая loopback (с 0.7.12 — раньше loopback был исключением и отдавал открытую панель). VPN:443при этом работает — это отдельный процесс. Хеш задаётся черезqeli set-web-password; осознанный отказ —web.insecure_no_auth = true. Откройте порт8080в файрволе.
Откройте https://<bind>: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 без ввода пароля (сервер хранит обратимо-зашифрованную копию; пароль не меняется).
Панель умеет не только раздавать 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]…).
- Import qeli:// link — вставить
-
Каждый профиль управляется НЕЗАВИСИМО. Создание профиля его не подключает — он лежит в статусе Disconnected. У каждого своя кнопка Connect / Disconnect; жмёте только на нужные. Статус (подключён + хвост лога) обновляется сам.
-
Несколько подключений одновременно — поднимайте сколько нужно: каждому профилю автоматически выдаётся свой TUN-интерфейс (
vpn0/vpn1/…, виден в списке), так что туннели не конфликтуют. К одному серверу — заведите несколько профилей (один тоннель на профиль). Любой режим, не только reality-tls. -
⚠️ Full-tunnel и несколько туннелей. Маршрут по умолчанию в системе один, поэтому несколько одновременных full-tunnel конфликтуют — для мульти-релея используйте split-tunnel (и разные пул-подсети на серверах), либо держите full-tunnel по одному. Полный заворот на сервере-боксе может отрезать саму панель/SSH — включайте осознанно. -
Хранилище: профили лежат в
/etc/qeli/clients/<name>.conf(тот же flat-INI). Это значит, то же самое можно сделать и файлами: положить конфиги туда и запускатьqeli client --config /etc/qeli/clients/<name>.conf(для нескольких — разныйdevв каждом файле). Готовый пример клиента —client-reality.confи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/<name>.conf(правьте руками — эффект тот же, что и галочка).
Флаг независим для каждого профиля — автозапускаются только помеченные, остальные остаются Disconnected до явного Connect. Снять автозапуск — снять галочку (или убрать строку из файла).
- в панели — галочка «Auto-connect this profile when the server/panel starts» в форме
профиля (в списке такой профиль помечен значком
qeli — один бинарь с подкомандами; есть ещё тонкий клиентский бинарь qeli-client.
Команды делятся по тому, как они общаются с сервером: правят конфиг на диске (нужен
рестарт) или идут через control-сокет (применяются на лету). qeli --help и
qeli <команда> --help печатают то же самое.
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. Руками не запускать.
Правят файл конфига/ключей на диске (-c/--config, дефолт /etc/qeli/server.conf),
а не сокет — где меняется конфиг или ключ, нужен рестарт сервиса:
# добавить пользователя (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=, рестартОтвечает на вопрос «клиент потерял настройки / сменил телефон — как выдать ему конфиг
заново». add-client для этого не годится: он создаёт пользователя и на существующем
имени падает с ошибкой.
qeli share-link <username> [--host <адрес[:порт]>] [--profile <имя>]
[--label <текст>] [--reset] [-c <конфиг>]
| Флаг | По умолчанию | Что делает |
|---|---|---|
<username> |
— | обязателен: существующий пользователь из 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 и из панели совпадают.
# типовой случай: адрес уже задан в 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:
sudo qeli share-link alice --reset # печатает НОВЫЙ пароль один раз
sudo systemctl reload qeli # обязательно: иначе сервер проверяет старый пароль
⚠️ --resetразрушающий: конфиг, которым пользователь пользуется сейчас, перестаёт работать — ему нужно передать новую ссылку. И, в отличие от панели, у CLI нет канала к работающему воркеру, поэтому перечитать пользователей нужно вручную (reload); команда сама об этом напоминает в выводе.
Идут через --socket (дефолт /var/run/qeli/control.sock) — применяются немедленно:
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 — со всех)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, как только причина отпадёт.
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.
Задаётся 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. Бенчмарки всех режимов — BENCHMARK.md.
- Сервер отказывается стартовать: «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). Свои сети смотрите через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 <ip>(или--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, иначе заблокируете сами себя.
По ролям — удаляйте только то, что ставили. <ПОРТ> ниже = порт вашего профиля (напр. 443).
# 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 (он трогает ОС):
# 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— они исчезнут сами после перезагрузки.
Чистая остановка (Ctrl+C) сама восстанавливает /etc/resolv.conf, снимает
kill-switch / NAT и удаляет tun. Руками — только если клиент упал:
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общий — не удаляйте его, пока не снесли сервер.
- Windows: закрыть приложение → удалить
QeliWin(папку portable-сборки или через «Приложения и возможности»). Wintun-адаптер эфемерный — создаётся и удаляется на каждый сеанс, после «Отключить» в системе не остаётся; маршруты/DNS восстанавливаются там же. Данные (профили / настройки / device-id) — удалить папки:%AppData%\QeliWin,%LocalAppData%\qeli,%ProgramData%\QeliWin. - macOS: закрыть → удалить
QeliMac.app.utunуправляется ядром — исчезает при отключении. Данные — удалить~/.local/share/qeli; если включали автозапуск — снять LaunchAgent из~/Library/LaunchAgents(файл сqeliв имени).
Настройки → Приложения → qeli → Удалить. Сносит всё: профили (в шифрованном хранилище), device-id, виджет, QS-плитку, автозапуск на буте. Для полной чистоты — отозвать VPN-согласие и выключить Always-on VPN (если включали): Настройки → Сеть/Подключения → VPN → qeli.
OpenWrt:
/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 restartKeenetic: остановить и удалить init-скрипт, бинарь и конфиг — обратно шагам установки
(см. docs/*/KEENETIC-DEPLOY.md).
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.