Skip to content

Docker Installation

Deploy SSH-KLM using Docker Compose for development, testing, or small production environments.

  • Development and testing environments
  • Proof of concept deployments
  • Small-scale production (< 100 hosts)
  • Quick evaluation of SSH-KLM features
RequirementVersionNotes
Docker20.10+docker --version
Docker Compose2.0+docker compose version
Memory4 GB+Available RAM
Disk20 GB+For images and data
Terminal window
# Create project directory
mkdir ssh-klm && cd ssh-klm
# Download docker-compose.yml
curl -o docker-compose.yml \
https://raw.githubusercontent.com/qcecuring/ssh-klm/main/docker-compose.yml
# Download environment template
curl -o .env.example \
https://raw.githubusercontent.com/qcecuring/ssh-klm/main/.env.example
Terminal window
# Copy environment template
cp .env.example .env
# Edit configuration
nano .env

Key configuration options:

Terminal window
# .env file
POSTGRES_PASSWORD=your-secure-password
REDIS_PASSWORD=your-redis-password
JWT_SECRET=your-jwt-secret-min-32-chars
ADMIN_EMAIL=admin@yourcompany.com
ADMIN_PASSWORD=your-admin-password
Terminal window
# Pull latest images
docker compose pull
# Start all services
docker compose up -d
# Verify all services are healthy
docker compose ps
Terminal window
# Check API health
curl http://localhost:8081/health
# Expected response:
# {"status":"healthy","version":"2.1.0"}
  1. Open http://localhost:8081 in your browser
  2. Login with credentials from .env file
  3. Complete initial setup wizard
docker-compose.yml
version: '3.8'
services:
api:
image: qcecuring/ssh-klm-api:latest
ports:
- "8081:8081"
environment:
- DATABASE_URL=postgres://postgres:${POSTGRES_PASSWORD}@db:5432/sshklm
- REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379
- JWT_SECRET=${JWT_SECRET}
depends_on:
- db
- redis
restart: unless-stopped
worker:
image: qcecuring/ssh-klm-worker:latest
environment:
- DATABASE_URL=postgres://postgres:${POSTGRES_PASSWORD}@db:5432/sshklm
- REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379
depends_on:
- db
- redis
restart: unless-stopped
db:
image: postgres:14-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=sshklm
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
restart: unless-stopped
volumes:
postgres_data:
redis_data:
docker-compose.prod.yml
version: '3.8'
services:
api:
image: qcecuring/ssh-klm-api:2.1.0 # Pin version
deploy:
resources:
limits:
cpus: '2'
memory: 4G
logging:
driver: json-file
options:
max-size: "100m"
max-file: "5"
Terminal window
# .env for external PostgreSQL
DATABASE_URL=postgres://user:pass@external-db.example.com:5432/sshklm

Issue: API container exits immediately

Solution:

Terminal window
# Check logs
docker compose logs api
# Common fix: wait for database
docker compose down
docker compose up -d db redis
sleep 10
docker compose up -d

Issue: FATAL: password authentication failed

Solution:

Terminal window
# Reset database
docker compose down -v # Warning: deletes data
docker compose up -d

Issue: Services killed by OOM

Solution:

Terminal window
# Increase Docker memory limit
# Docker Desktop: Settings → Resources → Memory
# Linux: Adjust vm.overcommit_memory
Terminal window
# Backup PostgreSQL
docker compose exec db pg_dump -U postgres sshklm > backup.sql
# Backup volumes
docker run --rm -v ssh-klm_postgres_data:/data -v $(pwd):/backup \
alpine tar czf /backup/postgres-data.tar.gz /data
Terminal window
# Pull new images
docker compose pull
# Restart with new version
docker compose up -d
# Verify upgrade
curl http://localhost:8081/health