* 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>
4.3 KiB
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:
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).