A production-ready OpenSSH server Docker image based on Debian Bookworm, designed for secure remote access, development environments, and CI/CD pipelines.
- Secure by Default: Password authentication disabled, public key authentication preferred
- Flexible User Management: Customizable UID/GID for seamless host volume permissions
- Persistent Configuration: All configs and host keys stored in
/appvolume - Development Tools: Includes git, golang, curl, wget, and common utilities
- Timestamped Logging: Built-in log management with timestamps
- Easy SSH Key Management: Multiple ways to inject public keys
- Optional Sudo Access: Configurable sudo permissions
- Small Footprint: Based on Debian Bookworm Slim
# Pull the image
docker pull ghcr.io/optimode/openssh:bookworm
# Create config directory
mkdir -p ./config/.ssh
# Add your SSH public key
cat ~/.ssh/id_rsa.pub > ./config/.ssh/authorized_keys
# Run the container
docker run -d \
--name openssh \
-p 2222:2222 \
-v ./config:/app \
-e USER_NAME=devuser \
-e PUID=1000 \
-e PGID=1000 \
ghcr.io/optimode/openssh:bookworm
# Connect
ssh -p 2222 devuser@localhostCreate a docker-compose.yml file:
services:
openssh:
image: ghcr.io/optimode/openssh:bookworm
container_name: openssh
restart: unless-stopped
ports:
- "2222:2222"
volumes:
- ./config:/app
- ./workspace:/workspace
environment:
- TZ=Europe/Budapest
- PUID=1000
- PGID=1000
- USER_NAME=devuser
- SUDO_ACCESS=false
- PASSWORD_ACCESS=falseThen run:
# Add your SSH public key
mkdir -p ./config/.ssh
cat ~/.ssh/id_rsa.pub > ./config/.ssh/authorized_keys
# Start the container
docker-compose up -d
# Connect
ssh -p 2222 devuser@localhost| Variable | Default | Description |
|---|---|---|
USER_NAME |
app |
Username for SSH access |
PUID |
911 |
User ID (useful for matching host user permissions) |
PGID |
911 |
Group ID (useful for matching host group permissions) |
USER_HOME |
/app |
User home directory |
USER_PASSWORD |
<random> |
User password (auto-generated if not set) |
USER_PASSWORD_FILE |
- | Path to file containing password (Docker secrets) |
| Variable | Default | Description |
|---|---|---|
LISTEN_PORT |
2222 |
SSH server listening port |
PASSWORD_ACCESS |
false |
Enable/disable password authentication |
PUBLIC_KEY |
- | SSH public key (single key as string) |
PUBLIC_KEY_FILE |
- | Path to file containing a public key |
PUBLIC_KEY_DIR |
- | Path to directory containing multiple key files |
| Variable | Default | Description |
|---|---|---|
SUDO_ACCESS |
false |
Grant sudo privileges to the user |
UMASK |
022 |
Default umask for file creation |
| Variable | Default | Description |
|---|---|---|
TZ |
UTC |
Timezone (e.g., Europe/Budapest, America/New_York) |
| Path | Purpose |
|---|---|
/app |
Required - Persistent storage for SSH config, host keys, and user data |
/workspace |
Optional - Additional workspace directory |
| Port | Protocol | Description |
|---|---|---|
2222 |
TCP | SSH server port (configurable via LISTEN_PORT) |
There are multiple ways to provide SSH public keys for authentication:
mkdir -p ./config/.ssh
cat ~/.ssh/id_rsa.pub > ./config/.ssh/authorized_keys
chmod 600 ./config/.ssh/authorized_keysenvironment:
- PUBLIC_KEY=ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAB...environment:
- PUBLIC_KEY_FILE=/secrets/ssh-key.pub
volumes:
- ./my-key.pub:/secrets/ssh-key.pub:roenvironment:
- PUBLIC_KEY_DIR=/secrets/keys
volumes:
- ./keys:/secrets/keys:roMultiple methods can be used simultaneously - all keys will be added to authorized_keys.
services:
devssh:
image: optimode/openssh:bookworm
container_name: devssh
ports:
- "2222:2222"
volumes:
- ./config:/app
- ./projects:/workspace
- /var/run/docker.sock:/var/run/docker.sock # Docker-in-Docker
environment:
- USER_NAME=developer
- PUID=1000
- PGID=1000
- SUDO_ACCESS=true
- PASSWORD_ACCESS=false
- TZ=America/New_Yorkservices:
openssh:
image: optimode/openssh:bookworm
container_name: openssh-pass
ports:
- "2222:2222"
volumes:
- ./config:/app
environment:
- USER_NAME=testuser
- USER_PASSWORD=SecurePassword123
- PASSWORD_ACCESS=true
- SUDO_ACCESS=falseservices:
openssh:
image: optimode/openssh:bookworm
container_name: openssh-secure
ports:
- "2222:2222"
volumes:
- ./config:/app
secrets:
- ssh_password
environment:
- USER_NAME=admin
- USER_PASSWORD_FILE=/run/secrets/ssh_password
- PASSWORD_ACCESS=true
secrets:
ssh_password:
file: ./secrets/password.txtservices:
openssh:
image: optimode/openssh:bookworm
container_name: openssh-custom
ports:
- "2200:2200"
volumes:
- ./config:/app
environment:
- LISTEN_PORT=2200
- USER_NAME=sshuser
- TZ=Asia/Tokyo
- PUID=1001
- PGID=1001# Clone the repository
git clone https://github.com/optimode/docker-openssh.git
cd docker-openssh
# Build the image
./build
# Or use docker build directly
docker build -t optimode/openssh:bookworm ./app/
├── .ssh/
│ └── authorized_keys # SSH public keys
├── sshd/
│ └── sshd_config # OpenSSH server configuration
├── ssh_host_keys/ # Persistent host keys
└── logs/
└── openssh/
└── sshd.log # SSH server logs with timestamps
Logs are stored in /app/logs/openssh/sshd.log with timestamps in format [YYYY-MM-DD HH:MM:SS TZ].
View logs:
# Real-time logs
docker logs -f openssh
# Persistent log file
docker exec openssh tail -f /app/logs/openssh/sshd.logProblem: Cannot connect to SSH server
Solutions:
- Check if container is running:
docker ps - Verify port mapping:
docker port openssh - Check firewall rules on host
- Verify SSH service is running:
docker exec openssh ps aux | grep sshd
Problem: Authentication fails with public key
Solutions:
- Verify key is in
authorized_keys:docker exec openssh cat /app/.ssh/authorized_keys - Check key permissions: Should be 600 for
authorized_keys, 700 for.ssh - Ensure the correct private key is being used:
ssh -i ~/.ssh/id_rsa -p 2222 user@localhost - Check logs:
docker logs openssh
Problem: Files in mounted volumes have wrong ownership
Solutions:
- Set
PUIDandPGIDto match your host user:id -u # Get your UID id -g # Get your GID
- Update docker-compose.yml with correct values
- Restart container:
docker-compose down && docker-compose up -d
Problem: User cannot write to /workspace directory
Solutions:
- Ensure proper ownership of host directory:
sudo chown -R 1000:1000 ./workspace # Use your PUID:PGID - Or set permissions to allow write access:
chmod -R 755 ./workspace
Problem: Sudo commands fail despite SUDO_ACCESS=true
Solutions:
- Verify environment variable is set:
docker exec openssh env | grep SUDO - Check sudoers file:
docker exec openssh cat /etc/sudoers | grep app - If password required, ensure
USER_PASSWORDis set - Restart container after changing
SUDO_ACCESS
- Disable Password Authentication: Always use key-based authentication in production
- Use Strong Keys: Generate keys with
ssh-keygen -t ed25519orssh-keygen -t rsa -b 4096 - Limit Sudo Access: Only enable
SUDO_ACCESS=truewhen necessary - Firewall Rules: Restrict SSH port access to known IPs
- Regular Updates: Keep the image updated for security patches
- Monitor Logs: Regularly check
/app/logs/openssh/sshd.logfor suspicious activity - Use Docker Secrets: For sensitive data like passwords, use Docker secrets instead of environment variables
- Base Image: debian:bookworm-slim
- OpenSSH Version: 8.4+
- Exposed Port: 2222 (default)
MIT License - See LICENSE file for details
Contributions are welcome! Please feel free to submit a Pull Request.
Optimode (Laszlo Malina)