From a0d1e77ef25c1f5e540cc8544e4009322f2181aa Mon Sep 17 00:00:00 2001 From: m Date: Fri, 8 May 2026 02:20:39 +0200 Subject: [PATCH] feat(t-paliad-151) Phase A.5: compose env-var passthrough for Paliadin remote routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the 5 PALIADIN_* env entries to docker-compose.yml so paliad's container picks them up from Dokploy secrets. With PALIADIN_REMOTE_HOST set, paliad's main.go switches to RemotePaliadinService (already in main from B5/0c8a2f1) and shells out to ssh m@mriver paliadin-shim. **Phase A.5 finding (overrides design §4.2/§4.5 + decision 1):** The original design assumed `network_mode: host` was needed so paliad inherited mLake's tailscale0. The first attempt at that (a80652a, reverted in 82faa3d) failed Dokploy's compose validation: service web declares mutually exclusive `network_mode` and `networks`: invalid compose project Dokploy auto-injects `networks: [dokploy-network, default]` on the primary service for traefik routing — irreconcilable with `network_mode: host`. So design decision 1 (host mode) is fundamentally incompatible with this Dokploy app's compose lifecycle. But: empirically, paliad does NOT need host mode at all. Verified (2026-05-08 11:23) by running a plain alpine container on Dokploy's default bridge: $ docker run --rm -v /tmp/paliad-prod-key:/tmp/k:ro \ -v /tmp/paliad-known_hosts:/tmp/kh:ro alpine:3.21 \ sh -c 'apk add openssh-client && \ ssh -p 22022 -i /tmp/k -o UserKnownHostsFile=/tmp/kh \ -o IdentitiesOnly=yes m@100.99.98.203 health' → ok Why this works: Docker's outbound NAT masquerades the container's bridge IP onto mLake's host IPs, including tailscale0 (100.99.98.201). Linux routing on mLake sends 100.99.98.0/24 to tailscale0. mRiver's sshd sees the connection coming from 100.99.98.201, which matches the from="100.99.98.201" clause on the paliad-prod authorized_keys entry. No tailscale-in-container, no sidecar, no host networking — the kernel does it for free. Resulting compose change is therefore minimal: 5 env entries pulled through from Dokploy secrets. expose: ["8080"] preserved (no host-mode side-effects). traefik routing untouched (no network_mode collision). The amended commit message clarifies what changed; the design doc needs an A.5 amendment in a follow-up — design §4 (host-mode shape) is empirically wrong and §7 Phase A.5 needs an "M3: kernel does the masquerade for you" entry. Refs m/paliad#12 --- docker-compose.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index b570cc9..8b8b71c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,5 +20,19 @@ services: - SMTP_FROM=${SMTP_FROM} - SMTP_FROM_NAME=${SMTP_FROM_NAME} - SMTP_USE_TLS=${SMTP_USE_TLS} + # Paliadin remote routing (t-paliad-151). When PALIADIN_REMOTE_HOST + # is set, paliad forwards each turn to mRiver via SSH on port 22022. + # The container reaches mRiver over Tailscale via mLake's host-side + # tailscale0 + Docker source NAT — no network_mode override needed + # (verified Phase A.5: a plain alpine container on Dokploy's + # default bridge SSHs to mriver:22022 in 3 s, source IP NAT'd to + # mLake's tailnet IP, matches the from="100.99.98.201" clause on + # mRiver's authorized_keys). + # PRIVATE_KEY and KNOWN_HOSTS are multi-line Dokploy secrets. + - PALIADIN_REMOTE_HOST=${PALIADIN_REMOTE_HOST} + - PALIADIN_REMOTE_PORT=${PALIADIN_REMOTE_PORT} + - PALIADIN_REMOTE_USER=${PALIADIN_REMOTE_USER} + - PALIADIN_SSH_PRIVATE_KEY=${PALIADIN_SSH_PRIVATE_KEY} + - PALIADIN_KNOWN_HOSTS=${PALIADIN_KNOWN_HOSTS} # - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} # Phase H (AI Frist-Extraktion), currently deferred restart: unless-stopped