Configuration: configuration examples
This page collects practical KDL configuration examples you can adapt for common Ferron deployment patterns.
Language-specific content configuration example
Below is an example of Ferron configuration involving conditionals to serve language-specific content:
// Snippet for common language settings
snippet "LANG_COMMON" {
set_constant "LANGUAGES" "en,de,pl"
}
example.com {
// Generic response
status 200 body="lang: Unknown"
condition "LANG_PL" {
use "LANG_COMMON"
is_language "pl"
}
condition "LANG_DE" {
use "LANG_COMMON"
is_language "de"
}
condition "LANG_EN" {
use "LANG_COMMON"
is_language "en"
}
if "LANG_PL" {
// Polish language
status 200 body="lang: Polski"
}
if "LANG_DE" {
// German language
status 200 body="lang: Deutsch"
}
if "LANG_EN" {
// English language
status 200 body="lang: English"
}
}Location block example
Below is an example of Ferron configuration involving location blocks:
example.com {
root "/var/www/example.com"
// Static assets with different settings
location "/static" remove_base=#true {
root "/var/www/static"
compressed
file_cache_control "public, max-age=31536000"
}
// API endpoints with proxy
location "/api" {
proxy "http://backend:8080"
proxy_request_header "X-Forwarded-For" "{client_ip}"
limit rate=50 burst=100
}
// Admin area with authentication
location "/admin" {
status 401 realm="Admin Access" users="admin"
root "/var/www/admin"
}
// PHP files
fcgi_php "tcp://localhost:9000/"
}Complete example combining multiple configuration aspects
Below is a complete example of Ferron configuration, combining multiple aspects of the configuration:
// Global configuration
* {
// Protocol and performance settings
protocols "h1" "h2"
h2_initial_window_size 65536
h2_max_concurrent_streams 100
timeout 300000
// Network settings
listen_ip "0.0.0.0"
default_http_port 80
default_https_port 443
// Security defaults
tls_cipher_suite "TLS_AES_256_GCM_SHA384" "TLS_AES_128_GCM_SHA256"
ocsp_stapling
block "192.168.1.100"
// Global caching
cache_max_entries 1024
// Load balancing settings
lb_health_check_window 5000
// Logging
log "/var/log/ferron/access.log"
error_log "/var/log/ferron/error.log"
// Static file defaults
compressed
etag
}
// Define reusable snippets
snippet "security_headers" {
// Common security headers
header "X-Frame-Options" "DENY"
header "X-Content-Type-Options" "nosniff"
header "X-XSS-Protection" "1; mode=block"
header "Referrer-Policy" "strict-origin-when-cross-origin"
}
snippet "cors_headers" {
// CORS headers for API endpoints
header "Access-Control-Allow-Origin" "*"
header "Access-Control-Allow-Methods" "GET, POST, PUT, DELETE, OPTIONS"
header "Access-Control-Allow-Headers" "Authorization, Content-Type, X-Requested-With"
header "Access-Control-Max-Age" "86400"
}
snippet "static_caching" {
// Aggressive caching for static assets
file_cache_control "public, max-age=31536000, immutable"
compressed
etag
}
snippet "admin_protection" {
// Admin area protection
status 401 realm="Admin Area" users="admin,superuser"
user "admin" "$2b$10$hashedpassword12345"
user "superuser" "$2b$10$anotherhashpassword67890"
limit rate=10 burst=20
}
snippet "mobile_condition" {
condition "is_mobile" {
is_regex "{header:User-Agent}" "(Mobile|Android|iPhone|iPad)" case_insensitive=#true
}
}
snippet "admin_ip_condition" {
condition "is_admin_ip" {
is_remote_ip "192.168.1.10" "10.0.0.5"
}
}
snippet "api_request_condition" {
condition "is_api_request" {
is_regex "{path}" "^/api/"
}
}
snippet "static_asset_condition" {
condition "is_static_asset" {
is_regex "{path}" "\\.(css|js|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot|ico)(?:$|[?#])" case_insensitive=#true
}
}
snippet "development_condition" {
condition "is_development" {
is_equal "{header:X-Environment}" "development"
}
}
// Main website with conditional configuration
example.com {
// TLS configuration
tls "/etc/ssl/certs/example.com.crt" "/etc/ssl/private/example.com.key"
auto_tls_contact "admin@example.com"
// Basic settings
root "/var/www/example.com"
server_administrator_email "admin@example.com"
// Use security headers snippet
use "security_headers"
// Import condition snippets
use "mobile_condition"
use "admin_ip_condition"
use "api_request_condition"
use "static_asset_condition"
use "development_condition"
// Additional security header
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
// Conditional configuration based on mobile detection
if "is_mobile" {
// Add headers that aren't inherited
use "security_headers"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
// Mobile-specific settings
header "X-Mobile-Detected" "true"
root "/var/www/example.com/mobile"
// Lighter rate limiting for mobile
limit rate=50 burst=100
}
if_not "is_mobile" {
// Add headers that aren't inherited
use "security_headers"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
// Desktop settings
header "X-Mobile-Detected" "false"
limit rate=100 burst=200
}
// Admin IP gets special treatment
if "is_admin_ip" {
// Add headers that aren't inherited
use "security_headers"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
// No rate limiting for admin IPs
limit #false
// Additional debug headers
header "X-Admin-Access" "true"
header "X-Client-IP" "{client_ip}"
// Enhanced logging for admin access
log "/var/log/ferron/admin-access.log"
}
// Development environment conditional settings
if "is_development" {
// Add headers that aren't inherited
use "security_headers"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
// Development-specific headers
header "X-Environment" "development"
header "X-Debug-Mode" "enabled"
// Disable caching in development
header "Cache-Control" "no-cache, no-store, must-revalidate"
header "Pragma" "no-cache"
header "Expires" "0"
}
if_not "is_development" {
// Add headers that aren't inherited
use "security_headers"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
// Production caching
cache
cache_vary "Accept-Encoding" "Accept-Language"
file_cache_control "public, max-age=3600"
}
// URL rewriting
rewrite "^/old-section/(.*)" "/new-section/$1" last=#true
// Error pages
error_page 404 "/var/www/errors/404.html"
error_page 500 "/var/www/errors/500.html"
// Static assets location with conditional caching
location "/assets" remove_base=#true {
root "/var/www/assets"
if "is_static_asset" {
// Add headers that aren't inherited
use "security_headers"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
use "static_caching"
}
// CORS for web fonts
if_not "is_static_asset" {
// Add headers that aren't inherited
use "security_headers"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
header "Access-Control-Allow-Origin" "*"
}
}
// API endpoints
location "/api" {
if "is_api_request" {
// Add headers that aren't inherited
use "security_headers"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
use "cors_headers"
// API-specific rate limiting
limit rate=1000 burst=2000
// Proxy to API backend
proxy "http://api-backend:8080"
proxy_request_header_replace "X-Real-IP" "{client_ip}"
proxy_request_header "X-Forwarded-Proto" "{scheme}"
}
}
// Admin area with conditional access
location "/admin" {
if "is_admin_ip" {
// Add headers that aren't inherited
use "security_headers"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
// Admin IPs get direct access
root "/var/www/admin"
// Special admin headers
header "X-Admin-Direct-Access" "true"
}
if_not "is_admin_ip" {
// Add headers that aren't inherited
use "security_headers"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
// Non-admin IPs require authentication
use "admin_protection"
}
}
// PHP application
fcgi_php "tcp://localhost:9000/"
}
// API subdomain with extensive conditional logic
api.example.com {
// TLS configuration
tls "/etc/ssl/certs/api.example.com.crt" "/etc/ssl/private/api.example.com.key"
// Use CORS headers snippet
use "cors_headers"
// Import reusable condition
use "admin_ip_condition"
// Conditional backend selection based on request path
condition "is_v1_api" {
is_regex "{path}" "^/v1/"
}
condition "is_v2_api" {
is_regex "{path}" "^/v2/"
}
condition "is_auth_request" {
is_regex "{path}" "^/(login|register|refresh|logout)"
}
// Version-specific backend routing
if "is_v1_api" {
// Use CORS headers snippet (again, since it's not inherited)
use "cors_headers"
proxy "http://api-v1-backend1:8080"
proxy "http://api-v1-backend2:8080"
// V1 specific headers
header "X-API-Version" "1.0"
// More restrictive rate limiting for legacy API
limit rate=500 burst=1000
}
if "is_v2_api" {
// Use CORS headers snippet (again, since it's not inherited)
use "cors_headers"
proxy "http://api-v2-backend1:8080"
proxy "http://api-v2-backend2:8080"
proxy "http://api-v2-backend3:8080"
// V2 specific headers
header "X-API-Version" "2.0"
// Higher rate limits for new API
limit rate=2000 burst=4000
}
// Authentication endpoints get special treatment
if "is_auth_request" {
// Use CORS headers snippet (again, since it's not inherited)
use "cors_headers"
// Route to dedicated auth service
proxy "http://auth-service:9090"
// Stricter rate limiting for auth endpoints
limit rate=100 burst=200
// Additional security headers
header "X-Auth-Endpoint" "true"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains; preload"
}
// Admin IP gets enhanced access
if "is_admin_ip" {
// Use CORS headers snippet (again, since it's not inherited)
use "cors_headers"
// No rate limiting for admin IPs
limit #false
// Admin-specific headers
header "X-Admin-API-Access" "true"
// Enhanced logging
log "/var/log/ferron/api-admin.log"
}
// Health checking
lb_health_check
lb_health_check_max_fails 3
// Proxy settings
proxy_keepalive
proxy_request_header_replace "X-Real-IP" "{client_ip}"
proxy_request_header "X-Forwarded-Proto" "{scheme}"
// Health check endpoint
status 200 url="/health" body="OK"
// Version info endpoint
status 200 url="/version" body="{\"api_versions\":[\"v1\",\"v2\"],\"server\":\"Ferron\"}"
}
// Development subdomain with environment-based configuration
dev.example.com {
// Basic TLS
auto_tls
auto_tls_contact "dev@example.com"
// Use security headers but with relaxed settings
use "security_headers"
// Import reusable condition
use "admin_ip_condition"
// Override some security headers for development
header "X-Frame-Options" "SAMEORIGIN"
// Enhanced logging
log "/var/log/ferron/dev.access.log"
error_log "/var/log/ferron/dev.error.log"
// Development-specific conditions
condition "is_hot_reload" {
is_regex "{path}" "^/(sockjs-node|__webpack_hmr)"
}
condition "is_source_map" {
is_regex "{path}" "\\.map(?:$|[?#])"
}
// Hot reload support
if "is_hot_reload" {
// Non-inherited headers, again
use "security_headers"
header "X-Frame-Options" "SAMEORIGIN"
proxy "http://dev-hmr:3001"
// WebSocket support
proxy_request_header "Connection" "Upgrade"
proxy_request_header "Upgrade" "websocket"
// No caching for hot reload
header "Cache-Control" "no-cache"
}
// Source maps handling
if "is_source_map" {
// Only allow source maps for admin IPs
if "is_admin_ip" {
root "/var/www/dev/sourcemaps"
}
if_not "is_admin_ip" {
status 404 body="Not found"
}
}
// Test endpoints with conditional responses
if "is_admin_ip" {
status 200 url="/test" body="Development server is working (Admin Access)"
status 200 url="/debug" body="{\"client_ip\":\"{client_ip}\",\"method\":\"{method}\",\"path\":\"{path}\"}"
}
if_not "is_admin_ip" {
status 200 url="/test" body="Development server is working"
}
// Default proxy to development backend
proxy "http://dev-backend:3000"
proxy_request_header "X-Dev-Mode" "true"
proxy_request_header "X-Environment" "development"
// Relaxed rate limiting
limit rate=1000 burst=5000
}
// Static content CDN with intelligent caching
cdn.example.com {
// TLS configuration
tls "/etc/ssl/certs/cdn.example.com.crt" "/etc/ssl/private/cdn.example.com.key"
// Static file serving
root "/var/www/cdn"
directory_listing #false
// Use static caching snippet
use "static_caching"
// Import reusable condition
use "admin_ip_condition"
// Conditional caching based on file type
condition "is_image" {
is_regex "{path}" "\\.(png|jpg|jpeg|gif|webp|svg)(?:$|[?#])" case_insensitive=#true
}
condition "is_font" {
is_regex "{path}" "\\.(woff|woff2|ttf|eot|otf)(?:$|[?#])" case_insensitive=#true
}
condition "is_media" {
is_regex "{path}" "\\.(mp4|webm|ogg|mp3|wav)(?:$|[?#])" case_insensitive=#true
}
// Image-specific settings
if "is_image" {
// Extra long caching for images
file_cache_control "public, max-age=2592000, immutable"
// Image-specific headers
header "X-Content-Type" "image"
}
// Font-specific settings
if "is_font" {
// CORS for web fonts
header "Access-Control-Allow-Origin" "*"
header "Access-Control-Allow-Methods" "GET, HEAD, OPTIONS"
// Font-specific caching
file_cache_control "public, max-age=31536000, immutable"
}
// Media-specific settings
if "is_media" {
// Partial content support for media
header "Accept-Ranges" "bytes"
// Media-specific caching
file_cache_control "public, max-age=604800"
}
// Admin IP gets special access
if "is_admin_ip" {
// Allow directory listing for admin IPs
directory_listing #true
// Admin headers
header "X-Admin-CDN-Access" "true"
}
// No rate limiting for CDN
limit #false
// Geographic optimization (example condition)
condition "is_european_request" {
is_regex "{header:CF-IPCountry}" "^(DE|FR|GB|IT|ES|NL|BE|CH|AT|SE|NO|DK|FI|PL)$"
}
if "is_european_request" {
header "X-CDN-Region" "Europe"
// Could proxy to European CDN nodes here
}
if_not "is_european_request" {
header "X-CDN-Region" "Global"
}
}