LAN jump key: persist via named volume + one-line authorize hint
Validate / docs-check (push) Successful in 7s
Validate / base-change-warning (push) Successful in 9s
Validate / validate-omos (push) Successful in 4m26s
Validate / validate-with-pi (push) Successful in 4m30s
Validate / validate-pi-only (push) Successful in 3m33s
Validate / validate-omos-with-pi (push) Successful in 8m44s
Validate / validate-base (push) Successful in 9m8s
Validate / docs-check (push) Successful in 7s
Validate / base-change-warning (push) Successful in 9s
Validate / validate-omos (push) Successful in 4m26s
Validate / validate-with-pi (push) Successful in 4m30s
Validate / validate-pi-only (push) Successful in 3m33s
Validate / validate-omos-with-pi (push) Successful in 8m44s
Validate / validate-base (push) Successful in 9m8s
Persist ~/.ssh-local (devbox-ssh-local named volume) so the generated LAN-jump key survives 'docker compose up --force-recreate'. Authorize it on the host once per machine instead of after every container update. setup-lan-access.sh now prints a copy-paste 'echo <pubkey> >> ~/.ssh/authorized_keys' line whenever it generates a new key (not only when HOST_SSH_USER is unset), and stays silent once the key is persisted. README + CHANGELOG updated.
This commit is contained in:
+16
-1
@@ -8,7 +8,22 @@ Tags follow `v{opencode_version}[letter]` — bare tag for the first build on a
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
_(no changes since v1.15.13d)_
|
### Added: persist the LAN-jump key + one-line authorize hint (authorize once per machine)
|
||||||
|
|
||||||
|
The jump keypair (`~/.ssh-local/devbox_jump_ed25519`) was stored on the
|
||||||
|
container's ephemeral overlay, so `docker compose up --force-recreate` (every
|
||||||
|
image update) regenerated it — forcing you to re-authorize the new key on the
|
||||||
|
host each time. The compose files now persist `~/.ssh-local` via a named volume
|
||||||
|
(`devbox-ssh-local`), matching the pattern already used for `.pi`, shell
|
||||||
|
history, etc. The key is generated **once** and reused across updates, so you
|
||||||
|
authorize it on the host **once per machine**.
|
||||||
|
|
||||||
|
`setup-lan-access.sh` now also prints a ready-to-paste authorize line whenever
|
||||||
|
it generates a **new** key (not just when `HOST_SSH_USER` is unset), e.g.
|
||||||
|
`echo 'ssh-ed25519 …' >> ~/.ssh/authorized_keys` — no helper file to locate, no
|
||||||
|
workspace path to guess. It stays silent once the key is persisted.
|
||||||
|
|
||||||
|
_(no other changes since v1.15.13d)_
|
||||||
|
|
||||||
## v1.15.13d — 2026-06-04
|
## v1.15.13d — 2026-06-04
|
||||||
|
|
||||||
|
|||||||
@@ -155,15 +155,20 @@ The devbox works the same way whether the host is **native Linux Docker** or a *
|
|||||||
- **Native Linux Docker:** the host NATs container egress onto its LAN, so other devices on your LAN are reachable directly. Nothing to configure.
|
- **Native Linux Docker:** the host NATs container egress onto its LAN, so other devices on your LAN are reachable directly. Nothing to configure.
|
||||||
- **VM-backed (macOS / Docker Desktop):** the container runs in a Linux VM behind the host's network stack. The host's *directly-attached* LAN peers are **not** bridged into the container by default — only the host itself and *routed* subnets are reachable.
|
- **VM-backed (macOS / Docker Desktop):** the container runs in a Linux VM behind the host's network stack. The host's *directly-attached* LAN peers are **not** bridged into the container by default — only the host itself and *routed* subnets are reachable.
|
||||||
|
|
||||||
On every start the entrypoint detects which case applies. On VM-backed hosts it generates a writable `~/.ssh-local/config` that uses the **host as an SSH jump** to reach LAN peers; on native Linux it does nothing.
|
On every start the entrypoint detects which case applies. On VM-backed hosts it generates a writable `~/.ssh-local/config` that uses the **host as an SSH jump** to reach LAN peers; on native Linux it does nothing. The jump keypair lives in `~/.ssh-local`, which is persisted by the `devbox-ssh-local` named volume — so it's generated **once** and reused across container updates.
|
||||||
|
|
||||||
**To enable it on a VM-backed host:**
|
**To enable it on a VM-backed host (one-time setup per machine):**
|
||||||
|
|
||||||
1. Set `HOST_SSH_USER=<your host username>` in `.env`.
|
1. Set `HOST_SSH_USER=<your host username>` in `.env`.
|
||||||
2. Start the container once. The entrypoint prints a public key — append it to your host's `~/.ssh/authorized_keys`.
|
2. Start the container once. When it generates the jump key it prints a ready-to-paste line — run it **on the host** to authorize the key:
|
||||||
|
```bash
|
||||||
|
echo 'ssh-ed25519 AAAA…devbox-jump@…' >> ~/.ssh/authorized_keys
|
||||||
|
```
|
||||||
3. Ensure the host's SSH server is on (on macOS: System Settings → General → Sharing → Remote Login).
|
3. Ensure the host's SSH server is on (on macOS: System Settings → General → Sharing → Remote Login).
|
||||||
4. Reach the host itself with `dssh host`. (`dssh`/`dscp` wrap `ssh -F ~/.ssh-local/config`.)
|
4. Reach the host itself with `dssh host`. (`dssh`/`dscp` wrap `ssh -F ~/.ssh-local/config`.)
|
||||||
|
|
||||||
|
Because the key is persisted, you do this **once per machine** — not after every `docker compose up --force-recreate`. You'll only see the authorize line again if you reset the `devbox-ssh-local` volume.
|
||||||
|
|
||||||
That alone gets you `container → host`. To reach **named LAN peers** by name, give them a `ProxyJump host` override. Don't add it to the shared `~/.ssh/config` entries — the host itself reaches those peers *directly*, and a jump-through-`host` would break the host's own access (and that file is mounted read-only anyway). Instead, drop the overrides in a **host-owned** file that the container Includes ahead of your `~/.ssh/config`:
|
That alone gets you `container → host`. To reach **named LAN peers** by name, give them a `ProxyJump host` override. Don't add it to the shared `~/.ssh/config` entries — the host itself reaches those peers *directly*, and a jump-through-`host` would break the host's own access (and that file is mounted read-only anyway). Instead, drop the overrides in a **host-owned** file that the container Includes ahead of your `~/.ssh/config`:
|
||||||
|
|
||||||
```sshconfig
|
```sshconfig
|
||||||
|
|||||||
@@ -59,6 +59,11 @@ services:
|
|||||||
# allowing both native and containerized opencode on the same machine.
|
# allowing both native and containerized opencode on the same machine.
|
||||||
- devbox-opencode-config:/home/developer/.config/opencode
|
- devbox-opencode-config:/home/developer/.config/opencode
|
||||||
- devbox-pi-config:/home/developer/.pi
|
- devbox-pi-config:/home/developer/.pi
|
||||||
|
# Persist the generated LAN-jump keypair (~/.ssh-local) across recreates.
|
||||||
|
# setup-lan-access.sh generates this key once and reuses it; persisting
|
||||||
|
# it means you authorize it on the host ONCE rather than re-authorizing
|
||||||
|
# after every `docker compose up --force-recreate`.
|
||||||
|
- devbox-ssh-local:/home/developer/.ssh-local
|
||||||
|
|
||||||
# NOTE: Do NOT bind-mount ~/.agents/skills/ from the host. The
|
# NOTE: Do NOT bind-mount ~/.agents/skills/ from the host. The
|
||||||
# container manages its own skills directory independently — the
|
# container manages its own skills directory independently — the
|
||||||
@@ -134,6 +139,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
devbox-opencode-config:
|
devbox-opencode-config:
|
||||||
devbox-pi-config:
|
devbox-pi-config:
|
||||||
|
devbox-ssh-local:
|
||||||
devbox-data:
|
devbox-data:
|
||||||
devbox-state:
|
devbox-state:
|
||||||
devbox-shell-history:
|
devbox-shell-history:
|
||||||
|
|||||||
@@ -97,9 +97,15 @@ mkdir -p "${SSH_LOCAL}/cm" 2>/dev/null || true
|
|||||||
chmod 700 "${SSH_LOCAL}" "${SSH_LOCAL}/cm" 2>/dev/null || true
|
chmod 700 "${SSH_LOCAL}" "${SSH_LOCAL}/cm" 2>/dev/null || true
|
||||||
|
|
||||||
# ── Jump key (generated once; preserved across restarts) ──────────────
|
# ── Jump key (generated once; preserved across restarts) ──────────────
|
||||||
|
# Persisted via a named volume on ~/.ssh-local (see compose), so a fresh key
|
||||||
|
# is generated only on the very first start (or if the volume is wiped). When
|
||||||
|
# we DO generate one it must be (re-)authorized on the host, so we flag it and
|
||||||
|
# print a copy-paste authorize line below.
|
||||||
|
KEY_JUST_GENERATED=0
|
||||||
if [ ! -f "$KEY" ]; then
|
if [ ! -f "$KEY" ]; then
|
||||||
ssh-keygen -t ed25519 -N '' -C "devbox-jump@${HOSTNAME:-container}" -f "$KEY" >/dev/null 2>&1 || exit 0
|
ssh-keygen -t ed25519 -N '' -C "devbox-jump@${HOSTNAME:-container}" -f "$KEY" >/dev/null 2>&1 || exit 0
|
||||||
chmod 600 "$KEY" 2>/dev/null || true
|
chmod 600 "$KEY" 2>/dev/null || true
|
||||||
|
KEY_JUST_GENERATED=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Render the writable config ────────────────────────────────────────
|
# ── Render the writable config ────────────────────────────────────────
|
||||||
@@ -187,18 +193,33 @@ ${INCLUDE_BLOCK}
|
|||||||
EOF
|
EOF
|
||||||
chmod 600 "$CONFIG" 2>/dev/null || true
|
chmod 600 "$CONFIG" 2>/dev/null || true
|
||||||
|
|
||||||
# ── One-time hint when we can't authenticate yet ──────────────────────
|
# ── Authorize hints ───────────────────────────────────────────────────
|
||||||
|
# Print the copy-paste authorize line whenever we either (a) can't yet
|
||||||
|
# authenticate (HOST_SSH_USER unset) or (b) just generated a NEW key that the
|
||||||
|
# host won't recognize. With ~/.ssh-local persisted via a named volume, case
|
||||||
|
# (b) fires only on first-ever start (or after the volume is reset) — so this
|
||||||
|
# is normally a one-time, one-line step per machine, with no file to locate.
|
||||||
|
PUBKEY_TEXT="$(cat "${KEY}.pub" 2>/dev/null)"
|
||||||
if [ -z "${HOST_SSH_USER:-}" ]; then
|
if [ -z "${HOST_SSH_USER:-}" ]; then
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
[devbox] LAN-access jump config generated at ~/.ssh-local/config, but
|
[devbox] LAN-access jump config generated at ~/.ssh-local/config, but
|
||||||
HOST_SSH_USER is unset so it can't authenticate to the host yet.
|
HOST_SSH_USER is unset so it can't authenticate to the host yet.
|
||||||
To enable container -> host -> LAN-peer access:
|
To enable container -> host -> LAN-peer access:
|
||||||
1. Set HOST_SSH_USER=<your host username> in the container env.
|
1. Set HOST_SSH_USER=<your host username> in the container env.
|
||||||
2. Authorize this key on the host (append to ~/.ssh/authorized_keys):
|
2. Authorize this key on the host (run ON THE HOST, once):
|
||||||
$(cat "${KEY}.pub" 2>/dev/null)
|
echo '${PUBKEY_TEXT}' >> ~/.ssh/authorized_keys
|
||||||
3. Ensure the host's SSH server (Remote Login) is enabled.
|
3. Ensure the host's SSH server (Remote Login) is enabled.
|
||||||
Then: dssh host (or add 'ProxyJump host' to targets in ~/.ssh/config)
|
Then: dssh host (or add 'ProxyJump host' to targets in ~/.ssh/config)
|
||||||
EOF
|
EOF
|
||||||
|
elif [ "$KEY_JUST_GENERATED" = "1" ]; then
|
||||||
|
cat <<EOF
|
||||||
|
[devbox] Generated a NEW LAN-jump key. Authorize it on the host (${HOST_SSH_USER}@host),
|
||||||
|
then 'dssh host' and your LAN peers will work. Run this ONCE, ON THE HOST:
|
||||||
|
echo '${PUBKEY_TEXT}' >> ~/.ssh/authorized_keys
|
||||||
|
(Ensure the host's SSH server / Remote Login is enabled.)
|
||||||
|
This key is persisted in the ~/.ssh-local volume, so you won't need to
|
||||||
|
repeat this on container updates — only if that volume is reset.
|
||||||
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
Reference in New Issue
Block a user