opencode-config/docs/decisions/021-pr-51-docker-port-expose.md
Sergey 655a98d077
fix(docker): expose port 4096 on 0.0.0.0 for NPM proxy (#51)
* 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>
2026-07-24 20:27:37 +03:00

4.3 KiB
Raw Permalink Blame History

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.dev193.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).