* fix(docker): expose port 4096 on 0.0.0.0 for NPM proxy * test(docker): add docker-compose port exposure test * docs(handoff): set PR number for docker port expose --------- Co-authored-by: opencode-agent <agent@slaid098.dev>
38 lines
No EOL
4.3 KiB
Markdown
38 lines
No EOL
4.3 KiB
Markdown
# ADR-021 (PR #51): Expose opencode port 4096 on 0.0.0.0 for cross-host NPM proxy
|
||
|
||
## Статус
|
||
Accepted (2026-07-24)
|
||
|
||
## Контекст
|
||
|
||
opencode-config мигрирует на linux-1 (`193.3.168.35`). Web UI opencode слушает порт 4096 (`opencode serve --hostname 0.0.0.0 --port 4096`). Публичный доступ к домену `opencode.slaid098.dev` идёт через NPM (Nginx Proxy Manager, контейнер `jc21/nginx-proxy-manager`), который живёт на linux-2 (`92.119.114.77`) и проксирует `opencode.slaid098.dev` → `193.3.168.35:4096`.
|
||
|
||
Текущий `docker-compose.yml` биндит порт как `127.0.0.1:4096:4096` (localhost-only). Это работало, пока opencode жил на linux-2: Cloudflare named tunnel (`cloudflared`) запускался на том же хосте и обращался к `127.0.0.1:4096` локально. После миграции на linux-1 NPM на linux-2 должен стучаться на публичный IP linux-1 — localhost-only биндинг отвергает соединение на loopback-интерфейсе, NPM не достучится.
|
||
|
||
Топология подтверждена SSH-аудитом (memory `technical/opencode-config-migration-state-2026-07-24.md`): NPM на linux-2, opencode мигрирует на linux-1 (раньше Cloudflare tunnel, теперь NPM-прокси).
|
||
|
||
## Решение
|
||
|
||
Перевязать порт 4096 в `docker-compose.yml` с `127.0.0.1:4096:4096` на `0.0.0.0:4096:4096`:
|
||
|
||
```yaml
|
||
ports:
|
||
- "0.0.0.0:4096:4096"
|
||
```
|
||
|
||
`0.0.0.0:4096` биндит контейнерный порт 4096 на все интерфейсы хоста, NPM на linux-2 достучится через публичный IP linux-1 (`193.3.168.35:4096`).
|
||
|
||
Дополнительно — 5 тестов в `tests/test_docker_compose.py` (parsed + raw check на оба условия), чтобы предотвратить регрессию обратно к localhost-only.
|
||
|
||
### Альтернативы
|
||
|
||
- **Оставить `127.0.0.1:4096` + Cloudflare named tunnel на linux-1** — отклонено: миграционный план переводит публичный доступ на NPM-прокси (centralized SSL-termination + domain management на linux-2), Cloudflare tunnel на linux-1 потребовал бы отдельной настройки и токена. NPM уже управляет 9 доменами `*.slaid098.dev`, добавить `opencode.slaid098.dev` проще, чем поднимать второй tunnel.
|
||
|
||
- **Биндить на конкретный публичный IP linux-1 (`193.3.168.35:4096:4096`)** — отклонено: hardcoded IP в compose хрупок (при смене хоста/IP потребует правки файла). `0.0.0.0` переносим между хостами; доступ ограничивается firewall на linux-1 (ufw/iptables, разрешить 4096 только с linux-2 IP), что конфигурируется вне compose и не требует правок при миграции.
|
||
|
||
- **Не открывать, проксировать через SSH-туннель linux-2→linux-1** — отклонено: SSH-туннель — ручная/хрупкая инфраструктура (restart, no systemd unit, no health-check), NPM → прямой TCP — стандартный паттерн reverse proxy. Дополнительный слой без выгоды.
|
||
|
||
- **Поднять NPM на linux-1 (чтобы NPM и opencode на одном хосте, localhost-only OK)** — отклонено: linux-1 не имеет NPM, установка дублирует инфраструктуру (9 доменов уже на linux-2 NPM, SSL-сертификаты, database.sqlite). Миграция opencode не должна тянуть за собой миграцию NPM.
|
||
|
||
## Альтернативы
|
||
См. блок «Альтернативы» выше (включён в Решение для единого контекста). Кратко: отклонены — Cloudflare tunnel на linux-1, hardcoded public IP, SSH-туннель, NPM на linux-1. Выбран `0.0.0.0` + firewall на linux-1 (переносимость + security на уровне хоста, не compose). |