Skip to content

feat(docker): run as the host user via MW_UID/MW_GID - #2189

Open
Hermsi1337 wants to merge 8 commits into
masterfrom
feat/docker-host-uid
Open

Hermsi1337 wants to merge 8 commits into
masterfrom
feat/docker-host-uid

Conversation

@Hermsi1337

@Hermsi1337 Hermsi1337 commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

Closes #2188

Stacked on #2183 (needs the SSH tooling), so the base is feat/docker-ssh-support.

  • the image gets a mw user and docker/entrypoint.sh as entrypoint
  • with MW_UID (and optionally MW_GID, defaults to MW_UID) the entrypoint moves mw to those IDs via usermod/groupmod --non-unique and starts the CLI through setpriv with HOME=/home/mw. setpriv is already in the base image, so no extra package like gosu
  • without the variables nothing changes: the CLI runs as root like before
  • README: examples pass -e MW_UID="$(id -u)" -e MW_GID="$(id -g)", and the key is now mounted at /ssh/... instead of /root/.ssh/... so the non-root user can read it
  • CI: checks that the CLI process really runs as 1234:2345 when the variables are set

Same idea as the entrypoint in mittwald/golangci-lint-cfg, except the GID is separate (on macOS UID and GID differ, e.g. 501:20).

Tested on Docker Desktop (arm64) with an image built from this branch and the v1.28.1 tarball:

  • --version and project list with and without MW_UID, also with an already existing GID (MW_GID=20)
  • container exec against a real container as UID 1234, key from /ssh/key via MITTWALD_SSH_IDENTITY_FILE
  • scp into the working dir as UID 1234 against a local sshd: the file belongs to 1234:2345
  • the CI check fails when the variables are not set (process runs as 0:0)

container cp only picks up the key from /ssh/... together with #2187, since cp ignored --ssh-identity-file so far.

Follow-ups after testing:

  • usermod printed usermod: no changes to stdout when MW_UID matched the mw user (UID 1000, the most common Linux UID), which broke -o json piping. Its output is discarded now, and CI checks that --version prints exactly one line in that case
  • MW_UID/MW_GID must be numeric, otherwise the entrypoint fails with a clear message instead of a groupmod error about a group ID
  • /var/log/lastlog and faillog are removed and useradd --no-log-init is used, so usermod with large UIDs (LDAP/AD) doesn't create huge sparse files in the container layer
  • the uid CI step prints the container logs and cleans up via an EXIT trap
  • the ubuntu user (UID 1000 on 24.04+) is removed so mw keeps UID 1000 after the rebase onto chore(docker): update base image to ubuntu 26.04 #2185

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.
@Hermsi1337
Hermsi1337 force-pushed the feat/docker-host-uid branch from 0bd6fbd to a8ec146 Compare November 1, 2026 10:35
usermod printed "no changes" to stdout when MW_UID matched the mw user, which broke JSON output. Also drop lastlog/faillog so usermod does not create huge sparse files for large UIDs.
@Hermsi1337
Hermsi1337 force-pushed the feat/docker-host-uid branch from a8ec146 to c7729c1 Compare November 1, 2026 11:20
Base automatically changed from feat/docker-ssh-support to master November 2, 2026 09:42
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.

1 participant