Заданы права системных каталогов независимо от umask, добавлен журнал незавершённой установки и исправлена подсказка прав профиля. Проверены явные флаги systemd через подставные API ОС. Проверка: 72 теста на Python 3.8 и 3.14, оба shell-набора. Настоящий boot/systemd остаётся непроверенным.
174 lines
15 KiB
Markdown
174 lines
15 KiB
Markdown
# Профили proxy-client и системная служба
|
||
|
||
Дата: 2026-11-02
|
||
|
||
Статус: реализовано; запуск после загрузки ОС и восстановление настоящей
|
||
службы systemd требуют отдельной проверки на Linux-ВМ.
|
||
|
||
## Задача и границы
|
||
|
||
На Linux-ВМ, компьютерах и ноутбуках нужен прокси, доступный после загрузки
|
||
без входа пользователя и ручного запуска. Приложения уже знают его адрес.
|
||
Одновременно пользователь должен иметь возможность запустить другой прокси
|
||
на другом порту в открытом терминале.
|
||
|
||
Это расширяет [первоначальный дизайн](2026-07-15-proxy-client-design.md):
|
||
добавляет системную службу и несколько пользовательских профилей.
|
||
Остальные ограничения и принцип личного инструмента сохраняются.
|
||
Термины определены в [CONTEXT.md](../../CONTEXT.md).
|
||
|
||
Не добавляем несколько системных экземпляров, фоновый пользовательский режим,
|
||
TUN, системную маршрутизацию, автоматический выбор прокси или поддержку Windows.
|
||
Для системного режима требуется systemd; ручной режим сохраняет независимость
|
||
от него. Пакет по-прежнему можно использовать отдельно от остальных dotfiles.
|
||
|
||
## Пользовательские профили
|
||
|
||
Профиль по умолчанию сохраняет нынешние файлы
|
||
`~/.config/proxy-client/config` и `default.url`. Отсутствие выбора профиля
|
||
не меняет поведения существующих команд, включая прежний внешний прокси
|
||
при отсутствии конфигурации. Учитываются существующие настройки XDG.
|
||
|
||
Дополнительные профили размещаются в
|
||
`~/.config/proxy-client/profiles/<имя>/`, каждый со своими `config` и
|
||
`default.url`. Имя `default` обозначает существующий профиль по умолчанию.
|
||
Неизвестное имя даёт ошибку, а не переход к другому профилю.
|
||
|
||
Один общий параметр выбора профиля действует на запуск, остановку, проверку,
|
||
вывод окружения и запуск дочерних команд. Существующий выбор файла VLESS-ссылки
|
||
через `start -f` остаётся разовым переопределением ссылки выбранного профиля.
|
||
Bash-команды без явного выбора продолжают использовать профиль по умолчанию.
|
||
|
||
Каждый профиль получает собственные сведения о процессе, блокировку и
|
||
сгенерированный JSON. Запуск и остановка одного не затрагивают остальные.
|
||
Два экземпляра могут работать одновременно, если их локальные порты различны.
|
||
Занятый порт даёт ошибку; чужой процесс не останавливается.
|
||
|
||
Ручной запуск остаётся на переднем плане, с выводом в терминал и остановкой
|
||
через Ctrl+C либо команду остановки выбранного профиля. Само обращение к прокси
|
||
через `run` или `env` ничего не запускает.
|
||
|
||
## Bash-команды
|
||
|
||
`proxy_on` без параметров выбирает профиль по умолчанию, с `--profile` —
|
||
именованный. Он меняет только окружение текущего терминала после успешной
|
||
проверки. `proxy_off` очищает переменные, но не останавливает процессы.
|
||
`myip` использует текущее окружение.
|
||
|
||
`pclaude` и `pcodex` принимают ведущий `--proxy-profile` для выбора профиля.
|
||
Без него остаётся профиль по умолчанию; остальные аргументы и код возврата
|
||
дочерней программы сохраняются. Обычный `--profile` относится к дочерней
|
||
программе. Bash-модуль передаёт выбор CLI и не дублирует правила профилей.
|
||
|
||
Выбор через `proxy_on` не меняет профиль по умолчанию: обычная команда
|
||
наследует окружение, а обёртка с префиксом `p` явно выбирает свой профиль.
|
||
Это различие должно быть показано в README пакета.
|
||
|
||
## Системная служба
|
||
|
||
Одна служба `proxy-client.service` читает один комплект настроек из
|
||
`/etc/proxy-client/`. Ей не нужны именованные профили или домашний каталог
|
||
пользователя. Исполняемые файлы устанавливаются в системное расположение,
|
||
без ссылок на пользовательский каталог исходников. Xray работает под отдельной
|
||
непривилегированной учётной записью и слушает только loopback.
|
||
|
||
Временные файлы процесса, блокировка и сгенерированный JSON находятся в
|
||
закрытом `/run/proxy-client/`. Секреты доступны только администратору и
|
||
служебной учётной записи. Пользовательские команды остановки не управляют
|
||
системным экземпляром: за него отвечает systemd.
|
||
|
||
Установка оформляется подкомандой `service install`, в соответствии с
|
||
существующим интерфейсом CLI. Она размещает необходимые файлы и регистрирует
|
||
службу. Запуск сейчас и автозапуск после загрузки выбираются явно; установщик
|
||
может предоставить явные параметры для совмещения этих действий с установкой.
|
||
Точное написание параметров определяется при реализации.
|
||
|
||
Для первоначального заполнения можно скопировать выбранный пользовательский
|
||
профиль. Источник должен быть указан однозначно: повышение прав не должно
|
||
подменить его домашним каталогом root. Копия становится самостоятельной:
|
||
дальнейшие изменения домашнего профиля не меняют службу. Повторная установка
|
||
сохраняет существующие настройки и не перезапускает службу скрыто.
|
||
|
||
Systemd отвечает за запуск, остановку и перезапуск после аварии. Явная
|
||
остановка должна оставлять службу остановленной до следующего запуска.
|
||
Если автозапуск включён, после перезагрузки она запускается снова.
|
||
|
||
Отсутствие внешней сети при загрузке не должно приводить к окончательному
|
||
отказу службы. Готовность локального порта и доступность удалённого маршрута
|
||
различаются: автозапуск не гарантирует успешность первого запроса любого
|
||
приложения. Для приложений, не умеющих повторять запрос, порядок запуска и
|
||
ожидание готовности потребуют отдельной настройки.
|
||
|
||
## Журналы и совместная работа
|
||
|
||
Вывод службы направляется в journald. Отдельный текстовый журнал и собственная
|
||
ротация не нужны. Хранение между загрузками зависит от настройки journald;
|
||
установщик проверяет её и сообщает результат, не меняя глобальную политику
|
||
журналирования машины. Секреты не должны попадать в журнал.
|
||
|
||
Если системная служба занимает порт прежнего пользовательского Xray, второй
|
||
запуск на этом порту завершается ошибкой. Чтобы использовать системный прокси
|
||
через пользовательские команды, подходит профиль типа `external`. Для второго
|
||
Xray нужен другой порт. Установка службы не меняет домашний профиль молча.
|
||
|
||
## Устройство модулей
|
||
|
||
Применяем `codebase-design`: выбор профиля и все его пути должны определяться
|
||
в одном месте, чтобы команды не повторяли правила размещения файлов.
|
||
Управление процессом использует уже выбранные настройки и расположение файлов.
|
||
Системная установка скрывает размещение, права и взаимодействие с systemd
|
||
за небольшим интерфейсом; не копирует разбор VLESS и управление Xray.
|
||
|
||
Не вводим обобщённую поддержку других менеджеров служб и дополнительные
|
||
слои ради возможного будущего использования. Реально различаются
|
||
пользовательское и системное размещение, а также способ управления процессом.
|
||
|
||
## Проверки
|
||
|
||
Согласованы три интерфейса для новых тестов TDD:
|
||
|
||
1. CLI пользовательских профилей: прежнее поведение без имени, выбор
|
||
именованного профиля, два одновременных процесса, независимая остановка,
|
||
отказ при занятом порте и правильное окружение дочерней команды.
|
||
2. Установка службы через CLI и управление через systemd: размещение файлов,
|
||
сохранение настроек при повторной установке, явное включение автозапуска,
|
||
запуск и остановка, восстановление после аварии и доступность журналов.
|
||
|
||
3. Bash-команды: выбор профиля, передача аргументов и кода возврата,
|
||
сохранение окружения при ошибке и отсутствие остановки процессов.
|
||
|
||
Тесты проверяют наблюдаемое поведение через эти интерфейсы, а не внутренние
|
||
функции и последовательности их вызовов. Идём по одному сценарию:
|
||
падающий тест, минимальная реализация, следующий сценарий.
|
||
|
||
Локальные проверки используют временные каталоги, синтетические профили и
|
||
подставные внешние программы. Это не доказывает работу настоящего systemd.
|
||
Окончательная проверка системного режима нужна в отдельной Linux-среде
|
||
с systemd: запуск до входа пользователя после загрузки, восстановление после
|
||
аварии, явная остановка и одновременная работа ручного экземпляра.
|
||
Изменение текущей машины или её перезагрузка не входят в проверку по умолчанию.
|
||
|
||
Локальный набор прошёл на Python 3.8 и 3.14: 72 теста, проверки Bash-команд
|
||
и пользовательского установщика. Дополнительно проверены Bash-команды вместе
|
||
с настоящим CLI и двумя локальными тестовыми портами. Unit прошёл статическую
|
||
проверку в изолированном корне с тестовыми базовыми target-файлами.
|
||
Shellcheck в среде отсутствует. Эти результаты не заменяют проверку загрузки ОС.
|
||
|
||
## Документация и альтернативы
|
||
|
||
Подробные инструкции размещены в
|
||
[`proxy-client/README.md`](../../proxy-client/README.md): профили, системная
|
||
установка и обновление, управление, автозапуск, журналы и диагностика.
|
||
В корневом README достаточно существующей ссылки на пакет. Этот документ
|
||
хранит причины решений; рабочие команды и примеры живут в README пакета.
|
||
|
||
Пользовательская служба с linger позволила бы запускать прокси до входа,
|
||
но выбрано явное разделение системных и домашних настроек. Несколько
|
||
именованных системных служб пока не нужны. Запуск в терминале сохраняется
|
||
для дополнительных прокси, но сам по себе не решает задачу загрузки машины.
|
||
|
||
Правила systemd сверены с документацией
|
||
[каталогов службы](https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#RuntimeDirectory=),
|
||
[перезапуска](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html#Restart=)
|
||
и [хранения журналов](https://www.freedesktop.org/software/systemd/man/latest/journald.conf.html#Storage=).
|