Skip to content

feat(docker): support ssh-based commands in the docker image - #2183

Merged
martin-helmich merged 5 commits into
masterfrom
feat/docker-ssh-support
Nov 2, 2026
Merged

martin-helmich merged 5 commits into
masterfrom
feat/docker-ssh-support

Conversation

@Hermsi1337

@Hermsi1337 Hermsi1337 commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

Closes #2182

The Docker image had no ssh and no rsync, so every SSH-based command (container exec|cp|port-forward, app ssh, app download|upload, ...) failed in the container.

  • install openssh-client and rsync in the runtime image
  • GatewayPorts yes in /etc/ssh/ssh_config.d/, so port-forward binds to the container interface and the port can be published with docker run -p. This only affects the container's own network namespace. With --network host the forwarding would listen on all host interfaces though, so the README example uses -p 127.0.0.1:...
  • README: how to mount the SSH key and set MITTWALD_SSH_IDENTITY_FILE
  • README: shell function for ~/.bashrc/~/.zshrc to use the image like a local mw. It only adds -t when stdin and stdout are terminals, so pipes work, and the key is configurable via MW_SSH_KEY (only that one key gets mounted). Keys are mounted with --mount ...,readonly, so a missing key fails instead of docker creating a directory. Plus notes on root-owned downloads on Linux, paths outside the working dir, and not combining port forwarding with --network host
  • CI: the docker job checks that ssh, scp, ssh-keygen, rsync and GatewayPorts yes are in the image

Tested with an image built from this Dockerfile and the v1.28.1 linux-arm64 release tarball: container exec, app download --dry-run and container port-forward (HTTP 301 from the container through -p 127.0.0.1:18080:18080) worked against a real project.

container cp only honors MITTWALD_SSH_IDENTITY_FILE with #2187, until then it only finds keys at the default ~/.ssh/id_* paths.

Follow-ups after testing: the mw() function only mounts the key if it exists (token-only commands work without a key), the port-forward example passes --project-id (no persisted context in a fresh container), and the ownership note now also covers rsync keeping the remote numeric owner.

Install openssh-client and rsync, bind port forwardings to the container interface and document how to pass the ssh key.

Closes #2182
Allocate a TTY only when interactive, fail on missing keys instead of creating a directory, make the key configurable, warn about host networking and document root-owned downloads. CI now checks that ssh, scp, ssh-keygen, rsync and GatewayPorts are in the image.
@martin-helmich
martin-helmich merged commit 59059fa into master Nov 2, 2026
11 checks passed
@martin-helmich
martin-helmich deleted the feat/docker-ssh-support branch November 2, 2026 09:42
martin-helmich pushed a commit that referenced this pull request Nov 2, 2026
Closes #2184

- both stages on `ubuntu:26.04`
- the builder picks the tarball via `TARGETARCH` instead of `uname -p`.
On 26.04 `uname -p` returns `unknown`, so arm64 would have gotten the
x64 tarball
- the builder runs on `$BUILDPLATFORM`, so the tarball is extracted
natively, not under QEMU. The final stage is still built per target
platform
- dropped the `ARCH` build arg. Neither workflow sets it, and with
`TARGETARCH` picking the tarball it could combine an arm64 base with x64
binaries. `--platform` is now the only way to pick the architecture

Tested with the v1.28.1 release tarballs: arm64 and amd64 images both
start with the right arch (`mw --version` shows `linux-arm64` /
`linux-x64`), and `mw project list` against the API works on both. The
CI path (only the linux-x64 tarball, `PKG_SOURCE=dist`) builds and runs
too.

This touches the same lines of the Dockerfile as #2183, whichever goes
in second needs a small rebase. `openssh-client` and `rsync` install
fine on 26.04 (OpenSSH 10.2, rsync 3.4.1).

The builder now fails with `unsupported architecture: <arch>` for
anything but amd64/arm64 instead of silently packing the x64 binary
(e.g. `--platform linux/s390x` used to build an image that crashed on
start).
martin-helmich pushed a commit that referenced this pull request Nov 2, 2026
Closes #2186

`container cp` had `--ssh-identity-file` in its flags but never handed
it to scp. The scp args are now built in `buildScpArgs`
(`src/lib/resources/ssh/scp.ts`), which adds `-i <file>` when set, same
as `buildSSHClientFlags` does for ssh. Without the flag the args are
exactly as before.

Unit tests cover `-i` placement, paths with spaces, the unset case and
`-p`/`-r`.

This also matters for the Docker image (#2183): there the key gets
mounted at an arbitrary path and passed via
`MITTWALD_SSH_IDENTITY_FILE`, which so far only worked for everything
except `container cp`.

`ScpArgsOptions` requires the `ssh-identity-file` key
(`Pick<SSHConnectionFlags, ...>`), so a caller dropping it fails to
compile instead of silently losing the key again.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support SSH-based commands in the Docker image

2 participants