Custom Headers Configuration
BWS allows you to configure custom HTTP headers for responses, providing control over caching, security, and client behavior.
Header Configuration
Headers are configured per site in the config.toml
file:
[[sites]]
name = "example"
hostname = "localhost"
port = 8080
static_dir = "static"
[sites.headers]
"Cache-Control" = "public, max-age=3600"
"X-Frame-Options" = "DENY"
"X-Content-Type-Options" = "nosniff"
Common Header Types
Security Headers
Content Security Policy (CSP)
[sites.headers]
"Content-Security-Policy" = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
Frame Protection
[sites.headers]
"X-Frame-Options" = "DENY" # Block all framing
"X-Frame-Options" = "SAMEORIGIN" # Allow same-origin framing
"X-Frame-Options" = "ALLOW-FROM https://example.com" # Allow specific origin
Content Type Protection
[sites.headers]
"X-Content-Type-Options" = "nosniff" # Prevent MIME sniffing
XSS Protection
[sites.headers]
"X-XSS-Protection" = "1; mode=block"
HTTPS Enforcement
[sites.headers]
"Strict-Transport-Security" = "max-age=31536000; includeSubDomains"
Caching Headers
Standard Caching
[sites.headers]
"Cache-Control" = "public, max-age=3600" # 1 hour
"Cache-Control" = "public, max-age=86400" # 1 day
"Cache-Control" = "public, max-age=31536000" # 1 year
No Caching
[sites.headers]
"Cache-Control" = "no-cache, no-store, must-revalidate"
"Pragma" = "no-cache"
"Expires" = "0"
ETag Support
[sites.headers]
"ETag" = ""custom-etag-value""
CORS Headers
Basic CORS
[sites.headers]
"Access-Control-Allow-Origin" = "*"
"Access-Control-Allow-Methods" = "GET, POST, PUT, DELETE, OPTIONS"
"Access-Control-Allow-Headers" = "Content-Type, Authorization"
Restricted CORS
[sites.headers]
"Access-Control-Allow-Origin" = "https://example.com"
"Access-Control-Allow-Credentials" = "true"
"Access-Control-Max-Age" = "86400"
Custom Application Headers
API Versioning
[sites.headers]
"X-API-Version" = "v1.0.0"
"X-Service-Name" = "BWS"
Environment Information
[sites.headers]
"X-Environment" = "production"
"X-Deploy-Version" = "2024.01.15"
Rate Limiting Info
[sites.headers]
"X-RateLimit-Limit" = "1000"
"X-RateLimit-Window" = "3600"
Site-Specific Configurations
Development Environment
[[sites]]
name = "dev"
hostname = "localhost"
port = 8080
static_dir = "src"
[sites.headers]
"Cache-Control" = "no-cache, no-store, must-revalidate"
"X-Environment" = "development"
"X-Debug-Mode" = "enabled"
"Access-Control-Allow-Origin" = "*"
"Access-Control-Allow-Methods" = "GET, POST, PUT, DELETE, OPTIONS"
Production Environment
[[sites]]
name = "prod"
hostname = "example.com"
port = 8080
static_dir = "dist"
[sites.headers]
"Cache-Control" = "public, max-age=31536000"
"X-Environment" = "production"
"X-Frame-Options" = "DENY"
"X-Content-Type-Options" = "nosniff"
"Strict-Transport-Security" = "max-age=31536000; includeSubDomains"
"Content-Security-Policy" = "default-src 'self'"
API Server
[[sites]]
name = "api"
hostname = "api.example.com"
port = 8081
static_dir = "api-docs"
[sites.headers]
"Content-Type" = "application/json"
"X-API-Version" = "v2.1.0"
"Access-Control-Allow-Origin" = "https://app.example.com"
"Access-Control-Allow-Methods" = "GET, POST, PUT, DELETE"
"Access-Control-Allow-Headers" = "Content-Type, Authorization, X-Requested-With"
"Access-Control-Max-Age" = "86400"
"Cache-Control" = "no-cache"
CDN/Asset Server
[[sites]]
name = "cdn"
hostname = "cdn.example.com"
port = 8082
static_dir = "assets"
[sites.headers]
"Cache-Control" = "public, max-age=31536000, immutable"
"Access-Control-Allow-Origin" = "*"
"X-Content-Type-Options" = "nosniff"
"Vary" = "Accept-Encoding"
Advanced Header Patterns
Multi-Value Headers
Some headers can have multiple values separated by commas:
[sites.headers]
"Vary" = "Accept-Encoding, Accept-Language, User-Agent"
"Access-Control-Expose-Headers" = "X-Total-Count, X-Page-Count"
Conditional Headers
Different headers for different file types (handled by custom logic):
# Base headers for all files
[sites.headers]
"X-Served-By" = "BWS"
"X-Content-Type-Options" = "nosniff"
# Note: File-specific headers would require application logic
# This is the base configuration that applies to all responses
Header Testing
Check Headers with curl
# View all response headers
curl -I http://localhost:8080/
# Check specific header
curl -I http://localhost:8080/ | grep "Cache-Control"
# Verbose output with request/response
curl -v http://localhost:8080/
Check Headers with HTTPie
# View headers
http HEAD localhost:8080
# Check specific response
http GET localhost:8080/api/health
Browser Developer Tools
- Open DevTools (F12)
- Navigate to Network tab
- Reload page
- Click on any request
- View Response Headers section
Security Best Practices
Minimal Security Headers
[sites.headers]
"X-Frame-Options" = "DENY"
"X-Content-Type-Options" = "nosniff"
"X-XSS-Protection" = "1; mode=block"
"Referrer-Policy" = "strict-origin-when-cross-origin"
Enhanced Security Headers
[sites.headers]
"Strict-Transport-Security" = "max-age=31536000; includeSubDomains; preload"
"Content-Security-Policy" = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:"
"X-Frame-Options" = "DENY"
"X-Content-Type-Options" = "nosniff"
"X-XSS-Protection" = "1; mode=block"
"Referrer-Policy" = "strict-origin-when-cross-origin"
"Permissions-Policy" = "camera=(), microphone=(), geolocation=()"
API Security Headers
[sites.headers]
"X-Content-Type-Options" = "nosniff"
"X-Frame-Options" = "DENY"
"Cache-Control" = "no-store"
"Content-Security-Policy" = "default-src 'none'"
"X-Permitted-Cross-Domain-Policies" = "none"
Performance Headers
Optimal Caching Strategy
# Static assets (CSS, JS, images)
[sites.headers]
"Cache-Control" = "public, max-age=31536000, immutable"
"Vary" = "Accept-Encoding"
# HTML files
# Cache-Control = "public, max-age=3600" # Shorter cache
# API responses
# Cache-Control = "no-cache" # No caching
Compression Headers
[sites.headers]
"Vary" = "Accept-Encoding"
"Content-Encoding" = "gzip" # If serving pre-compressed files
Troubleshooting
Headers Not Appearing
- Check TOML syntax in config file
- Restart BWS after configuration changes
- Verify header names are correct (case-sensitive)
- Use browser dev tools to inspect
CORS Issues
# Debug CORS headers
[sites.headers]
"Access-Control-Allow-Origin" = "*"
"Access-Control-Allow-Methods" = "GET, POST, PUT, DELETE, OPTIONS"
"Access-Control-Allow-Headers" = "Content-Type, Authorization, X-Requested-With"
"Access-Control-Max-Age" = "86400"
CSP Violations
- Start with permissive policy
- Use browser console to identify violations
- Gradually restrict policy
- Test thoroughly
Cache Problems
# Force no-cache for debugging
[sites.headers]
"Cache-Control" = "no-cache, no-store, must-revalidate"
"Pragma" = "no-cache"
"Expires" = "0"
Common Header Combinations
Static Website
[sites.headers]
"Cache-Control" = "public, max-age=3600"
"X-Frame-Options" = "SAMEORIGIN"
"X-Content-Type-Options" = "nosniff"
"Referrer-Policy" = "strict-origin-when-cross-origin"
Single Page Application (SPA)
[sites.headers]
"Cache-Control" = "public, max-age=3600"
"X-Frame-Options" = "DENY"
"X-Content-Type-Options" = "nosniff"
"Content-Security-Policy" = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
Documentation Site
[sites.headers]
"Cache-Control" = "public, max-age=1800"
"X-Frame-Options" = "SAMEORIGIN"
"X-Content-Type-Options" = "nosniff"
"Content-Security-Policy" = "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:"
Next Steps
- Learn about Health Monitoring
- Configure Docker Deployment
- Explore Performance Tuning