143 lines
3.7 KiB
Text
143 lines
3.7 KiB
Text
# Caddyfile for Eliza Kragh v. MAD Court Docket Website
|
|
# This file should be placed in the Caddy configuration directory on the remote server
|
|
|
|
# Replace with your actual domain
|
|
docket.example.com {
|
|
# Enable automatic HTTPS
|
|
tls {
|
|
# Use Let's Encrypt for SSL certificates
|
|
# email admin@example.com
|
|
}
|
|
|
|
# Security headers
|
|
header {
|
|
# Security headers for legal document website
|
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
|
X-Content-Type-Options "nosniff"
|
|
X-Frame-Options "SAMEORIGIN"
|
|
X-XSS-Protection "1; mode=block"
|
|
Referrer-Policy "strict-origin-when-cross-origin"
|
|
|
|
# Remove server information
|
|
-Server
|
|
-X-Powered-By
|
|
}
|
|
|
|
# Rate limiting for API endpoints
|
|
rate_limit {
|
|
zone api {
|
|
key {remote_host}
|
|
events 100
|
|
window 1m
|
|
}
|
|
zone auth {
|
|
key {remote_host}
|
|
events 10
|
|
window 1m
|
|
}
|
|
}
|
|
|
|
# API routes with rate limiting
|
|
@api path /api/*
|
|
rate_limit @api api
|
|
|
|
@auth path /api/auth/*
|
|
rate_limit @auth auth
|
|
|
|
# Reverse proxy to frontend container
|
|
reverse_proxy frontend:3000 {
|
|
# Health check
|
|
health_uri /
|
|
health_interval 30s
|
|
health_timeout 10s
|
|
|
|
# Load balancing (if multiple instances)
|
|
lb_policy round_robin
|
|
|
|
# Headers for proper forwarding
|
|
header_up Host {host}
|
|
header_up X-Real-IP {remote_host}
|
|
header_up X-Forwarded-For {remote_host}
|
|
header_up X-Forwarded-Proto {scheme}
|
|
header_up X-Forwarded-Host {host}
|
|
}
|
|
|
|
# Logging for legal compliance
|
|
log {
|
|
output file /var/log/caddy/docket-access.log {
|
|
roll_size 100mb
|
|
roll_keep 10
|
|
roll_keep_for 720h
|
|
}
|
|
format json
|
|
level INFO
|
|
}
|
|
|
|
# Error handling
|
|
handle_errors {
|
|
@5xx expression {http.error.status_code} >= 500
|
|
respond @5xx "Service temporarily unavailable" 503
|
|
|
|
@4xx expression {http.error.status_code} >= 400 && {http.error.status_code} < 500
|
|
respond @4xx "Page not found" 404
|
|
}
|
|
}
|
|
|
|
# Admin subdomain (optional - for enhanced security)
|
|
admin.docket.example.com {
|
|
tls {
|
|
# email admin@example.com
|
|
}
|
|
|
|
# Additional security for admin interface
|
|
header {
|
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
|
X-Content-Type-Options "nosniff"
|
|
X-Frame-Options "DENY"
|
|
X-XSS-Protection "1; mode=block"
|
|
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'"
|
|
}
|
|
|
|
# Stricter rate limiting for admin
|
|
rate_limit {
|
|
zone admin {
|
|
key {remote_host}
|
|
events 20
|
|
window 1m
|
|
}
|
|
}
|
|
rate_limit admin
|
|
|
|
# Only allow admin routes
|
|
@admin path /admin*
|
|
handle @admin {
|
|
reverse_proxy frontend:3000 {
|
|
header_up Host {host}
|
|
header_up X-Real-IP {remote_host}
|
|
header_up X-Forwarded-For {remote_host}
|
|
header_up X-Forwarded-Proto {scheme}
|
|
}
|
|
}
|
|
|
|
# Redirect non-admin requests to main site
|
|
redir https://docket.example.com{uri} permanent
|
|
|
|
log {
|
|
output file /var/log/caddy/admin-access.log {
|
|
roll_size 50mb
|
|
roll_keep 20
|
|
roll_keep_for 2160h # 90 days
|
|
}
|
|
format json
|
|
level INFO
|
|
}
|
|
}
|
|
|
|
# HTTP to HTTPS redirect
|
|
http://docket.example.com {
|
|
redir https://docket.example.com{uri} permanent
|
|
}
|
|
|
|
http://admin.docket.example.com {
|
|
redir https://admin.docket.example.com{uri} permanent
|
|
}
|