Skip to content

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