feat(t-paliad-151) Phase A.5: compose env-var passthrough for Paliadin remote routing

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
This commit is contained in:
m
2026-05-08 02:20:39 +02:00
parent e4110cf2db
commit a0d1e77ef2

View File

@@ -20,5 +20,19 @@ services:
- SMTP_FROM=${SMTP_FROM} - SMTP_FROM=${SMTP_FROM}
- SMTP_FROM_NAME=${SMTP_FROM_NAME} - SMTP_FROM_NAME=${SMTP_FROM_NAME}
- SMTP_USE_TLS=${SMTP_USE_TLS} - 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 # - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} # Phase H (AI Frist-Extraktion), currently deferred
restart: unless-stopped restart: unless-stopped