- Rename environment variables to match the owner role - Add backward compatibility: legacy ADMIN vars still accepted with deprecation warning - Update .env.example, docs and quickstart accordingly
216 lines
5.6 KiB
Markdown
216 lines
5.6 KiB
Markdown
# Installation & Deployment
|
|
|
|
This guide covers production deployment of Keywarden using Docker.
|
|
|
|
## Docker Deployment
|
|
|
|
Keywarden is designed as a single-container application with an embedded SQLite database. No external database server is required.
|
|
|
|
### Docker Image
|
|
|
|
Build from source or use the pre-built image:
|
|
|
|
```bash
|
|
# Build from source
|
|
docker compose build
|
|
|
|
# Or build manually
|
|
docker build -t keywarden .
|
|
```
|
|
|
|
### Multi-Stage Build
|
|
|
|
The Dockerfile uses a two-stage build:
|
|
|
|
1. **Builder stage** (`golang:1.26-alpine`): Compiles the Go binary with CGO (required for SQLite)
|
|
2. **Runtime stage** (`alpine:3.21`): Minimal image with only the compiled binary and runtime dependencies (`ca-certificates`, `sqlite-libs`, `tzdata`, `curl`)
|
|
|
|
The runtime container runs as a non-root user (`keywarden`).
|
|
|
|
### Docker Compose
|
|
|
|
A complete `docker-compose.yml`:
|
|
|
|
```yaml
|
|
services:
|
|
keywarden:
|
|
image: git.techniverse.net/scriptos/keywarden:latest
|
|
container_name: keywarden
|
|
restart: unless-stopped
|
|
ports:
|
|
- "${KEYWARDEN_PORT:-8080}:${KEYWARDEN_PORT:-8080}"
|
|
volumes:
|
|
- ./data:/data
|
|
env_file:
|
|
- .env
|
|
networks:
|
|
keywarden_net:
|
|
ipv4_address: 172.23.64.10
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:${KEYWARDEN_PORT:-8080}/api/health"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
start_period: 10s
|
|
retries: 3
|
|
|
|
networks:
|
|
keywarden_net:
|
|
name: keywarden.dockernetwork.local
|
|
driver: bridge
|
|
ipam:
|
|
config:
|
|
- subnet: 172.23.64.0/24
|
|
gateway: 172.23.64.1
|
|
ip_range: 172.23.64.128/25
|
|
```
|
|
|
|
### Environment File (.env)
|
|
|
|
Create a `.env` file alongside `docker-compose.yml`:
|
|
|
|
```env
|
|
# Security (REQUIRED - change these!)
|
|
KEYWARDEN_SESSION_KEY=generate-a-random-string-of-at-least-32-chars
|
|
KEYWARDEN_ENCRYPTION_KEY=generate-another-random-string-32-chars
|
|
|
|
# Application
|
|
KEYWARDEN_PORT=8080
|
|
KEYWARDEN_LOG_LEVEL=INFO
|
|
|
|
# Initial owner (only used on first startup)
|
|
KEYWARDEN_OWNER_USER=admin
|
|
KEYWARDEN_OWNER_EMAIL=admin@example.com
|
|
|
|
# HTTPS / Reverse Proxy
|
|
KEYWARDEN_BASE_URL=https://keywarden.example.com
|
|
KEYWARDEN_TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
|
KEYWARDEN_SECURE_COOKIES=true
|
|
|
|
# Rate Limiting
|
|
KEYWARDEN_RATE_LIMIT_LOGIN=10
|
|
KEYWARDEN_MAX_REQUEST_SIZE=10485760
|
|
|
|
# Email (optional)
|
|
KEYWARDEN_SMTP_HOST=smtp.example.com
|
|
KEYWARDEN_SMTP_PORT=587
|
|
KEYWARDEN_SMTP_USER=keywarden@example.com
|
|
KEYWARDEN_SMTP_PASSWORD=smtp-password
|
|
KEYWARDEN_SMTP_FROM=keywarden@example.com
|
|
KEYWARDEN_SMTP_TLS=true
|
|
```
|
|
|
|
See [Environment Variables](environment-variables.md) for a complete reference.
|
|
|
|
## Data Persistence
|
|
|
|
All persistent data is stored in the `/data` volume:
|
|
|
|
| Path | Content |
|
|
|---|---|
|
|
| `/data/keywarden.db` | SQLite database (users, keys, servers, settings, audit log) |
|
|
| `/data/keys/` | Reserved for future use |
|
|
| `/data/master/` | Reserved for future use |
|
|
| `/data/avatars/` | User profile pictures |
|
|
|
|
> **Important:** The SQLite database contains encrypted private keys. Back up the `/data` volume regularly. See [Backup & Restore](backup-restore.md).
|
|
|
|
## Reverse Proxy Setup
|
|
|
|
For production use, place Keywarden behind a reverse proxy with TLS termination.
|
|
|
|
### Nginx
|
|
|
|
```nginx
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name keywarden.example.com;
|
|
|
|
ssl_certificate /etc/ssl/certs/keywarden.crt;
|
|
ssl_certificate_key /etc/ssl/private/keywarden.key;
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1: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;
|
|
|
|
# Recommended limits
|
|
client_max_body_size 10m;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Caddy
|
|
|
|
```caddyfile
|
|
keywarden.example.com {
|
|
reverse_proxy localhost:8080
|
|
}
|
|
```
|
|
|
|
### Traefik
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.keywarden.rule=Host(`keywarden.example.com`)"
|
|
- "traefik.http.routers.keywarden.tls=true"
|
|
- "traefik.http.services.keywarden.loadbalancer.server.port=8080"
|
|
```
|
|
|
|
### Important Notes for Reverse Proxy
|
|
|
|
1. **Set `KEYWARDEN_BASE_URL`**: Required for correct email links and cookie configuration
|
|
2. **Set `KEYWARDEN_TRUSTED_PROXIES`**: Configure the CIDR range of your reverse proxy so Keywarden can extract the real client IP from `X-Forwarded-For` headers
|
|
3. **Set `KEYWARDEN_SECURE_COOKIES=true`**: Enable secure cookie flag when using HTTPS (auto-derived from `KEYWARDEN_BASE_URL` if the URL starts with `https://`)
|
|
|
|
## Health Check
|
|
|
|
Keywarden provides a health check endpoint at `/api/health` that returns JSON:
|
|
|
|
```json
|
|
{
|
|
"status": "healthy",
|
|
"uptime": "2d 5h 30m",
|
|
"uptime_seconds": 194400,
|
|
"checks": {
|
|
"database": {
|
|
"status": "ok"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
The Docker HEALTHCHECK is configured automatically in the Dockerfile.
|
|
|
|
## Updating
|
|
|
|
To update Keywarden:
|
|
|
|
```bash
|
|
# Pull latest image and restart
|
|
docker compose pull
|
|
docker compose down
|
|
docker compose up -d
|
|
```
|
|
|
|
Database migrations run automatically on startup. No manual migration steps are required.
|
|
|
|
## System Master Key
|
|
|
|
On first startup, Keywarden generates an **Ed25519 system master key**. This key is used for all SSH connections to managed servers (deploying keys, creating users, etc.).
|
|
|
|
The public key is displayed in:
|
|
- The startup log output
|
|
- The Admin Settings page (owner only)
|
|
|
|
You must deploy this public key to every server you want to manage:
|
|
|
|
```bash
|
|
# On each target server
|
|
echo "<master-public-key>" >> /root/.ssh/authorized_keys
|
|
```
|
|
|
|
The master key can be regenerated from the Admin Settings page if needed (owner only). After regeneration, redeploy the new public key to all servers.
|