f802a5ac46
Веб-SAC остаётся за allowlist; sac-api.kalinamall.ru открыт для мобильных клиентов. Документация по connection coalescing Git+SAC. Co-authored-by: Cursor <cursoragent@cursor.com>
94 lines
4.2 KiB
Markdown
94 lines
4.2 KiB
Markdown
# SAC: веб, Seaca (sac-api) и HAProxy
|
||
|
||
## Два имени — один сервер
|
||
|
||
| Имя | Клиенты | IP-allowlist HAProxy | Бэкенд |
|
||
|-----|---------|----------------------|--------|
|
||
| **`sac.kalinamall.ru`** | Веб-интерфейс SAC (браузер) | **Да** (`git-sac-allowed`) | 192.168.160.145:443 |
|
||
| **`sac-api.kalinamall.ru`** | Seaca (Android), mobile API | **Нет** (доступ с любого IP) | тот же 192.168.160.145:443 |
|
||
|
||
Защита `sac-api`: код регистрации `sacmob_…`, JWT, отзыв устройств в веб-SAC.
|
||
|
||
### DNS
|
||
|
||
Добавьте **A**-запись:
|
||
|
||
```text
|
||
sac-api.kalinamall.ru → тот же публичный IP, что у sac / ext / git (хост HAProxy)
|
||
```
|
||
|
||
### nginx на 192.168.160.145
|
||
|
||
В `server_name` должны быть **оба** имени (wildcard `*.kalinamall.ru` в сертификате это покрывает):
|
||
|
||
```nginx
|
||
server_name sac.kalinamall.ru sac-api.kalinamall.ru;
|
||
```
|
||
|
||
Для чужих имён (например `ext.kalinamall.ru`) — отдельный default или `return 444`, иначе SAC ответит на любой Host.
|
||
|
||
### Seaca
|
||
|
||
В приложении указывают **`https://sac-api.kalinamall.ru`**, не `sac.kalinamall.ru`.
|
||
|
||
---
|
||
|
||
## Git → SAC в одном браузере: «Page Not Found — Gitea»
|
||
|
||
### Симптом
|
||
|
||
1. Открыли **`git.kalinamall.ru`** — Gitea работает.
|
||
2. В **той же вкладке/браузере** перешли на **`sac.kalinamall.ru`**.
|
||
3. В адресной строке SAC, на экране — **Gitea 404** («Page Not Found - Gitea»).
|
||
|
||
В логах HAProxy при этом может быть **`be_git`**, хотя URL — sac.
|
||
|
||
### Причина: HTTP/2 connection coalescing
|
||
|
||
Git и SAC снаружи идут на **один IP:443** HAProxy. В режиме **TCP passthrough** backend выбирается **один раз** при ClientHello (SNI) на **TCP-соединение**.
|
||
|
||
Современные браузеры (Chrome, Firefox) при **HTTP/2** могут **объединять** несколько hostname на одном IP в **одно TLS-соединение**, если сертификаты «совместимы» (часто так с `*.kalinamall.ru`).
|
||
|
||
Тогда:
|
||
|
||
1. Первое соединение: SNI `git.kalinamall.ru` → HAProxy → **Gitea**.
|
||
2. Запрос к `sac.kalinamall.ru` идёт **по тому же TCP** (без нового SNI для HAProxy).
|
||
3. Gitea получает `Host: sac.kalinamall.ru` → отдаёт **404 Gitea**.
|
||
|
||
Это **не ошибка маршрутизации ACL** и **не баг SAC** — ограничение схемы «несколько HTTPS-имён на одном IP + TCP passthrough».
|
||
|
||
### Обходные пути (без смены архитектуры)
|
||
|
||
| Способ | Комментарий |
|
||
|--------|-------------|
|
||
| **Новая вкладка / приватное окно** для SAC после Git | Новое TCP-соединение, свой SNI |
|
||
| **Закрыть вкладку с Git** перед SAC | Сброс keep-alive / H2 coalescing |
|
||
| **Разные публичные IP** в DNS: `git.*` → IP1, `sac.*` → IP2 | Надёжное решение для passthrough |
|
||
| **`http2 off;`** в nginx Gitea и SAC | Часто уменьшает coalescing (на серверах .129 и .145) |
|
||
| **`Connection: close`** в ответах Git | Жёстче рвёт keep-alive (на .129) |
|
||
|
||
### Долгосрочно
|
||
|
||
- Отдельный WAN IP для Git и для SAC, **или**
|
||
- TLS-терминация на HAProxy с маршрутизацией по Host (больше изменений).
|
||
|
||
---
|
||
|
||
## Деплой изменений HAProxy
|
||
|
||
```bash
|
||
sudo cp ~/reverse-proxy/haproxy.cfg /etc/haproxy/haproxy.cfg
|
||
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
|
||
sudo systemctl reload haproxy
|
||
```
|
||
|
||
Проверка:
|
||
|
||
```bash
|
||
# веб SAC — только с allowlist IP
|
||
curl -sI --resolve sac.kalinamall.ru:443:ПУБЛИЧНЫЙ_IP https://sac.kalinamall.ru/dashboard
|
||
|
||
# mobile API — с любого IP
|
||
curl -s --resolve sac-api.kalinamall.ru:443:ПУБЛИЧНЫЙ_IP https://sac-api.kalinamall.ru/health
|
||
```
|