Files
paliad/docker-compose.yml
m a0d1e77ef2 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
2026-05-08 11:25:02 +02:00

39 lines
1.7 KiB
YAML

services:
web:
build: .
expose:
- "8080"
environment:
- PORT=8080
- SUPABASE_URL=${SUPABASE_URL}
- SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
- SUPABASE_JWT_SECRET=${SUPABASE_JWT_SECRET}
- GITEA_TOKEN=${GITEA_TOKEN}
- DATABASE_URL=${DATABASE_URL}
- CALDAV_ENCRYPTION_KEY=${CALDAV_ENCRYPTION_KEY}
- ALLOWED_EMAIL_DOMAINS=${ALLOWED_EMAIL_DOMAINS}
- PALIAD_BASE_URL=${PALIAD_BASE_URL}
- SMTP_HOST=${SMTP_HOST}
- SMTP_PORT=${SMTP_PORT}
- SMTP_USERNAME=${SMTP_USERNAME}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- 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