Files
kms/docs/self-hosting/deployment-options/docker-compose.mdx
zeekay 0ebffbd529 fix: white-label KMS branding and fix broken identifiers
- Fix 381 files where branding script corrupted variable names
  (e.g. isHanzo KMSTemplate -> isKmsTemplate)
- Rebrand from "Hanzo KMS" to just "KMS" for white-label support
  (allows Lux KMS, Hanzo KMS, etc. via configuration)
- 856 files, purely string replacements, no logic changes
2026-02-13 10:25:11 -08:00

665 lines
19 KiB
Plaintext

---
title: "Docker Compose"
description: "Deploy KMS using Docker Compose for development, testing, or small-scale production environments."
---
Learn how to deploy **KMS** using Docker Compose. This method runs KMS and its dependencies (PostgreSQL and Redis) as containers on a single Docker host. It's ideal for trying out KMS, development environments, or small-scale deployments that don't require high availability.
## Prerequisites
- A Linux server (Ubuntu 20.04+ recommended) or macOS/Windows with Docker Desktop
- [Docker Engine](https://docs.docker.com/engine/install/) (version 20.10+)
- [Docker Compose](https://docs.docker.com/compose/install/) (version 2.0+ recommended)
<Warning>
This Docker Compose configuration is not designed for high-availability production scenarios.
It includes just the essential components needed to set up an KMS proof of concept (POC).
To run KMS in a highly available manner, see the [Docker Swarm guide](/self-hosting/deployment-options/docker-swarm) or [Kubernetes guide](/self-hosting/deployment-options/kubernetes-helm).
</Warning>
## System Requirements
The following are minimum requirements for running KMS with Docker Compose:
| Component | Minimum | Recommended |
|-----------|---------|-------------|
| CPU | 2 cores | 4 cores |
| RAM | 4 GB | 8 GB |
| Disk | 20 GB | 50 GB+ (SSD recommended) |
These requirements include resources for KMS, PostgreSQL, and Redis containers. For larger deployments with many secrets or users, increase resources accordingly.
## Deployment Steps
<Tabs>
<Tab title="Docker Compose">
<Steps>
<Step title="Verify prerequisites">
Confirm that Docker and Docker Compose are installed on your machine:
```bash
docker --version
docker compose version
```
You should see version information for both commands. If not, install Docker and Docker Compose following the official documentation.
</Step>
<Step title="Download the Docker Compose file">
You can obtain the KMS docker compose file by using a command-line downloader such as `wget` or `curl`. If your system doesn't have either of these, you can use an equivalent command that works with your machine.
<Tabs>
<Tab title="curl">
```bash
curl -o docker-compose.prod.yml https://raw.githubusercontent.com/KMS/kms/main/docker-compose.prod.yml
```
</Tab>
<Tab title="wget">
```bash
wget -O docker-compose.prod.yml https://raw.githubusercontent.com/KMS/kms/main/docker-compose.prod.yml
```
</Tab>
</Tabs>
</Step>
<Step title="Configure environment variables">
KMS requires a set of credentials used for connecting to dependent services such as Postgres, Redis, etc. The default credentials can be downloaded using one of the commands listed below.
<Tabs>
<Tab title="curl">
```bash
curl -o .env https://raw.githubusercontent.com/KMS/kms/main/.env.example
```
</Tab>
<Tab title="wget">
```bash
wget -O .env https://raw.githubusercontent.com/KMS/kms/main/.env.example
```
</Tab>
</Tabs>
Once downloaded, the credentials file will be saved to your working directory as `.env` file. View all available configurations [here](/self-hosting/configuration/envars).
<Warning>
The `.env` file contains secrets that control the security of your deployment. Do not commit it to version control, and protect access to it:
```bash
chmod 600 .env
```
</Warning>
</Step>
<Step title="Start KMS">
Start all services in detached mode:
```bash
docker compose -f docker-compose.prod.yml up -d
```
This command starts three containers:
- **backend**: The main KMS application (exposed on host port 80, internal port 8080)
- **db**: PostgreSQL database for storing encrypted secrets
- **redis**: Redis for caching and job queues
</Step>
<Step title="Verify the deployment">
Check that all containers are running:
```bash
docker compose -f docker-compose.prod.yml ps
```
You should see all three services with a status of `Up`. Next, verify KMS is responding:
```bash
curl -s http://localhost:80/api/status | head -c 100
```
If successful, open your browser and navigate to `http://localhost:80` (or your configured domain) to create your admin account.
<Tip>
The first user to sign up becomes the instance administrator. Make sure to complete this step before exposing KMS to others.
</Tip>
</Step>
</Steps>
</Tab>
<Tab title="Podman Compose">
Podman Compose is an alternative way to run KMS using Podman as a replacement for Docker. Podman is backwards compatible with Docker Compose files.
<Steps>
<Step title="Verify prerequisites">
Confirm that Podman and Podman Compose are installed:
```bash
podman version
podman-compose version
```
If not installed, follow the [Podman installation guide](https://podman-desktop.io/docs/installation) and [Podman Compose guide](https://podman-desktop.io/docs/compose).
</Step>
<Step title="Download the Docker Compose file">
You can obtain the KMS docker compose file by using a command-line downloader such as `wget` or `curl`. If your system doesn't have either of these, you can use an equivalent command that works with your machine.
<Tabs>
<Tab title="curl">
```bash
curl -o docker-compose.prod.yml https://raw.githubusercontent.com/KMS/kms/main/docker-compose.prod.yml
```
</Tab>
<Tab title="wget">
```bash
wget -O docker-compose.prod.yml https://raw.githubusercontent.com/KMS/kms/main/docker-compose.prod.yml
```
</Tab>
</Tabs>
</Step>
<Step title="Configure environment variables">
KMS requires a set of credentials used for connecting to dependent services such as Postgres, Redis, etc. The default credentials can be downloaded using one of the commands listed below.
<Tabs>
<Tab title="curl">
```bash
curl -o .env https://raw.githubusercontent.com/KMS/kms/main/.env.example
```
</Tab>
<Tab title="wget">
```bash
wget -O .env https://raw.githubusercontent.com/KMS/kms/main/.env.example
```
</Tab>
</Tabs>
Once downloaded, the credentials file will be saved to your working directory as `.env` file. View all available configurations [here](/self-hosting/configuration/envars).
</Step>
<Step title="Set up Podman">
Initialize and start the Podman machine:
```bash
podman machine init --now
podman machine set --rootful
podman machine start
```
<Note>
If using a rootless Podman install, you can skip `podman machine set --rootful`.
</Note>
</Step>
<Step title="Start KMS">
```bash
podman-compose -f docker-compose.prod.yml up -d
```
Access the UI at `http://localhost:80`.
</Step>
</Steps>
</Tab>
</Tabs>
---
## Managing Your Deployment
### Stopping and Restarting Services
To stop all KMS services:
```bash
docker compose -f docker-compose.prod.yml down
```
To restart services:
```bash
docker compose -f docker-compose.prod.yml up -d
```
To restart a specific service (e.g., after configuration changes):
```bash
docker compose -f docker-compose.prod.yml restart backend
```
### Data Persistence and Volumes
The Docker Compose configuration uses named volumes to persist data:
| Volume | Purpose | Data Stored |
|--------|---------|-------------|
| `pg_data` | PostgreSQL data | All encrypted secrets, users, projects, and configuration |
| `redis_data` | Redis data | Cache and job queue data (can be regenerated) |
<Warning>
**Critical**: The `pg_data` volume contains all your encrypted secrets. Never delete this volume unless you intend to lose all data. Always back up before any maintenance operations.
</Warning>
To view volumes:
```bash
docker volume ls | grep -E "pg_data|redis_data"
```
To back up the PostgreSQL volume:
```bash
docker compose -f docker-compose.prod.yml exec db pg_dump -U kms kms > backup_$(date +%Y%m%d_%H%M%S).sql
```
### Viewing Logs
To view logs from all services:
```bash
docker compose -f docker-compose.prod.yml logs -f
```
To view logs from a specific service:
```bash
docker compose -f docker-compose.prod.yml logs -f backend
docker compose -f docker-compose.prod.yml logs -f db
docker compose -f docker-compose.prod.yml logs -f redis
```
To view the last 100 lines of logs:
```bash
docker compose -f docker-compose.prod.yml logs --tail=100 backend
```
Logs are also available directly from Docker:
```bash
docker logs <container_name> --since 1h
```
---
## Additional Configuration
<AccordionGroup>
<Accordion title="Firewall Configuration">
Configure your firewall to allow traffic to KMS while securing other services:
**Required ports:**
| Port | Service | Access |
|------|---------|--------|
| 80 | HTTP (KMS) | Public (or internal network) |
| 443 | HTTPS (if using TLS) | Public (or internal network) |
**Internal ports (should NOT be exposed publicly):**
| Port | Service | Notes |
|------|---------|-------|
| 5432 | PostgreSQL | Container-to-container only |
| 6379 | Redis | Container-to-container only |
**UFW (Ubuntu/Debian):**
```bash
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Ensure database ports are not exposed
sudo ufw deny 5432/tcp
sudo ufw deny 6379/tcp
sudo ufw enable
```
**firewalld (RHEL/CentOS):**
```bash
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
```
<Warning>
Never expose PostgreSQL (5432) or Redis (6379) ports to the public internet. These should only be accessible within the Docker network.
</Warning>
</Accordion>
<Accordion title="SMTP/Email Configuration">
KMS uses email for user invitations, password resets, and notifications. Configure SMTP by adding these variables to your `.env` file:
```env
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=your-smtp-username
SMTP_PASSWORD=your-smtp-password
[email protected]
SMTP_FROM_NAME=KMS
```
**Common SMTP providers:**
<Tabs>
<Tab title="AWS SES">
```env
SMTP_HOST=email-smtp.us-east-1.amazonaws.com
SMTP_PORT=587
SMTP_USERNAME=your-ses-smtp-username
SMTP_PASSWORD=your-ses-smtp-password
[email protected]
SMTP_FROM_NAME=KMS
```
</Tab>
<Tab title="SendGrid">
```env
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USERNAME=apikey
SMTP_PASSWORD=your-sendgrid-api-key
[email protected]
SMTP_FROM_NAME=KMS
```
</Tab>
<Tab title="Gmail">
```env
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=your-app-password
[email protected]
SMTP_FROM_NAME=KMS
```
<Note>
For Gmail, you must use an [App Password](https://support.google.com/accounts/answer/185833) instead of your regular password.
</Note>
</Tab>
</Tabs>
After updating the `.env` file, restart KMS:
```bash
docker compose -f docker-compose.prod.yml restart backend
```
</Accordion>
<Accordion title="Enable HTTPS with NGINX">
We recommend securing your KMS deployment with HTTPS using a reverse proxy like NGINX.
**1. Obtain SSL certificates** (e.g., via Let's Encrypt):
```bash
sudo apt install certbot
sudo certbot certonly --standalone -d secrets.example.com
```
**2. Create NGINX configuration directory:**
```bash
mkdir -p ./nginx/certs
sudo cp /etc/letsencrypt/live/secrets.example.com/fullchain.pem ./nginx/certs/
sudo cp /etc/letsencrypt/live/secrets.example.com/privkey.pem ./nginx/certs/
```
**3. Add NGINX service to `docker-compose.prod.yml`:**
```yaml
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/certs:/etc/nginx/certs:ro
depends_on:
- backend
```
**4. Create `./nginx/nginx.conf`:**
```nginx
events {}
http {
server {
listen 80;
server_name secrets.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name secrets.example.com;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
location / {
proxy_pass http://backend:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
```
**5. Update `.env`:**
```env
SITE_URL=https://secrets.example.com
```
**6. Restart services:**
```bash
docker compose -f docker-compose.prod.yml down
docker compose -f docker-compose.prod.yml up -d
```
</Accordion>
<Accordion title="Externalize Database and Redis">
For higher availability, use external managed services like AWS RDS and ElastiCache.
Update your `.env`:
```env
DB_CONNECTION_URI=postgresql://<user>:<password>@<host>:5432/<dbname>
REDIS_URL=redis://:<password>@<host>:6379
```
Remove or comment out `db` and `redis` services in `docker-compose.prod.yml`.
Ensure firewall/VPC access to these services is properly configured.
</Accordion>
<Accordion title="Backup Strategy">
Regular backups are critical for protecting your data.
**Database backup:**
```bash
docker compose -f docker-compose.prod.yml exec db pg_dump -U kms kms > backup_$(date +%Y%m%d).sql
```
**Automated daily backups (cron):**
```bash
# Add to crontab (crontab -e)
0 2 * * * cd /path/to/kms && docker compose -f docker-compose.prod.yml exec -T db pg_dump -U kms kms > /backups/kms_$(date +\%Y\%m\%d).sql
```
**Restore from backup:**
```bash
docker compose -f docker-compose.prod.yml exec -T db psql -U kms kms < backup.sql
```
<Warning>
Also back up your `ENCRYPTION_KEY` from the `.env` file. Without this key, you cannot decrypt secrets even if you restore the database.
</Warning>
</Accordion>
<Accordion title="Enable Prometheus Monitoring">
KMS exposes Prometheus metrics when enabled.
**1. Add to `.env`:**
```env
OTEL_TELEMETRY_COLLECTION_ENABLED=true
OTEL_EXPORT_TYPE=prometheus
```
**2. Expose port `9464` in `docker-compose.prod.yml`** by adding to the backend service:
```yaml
ports:
- "80:8080"
- "9464:9464"
```
**3. Configure Prometheus** to scrape `localhost:9464` or the container DNS.
See the [Monitoring Guide](/self-hosting/guides/monitoring-telemetry) for full setup.
</Accordion>
<Accordion title="Upgrade Instructions">
Keeping KMS up-to-date ensures you receive the latest features and security patches.
**1. Back up your database:**
```bash
docker compose -f docker-compose.prod.yml exec db pg_dump -U kms kms > backup_before_upgrade.sql
```
**2. Update the image tag** in `docker-compose.prod.yml` to the desired version.
**3. Pull and restart:**
```bash
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
```
**4. Verify the upgrade:**
```bash
docker compose -f docker-compose.prod.yml logs -f backend
```
Watch for successful database migration messages. See the [Upgrade Guide](/self-hosting/guides/upgrading-kms) for more details.
</Accordion>
</AccordionGroup>
---
## Troubleshooting
<AccordionGroup>
<Accordion title="Containers fail to start">
**Check container status:**
```bash
docker compose -f docker-compose.prod.yml ps -a
```
**View startup logs:**
```bash
docker compose -f docker-compose.prod.yml logs
```
**Common causes:**
- Port 80 already in use: Stop other services or change the port mapping
- Insufficient memory: Ensure at least 4GB RAM is available
- Invalid `.env` file: Check for syntax errors or missing required variables
</Accordion>
<Accordion title="Database connection errors">
**Check if PostgreSQL is running:**
```bash
docker compose -f docker-compose.prod.yml exec db pg_isready
```
**Verify database credentials:**
```bash
docker compose -f docker-compose.prod.yml exec db psql -U kms -c "SELECT 1"
```
**Check KMS logs for connection errors:**
```bash
docker compose -f docker-compose.prod.yml logs backend | grep -i "database\|postgres\|connection"
```
If the database was corrupted, you may need to restore from backup or recreate the volume:
```bash
docker compose -f docker-compose.prod.yml down -v # WARNING: Deletes all data
docker compose -f docker-compose.prod.yml up -d
```
</Accordion>
<Accordion title="Cannot access KMS in browser">
**Verify the service is running:**
```bash
curl -v http://localhost:80/api/status
```
**Check if the port is listening:**
```bash
sudo netstat -tlnp | grep :80
# or
sudo ss -tlnp | grep :80
```
**Check firewall rules:**
```bash
sudo ufw status
# or
sudo firewall-cmd --list-all
```
**Verify SITE_URL is correct** in your `.env` file and matches how you're accessing KMS.
</Accordion>
<Accordion title="Email/SMTP not working">
**Test SMTP connectivity:**
```bash
docker compose -f docker-compose.prod.yml exec backend nc -zv smtp.example.com 587
```
**Check KMS logs for email errors:**
```bash
docker compose -f docker-compose.prod.yml logs backend | grep -i "smtp\|email\|mail"
```
**Common issues:**
- Incorrect SMTP credentials
- Firewall blocking outbound port 587 or 465
- SMTP provider requires specific authentication (e.g., Gmail App Passwords)
</Accordion>
<Accordion title="Performance issues">
**Check resource usage:**
```bash
docker stats
```
**Check for slow database queries:**
```bash
docker compose -f docker-compose.prod.yml exec db psql -U kms -c "SELECT * FROM pg_stat_activity WHERE state = 'active'"
```
**Solutions:**
- Increase container memory limits in `docker-compose.prod.yml`
- Add more CPU cores to the host
- Consider migrating to a managed database for better performance
</Accordion>
<Accordion title="Reset admin password">
If you have lost access to your admin account, you can reset it via the database:
```bash
# Connect to the database
docker compose -f docker-compose.prod.yml exec db psql -U kms
# Find the user
SELECT id, email FROM users WHERE email = '[email protected]';
# The password must be reset through the application password reset flow
# or by deleting and recreating the user
```
For security reasons, passwords are hashed and cannot be directly reset in the database. Use the "Forgot Password" flow if SMTP is configured, or contact KMS support for assistance.
</Accordion>
</AccordionGroup>
---
Your KMS instance should now be running on port `80` (or `443` if using TLS). Visit `http://localhost:80` or `https://<your-domain>` to access your instance.
![self-hosted sign up](/images/self-hosting/applicable-to-all/selfhost-signup.png)