From 04db4a359e67f73e3f197a5265f7932e4e394a2a Mon Sep 17 00:00:00 2001 From: savsis Date: Thu, 10 Sep 2026 23:25:37 +0500 Subject: [PATCH] =?UTF-8?q?ui:=20dark=20scrollbars=20everywhere,=20=D0=94?= =?UTF-8?q?=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=20section=20(architecture/nodes/password/fail2ban)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- admin.html | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/admin.html b/admin.html index ef86a94..677a502 100644 --- a/admin.html +++ b/admin.html @@ -23,6 +23,11 @@ font-family: Montserrat, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; } + * { scrollbar-color: var(--border-strong) transparent; scrollbar-width: thin; } + ::-webkit-scrollbar { width: 10px; height: 10px; } + ::-webkit-scrollbar-track { background: transparent; } + ::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 10px; border: 2px solid var(--bg); background-clip: padding-box; } + ::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: padding-box; } button, input, select { font-family: inherit; font-size: 14px; } a { color: var(--accent); text-decoration: none; } @@ -207,6 +212,11 @@ font-family: "Fira Mono", ui-monospace, monospace; font-size: 12.5px; color: var(--accent); word-break: break-all; position: relative; } + .doc-block { margin-bottom: 30px; padding-bottom: 26px; border-bottom: 1px solid var(--border); } + .doc-block:last-child { border-bottom: none; } + .doc-block h2 { font-size: 16px; margin: 0 0 12px; font-weight: 600; } + .doc-block p { font-size: 13.5px; color: var(--text-dim); line-height: 1.65; margin: 0 0 10px; } + .doc-block code { background: rgba(255,255,255,0.06); padding: 1px 6px; border-radius: 5px; font-family: "Fira Mono", ui-monospace, monospace; font-size: 12px; } .copy-btn { position: absolute; top: 8px; right: 8px; background: var(--card2-tint); border: 1px solid var(--border); color: var(--muted); border-radius: 6px; padding: 4px 8px; font-size: 11px; cursor: pointer; @@ -283,6 +293,7 @@ + + +
+
Документация
+
Как устроена панель и как её обслуживать — без похода на GitHub
+ +
+

Архитектура

+

Панель — три процесса: bot.py (телеграм-бот, aiogram) и api.py (FastAPI — админка + выдача подписок) читают одну SQLite-базу; Xray — отдельный процесс, который реально гоняет трафик. Панель никогда не проксирует VPN-трафик сама, только управляет конфигом Xray и читает его статистику через встроенный Stats API.

+

На 443 порту одновременно живёт и настоящий HTTPS (для сайта/подписки), и замаскированный под HTTPS VLESS+Reality — их разводит nginx stream модуль по SNI входящего TLS-соединения, до расшифровки.

+
+ +
+

Ноды

+

Локальная нода (обычно de1) — Xray на том же сервере, что и панель, управляется напрямую правкой config.json. Управляемые ноды — отдельные серверы, панель ходит на них по SSH management-ключу (генерится сам при первом добавлении ноды, публичная часть раздаётся install-скриптом ноды — панель никогда не просит пароль от нового сервера).

+

Добавление ноды: Ноды → Добавить ноду → один bash <(curl ...)> на чистый сервер. Редактирование существующей: кнопка «Редактировать» у ноды — для de1 доступно только название (реальные параметры подключения там берутся из .env, не из базы).

+
+ +
+

Пароль и безопасность

+

Пароль админ-панели меняется командой mbs pass на сервере (без аргумента — сгенерит случайный). Панель физически откажется стартовать, если в .env стоит "change-me"/"admin"/что-то короче 8 символов — так что пропустить это не выйдет по-тихому.

+

Сессия логина живёт в httpOnly-куке, на /admin/api/login висит rate-limit (5 попыток в минуту с одного IP). SSH-доступ на сервер — сам по себе, панель на него не влияет; отдельно стоит подумать про отключение root-логина по паролю в пользу ключей, если этого ещё не сделано.

+
+ +
+

fail2ban

+

install.sh ставит и включает fail2ban автоматически (дефолтный jail — защита SSH от перебора паролей). Проверить, что работает:

+
fail2ban-client status
+

Посмотреть забаненные IP по конкретному джейлу: fail2ban-client status sshd. Разбанить: fail2ban-client set sshd unbanip АЙПИ.

+
+