Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a56a5846a5 |
+11
-2
@@ -37,8 +37,11 @@ SSH_KEY_PATH=~/.ssh
|
|||||||
# directly-attached LAN peers by default. On native Linux Docker the LAN is
|
# directly-attached LAN peers by default. On native Linux Docker the LAN is
|
||||||
# reachable directly and nothing is needed. The entrypoint detects this and,
|
# reachable directly and nothing is needed. The entrypoint detects this and,
|
||||||
# on VM-backed hosts, generates ~/.ssh-local/config so the host can be used
|
# on VM-backed hosts, generates ~/.ssh-local/config so the host can be used
|
||||||
# as an SSH jump (use the `dssh` alias, or add `ProxyJump host` to targets
|
# as an SSH jump (use the `dssh` alias). Reach the host itself with
|
||||||
# in your bind-mounted ~/.ssh/config).
|
# `dssh host`. To reach named LAN peers, put `ProxyJump host` overrides in a
|
||||||
|
# host-owned ~/.config/devbox-shell/ssh-lan.conf (bind-mounted in) rather than
|
||||||
|
# editing your ~/.ssh/config — see ssh-lan.conf.example. Public-IP hosts (and
|
||||||
|
# anything reached via a public jump host) connect directly, no jump needed.
|
||||||
#
|
#
|
||||||
# DEVBOX_LAN_ACCESS: auto (default) | jump | off
|
# DEVBOX_LAN_ACCESS: auto (default) | jump | off
|
||||||
# auto = set up the jump only on VM-backed hosts; no-op on native Linux.
|
# auto = set up the jump only on VM-backed hosts; no-op on native Linux.
|
||||||
@@ -54,6 +57,12 @@ SSH_KEY_PATH=~/.ssh
|
|||||||
#
|
#
|
||||||
# DEVBOX_HOST_ALIAS: host hostname to reach (default host.docker.internal).
|
# DEVBOX_HOST_ALIAS: host hostname to reach (default host.docker.internal).
|
||||||
# DEVBOX_HOST_ALIAS=host.docker.internal
|
# DEVBOX_HOST_ALIAS=host.docker.internal
|
||||||
|
#
|
||||||
|
# DEVBOX_LAN_AUTOJUMP_PRIVATE: 1 = ProxyJump ANY RFC1918 (private) IP through
|
||||||
|
# the host, so bare `dssh user@<ip>` works on whatever LAN the (roaming) host
|
||||||
|
# is currently joined to, without naming peers. Matches the typed address, not
|
||||||
|
# the resolved HostName, so named hosts with their own ProxyJump are unaffected.
|
||||||
|
# DEVBOX_LAN_AUTOJUMP_PRIVATE=0
|
||||||
|
|
||||||
# ── Skillset (agent skills and instructions) ─────────────────────────
|
# ── Skillset (agent skills and instructions) ─────────────────────────
|
||||||
# If you have a skillset repo, the entrypoint auto-deploys skills and
|
# If you have a skillset repo, the entrypoint auto-deploys skills and
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Docker image packaging [opencode](https://opencode.ai) into a production-ready d
|
|||||||
- `Dockerfile.variant` — `FROM`s the base and adds only opencode/omos/pi installs gated by build args: `INSTALL_OPENCODE` (default true), `INSTALL_OMOS`, `INSTALL_PI`, and `INSTALL_MEMPALACE`. All GitHub-sourced binaries are pinned with version ARGs. When `INSTALL_PI=true` it also clones `pi-fork` + `pi-observational-memory` (from `github.com/elpapi42`, refs `PI_FORK_REF`/`PI_OBSMEM_REF`) to `/opt` and runs `npm install` there at build time so the `fork`/`recall` extensions can load (a local-path `pi install` does not npm-install). The `pi-only` variant sets `INSTALL_OPENCODE=false`, `INSTALL_PI=true` — pi without opencode, the single source of truth for the separate `pi-devbox` image. It is built and smoke-tested here, but **published into the `joakimp/pi-devbox` repo** as the internal building-block tag `base-pi-only[-vX.Y.Z]` (NOT under `opencode-devbox`), so an opencode-devbox tag never ships without opencode.
|
- `Dockerfile.variant` — `FROM`s the base and adds only opencode/omos/pi installs gated by build args: `INSTALL_OPENCODE` (default true), `INSTALL_OMOS`, `INSTALL_PI`, and `INSTALL_MEMPALACE`. All GitHub-sourced binaries are pinned with version ARGs. When `INSTALL_PI=true` it also clones `pi-fork` + `pi-observational-memory` (from `github.com/elpapi42`, refs `PI_FORK_REF`/`PI_OBSMEM_REF`) to `/opt` and runs `npm install` there at build time so the `fork`/`recall` extensions can load (a local-path `pi install` does not npm-install). The `pi-only` variant sets `INSTALL_OPENCODE=false`, `INSTALL_PI=true` — pi without opencode, the single source of truth for the separate `pi-devbox` image. It is built and smoke-tested here, but **published into the `joakimp/pi-devbox` repo** as the internal building-block tag `base-pi-only[-vX.Y.Z]` (NOT under `opencode-devbox`), so an opencode-devbox tag never ships without opencode.
|
||||||
- `entrypoint.sh` — runs as root: UID/GID adjustment, SSH permissions, volume ownership fixes (skipped via `.devbox-owner` sentinel when ownership is already correct). Then drops to developer via gosu. Volume ownership loop covers `~/.pi/` when `INSTALL_PI=true`.
|
- `entrypoint.sh` — runs as root: UID/GID adjustment, SSH permissions, volume ownership fixes (skipped via `.devbox-owner` sentinel when ownership is already correct). Then drops to developer via gosu. Volume ownership loop covers `~/.pi/` when `INSTALL_PI=true`.
|
||||||
- `entrypoint-user.sh` — runs as developer: git config, opencode.jsonc generation (delegated to `generate-config.py`), LAN-access setup (delegated to `setup-lan-access.sh`), pi-toolkit + pi-extensions deploy (when pi installed), pi settings.json bootstrap, mempalace pi-bridge symlink, runtime `pi install /opt/{pi-fork,pi-observational-memory}` registration (idempotent), skillset auto-deploy from mounted skillset repo, OMOS setup.
|
- `entrypoint-user.sh` — runs as developer: git config, opencode.jsonc generation (delegated to `generate-config.py`), LAN-access setup (delegated to `setup-lan-access.sh`), pi-toolkit + pi-extensions deploy (when pi installed), pi settings.json bootstrap, mempalace pi-bridge symlink, runtime `pi install /opt/{pi-fork,pi-observational-memory}` registration (idempotent), skillset auto-deploy from mounted skillset repo, OMOS setup.
|
||||||
- `rootfs/usr/local/lib/opencode-devbox/setup-lan-access.sh` — host-OS-agnostic LAN reachability helper. Detects VM-backed hosts (macOS OrbStack / Docker Desktop, via `host.docker.internal` resolution) and generates a writable `~/.ssh-local/config` using the host as an SSH jump; no-op on native Linux. Controlled by `DEVBOX_LAN_ACCESS` / `HOST_SSH_USER` / `DEVBOX_HOST_ALIAS`. Ships the mechanism only (generic `host` jump alias); user targets stay in their bind-mounted `~/.ssh/config`. Non-fatal. Counted in the base hash, so editing it advances `base-latest`.
|
- `rootfs/usr/local/lib/opencode-devbox/setup-lan-access.sh` — host-OS-agnostic LAN reachability helper. Detects VM-backed hosts (macOS OrbStack / Docker Desktop, via `host.docker.internal` resolution) and generates a writable `~/.ssh-local/config` using the host as an SSH jump; no-op on native Linux. Controlled by `DEVBOX_LAN_ACCESS` / `HOST_SSH_USER` / `DEVBOX_HOST_ALIAS` / `DEVBOX_LAN_AUTOJUMP_PRIVATE`. Ships the mechanism only (generic `host` jump alias); user targets stay host-side — named-peer `ProxyJump host` overrides go in a bind-mounted `~/.config/devbox-shell/ssh-lan.conf` (Included before `~/.ssh/config`), never baked into the image. **Scoping invariant:** every `Include` in the generated config MUST be preceded by a bare `Host *` reset — an `Include` is scoped to the enclosing `Host`/`Match` block, so without the reset the included config only applies when targeting `host`/`mac` and named peers fall back to SSH defaults. The top `Host *` block also overrides `UserKnownHostsFile` and `ControlPath` into the writable `~/.ssh-local` sidecar (first-value-wins), because the bind-mounted `~/.ssh` is read-only — otherwise multiplexed hosts (`ControlPath ~/.ssh/cm/...`) fail to create their master socket. Non-fatal. Counted in the base hash, so editing it advances `base-latest`.
|
||||||
- `rootfs/usr/local/lib/opencode-devbox/generate-config.py` — generates `~/.config/opencode/opencode.jsonc` from env vars. Never overwrites an existing config (checks both `.json` and `.jsonc`). Auto-registers MCP servers for detected tools (mempalace via `mempalace-mcp`, gitea-mcp, context7 remote endpoint).
|
- `rootfs/usr/local/lib/opencode-devbox/generate-config.py` — generates `~/.config/opencode/opencode.jsonc` from env vars. Never overwrites an existing config (checks both `.json` and `.jsonc`). Auto-registers MCP servers for detected tools (mempalace via `mempalace-mcp`, gitea-mcp, context7 remote endpoint).
|
||||||
- `scripts/smoke-test.sh` — post-build image verification. Asserts binary presence, opencode startup, entrypoint correctness, config generation idempotency, and image size thresholds. Used by both CI workflows.
|
- `scripts/smoke-test.sh` — post-build image verification. Asserts binary presence, opencode startup, entrypoint correctness, config generation idempotency, and image size thresholds. Used by both CI workflows.
|
||||||
- `scripts/generate-dockerhub-md.py` — generates `DOCKER_HUB.md` from a hand-maintained `HUB_TEMPLATE` constant. `--check` fails if the committed file is out of sync (enforced by the `validate` workflow).
|
- `scripts/generate-dockerhub-md.py` — generates `DOCKER_HUB.md` from a hand-maintained `HUB_TEMPLATE` constant. `--check` fails if the committed file is out of sync (enforced by the `validate` workflow).
|
||||||
|
|||||||
+46
-1
@@ -8,7 +8,52 @@ Tags follow `v{opencode_version}[letter]` — bare tag for the first build on a
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
_(no changes since v1.15.13c)_
|
_(no changes since v1.15.13d)_
|
||||||
|
|
||||||
|
## v1.15.13d — 2026-06-04
|
||||||
|
|
||||||
|
LAN-access fixes + ergonomics. Letter-suffix rebuild on opencode `1.15.13`
|
||||||
|
(version unchanged). Touches `setup-lan-access.sh`, which is in the base hash,
|
||||||
|
so `base-latest` / `base-pi-only` advance and the fix propagates to `pi-devbox`.
|
||||||
|
|
||||||
|
### Fixed: LAN-access `Include` was scoped to the `host`/`mac` block (named peers ignored)
|
||||||
|
|
||||||
|
The generated `~/.ssh-local/config` placed `Include ~/.ssh/config` *inside* the
|
||||||
|
`Host host mac` block. Because SSH scopes an `Include` to the enclosing
|
||||||
|
`Host`/`Match` block, the user's `~/.ssh/config` was only consulted when
|
||||||
|
targeting `host`/`mac` — so `dssh pve` / `dssh <peer>` by name silently fell
|
||||||
|
back to SSH defaults (wrong user, unresolved hostname) and never applied the
|
||||||
|
peer's settings or any `ProxyJump`. Fixed by emitting a bare `Host *` scope
|
||||||
|
reset before every `Include`.
|
||||||
|
|
||||||
|
### Fixed: read-only `~/.ssh/cm` ControlPath broke multiplexed hosts
|
||||||
|
|
||||||
|
The bind-mounted `~/.ssh/config` commonly sets `ControlPath ~/.ssh/cm/...`
|
||||||
|
(CGNAT flow-cap multiplexing), but `~/.ssh` is read-only in the container, so
|
||||||
|
every `ControlMaster`-enabled host (e.g. `pmx-jh`, `proxmox*`, `synlig`) failed
|
||||||
|
with `cannot bind to path … Read-only file system`. The generated config now
|
||||||
|
sets `ControlPath ~/.ssh-local/cm/%r@%h:%p` in the top `Host *` block
|
||||||
|
(first-value-wins) so master sockets land in the writable sidecar.
|
||||||
|
|
||||||
|
### Added: host-owned `ssh-lan.conf` for named-peer jump overrides
|
||||||
|
|
||||||
|
When the host bind-mounts `~/.config/devbox-shell/ssh-lan.conf`, the generated
|
||||||
|
config now Includes it *before* `~/.ssh/config`. Put `ProxyJump host` overrides
|
||||||
|
there (first-value-wins inherits HostName/User/IdentityFile from `~/.ssh/config`)
|
||||||
|
instead of editing the shared `~/.ssh/config` — which would break the host's own
|
||||||
|
direct access to those peers and is read-only from the container anyway. New
|
||||||
|
[`ssh-lan.conf.example`](ssh-lan.conf.example).
|
||||||
|
|
||||||
|
### Added: `DEVBOX_LAN_AUTOJUMP_PRIVATE=1` opt-in RFC1918 auto-jump
|
||||||
|
|
||||||
|
Emits a catch-all that ProxyJumps any private (RFC1918) IP through the host, so
|
||||||
|
bare `dssh user@<ip>` reaches whatever LAN the (roaming) host is currently on,
|
||||||
|
without naming peers. Matches the typed address (not the resolved HostName), so
|
||||||
|
named hosts carrying their own ProxyJump are unaffected; public IPs stay direct.
|
||||||
|
|
||||||
|
All three land in `rootfs/usr/local/lib/opencode-devbox/setup-lan-access.sh`,
|
||||||
|
which is counted in the base hash → advances `base-latest` and propagates to
|
||||||
|
`pi-devbox` (built `FROM` the base).
|
||||||
|
|
||||||
## v1.15.13c — 2026-06-03
|
## v1.15.13c — 2026-06-03
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ docker compose exec -u developer devbox aws --version
|
|||||||
| `DEVBOX_LAN_ACCESS` | LAN-access mode: `auto` (jump only on VM-backed hosts), `jump` (always), `off` | `auto` |
|
| `DEVBOX_LAN_ACCESS` | LAN-access mode: `auto` (jump only on VM-backed hosts), `jump` (always), `off` | `auto` |
|
||||||
| `HOST_SSH_USER` | Username to SSH into the host as (required for the LAN jump) | — |
|
| `HOST_SSH_USER` | Username to SSH into the host as (required for the LAN jump) | — |
|
||||||
| `DEVBOX_HOST_ALIAS` | Hostname used to reach the container host | `host.docker.internal` |
|
| `DEVBOX_HOST_ALIAS` | Hostname used to reach the container host | `host.docker.internal` |
|
||||||
|
| `DEVBOX_LAN_AUTOJUMP_PRIVATE` | `1` = ProxyJump *any* RFC1918 (private) IP through the host, so bare `dssh user@<ip>` works on whatever LAN the host is currently on | `0` |
|
||||||
| `USER_UID` | Override container user UID | Auto-detect from `/workspace` |
|
| `USER_UID` | Override container user UID | Auto-detect from `/workspace` |
|
||||||
| `USER_GID` | Override container user GID | Auto-detect from `/workspace` |
|
| `USER_GID` | Override container user GID | Auto-detect from `/workspace` |
|
||||||
| `LANG` | System locale | `en_US.UTF-8` |
|
| `LANG` | System locale | `en_US.UTF-8` |
|
||||||
@@ -161,19 +162,25 @@ On every start the entrypoint detects which case applies. On VM-backed hosts it
|
|||||||
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. The entrypoint prints a public key — append it to your host's `~/.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 with `dssh host`, and reach LAN peers by adding `ProxyJump host` to their entries in your bind-mounted `~/.ssh/config`:
|
4. Reach the host itself with `dssh host`. (`dssh`/`dscp` wrap `ssh -F ~/.ssh-local/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
|
||||||
# in your host ~/.ssh/config (mounted read-only into the container)
|
# ~/.config/devbox-shell/ssh-lan.conf — on the host, bind-mounted in
|
||||||
Host my-nas
|
# Only ProxyJump goes here; HostName/User/IdentityFile are inherited
|
||||||
HostName 192.168.1.50
|
# (first-value-wins) from the matching block in your ~/.ssh/config.
|
||||||
User admin
|
Host my-nas pve pbs
|
||||||
ProxyJump host
|
ProxyJump host
|
||||||
```
|
```
|
||||||
|
|
||||||
Then `dssh my-nas` routes container → host → LAN peer. (`dssh`/`dscp` wrap `ssh -F ~/.ssh-local/config`; the host config is pulled in via `Include`.)
|
Now `dssh my-nas` routes container → host → LAN peer, pulling HostName/User/key from your existing `~/.ssh/config`. See [`ssh-lan.conf.example`](ssh-lan.conf.example).
|
||||||
|
|
||||||
> This ships the **mechanism** only — your specific target hosts live in your own `~/.ssh/config`, never baked into the image. Set `DEVBOX_LAN_ACCESS=off` to disable, or `=jump` to force it (e.g. native Linux with `extra_hosts: ["host.docker.internal:host-gateway"]`).
|
**Roaming / unnamed peers.** Because the jump always targets `host` (= the host on whatever LAN it's currently joined to), you can reach the *current* LAN from anywhere. To make bare `dssh user@<private-ip>` jump automatically without naming peers, set `DEVBOX_LAN_AUTOJUMP_PRIVATE=1` — it ProxyJumps any RFC1918 address through the host. It matches the address you *type* (not the resolved HostName), so named hosts that already carry their own ProxyJump are unaffected.
|
||||||
|
|
||||||
|
**Public IPs go direct.** The container has normal internet egress, so a host with a public IP (or one reached via a *public* jump host) connects straight out — the local `host` jump is not involved. e.g. a `Host bastion` whose `HostName` is public, and everything that `ProxyJump bastion`, works from the container by name with no extra setup.
|
||||||
|
|
||||||
|
> This ships the **mechanism** only — your specific target hosts are facts about *your* network (and a laptop roams between several), so they live in your own host-side config, never baked into the image. Set `DEVBOX_LAN_ACCESS=off` to disable, or `=jump` to force it (e.g. native Linux with `extra_hosts: ["host.docker.internal:host-gateway"]`).
|
||||||
|
|
||||||
### Custom opencode config
|
### Custom opencode config
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,30 @@
|
|||||||
# jump to authenticate. If unset we still generate the config but print
|
# jump to authenticate. If unset we still generate the config but print
|
||||||
# a hint with the public key to authorize on the host.
|
# a hint with the public key to authorize on the host.
|
||||||
# DEVBOX_HOST_ALIAS — host hostname to reach (default host.docker.internal).
|
# DEVBOX_HOST_ALIAS — host hostname to reach (default host.docker.internal).
|
||||||
|
# DEVBOX_LAN_AUTOJUMP_PRIVATE = 0 (default) | 1
|
||||||
|
# 1 → also emit a catch-all that ProxyJumps *any* RFC1918 (private) IP
|
||||||
|
# through the host. Lets bare `dssh user@<private-IP>` work on whatever
|
||||||
|
# LAN the (roaming) host is currently joined to, without naming peers.
|
||||||
|
# Matches by the address you TYPE, not the resolved HostName, so it never
|
||||||
|
# overrides named hosts that already carry their own ProxyJump.
|
||||||
|
#
|
||||||
|
# HOST-OWNED PEER POLICY (portable; keeps this image generic)
|
||||||
|
# Named LAN peers are facts about a *specific* host's network, not about the
|
||||||
|
# image — a roaming laptop sees different LANs. So we never bake peer names
|
||||||
|
# here. Instead, if the host bind-mounts ~/.config/devbox-shell/ssh-lan.conf
|
||||||
|
# (the same devbox-shell bridge dir used for shared aliases), we Include it
|
||||||
|
# *before* ~/.ssh/config. That file holds the host's own jump overrides, e.g.
|
||||||
|
# Host pve pve-2 pbs-vm
|
||||||
|
# ProxyJump host
|
||||||
|
# First-value-wins means ProxyJump is taken from there while HostName/User/
|
||||||
|
# IdentityFile are inherited from the matching block in ~/.ssh/config.
|
||||||
|
#
|
||||||
|
# SCOPING NOTE (important)
|
||||||
|
# `Include` is scoped to the enclosing Host/Match block. So every Include
|
||||||
|
# below is preceded by a bare `Host *` to reset the active context to
|
||||||
|
# match-all — otherwise the included config would only apply when targeting
|
||||||
|
# `host`/`mac` and named peers like `pve` would silently fall back to ssh
|
||||||
|
# defaults.
|
||||||
#
|
#
|
||||||
# Idempotent: re-renders the config every run (cheap); never regenerates the
|
# Idempotent: re-renders the config every run (cheap); never regenerates the
|
||||||
# key. Always non-fatal — never blocks container startup.
|
# key. Always non-fatal — never blocks container startup.
|
||||||
@@ -84,9 +108,51 @@ if [ -n "${HOST_SSH_USER:-}" ]; then
|
|||||||
USER_LINE=" User ${HOST_SSH_USER}"
|
USER_LINE=" User ${HOST_SSH_USER}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
INCLUDE_LINE=""
|
# Optional host-owned named-peer jump overrides (portable: lives on the host,
|
||||||
|
# not in the image). Included BEFORE ~/.ssh/config so its ProxyJump wins.
|
||||||
|
SSH_LAN_CONF="${HOME}/.config/devbox-shell/ssh-lan.conf"
|
||||||
|
LAN_CONF_BLOCK=""
|
||||||
|
if [ -r "$SSH_LAN_CONF" ]; then
|
||||||
|
LAN_CONF_BLOCK=$(cat <<'EOF'
|
||||||
|
|
||||||
|
# Host-owned named-peer jump overrides (bind-mounted; edit on the host).
|
||||||
|
# Scope reset to match-all so the Include applies to every target host.
|
||||||
|
Host *
|
||||||
|
Include ~/.config/devbox-shell/ssh-lan.conf
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optional opt-in RFC1918 catch-all: ProxyJump every private IP through the
|
||||||
|
# host. Matches the typed address, never the resolved HostName, so named hosts
|
||||||
|
# with their own ProxyJump are unaffected. Network-agnostic → roaming-safe.
|
||||||
|
AUTOJUMP_BLOCK=""
|
||||||
|
if [ "${DEVBOX_LAN_AUTOJUMP_PRIVATE:-0}" = "1" ]; then
|
||||||
|
AUTOJUMP_BLOCK=$(cat <<'EOF'
|
||||||
|
|
||||||
|
# RFC1918 auto-jump (DEVBOX_LAN_AUTOJUMP_PRIVATE=1): reach any private IP on
|
||||||
|
# the host's CURRENT LAN via bare `dssh user@<ip>`. Public IPs are unmatched
|
||||||
|
# and go direct via the container's NAT egress. NOTE: also matches the
|
||||||
|
# container's own bridge subnet and any private IP the host can't actually
|
||||||
|
# reach — for non-LAN private hosts behind a different jump, use their named
|
||||||
|
# entry (which matches first by name and keeps its own ProxyJump).
|
||||||
|
Host 10.* 192.168.* 172.16.* 172.17.* 172.18.* 172.19.* 172.20.* 172.21.* 172.22.* 172.23.* 172.24.* 172.25.* 172.26.* 172.27.* 172.28.* 172.29.* 172.30.* 172.31.*
|
||||||
|
ProxyJump host
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
|
INCLUDE_BLOCK=""
|
||||||
if [ -r "${HOME}/.ssh/config" ]; then
|
if [ -r "${HOME}/.ssh/config" ]; then
|
||||||
INCLUDE_LINE="Include ~/.ssh/config"
|
INCLUDE_BLOCK=$(cat <<'EOF'
|
||||||
|
|
||||||
|
# Your own target hosts. Scope reset to match-all so this Include applies to
|
||||||
|
# every target (an Include is otherwise scoped to the enclosing Host block).
|
||||||
|
# Add 'ProxyJump host' to LAN entries here (or in ssh-lan.conf above).
|
||||||
|
Host *
|
||||||
|
Include ~/.ssh/config
|
||||||
|
EOF
|
||||||
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat > "$CONFIG" <<EOF
|
cat > "$CONFIG" <<EOF
|
||||||
@@ -95,9 +161,15 @@ cat > "$CONFIG" <<EOF
|
|||||||
# (or the dssh / dscp aliases). See the script header for the full rationale.
|
# (or the dssh / dscp aliases). See the script header for the full rationale.
|
||||||
|
|
||||||
# ~/.ssh is typically mounted read-only, so keep our own known_hosts here.
|
# ~/.ssh is typically mounted read-only, so keep our own known_hosts here.
|
||||||
|
# Also redirect ControlPath into the writable sidecar: the bind-mounted
|
||||||
|
# ~/.ssh/config commonly sets 'ControlPath ~/.ssh/cm/...' for CGNAT multiplexing,
|
||||||
|
# but ~/.ssh is read-only here so the master socket can't be created and those
|
||||||
|
# hosts fail to connect. First-value-wins: setting it here (before the Include)
|
||||||
|
# overrides the read-only path for every host. Harmless when ControlMaster is off.
|
||||||
Host *
|
Host *
|
||||||
UserKnownHostsFile ~/.ssh-local/known_hosts
|
UserKnownHostsFile ~/.ssh-local/known_hosts
|
||||||
StrictHostKeyChecking accept-new
|
StrictHostKeyChecking accept-new
|
||||||
|
ControlPath ~/.ssh-local/cm/%r@%h:%p
|
||||||
|
|
||||||
# The container host (OrbStack / Docker Desktop). 'host' and 'mac' are aliases.
|
# The container host (OrbStack / Docker Desktop). 'host' and 'mac' are aliases.
|
||||||
Host host mac
|
Host host mac
|
||||||
@@ -109,10 +181,9 @@ ${USER_LINE}
|
|||||||
ControlPath ~/.ssh-local/cm/%r@%h:%p
|
ControlPath ~/.ssh-local/cm/%r@%h:%p
|
||||||
ControlPersist 4h
|
ControlPersist 4h
|
||||||
ServerAliveInterval 30
|
ServerAliveInterval 30
|
||||||
|
${LAN_CONF_BLOCK}
|
||||||
# Your own target hosts: add 'ProxyJump host' to their entries in your
|
${AUTOJUMP_BLOCK}
|
||||||
# bind-mounted ~/.ssh/config, pulled in below.
|
${INCLUDE_BLOCK}
|
||||||
${INCLUDE_LINE}
|
|
||||||
EOF
|
EOF
|
||||||
chmod 600 "$CONFIG" 2>/dev/null || true
|
chmod 600 "$CONFIG" 2>/dev/null || true
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# ssh-lan.conf.example — host-owned LAN-peer jump overrides for opencode-devbox
|
||||||
|
# ============================================================================
|
||||||
|
# WHAT THIS IS
|
||||||
|
# On a VM-backed host (macOS OrbStack / Docker Desktop) the container can't
|
||||||
|
# reach the host's LAN directly; it tunnels through the host via the `host`
|
||||||
|
# SSH jump that the entrypoint sets up (see the README "Reaching your LAN"
|
||||||
|
# section). To reach your LAN peers *by name*, they need `ProxyJump host`.
|
||||||
|
#
|
||||||
|
# WHY NOT JUST EDIT ~/.ssh/config?
|
||||||
|
# The host itself reaches those peers DIRECTLY — adding `ProxyJump host`
|
||||||
|
# there would break the host's own access (and ~/.ssh is mounted read-only
|
||||||
|
# into the container anyway). So container-only jump overrides live HERE.
|
||||||
|
#
|
||||||
|
# HOW IT'S WIRED
|
||||||
|
# If this file exists at ~/.config/devbox-shell/ssh-lan.conf on the host
|
||||||
|
# (the same bind-mounted devbox-shell bridge dir used for shared aliases),
|
||||||
|
# the generated ~/.ssh-local/config Includes it BEFORE your ~/.ssh/config.
|
||||||
|
# SSH's first-value-wins rule means ProxyJump is taken from here, while
|
||||||
|
# HostName / User / IdentityFile are inherited from the matching block in
|
||||||
|
# your ~/.ssh/config. So you only list the names + the jump — nothing else.
|
||||||
|
#
|
||||||
|
# SETUP
|
||||||
|
# 1. Copy to your host: cp ssh-lan.conf.example ~/.config/devbox-shell/ssh-lan.conf
|
||||||
|
# 2. Bind-mount ~/.config/devbox-shell into the container (most setups
|
||||||
|
# already do this for shared shell aliases).
|
||||||
|
# 3. List the host aliases (as named in your ~/.ssh/config) that should be
|
||||||
|
# reached through the host jump.
|
||||||
|
# 4. Restart the container, then: dssh <name>
|
||||||
|
#
|
||||||
|
# NOTE: these are facts about ONE host's LAN. A roaming laptop sees different
|
||||||
|
# networks — keep this per-host, never in the image. For ad-hoc private IPs on
|
||||||
|
# whatever LAN you're currently on, prefer DEVBOX_LAN_AUTOJUMP_PRIVATE=1
|
||||||
|
# instead of naming every peer.
|
||||||
|
|
||||||
|
# Example — names must match Host blocks already defined in your ~/.ssh/config:
|
||||||
|
Host pve pve-2 pbs-vm my-nas
|
||||||
|
ProxyJump host
|
||||||
|
|
||||||
|
# You can also give a peer its own settings here if it isn't in ~/.ssh/config
|
||||||
|
# at all (then specify everything, not just ProxyJump):
|
||||||
|
# Host lab-box
|
||||||
|
# HostName 192.168.1.77
|
||||||
|
# User admin
|
||||||
|
# IdentityFile ~/.ssh/id_ed25519
|
||||||
|
# ProxyJump host
|
||||||
Reference in New Issue
Block a user