diff --git a/README.md b/README.md
index 70c611a..70addb2 100644
--- a/README.md
+++ b/README.md
@@ -23,9 +23,9 @@ TLS: HAProxy на **443** в режиме **TCP + SNI**, **не терминир
| Zabbix (веб) | **`zabbix.kalinamall.ru`** | **192.168.160.53** | **80** (HTTP) | **`zabbix-allowed`** |
| Synology DSM | **`heap.kalinamall.ru`** | **192.168.160.185** | 443 → **5001** | **`syno-allowed`** |
| Synology DSM | **`exchange.kalinamall.ru`** | **192.168.160.35** | 443 → **5001** | **`syno-allowed`** |
-| Почтовый шлюз (KSMG) | `ksmg.kalinamall.ru` | **192.168.160.57** | 25 | нет |
+| Почтовый шлюз (KSMG) | `ksmg.kalinamall.ru` | **192.168.160.57** | 25 | нет (с интернета на HAProxy не проброшен; см. [security/architecture.md](docs/security/architecture.md)) |
-DNS: **A** для `ext`, `autodiscover`, `rds`, `erp`, `git`, `sac`, **`sac-api`**, **`zabbix`**, **`heap`**, **`exchange`**, `ksmg` → публичный IP HAProxy.
+DNS: **A** для `ext`, `autodiscover`, `rds`, `erp`, `git`, `sac`, **`sac-api`**, **`zabbix`**, **`heap`**, **`exchange`** → публичный IP HAProxy. Inbound SMTP (**25**) с интернета на HAProxy **не** пробрасывается; `ksmg` / MX — отдельная схема (см. [security/architecture.md](docs/security/architecture.md)).
Снаружи Zabbix — **`http://zabbix.kalinamall.ru`**. Synology DSM — **`https://heap.kalinamall.ru`**, **`https://exchange.kalinamall.ru`** (TLS на NAS, wildcard `*.kalinamall.ru`). Имя **`exchange.kalinamall.ru`** — NAS, не OWA (**`ext.kalinamall.ru`**).
diff --git a/docs/haproxy-install.md b/docs/haproxy-install.md
index 0518140..373fcca 100644
--- a/docs/haproxy-install.md
+++ b/docs/haproxy-install.md
@@ -63,7 +63,7 @@ sudo haproxy -c -f /etc/haproxy/haproxy.cfg
## Порты на фаерволе
-На хосте с HAProxy с интернета обычно открывают только то, что слушает конфиг: **25**, **80** (Zabbix HTTP), **443** (и при использовании — **8404** для stats). Остальной трафик — по политике безопасности.
+На хосте с HAProxy с **интернета** (MikroTik DNAT) доступны только **80** (Zabbix HTTP) и **443**. Порт **25** в конфиге есть, но с периметра **не проброшен**. Остальной трафик — по политике безопасности.
**Полный план:** [docs/security/README.md](security/README.md) — UFW, бэкенды, чеклист, скрипты `scripts/security/`.
diff --git a/docs/security/README.md b/docs/security/README.md
index ebf99e3..cc278d3 100644
--- a/docs/security/README.md
+++ b/docs/security/README.md
@@ -1,13 +1,13 @@
-# Безопасность периметра HAProxy (kalinamall.ru)
+# Безопасность периметра HAProxy (kalinamall.ru)
-План защиты хоста **haproxy.kalinamall.ru** и **бэкендов** за ним. HAProxy слушает **25**, **80**, **443**; фильтрация по SNI/Host и allowlist уже в `haproxy.cfg`, но **UFW на хосте inactive** — ниже поэтапное включение **defense in depth**.
+План защиты хоста **haproxy.kalinamall.ru** и **бэкендов** за ним. HAProxy слушает **25**, **80**, **443**; с **интернета** (MikroTik DNAT) доступны только **80** и **443**. Фильтрация по SNI/Host и allowlist уже в `haproxy.cfg`, но **UFW на хосте inactive** — ниже поэтапное включение **defense in depth**.
## Модель угроз (кратко)
| Уровень | Что закрывает |
|---------|----------------|
-| **MikroTik / провайдер** | DDoS, geo, лишние порты до DMZ |
-| **UFW на HAProxy** | Вход только 25/80/443 + SSH с доверенных IP |
+| **MikroTik / провайдер** | DDoS, geo; DNAT на HAProxy только **80/443** |
+| **UFW на HAProxy** | SSH с доверенных IP; **80/443** (и **25** только если нужен с LAN) |
| **HAProxy ACL** | Неизвестный SNI, allowlist по сервисам |
| **UFW на бэкендах** | Сервисы доступны **только с IP HAProxy** (`192.168.160.117`) |
| **Приложение** | Auth OWA, RD Gateway, Gitea, SAC, 1С |
@@ -51,4 +51,4 @@ Allowlist-файлы в `/etc/haproxy/` (**не** заменяют UFW):
- `git-sac-allowed`, `rds-allowed`, `1c-allowed`, `zabbix-allowed`, `syno-allowed`
-Сервисы **без** allowlist на 443: **Exchange** (`ext`, `autodiscover`), **sac-api**, **SMTP 25** — усилить на уровне приложения и мониторинга; при необходимости добавить allowlist или rate-limit (см. [haproxy-host.md](haproxy-host.md)).
+Сервисы **без** allowlist на 443: **Exchange** (`ext`, `autodiscover`), **sac-api**. **SMTP 25** с интернета на HAProxy **не проброшен** (см. [architecture.md](architecture.md)); `fe_smtp` — для LAN/внутреннего использования.
diff --git a/docs/security/architecture-flow.svg b/docs/security/architecture-flow.svg
index a8c8f5e..c441e66 100644
--- a/docs/security/architecture-flow.svg
+++ b/docs/security/architecture-flow.svg
@@ -23,7 +23,7 @@
DNAT публичный IP
- HAProxy 192.168.160.117 (25 80 443)
+ HAProxy 192.168.160.117 (80 443)
diff --git a/docs/security/architecture.md b/docs/security/architecture.md
index 466c938..9d81335 100644
--- a/docs/security/architecture.md
+++ b/docs/security/architecture.md
@@ -9,20 +9,23 @@
Та же схема текстом:
```text
-Интернет → MikroTik (DNAT) → HAProxy .117 (25/80/443) → ACL (SNI/Host) → бэкенды .160.0/24
+Интернет → MikroTik (DNAT 80/443) → HAProxy .117 → ACL (SNI/Host) → бэкенды .160.0/24
```
+**Периметр MikroTik:** с интернета на HAProxy проброшены только **80** и **443**. Порт **25** (и прочие) на HAProxy снаружи **недоступны** — DNAT не настроен.
+
## Два контура
### 1. Публичный вход (через HAProxy)
-Клиент → публичный IP → **HAProxy** → (проверки) → один бэкенд.
+Клиент → публичный IP → **MikroTik (DNAT 80/443)** → **HAProxy** → (проверки) → один бэкенд.
-На HAProxy уже есть:
+На HAProxy с интернета доступны только:
- **443/TCP**: отклонение неизвестного SNI; allowlist для git, sac-web, rds, erp, syno.
- **80/HTTP**: только `Host: zabbix.kalinamall.ru` + `zabbix-allowed`.
-- **25/SMTP**: passthrough на KSMG без IP-фильтра на frontend.
+
+**25/SMTP** в `haproxy.cfg` слушает на хосте, но **с интернета не проброшен** (MikroTik DNAT только 80/443). Inbound-почта на KSMG идёт **не через** HAProxy:25 с периметра.
### 2. Внутренняя сеть (LAN / VPN)
@@ -58,7 +61,7 @@ Health-check HAProxy и прокси идут **с этого IP**. Правил
## Принципы
1. **Default deny** на вход (UFW `incoming deny`, бэкенды — только HAProxy + admin).
-2. **Минимум открытых портов** с интернета: 25, 80, 443 на одном хосте.
+2. **Минимум открытых портов** с интернета на HAProxy: **80** и **443** (DNAT на MikroTik).
3. **Не дублировать** смысл правил без нужды: allowlist в HAProxy для HTTP/SNI; UFW — транспорт и админ.
4. **Сначала dry-run**, потом `--apply`; для SSH — **console/IPMI** или сессия, которую UFW не оборвёт.
5. **Логи**: HAProxy + UFW + fail2ban; алерты на аномалии (Zabbix уже в инфраструктуре).
diff --git a/docs/security/backend-hosts.md b/docs/security/backend-hosts.md
index a2388e8..6275333 100644
--- a/docs/security/backend-hosts.md
+++ b/docs/security/backend-hosts.md
@@ -1,4 +1,4 @@
-# Firewall на бэкендах
+# Firewall на бэкендах
Цель: сервисный порт доступен **с HAProxy** (`192.168.160.117`) и при необходимости с **admin**-подсетей; **не** с произвольного LAN/Internet напрямую.
@@ -40,7 +40,9 @@ UFW_EXTRA_SERVICES="2222/tcp" # если Gitea SSH с admin LAN
### KSMG (192.168.160.57:25)
-Почта с интернета приходит на **HAProxy:25** → KSMG. На KSMG в `EXTRA_ALLOWED` укажите **192.168.160.117**. Если другие MTA шлют **напрямую** на `.57` (минуя HAProxy), их IP тоже нужно явно разрешить — иначе после UFW почта встанет.
+С **интернета** на HAProxy проброшены только **80/443** — inbound SMTP **не** приходит на **HAProxy:25**. Почта с периметра идёт **напрямую на KSMG** (или иным маршрутом), минуя HAProxy.
+
+`fe_smtp` в `haproxy.cfg` — для **LAN** (прокси на KSMG с `.117`). На KSMG в `EXTRA_ALLOWED` укажите **192.168.160.117**, если этот путь используется. IP внешних MTA, шлющих **напрямую** на `.57`, тоже нужно явно разрешить — иначе после UFW почта встанет.
### RDS (192.168.160.40)
diff --git a/docs/security/checklist.md b/docs/security/checklist.md
index 57a9170..efdb00f 100644
--- a/docs/security/checklist.md
+++ b/docs/security/checklist.md
@@ -1,8 +1,8 @@
-# Чеклист после внедрения защиты
+# Чеклист после внедрения защиты
## HAProxy (192.168.160.117)
-- [ ] `ufw status verbose` — active; есть 22 из admin, 25/80/443 open
+- [ ] `ufw status verbose` — active; есть 22 из admin, **80/443** open (25 — только если явно включён для LAN)
- [ ] SSH с admin-IP работает; с random IP — **нет** (или только ключ + fail2ban)
- [ ] `ss -tlnp` — нет лишних listen (8404, 3000, …)
- [ ] `haproxy -c -f /etc/haproxy/haproxy.cfg` — OK
@@ -13,7 +13,7 @@
## MikroTik / периметр
-- [ ] С интернета на публичный IP: открыты только **25, 80, 443**
+- [ ] С интернета на публичный IP: открыты только **80, 443**
- [ ] Нет DNAT 3389, 5001, 4430 на внутренние хосты
- [ ] HAProxy health-check не блокируется
@@ -27,8 +27,8 @@
## KSMG (.57)
-- [ ] Почта inbound через HAProxy:25 — OK
-- [ ] Прямые отправители (если есть) — в `EXTRA_ALLOWED`
+- [ ] Inbound-почта с интернета **не** идёт через HAProxy:25 (DNAT на MikroTik только 80/443)
+- [ ] На KSMG в `EXTRA_ALLOWED` — **192.168.160.117** (если используется `fe_smtp` из LAN) и прямые MTA
## Документация и runbook
diff --git a/docs/security/deployment-plan.md b/docs/security/deployment-plan.md
index 579f213..77ccd0b 100644
--- a/docs/security/deployment-plan.md
+++ b/docs/security/deployment-plan.md
@@ -1,10 +1,10 @@
-# План развёртывания защиты
+# План развёртывания защиты
Оценка: **2–4 рабочих дня** с окнами обслуживания на бэкендах (по одному хосту).
## Фаза 0 — Подготовка (без изменений на проде)
-- [ ] Зафиксировать **публичный IP** HAProxy и правила DNAT на MikroTik.
+- [ ] Зафиксировать **публичный IP** HAProxy и правила DNAT на MikroTik (**только 80/443**).
- [ ] Убедиться, что **SSH** на `192.168.160.117` доступен с admin-IP (не только с одного ноутбука).
- [ ] Снимок/backup: `haproxy.cfg`, allowlist, `/etc/ssh/sshd_config`.
- [ ] Клонировать репозиторий на HAProxy: `git pull kalinamall main`.
@@ -36,7 +36,7 @@
- [ ] Dry-run: `bash scripts/security/haproxy-ufw-apply.sh`
- [ ] **Не закрывая SSH-сессию**, в second tab: `bash scripts/security/haproxy-ufw-apply.sh --apply`
- [ ] Проверить с admin-IP: `ssh haproxy.kalinamall.ru`, `curl` на 80/443 с allowlist.
-- [ ] Проверить SMTP 25 с внешнего MTA (если используется).
+- [ ] Убедиться, что **25** с интернета на HAProxy **не** доступен (ожидаемо: DNAT не настроен).
**Откат:** `ufw disable` (временно) или `ufw delete` по номерам правил; env-файл сохранить.
@@ -68,7 +68,7 @@
## Фаза 4 — MikroTik и мониторинг
-- [ ] На MikroTik: с интернета на HAProxy только **25, 80, 443** (не пробрасывать 3389, 5001, 4430 на внутренние IP).
+- [ ] На MikroTik: с интернета на HAProxy только **80, 443** (не пробрасывать 25, 3389, 5001, 4430 на внутренние IP).
- [ ] Raw/firewall: опционально drop obvious scanners (согласовать с `rds-allowed` / RU geo).
- [ ] Zabbix: триггеры на `ufw status`, `fail2ban`, рост `fe_https_sni` reject, backend DOWN.
- [ ] Ротация логов `/var/log/haproxy.log`.
diff --git a/docs/security/haproxy-host.md b/docs/security/haproxy-host.md
index 243c393..ea9159c 100644
--- a/docs/security/haproxy-host.md
+++ b/docs/security/haproxy-host.md
@@ -1,4 +1,4 @@
-# Hardening хоста HAProxy
+# Hardening хоста HAProxy
Хост: **haproxy.kalinamall.ru**, **192.168.160.117**, Ubuntu 24.04, HAProxy 2.8.x.
@@ -7,12 +7,16 @@
| Порт | Frontend | Назначение |
|------|----------|------------|
| 22 | sshd | Администрирование (не в haproxy.cfg) |
-| 25 | fe_smtp | SMTP → KSMG |
+| 25 | fe_smtp | SMTP → KSMG (**LAN**; с интернета не проброшен) |
| 80 | fe_http_zabbix | HTTP Zabbix |
| 443 | fe_https_sni | TLS passthrough по SNI |
Не включать **8404/stats** на `0.0.0.0` без VPN и пароля.
+## Периметр (MikroTik)
+
+С **интернета** на публичный IP HAProxy проброшены только **TCP 80** и **443**. Остальные порты HAProxy (в т.ч. **25**) снаружи **недоступны** — DNAT не настроен.
+
## UFW
Скрипт: [haproxy-ufw-apply.sh](../../scripts/security/haproxy-ufw-apply.sh).
@@ -23,7 +27,8 @@
default incoming: deny
default outgoing: allow
allow 22/tcp from SSH_ALLOWED
-allow 25, 80, 443/tcp from anywhere # сервисы периметра
+allow 80, 443/tcp from anywhere # сервисы периметра (MikroTik DNAT)
+# allow 25/tcp from LAN_CIDR # только если нужен SMTP через HAProxy изнутри сети
```
**SSH_ALLOWED** — несколько CIDR/ IP через пробел в env. Минимум:
diff --git a/scripts/security/haproxy-ufw-apply.sh b/scripts/security/haproxy-ufw-apply.sh
index ffd614e..64b8d82 100755
--- a/scripts/security/haproxy-ufw-apply.sh
+++ b/scripts/security/haproxy-ufw-apply.sh
@@ -1,5 +1,5 @@
-#!/usr/bin/env bash
-# UFW для HAProxy: default deny, SSH из SSH_ALLOWED, inbound 25/80/443.
+#!/usr/bin/env bash
+# UFW для HAProxy: default deny, SSH из SSH_ALLOWED, inbound 80/443 (25 — опционально для LAN).
# Dry-run по умолчанию; --apply для включения.
#
# cp haproxy-ufw.env.example /etc/haproxy/security/haproxy-ufw.env
@@ -37,7 +37,7 @@ done
source "$ENV_FILE"
SSH_ALLOWED=${SSH_ALLOWED:-}
-INBOUND_TCP=${INBOUND_TCP:-25 80 443}
+INBOUND_TCP=${INBOUND_TCP:-80 443}
UFW_IPV6=${UFW_IPV6:-no}
[[ -n $SSH_ALLOWED ]] || die "SSH_ALLOWED is empty — lockout risk"
diff --git a/scripts/security/haproxy-ufw.env.example b/scripts/security/haproxy-ufw.env.example
index e8c78e7..a344abe 100644
--- a/scripts/security/haproxy-ufw.env.example
+++ b/scripts/security/haproxy-ufw.env.example
@@ -1,11 +1,14 @@
-# UFW для haproxy.kalinamall.ru — пример.
+# UFW для haproxy.kalinamall.ru — пример.
# Копия: /etc/haproxy/security/haproxy-ufw.env (не коммитить в GitHub с prod-IP при необходимости)
# IP/CIDR для SSH (через пробел). Обязательно перед --apply.
SSH_ALLOWED="192.168.160.0/24 5.100.81.121"
-# Публичные сервисы HAProxy (пробел)
-INBOUND_TCP="25 80 443"
+# Публичные сервисы HAProxy с периметра (пробел). MikroTik DNAT: только 80 и 443.
+INBOUND_TCP="80 443"
+
+# Добавьте 25, если нужен SMTP через HAProxy только из LAN (не с интернета):
+# INBOUND_TCP="80 443 25"
# IPv6: yes | no
UFW_IPV6=no