Dockerize your OpenSSH-server with rsync and bash installed, upon a customizable alpine-image
5M+
Make your OpenSSH fly on Alpine.
A slim, highly configurable OpenSSH server (sshd) on Alpine Linux with bash, bash-completion and rsync preinstalled. Typical uses: an SSH/SFTP sidecar for exchanging files with other containers or volumes, an rsync endpoint, or a lightweight jump host. Everything is configured through environment variables at container start — no image rebuild needed.
Images are built for linux/amd64 and linux/arm64 and rebuilt weekly so they stay current with Alpine security updates.
docker run --rm \
--publish 1337:22 \
--env ROOT_PASSWORD=MyRootPW123 \
hermsi/alpine-sshd
ssh [email protected] -p 1337
docker run --rm \
--publish 1337:22 \
--env ROOT_KEYPAIR_LOGIN_ENABLED=true \
--volume /path/to/authorized_keys:/root/.ssh/authorized_keys \
hermsi/alpine-sshd
ssh [email protected] -p 1337 -i /path/to/private_key
In this mode password authentication for root is disabled entirely.
Users are declared as comma-separated name:uid:gid triplets. Each user authenticates with the public key mounted at /conf.d/authorized_keys/<username>:
docker run --rm \
--publish 1337:22 \
--env SSH_USERS="hermsi:1000:1000,dennis:1001:1001" \
--volume /path/to/hermsi.pub:/conf.d/authorized_keys/hermsi \
--volume /path/to/dennis.pub:/conf.d/authorized_keys/dennis \
hermsi/alpine-sshd
ssh mydomain.tld -l hermsi -p 1337 -i /path/to/hermsi_private_key
Additional users authenticate by keypair only. The root account stays locked unless you explicitly unlock it (see below).
The tag set encodes the exact OpenSSH package version and the Alpine release the image was built from:
| Tag pattern | Example | Description |
|---|---|---|
latest | latest | Most recent build |
<ssh-version> | 10.3_p1-r0 | Exact Alpine openssh package version |
<ssh-version>-alpine | 10.3_p1-r0-alpine | Same, with explicit distro marker |
<ssh-version>-alpine<alpine-version> | 10.3_p1-r0-alpine3.24 | Fully pinned: OpenSSH version and Alpine release |
Versions are detected automatically at build time from the current alpine:latest image, so new OpenSSH releases are published as soon as Alpine ships them. Independent of version changes, all tags are rebuilt and re-pushed every Monday at 02:00 UTC with a fresh package index, so even a pinned tag receives Alpine security fixes. For the full list of available tags see Docker Hub.
The same image is published to three registries:
docker pull hermsi/alpine-sshd:latest
docker pull quay.io/hermsi1337/alpine-sshd:latest
docker pull ghcr.io/hermsi1337/docker-sshd:latest
| Variable | Default | Description |
|---|---|---|
ROOT_LOGIN_UNLOCKED | false | Unlock the root account for SSH login. When unlocked without ROOT_PASSWORD, a random password is generated (and not printed), so set one explicitly if you want password login. |
ROOT_PASSWORD | (unset) | Password for root. Setting it implies ROOT_LOGIN_UNLOCKED=true. |
ROOT_KEYPAIR_LOGIN_ENABLED | false | Key-based login for root (implies ROOT_LOGIN_UNLOCKED=true, disables password authentication). Requires a public key mounted at /root/.ssh/authorized_keys. |
SSH_USERS | (unset) | Comma-separated list of additional users as name:uid:gid (e.g. hermsi:1000:1000,dennis:1001:1001). Invalid entries are skipped; an existing GID reuses the existing group. |
USER_LOGIN_SHELL | /bin/bash | Login shell for additional users. If the configured shell is not executable, the fallback is used. |
USER_LOGIN_SHELL_FALLBACK | /bin/ash | Fallback shell if USER_LOGIN_SHELL cannot be used. |
DEBUG | (unset) | Set to true to trace the entrypoint (set -x) for troubleshooting. |
KEYPAIR_LOGIN | (unset) | Deprecated alias for ROOT_KEYPAIR_LOGIN_ENABLED, kept for backward compatibility. |
| Path / Port | Purpose |
|---|---|
22/tcp | sshd listens here — publish it to any host port you like. |
/etc/ssh (volume) | sshd configuration and host keys. On first start with an empty volume, the stock configuration is restored and host keys are generated. Mount a volume here to keep host keys stable across container re-creations (avoids "host key changed" warnings). |
/root/.ssh/authorized_keys | Public key(s) for root when ROOT_KEYPAIR_LOGIN_ENABLED=true. |
/conf.d/authorized_keys/<username> | Public key(s) for each user listed in SSH_USERS. |
Arguments appended after the image name are handed straight to sshd (it runs in the foreground with -D -e):
docker run --rm --publish 1337:22 --env ROOT_PASSWORD=secret \
hermsi/alpine-sshd -o LogLevel=VERBOSE
services:
sshd:
image: hermsi/alpine-sshd:latest
ports:
- "1337:22"
environment:
SSH_USERS: "hermsi:1000:1000"
volumes:
- ./keys/hermsi.pub:/conf.d/authorized_keys/hermsi:ro
- ssh_host_config:/etc/ssh
restart: unless-stopped
volumes:
ssh_host_config:
linux/amd64 and linux/arm64 — published as a single multi-arch manifest, so docker pull automatically selects the right variant for your platform.
The image is intentionally slim and vanilla. If you need extra tools such as git, build your own image on top:
FROM hermsi/alpine-sshd:latest
RUN apk add --no-cache \
git
Development, CI/CD internals (build pipeline, version detection, release invariants) and common maintenance tasks are documented in AGENTS.md. Pull requests trigger a full multi-arch build for validation, but nothing is pushed to the registries until the change lands on master.
Content type
Image
Digest
sha256:8420f9f95…
Size
7.8 MB
Last updated
about 5 hours ago
docker pull hermsi/alpine-sshd