Caddy & Docker Deployment¶
This guide covers deploying LightHouse using Docker with a Caddy reverse proxy.
Project Layout¶
📁 caddy/
├── Caddyfile
├── 📁 config/
└── 📁 data/
docker-compose.yaml
📁 lighthouse/
├── config.yaml
└── 📁 data/
└── 📁 keys/
Configuration Files¶
services:
caddy:
image: caddy:latest
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./caddy/Caddyfile:/etc/caddy/Caddyfile
- ./caddy/data:/data
- ./caddy/config:/config
lighthouse:
image: oidfed/lighthouse:latest
restart: unless-stopped
volumes:
- ./lighthouse/config.yaml:/config.yaml:ro
- ./lighthouse/data:/data
lighthouse.example.com {
reverse_proxy lighthouse:7672
}
For separate admin API access (recommended for production):
# Public federation endpoints
lighthouse.example.com {
reverse_proxy lighthouse:7672
}
# Admin API (restrict access via firewall or Caddy matchers)
admin.lighthouse.example.com {
reverse_proxy lighthouse:7673
}
server:
port: 7672
# Entity identifier - CHANGE THIS to your domain
entity_id: "https://lighthouse.example.com"
# Signing configuration
signing:
kms: filesystem
pk_backend: db
auto_generate_keys: true
filesystem:
key_dir: "/data/keys"
# Storage configuration
storage:
driver: sqlite
data_dir: "/data"
# Admin API
api:
admin:
enabled: true
users_enabled: true
# Federation endpoints
endpoints:
fetch:
path: "/fetch"
list:
path: "/list"
resolve:
path: "/resolve"
trust_mark:
path: "/trustmark"
trust_mark_status:
path: "/trustmark/status"
trust_mark_list:
path: "/trustmark/list"
historical_keys:
path: "/historical-keys"
For more configuration options, see Configuration.
Project Layout¶
📁 caddy/
├── Caddyfile
├── 📁 config/
└── 📁 data/
docker-compose.yaml
📁 lighthouse/
├── config.yaml
└── 📁 data/
└── 📁 keys/
📁 postgres/
└── 📁 data/
Configuration Files¶
services:
caddy:
image: caddy:latest
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./caddy/Caddyfile:/etc/caddy/Caddyfile
- ./caddy/data:/data
- ./caddy/config:/config
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: lighthouse
POSTGRES_PASSWORD: changeme # Change this!
POSTGRES_DB: lighthouse
volumes:
- ./postgres/data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U lighthouse"]
interval: 5s
timeout: 5s
retries: 5
lighthouse:
image: oidfed/lighthouse:latest
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
LH_STORAGE_DSN: "host=postgres user=lighthouse password=changeme dbname=lighthouse sslmode=disable"
volumes:
- ./lighthouse/config.yaml:/config.yaml:ro
- ./lighthouse/data:/data
lighthouse.example.com {
reverse_proxy lighthouse:7672
}
For separate admin API access (recommended for production):
# Public federation endpoints
lighthouse.example.com {
reverse_proxy lighthouse:7672
}
# Admin API (restrict access via firewall or Caddy matchers)
admin.lighthouse.example.com {
reverse_proxy lighthouse:7673
}
server:
port: 7672
# Entity identifier - CHANGE THIS to your domain
entity_id: "https://lighthouse.example.com"
# Signing configuration
signing:
kms: filesystem
pk_backend: db
auto_generate_keys: true
filesystem:
key_dir: "/data/keys"
# Storage configuration
storage:
driver: postgres
# DSN set via LH_STORAGE_DSN environment variable in docker-compose.yaml
# Admin API
api:
admin:
enabled: true
users_enabled: true
# Separate port for admin API (optional)
# port: 7673
# Federation endpoints
endpoints:
fetch:
path: "/fetch"
list:
path: "/list"
resolve:
path: "/resolve"
trust_mark:
path: "/trustmark"
trust_mark_status:
path: "/trustmark/status"
trust_mark_list:
path: "/trustmark/list"
historical_keys:
path: "/historical-keys"
# Statistics (optional, recommended for production)
stats:
enabled: true
retention:
detailed_days: 90
aggregated_days: 365
For more configuration options, see Configuration.
Environment Variables
Configuration can also be passed via environment variables:
environment:
LH_STORAGE_DSN: "host=postgres user=lighthouse password=${DB_PASSWORD} dbname=lighthouse"
LH_ENTITY_ID: "https://lighthouse.example.com"
See Configuration for details.
Initial Setup¶
After starting the containers with docker compose up -d, configure your
federation entity using the Admin API.
1. Create an Admin User¶
# Via API (basic auth disabled initially if no users exist)
curl -X POST https://lighthouse.example.com/api/v1/admin/users \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "your-secure-password"}'
Authentication Behavior
When no users exist, the Admin API does not require authentication. This allows you to create the first admin user. Once at least one user exists, all API requests require HTTP Basic Authentication.
2. Configure Federation Metadata¶
curl -X PUT https://lighthouse.example.com/api/v1/admin/entity-configuration/metadata/federation_entity \
-u admin:your-secure-password \
-H "Content-Type: application/json" \
-d '{
"organization_name": "Example Organization",
"homepage_uri": "https://example.com",
"contacts": ["admin@example.com"]
}'
3. Set Authority Hints (if not a Trust Anchor)¶
curl -X POST https://lighthouse.example.com/api/v1/admin/entity-configuration/authority-hints \
-u admin:your-secure-password \
-H "Content-Type: application/json" \
-d '{"entity_id": "https://trust-anchor.example.org"}'
4. Configure Trust Mark Issuance (optional)¶
curl -X POST https://lighthouse.example.com/api/v1/admin/trust-marks/issuance-spec \
-u admin:your-secure-password \
-H "Content-Type: application/json" \
-d '{
"trust_mark_type": "https://lighthouse.example.com/trustmarks/member",
"lifetime": "8760h"
}'
Verification¶
Check that LightHouse is running correctly:
# Fetch entity configuration
curl https://lighthouse.example.com/.well-known/openid-federation
# Check Admin API
curl https://lighthouse.example.com/api/v1/admin/entity-configuration \
-u admin:your-secure-password
Next Steps¶
- Configuration Reference - Full configuration options
- Admin API - Manage your federation via REST API
- CLI Tool - Command-line management with
lhcli - Migration Guide - Upgrading from older versions