129 lines
4.1 KiB
YAML
129 lines
4.1 KiB
YAML
http:
|
|
middlewares:
|
|
# ============================================================================
|
|
# SECURITY MIDDLEWARES
|
|
# ============================================================================
|
|
|
|
# Security Headers - Comprehensive hardening
|
|
security-headers:
|
|
headers:
|
|
browserXssFilter: true
|
|
contentTypeNosniff: true
|
|
forceSTSHeader: true
|
|
stsIncludeSubdomains: true
|
|
stsPreload: true
|
|
stsSeconds: 31536000 # 1 year
|
|
customFrameOptionsValue: "SAMEORIGIN"
|
|
contentSecurityPolicy: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; media-src 'self'; object-src 'none'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';"
|
|
customResponseHeaders:
|
|
X-Robots-Tag: "noindex, nofollow"
|
|
X-Download-Options: "noopen"
|
|
X-Permitted-Cross-Domain-Policies: "none"
|
|
Permissions-Policy: "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
|
|
Referrer-Policy: "strict-origin-when-cross-origin"
|
|
sslProxyHeaders:
|
|
X-Forwarded-Proto: https
|
|
|
|
# Rate Limiting - External
|
|
rate-limit:
|
|
rateLimit:
|
|
average: 100
|
|
burst: 200
|
|
period: 1m
|
|
|
|
# Rate Limiting - Internal (more lenient)
|
|
rate-limit-internal:
|
|
rateLimit:
|
|
average: 300
|
|
burst: 500
|
|
period: 1m
|
|
|
|
# Rate Limiting - Strict (for auth endpoints)
|
|
rate-limit-strict:
|
|
rateLimit:
|
|
average: 10
|
|
burst: 20
|
|
period: 1m
|
|
|
|
# Geo-blocking (optional - configure countries as needed)
|
|
geo-block:
|
|
plugin:
|
|
geo-block:
|
|
allowLocalRequests: true
|
|
logLocalRequests: false
|
|
logAllowedRequests: false
|
|
logApiRequests: true
|
|
api: "https://get.geojs.io/v1/ip/country/{ip}"
|
|
apiTimeoutMs: 150
|
|
cacheSize: 1000
|
|
forceMonthlyUpdate: true
|
|
allowUnknownCountries: false
|
|
unknownCountryApiResponse: "nil"
|
|
blackListMode: false
|
|
# Countries allowed (ISO 3166-1 alpha-2)
|
|
countries:
|
|
- SE # Sweden
|
|
- NO # Norway
|
|
- DK # Denmark
|
|
- FI # Finland
|
|
# Add more as needed
|
|
|
|
# Compress responses
|
|
compress:
|
|
compress:
|
|
excludedContentTypes:
|
|
- text/event-stream
|
|
|
|
# Redirect to HTTPS (fallback)
|
|
redirect-https:
|
|
redirectScheme:
|
|
scheme: https
|
|
permanent: true
|
|
|
|
# Add X-Forwarded headers
|
|
forwarded-headers:
|
|
headers:
|
|
customRequestHeaders:
|
|
X-Forwarded-Port: "443"
|
|
sslProxyHeaders:
|
|
X-Forwarded-Proto: https
|
|
|
|
# Real IP from Cloudflare
|
|
cloudflare-real-ip:
|
|
plugin:
|
|
cloudflarewarp:
|
|
disableDefault: false
|
|
|
|
# ============================================================================
|
|
# AUTHENTICATION MIDDLEWARES
|
|
# ============================================================================
|
|
|
|
# Authelia forward auth (from Docker labels)
|
|
authelia:
|
|
forwardAuth:
|
|
address: "http://authelia:9091/api/verify?rd=https://auth.lemonlink.eu/"
|
|
trustForwardHeader: true
|
|
authResponseHeaders:
|
|
- Remote-User
|
|
- Remote-Groups
|
|
- Remote-Name
|
|
- Remote-Email
|
|
|
|
# Basic Auth fallback (for emergencies)
|
|
basic-auth:
|
|
basicAuth:
|
|
users:
|
|
# Generate with: htpasswd -nb admin yourpassword | sed -e s/\$/\$\$/g
|
|
# Replace $ with $$ in the hash for YAML
|
|
- "admin:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/" # admin:admin - CHANGE THIS!
|
|
realm: "LemonLink Secured"
|
|
|
|
# ============================================================================
|
|
# CROWDSEC MIDDLEWARE
|
|
# ============================================================================
|
|
|
|
crowdsec-bouncer:
|
|
forwardAuth:
|
|
address: http://crowdsec-bouncer-traefik:8080/api/v1/forwardAuth
|
|
trustForwardHeader: true
|