chore: сделал
This commit is contained in:
1 parent
602199d510
commit
45e7a1d22f
25 files changed
+1164
-113
No files matched your search
+17
-3
@@ -5,7 +5,7 @@ Django приложение связывающее все части сайта
|
||||
-[x] Реализует кастомный менеджер модели и кастомную модель пользователя с отключенным email.
|
||||
-[x] Модель данных для поддержки интерфейса и функционала
|
||||
-[ ] Настройки домена и прокси у готовой точки
|
||||
-[ ] Клиенты и статистика через API панели 3x-ui
|
||||
-[x] Клиенты и статистика через API панели 3x-ui
|
||||
|
||||
Зависимости: `Telegram` (интерфейс бота, пользователи, уведомления) и `serverus` (настройка серверов).
|
||||
|
||||
@@ -13,6 +13,7 @@ Django приложение связывающее все части сайта
|
||||
|
||||
- `Point` - точка доступа: сервер с панелью 3x-ui и необязательный сервер маскировки. Владелец - `Telegram.User`. Хранит домен, прокси на выходе и доступ к панели.
|
||||
- `Server` - сервер точки с ролью `panel` или `mask`. Хранит текущие порт ssh, пароль root, ключ и отпечаток ssh, а также пароль root, присланный пользователем при добавлении (`default_root_password`).
|
||||
- `Key` - ключ клиента на панели точки: имя (оно же email клиента в панели), `uuid` и `sub_id`. Клиенту выдается `key.subscription_url`, после переустановки ключ восстанавливается с теми же ссылками.
|
||||
|
||||
С маскировкой клиенты подключаются к серверу маскировки, он перенаправляет трафик на панель и скрывает ее адрес. Маскировка требует домен.
|
||||
|
||||
@@ -20,14 +21,17 @@ Django приложение связывающее все части сайта
|
||||
|
||||
- создание: `Point.objects.create_point(owner, panel, mask=None, *, domain, outbound_proxy)` создает точку вместе с серверами, имя и доступ к панели генерирует сама. `Server.objects.create_server(point, role, credentials)`. `Credentials` - адрес и пароль root, которые прислал пользователь
|
||||
- поиск: `Point.objects.owned_by(owner)`, дальше `find_by_name`, `find_by_pk`, `find_last`. У серверов `find_by_address` и `is_address_taken`, в том числе в пределах точки через `point.servers`
|
||||
- изменение: `point.set_status(status, error)`, `server.reset_fingerprint()`
|
||||
- изменение: `point.set_status(status, error)`, `server.reset_fingerprint()`. Статусы: `installing`, `updating` (меняется домен или прокси готовой точки), `ready`, `error`, `releasing`. Пока точка занята, с ней ничего не сделать. Неудачная смена домена или прокси оставляет точку `ready` с текстом ошибки: serverus применяет их только после выпуска сертификата и проверки прокси
|
||||
- ключи: `services.issue_key(point, name)`, `services.revoke_key(key)`, поиск `point.keys.find_by_name(name)`
|
||||
- удаление: `point.delete()`, серверы удаляются вместе с точкой
|
||||
|
||||
Соглашение для поиска: `get_*` и `point.server(role)` бросают `DoesNotExist`, если записи нет, а `find_*` возвращают `None`, и это видно по типу. `point.panel` всегда есть, потому что панель создается вместе с точкой, а `point.mask` может быть `None`.
|
||||
|
||||
## Модули
|
||||
|
||||
- `services.py` - сценарии поверх serverus: `install_point`, `reinstall`, `release_point`, у готовой точки `set_domain` (новый сертификат) и `set_outbound_proxy`.
|
||||
- `services.py` - сценарии поверх serverus: `install_point`, `reinstall`, `release_point`, у готовой точки `set_domain` (новый сертификат) и `set_outbound_proxy`. Ключи через API панели: `issue_key`, `revoke_key`, `key_traffic`, `restore_keys`.
|
||||
- `fields.py` - `EncryptedTextField`: секреты в базе зашифрованы Fernet ключами `FIELD_ENCRYPTION_KEYS` из `.env`.
|
||||
- `management/commands/serve_ssh.py` - ручной вход на сервер: `make serve_ssh ip=<ip>`.
|
||||
- `tasks.py` - задачи dramatiq: запускают сценарий и присылают результат в чат. Воркер: `make dj_worker`.
|
||||
- `bot/interface.py` - интерфейс бота `MyPointInterface` (выбирается у бота в админке).
|
||||
- `bot/texts.py` - кнопки и тексты.
|
||||
@@ -38,6 +42,7 @@ Django приложение связывающее все части сайта
|
||||
2. панель: 3x-ui с логином, паролем, портом и путем, которые сгенерировал App, сертификат на домен или ip, подписка, подключение reality `main`, исходящий прокси точки
|
||||
3. маскировка: перенаправление трафика на адрес панели
|
||||
4. facts: `uname -a` для карточки сервера
|
||||
5. ключи точки восстанавливаются на панели (`restore_keys`), при первой установке их нет
|
||||
|
||||
"Переустановить" сбрасывает отпечаток ssh сервера и повторяет установку с новым паролем от провайдера или, по кнопке "Использовать старый", с паролем, присланным при добавлении сервера. Отпечаток можно сбросить и в админке.
|
||||
|
||||
@@ -52,3 +57,12 @@ Django приложение связывающее все части сайта
|
||||
Решение: за Cloudflare не работаем. Reality через проксирование Cloudflare невозможен: Cloudflare сам завершает TLS.
|
||||
- [x] нужна функция установки прокси в исходящие (outbound)
|
||||
При установке ставится `point.outbound_proxy`, у готовой точки - `services.set_outbound_proxy(point, proxy)`. Поддерживаются socks5, http(s) и cf_warp.
|
||||
- [x] кнопки "Домен" и "Прокси" у готовой точки: задачи `tasks.set_domain` и `tasks.set_outbound_proxy`, прокси в брокер уходит зашифрованным
|
||||
|
||||
## Секреты
|
||||
|
||||
Ключи и пароли серверов (`private_key`, `root_password`, `default_root_password`), доступ к панели (`panel_password`, `panel_api_token`), исходящий прокси и ключи клиентов (`uuid`, `sub_id`) хранятся зашифрованными (`App.fields.EncryptedTextField`, Fernet). Дамп базы без ключа не дает доступа к серверам. Искать по этим полям нельзя.
|
||||
|
||||
- Ключ - `FIELD_ENCRYPTION_KEYS` в `.env` (настройки сами читают `.env`, как бы ни был запущен сайт, воркер или бот). Потеря ключа - потеря доступа ко всем серверам: храните его отдельно от бэкапов базы.
|
||||
- Смена ключа: новый ключ первым через запятую, старый следом, пересохранить записи, убрать старый.
|
||||
- Ручной вход на сервер: `make serve_ssh ip=<ip>` (или `manage.py serve_ssh <ip> [команда]`). Ключ и отпечаток берутся из базы, ключ живет во временной папке только на время сессии. В админке и боте приватный ключ не показывается.
|
||||
Reference in new issue
Block a user