From edc1c68abad20408aafbf2290e94d2d1cb56a625 Mon Sep 17 00:00:00 2001 From: infra-bot Date: Thu, 27 Aug 2026 16:30:01 +0300 Subject: [PATCH] README: SVG architecture diagram replaces mermaid; embed + text fallback; assets/readme added --- .gitignore | 1 + README.md | 31 +++---- assets/readme/architecture.svg | 140 ++++++++++++++++++++++++++++++ scripts/validate_readme_assets.py | 17 ++++ 4 files changed, 170 insertions(+), 19 deletions(-) create mode 100644 assets/readme/architecture.svg create mode 100644 scripts/validate_readme_assets.py diff --git a/.gitignore b/.gitignore index d75f0f0..00b8815 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ !install.sh !scripts/** !config/** +!assets/** *.sql.gz *.tar.gz .env diff --git a/README.md b/README.md index dec9a65..573e125 100644 --- a/README.md +++ b/README.md @@ -25,28 +25,21 @@ MySQL слушает TCP и ловит сканеры портянкой aborted ## Архитектура -```mermaid -flowchart TB - U["Браузер"] -->|"HTTPS :443"| NG +

+ Схема: браузер по HTTPS заходит на nginx; nginx через unix-сокет передаёт php-fpm; php-fpm работает с Percona MySQL только локально и с двумя memcached; cron выполняет агентов и бэкапы; CrowdSec и fail2ban читают журналы и блокируют атакующих; TCP у MySQL закрыт +

- subgraph VPS["Ubuntu 24.04, без Docker"] - NG["nginx
TLS · статика · urlrewrite
limit_req zones"] +
+Текстовая версия схемы - NG -->|"fastcgi, unix-сокет
/run/php/bitrix-fpm.sock"| PHP["php-fpm pool 'bitrix'
dynamic, max 30, max_requests 500"] - PHP -->|"localhost = сокет"| DB[("Percona MySQL 8.0
bind 127.0.0.1 only")] - PHP --> MC1[("memcached cache
127.0.0.1:11211")] - PHP --> MC2[("memcached sessions
127.0.0.1:11212")] +- Браузер → HTTPS :443 → nginx (TLS, статика, urlrewrite, limit_req) +- nginx → fastcgi unix-сокет → php-fpm pool «bitrix» (dynamic, max 30) +- php-fpm → `localhost` = сокет → Percona MySQL 8.0; TCP :3306/:33060 закрыты +- php-fpm → memcached :11211 (кэш) и :11212 (сессии) +- cron CLI php → агенты каждую минуту, обмен 1С каждые 5 минут, бэкапы в `/var/backups/bitrix` +- nginx access.log → CrowdSec + firewall-bouncer; sshd → fail2ban; оба банят источники атак - CRON["cron (CLI php)
agents · exchange · backup"] - CRON --> PHP - CRON --> DB - end - - LOGS["nginx access.log (combined)"] -.->|parse| CS["CrowdSec + firewall-bouncer"] - SSHD["sshd journal"] -.-> F2B["fail2ban"] - CRON --> BAK["backups:
mysqldump + code tarball
retention 14 дней"] - CS -.->|"блокирует"| U -``` +
Ключевые отличия от «Bitrix VM по умолчанию»: diff --git a/assets/readme/architecture.svg b/assets/readme/architecture.svg new file mode 100644 index 0000000..fb15449 --- /dev/null +++ b/assets/readme/architecture.svg @@ -0,0 +1,140 @@ + + bitrix-vps-infra: схема взаимодействия сервисов + Браузер обращается к nginx по HTTPS; nginx передаёт PHP в php-fpm через unix-сокет; php-fpm работает с Percona MySQL только по локальному сокету и с двумя инстансами memcached; cron на CLI php выполняет агентов, обмен с 1С и бэкапы; nginx отдаёт логи CrowdSec и fail2ban, которые блокируют атакующих. TCP у MySQL закрыт. + + + + + + + + + + + + + + + + + Архитектура стека + один VPS, нативные пакеты, без Docker + + + + + + Браузер + посетители + + + + + + VPS · UBUNTU 24.04 · НАТИВНО, БЕЗ DOCKER + + + + + + + nginx + TLS · статика без PHP · urlrewrite · limit_req · gzip + + + + + + + php-fpm 8.4 + pool «bitrix»: dynamic · max_children 30 + listen /run/php/bitrix-fpm.sock + max_requests 500 · slowlog > 5s + + + + + + memcached · кэш + 127.0.0.1:11211 · igbinary + + + memcached · сессии + 127.0.0.1:11212 · отдельно от кэша + + + + + + + Percona MySQL 8.0 + innodb_buffer_pool_size = 4G + + ✕ внешние :3306 + + ✕ только unix-сокет + + + + + + cron · CLI php + агенты раз в минуту · exchange */5 + + + бэкапы + /var/backups/bitrix · 14 дней + + + + + + ЗАЩИТА ПЕРИМЕТРА + + + CrowdSec + access.log · баны в nftables + + + fail2ban + sshd jail · ban 1h + + + + + + HTTPS :443 + + + fastcgi + unix socket + + + + + + localhost = сокет + + + + + + + + + + + + + отбой атакующих + + + + HTTP-запросы + сокеты и данные + журналы + блокировка + + + + diff --git a/scripts/validate_readme_assets.py b/scripts/validate_readme_assets.py new file mode 100644 index 0000000..9ddfd10 --- /dev/null +++ b/scripts/validate_readme_assets.py @@ -0,0 +1,17 @@ +import io, collections, re +import xml.etree.ElementTree as ET + +t = io.open('assets/readme/architecture.svg', encoding='utf-8').read() +ET.fromstring(t) +for bad in ('