From c7dc40c51e746f4fa00bf3f047eb7aee508fcc07 Mon Sep 17 00:00:00 2001 From: Dirk Riemann Date: Sat, 18 Apr 2026 13:00:02 +0200 Subject: [PATCH] =?UTF-8?q?fix(deploy):=20switch=20to=20network=5Fmode:=20?= =?UTF-8?q?host=20=E2=80=94=20reach=20postgis=20+=20ollama=20on=20loopback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shared postgis container is bound to 127.0.0.1 on the host (security hardening, infrastructure §T12). Ollama is similarly LAN-hardened. The previous `host.docker.internal + extra_hosts: host-gateway` approach points at the bridge gateway IP, not loopback, so the container couldn't reach either service. Switch to `network_mode: host` (same pattern goldstein uses) and update the default IX_POSTGRES_URL / IX_OLLAMA_URL to 127.0.0.1. Keep the GPU reservation block; drop the now-meaningless ports: declaration (host mode publishes directly). AppConfig defaults + .env.example + test_config assertions + inline docstring examples all follow. Caught on fourth deploy attempt. Co-Authored-By: Claude Opus 4.7 (1M context) --- .env.example | 4 ++-- docker-compose.yml | 21 +++++++++------------ docs/deployment.md | 4 ++-- src/ix/config.py | 7 +++++-- src/ix/genai/ollama_client.py | 2 +- tests/unit/test_config.py | 4 ++-- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.env.example b/.env.example index e3ccb54..0c75124 100644 --- a/.env.example +++ b/.env.example @@ -4,10 +4,10 @@ # the Postgres password. # --- Job store ----------------------------------------------------------- -IX_POSTGRES_URL=postgresql+asyncpg://infoxtractor:@host.docker.internal:5431/infoxtractor +IX_POSTGRES_URL=postgresql+asyncpg://infoxtractor:@127.0.0.1:5431/infoxtractor # --- LLM backend --------------------------------------------------------- -IX_OLLAMA_URL=http://host.docker.internal:11434 +IX_OLLAMA_URL=http://127.0.0.1:11434 IX_DEFAULT_MODEL=qwen3:14b # --- OCR ----------------------------------------------------------------- diff --git a/docker-compose.yml b/docker-compose.yml index c363804..c3aa30b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,22 +1,21 @@ # InfoXtractor Docker Compose stack. # -# Single service. Postgres + Ollama live in separate long-running -# containers on the host (postgis + ollama); we reach them via -# `host.docker.internal`, which is mapped to the gateway through -# `extra_hosts` so the container works whether the Compose plugin version -# adds it automatically or not. +# Single service. Uses host networking so the container can reach: +# - Ollama at 127.0.0.1:11434 +# - postgis at 127.0.0.1:5431 (bound to loopback only; security hardening) +# Both services are LAN-hardened on the host and never exposed publicly, +# so host-network access stays on-prem. This matches the `goldstein` +# container pattern on the same server. # -# The GPU reservation block matches the shape used by immich-ml / -# monitoring on the same host, so the existing NVIDIA runtime -# configuration applies without changes. +# The GPU reservation block matches immich-ml / the shape Docker Compose +# expects for GPU allocation on this host. services: infoxtractor: build: . container_name: infoxtractor + network_mode: host restart: always - ports: - - "8994:8994" env_file: .env deploy: resources: @@ -30,5 +29,3 @@ services: backup.enable: "true" backup.type: "postgres" backup.name: "infoxtractor" - extra_hosts: - - "host.docker.internal:host-gateway" diff --git a/docs/deployment.md b/docs/deployment.md index 5f34108..3de24c5 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -14,8 +14,8 @@ Mac (dev) │ curl /healthz (60 s gate) ▼ Docker container `infoxtractor` (port 8994) - ├─ host.docker.internal:11434 → Ollama (qwen3:14b) - └─ host.docker.internal:5431 → postgis (database `infoxtractor`) + ├─ 127.0.0.1:11434 → Ollama (qwen3:14b; host-network mode) + └─ 127.0.0.1:5431 → postgis (database `infoxtractor`; host-network mode) ``` ## One-time server setup diff --git a/src/ix/config.py b/src/ix/config.py index 9f12ae7..985ae52 100644 --- a/src/ix/config.py +++ b/src/ix/config.py @@ -33,13 +33,16 @@ class AppConfig(BaseSettings): ) # --- Job store --- + # Defaults assume the ix container runs with `network_mode: host` and + # reaches the shared `postgis` and `ollama` containers on loopback; + # spec §11 / docker-compose.yml ship that configuration. postgres_url: str = ( "postgresql+asyncpg://infoxtractor:" - "@host.docker.internal:5431/infoxtractor" + "@127.0.0.1:5431/infoxtractor" ) # --- LLM backend --- - ollama_url: str = "http://host.docker.internal:11434" + ollama_url: str = "http://127.0.0.1:11434" default_model: str = "qwen3:14b" # --- OCR --- diff --git a/src/ix/genai/ollama_client.py b/src/ix/genai/ollama_client.py index 21ca11e..bf4fab8 100644 --- a/src/ix/genai/ollama_client.py +++ b/src/ix/genai/ollama_client.py @@ -36,7 +36,7 @@ class OllamaClient: Parameters ---------- base_url: - Root URL of the Ollama server (e.g. ``http://host.docker.internal:11434``). + Root URL of the Ollama server (e.g. ``http://127.0.0.1:11434``). Trailing slashes are stripped. per_call_timeout_s: Hard per-call timeout for ``/api/chat``. Spec default: 1500 s. diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index 5ebbb4d..0c3a7b1 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -51,9 +51,9 @@ def test_defaults_match_spec(monkeypatch: pytest.MonkeyPatch) -> None: assert cfg.postgres_url == ( "postgresql+asyncpg://infoxtractor:" - "@host.docker.internal:5431/infoxtractor" + "@127.0.0.1:5431/infoxtractor" ) - assert cfg.ollama_url == "http://host.docker.internal:11434" + assert cfg.ollama_url == "http://127.0.0.1:11434" assert cfg.default_model == "qwen3:14b" assert cfg.ocr_engine == "surya" assert cfg.tmp_dir == "/tmp/ix"