BWS (Ben's Web Server)
A high-performance, multi-site web server built with Pingora, Cloudflare's battle-tested proxy framework.
🔄 Reverse Proxy & Load Balancing
BWS includes comprehensive reverse proxy functionality similar to Caddy, with support for multiple load balancing algorithms:
Load Balancing Algorithms
- Round Robin (
round_robin): Distributes requests evenly across all servers - Weighted (
weighted): Distributes requests based on server weights/capacity - Least Connections (
least_connections): Routes to server with fewest active connections
Basic Reverse Proxy Setup
[[]]
= "proxy_site"
= "proxy.example.com"
= 8080
[]
= true
# Backend servers (same upstream name for load balancing)
[[]]
= "backend-pool"
= "http://127.0.0.1:3001"
= 1
[[]]
= "backend-pool"
= "http://127.0.0.1:3002"
= 2 # Gets 2x traffic in weighted mode
# Route configuration
[[]]
= "/api/"
= "backend-pool"
= false
# Load balancing method
[]
= "round_robin" # or "weighted" or "least_connections"
# Proxy headers
[]
= true
= true
[]
= "BWS"
[]
= true
Advanced Proxy Configuration
[]
= true
# Request timeout settings
= { = 30, = 30 }
# Multiple upstream groups
[[]]
= "api-cluster"
= "http://api1.internal:8080"
= 3
[[]]
= "api-cluster"
= "http://api2.internal:8080"
= 2
[[]]
= "static-cluster"
= "http://cdn1.internal:8080"
= 1
[[]]
= "static-cluster"
= "http://cdn2.internal:8080"
= 1
# Multiple routes to different upstream groups
[[]]
= "/api/"
= "api-cluster"
[[]]
= "/static/"
= "static-cluster"
= true # Remove /static/ when forwarding
# Load balancing configuration
[]
= "least_connections"
Testing Load Balancing
Use the included test script to verify load balancing:
# Set up test configuration
# Run the load balancing test
For detailed information, see: Load Balancing Documentation →
🔒 SSL/TLS Configuration
BWS provides comprehensive SSL/TLS support with automatic certificate management through Let's Encrypt (ACME), plus support for custom certificates.
📖 Documentation
The full documentation includes:
- 📚 User Guide - Installation, configuration, and deployment
- 🚀 Quick Start - Get running in minutes
- 🔧 API Reference - Complete REST API documentation
- 🐳 Docker Guide - Container deployment options
- 💡 Examples - Real-world use cases and configurations
✨ Features
- 🚀 High Performance: Built on Pingora, CloudFlare's high-performance proxy framework
- 🌐 Multi-Site Hosting: Host multiple websites on different ports with individual configurations
- 🔄 Reverse Proxy: Comprehensive proxy functionality with load balancing (round-robin, weighted, least-connections)
- 🔌 WebSocket Proxy: Full WebSocket proxying support with load balancing
- 📋 Configurable Headers: Site-specific HTTP headers (CORS, security, custom headers)
- 🔒 SSL/TLS Support: ACME (Let's Encrypt) integration and manual certificate management
- 🛡️ Security Features: Security headers, request filtering, and access control
- 💨 Compression: Built-in gzip compression for static and dynamic content
- 📊 Health Monitoring: Built-in health check endpoints with detailed system information
- ⚡ Hot Reload: Configuration changes without server restart
- 🔧 Cross-Platform: Linux, macOS, and Windows support with static linking options
📦 Installation
From crates.io
From Docker (Recommended for Production)
# Pull and run the latest version
From Source
🔧 Quick Start
- Create a configuration file (
config.toml):
[]
= "BWS Multi-Site Server"
# HTTP Site
[[]]
= "main"
= "localhost"
= 8080
= "static"
= true
[]
= false
[]
= "BWS Main Site"
= "BWS/1.0"
# Reverse Proxy Site with Load Balancing
[[]]
= "proxy"
= "proxy.localhost"
= 8090
= "static"
[]
= true
# Multiple backend servers for load balancing
[[]]
= "api-servers"
= "http://127.0.0.1:3001"
= 2
[[]]
= "api-servers"
= "http://127.0.0.1:3002"
= 1
[[]]
= "api-servers"
= "http://127.0.0.1:3003"
= 1
# Proxy routes
[[]]
= "/api/"
= "api-servers"
= false
# Load balancing configuration
[]
= "weighted" # round_robin, weighted, or least_connections
# Proxy headers
[]
= true
= true
[]
= "BWS/1.0"
[]
= true
# HTTPS Site with Auto SSL
[[]]
= "secure"
= "secure.localhost"
= 8443
= "static"
[]
= true
= true
= ["secure.localhost", "ssl.localhost"]
[]
= true
= "admin@example.com"
= false
= "./acme-challenges"
[]
= "BWS Secure Site"
= "max-age=31536000"
# HTTPS Site with Manual SSL
[[]]
= "manual_ssl"
= "manual.localhost"
= 8444
= "static"
[]
= true
= false
= "./certs/manual.crt"
= "./certs/manual.key"
[]
= "BWS Manual SSL Site"
= "manual"
- Create static directories and files:
# Create directories for each site
# Add content to main site
# For SSL sites, you can use the same static directory or create separate ones
- Run the server:
# Run with default config.toml
# Specify a custom config file
# Enable verbose logging
# Show help
# Show version
- Test your setup:
# Test HTTP site
# Test HTTPS sites (if SSL is properly configured)
# Health checks
# View all sites configuration
� SSL/TLS Configuration
BWS supports per-site SSL/TLS configuration, allowing each site to have its own HTTPS setup:
Automatic SSL Certificates (ACME/Let's Encrypt)
[[]]
= "auto_ssl_site"
= "example.com"
= 443
= "static"
[]
= true
= true
= ["example.com", "www.example.com"]
[]
= true
= "admin@example.com"
= false # Set to true for testing
= "./acme-challenges"
Manual SSL Certificates
[[]]
= "manual_ssl_site"
= "secure.example.com"
= 443
= "static"
[]
= true
= false
= "/etc/ssl/certs/secure.example.com.crt"
= "/etc/ssl/private/secure.example.com.key"
Mixed HTTP/HTTPS Sites
You can run both HTTP and HTTPS sites simultaneously:
# HTTP site on port 80
[[]]
= "http_site"
= "example.com"
= 80
= "static"
[]
= false
# HTTPS site on port 443
[[]]
= "https_site"
= "example.com"
= 443
= "static"
[]
= true
= true
= ["example.com"]
[]
= true
= "admin@example.com"
= false
= "./acme-challenges"
�💻 Command Line Options
BWS supports the following command line options:
-c, --config <FILE>: Specify configuration file path (default:config.toml)-v, --verbose: Enable verbose logging with debug information-d, --daemon: Run as daemon (background process) - Unix only--pid-file <FILE>: PID file path when running as daemon (default:/tmp/bws-web-server.pid) - Unix only--log-file <FILE>: Log file path when running as daemon (default:/tmp/bws-web-server.log) - Unix only-h, --help: Show help information-V, --version: Show version information
Note: Daemon functionality is only available on Unix-like systems (Linux, macOS, etc.). On Windows, the server runs in foreground mode only.
Examples
# Use default config.toml
# Use custom configuration file
# Enable verbose logging to see headers and debug info
# Combine options
# Run as daemon (background process)
# Run as daemon with custom log and PID files
🔧 Daemon Management (Unix Only)
BWS can run as a daemon (background process) for production deployments on Unix-like systems (Linux, macOS, etc.). A management script is provided for easy daemon control:
Windows Note: Daemon functionality is not supported on Windows. Use your system's service manager or run in the foreground with a process manager like PM2 or NSSM.
# Start the daemon
# Stop the daemon
# Restart the daemon
# Check daemon status
Daemon Features
- Background Operation: Runs detached from the terminal
- PID File Management: Tracks process ID for management
- Log File Output: All output redirected to log files
- Graceful Shutdown: Handles termination signals properly
- Status Monitoring: Built-in health checks and status reporting
Manual Daemon Control
# Start daemon manually
# Stop daemon using PID file
# Check if daemon is running
|
🐳 Docker Deployment
BWS provides Docker images for easy deployment and scaling.
Quick Start with Docker
# Pull the latest image from GitHub Container Registry
# Run with default configuration
# Run with custom configuration
Using Docker Compose
# Start with the provided docker-compose.yml
# Start with daemon mode profile
# View logs
# Stop services
Available Docker Images
- Latest:
ghcr.io/benliao/bws:latest- Built from main branch - Versioned:
ghcr.io/benliao/bws:v0.1.2- Specific version releases - Platform Support: Available for
linux/amd64andlinux/arm64
Docker Environment Variables
BWS_CONFIG: Configuration file path (default:/app/config.toml)BWS_LOG_FILE: Log file path for daemon mode (default:/app/logs/bws.log)BWS_PID_FILE: PID file path for daemon mode (default:/app/run/bws.pid)RUST_LOG: Logging level (error,warn,info,debug,trace)
Docker Volumes
/app/config.toml: Mount your configuration file/app/static*: Mount your static content directories/app/logs: Persistent log storage/app/run: Persistent runtime files (PID files, etc.)
[]
= "BWS Multi-Site Server"
# Main site with production headers
[[]]
= "main"
= "localhost"
= 8080
= "static"
= true
[]
= "BWS Main Site"
= "BWS/1.0"
= "main"
= "production"
# Blog site with custom headers
[[]]
= "blog"
= "blog.localhost"
= 8081
= "static-blog"
[]
= "BWS Blog"
= "BWS/1.0"
= "blog"
= "blog-content"
= "BWS Team"
# API documentation site with CORS headers
[[]]
= "api"
= "api.localhost"
= 8082
= "static-api"
= true
[]
= "BWS API Documentation"
= "BWS/1.0"
= "api-docs"
= "v1.0"
= "*"
= "GET, POST, PUT, DELETE, OPTIONS"
# Development site with debug headers
[[]]
= "dev"
= "localhost"
= 8083
= "static-dev"
[]
= "BWS Development Site"
= "BWS/1.0"
= "development"
= "development"
= "enabled"
Configuration Options
- server.name: Display name for the server
- sites: Array of site configurations
- sites.name: Unique identifier for the site
- sites.hostname: Hostname for virtual host routing
- sites.port: Port number for the site
- sites.static_dir: Directory containing static files
- sites.default: Mark as default site (optional)
- sites.api_only: API-only site, no static files (optional)
- sites.headers: Custom HTTP headers to include in all responses for this site
- sites.ssl: SSL/TLS configuration for this site
- sites.ssl.enabled: Enable/disable SSL for this site
- sites.ssl.auto_cert: Use automatic certificate generation (ACME)
- sites.ssl.domains: Additional domains for the SSL certificate
- sites.ssl.cert_file: Path to SSL certificate file (manual SSL)
- sites.ssl.key_file: Path to SSL private key file (manual SSL)
- sites.ssl.acme: ACME configuration for automatic certificates
- sites.ssl.acme.enabled: Enable ACME certificate generation
- sites.ssl.acme.email: Email for ACME registration
- sites.ssl.acme.staging: Use staging environment for testing
- sites.ssl.acme.challenge_dir: Directory for ACME challenges
- sites.proxy: Reverse proxy configuration for this site
- sites.proxy.enabled: Enable/disable reverse proxy functionality
- sites.proxy.upstreams: Array of backend servers
- sites.proxy.upstreams.name: Upstream group name (group servers with same name)
- sites.proxy.upstreams.url: Backend server URL
- sites.proxy.upstreams.weight: Server weight for weighted load balancing
- sites.proxy.routes: Array of proxy routes
- sites.proxy.routes.path: Path pattern to match for proxying
- sites.proxy.routes.upstream: Upstream group name to proxy to
- sites.proxy.routes.strip_prefix: Remove matched path when forwarding
- sites.proxy.routes.websocket: Enable WebSocket proxying for this route
- sites.proxy.load_balancing: Load balancing configuration
- sites.proxy.load_balancing.method: Algorithm (
round_robin,weighted,least_connections) - sites.proxy.timeout: Request timeout settings
- sites.proxy.timeout.read: Read timeout in seconds
- sites.proxy.timeout.write: Write timeout in seconds
- sites.proxy.headers: Proxy header management
- sites.proxy.headers.add_x_forwarded: Add X-Forwarded-* headers
- sites.proxy.headers.add_forwarded: Add Forwarded header
- sites.proxy.headers.add: Custom headers to add
- sites.proxy.headers.remove: Headers to remove from responses
Configurable Headers
Each site can define custom HTTP headers that will be included in all responses from that site:
- Security Headers: CORS, CSP, security policies
- Custom Headers: Site identification, versioning, environment info
- API Headers: API versioning, CORS for API sites
- Debug Headers: Development flags, debug information
- Branding Headers: Custom site branding and identification
Development site
[[sites]] name = "dev" hostname = "localhost" port = 8083 static_dir = "static-dev"
### Configuration Options
- **name**: Unique identifier for the site
- **hostname**: Hostname for virtual host matching
- **port**: Port number to listen on
- **static_dir**: Directory containing static files for this site
- **default**: (optional) Set to true for the default/fallback site
- **api_only**: (optional) Set to true for API-only sites
## Available Endpoints
### Multi-Site Support
The server can host multiple websites simultaneously:
- **Main Site** (localhost:8080) - Original BWS website
- **Blog Site** (blog.localhost:8081) - Blog content with different styling
- **API Docs** (api.localhost:8082) - API documentation with dark theme
- **Dev Site** (localhost:8083) - Development environment
### Static Website Endpoints
Each site serves its own static content:
- **GET /** - Serves the site's `index.html` from its static directory
- **GET /about.html** - About page (if available in static directory)
- **GET /contact.html** - Contact page (if available in static directory)
- **GET /static/*** - Serves static assets (CSS, JS, images, etc.) with cache headers
### API Endpoints
#### Sites Information
- **GET /api/sites** - Returns information about all configured sites
```json
{
"server": "BWS Multi-Site Server",
"sites": [
{
"name": "main",
"hostname": "localhost",
"port": 8080,
"static_dir": "static",
"url": "http://localhost:8080"
}
],
"total_sites": 4
}
Health Check
- GET /api/health - Returns server health status (available on all sites)
File Content API
- GET /api/file?path=filename - Returns the content of the specified file
Error Handling
- 404 Not Found - Returns JSON error for non-existent endpoints
Getting Started
Prerequisites
- Rust 1.70+ (2021 edition)
- Cargo
Dependencies
pingora- High-performance proxy frameworkasync-trait- Async trait supportserde&serde_json- JSON serializationchrono- Date/time handlingtokio- Async runtimeenv_logger&log- Loggingtoml- Configuration file parsing
Building
Configuration
- Copy and modify
config.tomlto configure your sites - Create static directories for each site (e.g.,
static-blog/,static-api/) - Add HTML, CSS, JS files to each static directory
Running
# Start the multi-site server
RUST_LOG=info
The server will start multiple services based on your configuration.
Testing Multiple Sites
# Run comprehensive multi-site test
# Test configurable headers functionality
# Test reverse proxy and load balancing
# Test individual sites
# Test with virtual host headers
# Check sites configuration (includes header and proxy config)
# Test site-specific headers
# Test reverse proxy functionality
Virtual Host Setup (Optional)
Add entries to /etc/hosts for easier testing:
127.0.0.1 blog.localhost
127.0.0.1 api.localhost
Then access sites via:
Project Structure
├── src/
│ ├── bin/
│ │ └── main.rs # Server entry point and multi-site setup
│ ├── config/
│ │ └── site.rs # Site and proxy configuration structures
│ ├── handlers/
│ │ ├── proxy_handler.rs # Reverse proxy and load balancing implementation
│ │ └── static_handler.rs # Static file serving
│ ├── server/
│ │ ├── service.rs # Main web server service with proxy integration
│ │ └── middleware.rs # Request middleware and processing
│ ├── ssl/
│ │ ├── acme.rs # ACME certificate management
│ │ └── certificate.rs # SSL certificate handling
│ └── lib.rs # Library root with all modules
├── docs/
│ ├── load-balancing.md # Comprehensive load balancing documentation
│ └── reverse-proxy.md # Reverse proxy configuration guide
├── static/ # Main site files
│ ├── index.html # Main homepage
│ ├── about.html # About page
│ ├── contact.html # Contact page
│ ├── styles.css # Website styles
│ └── script.js # Website JavaScript
├── static-blog/ # Blog site files
│ └── index.html # Blog homepage
├── static-api/ # API documentation site
│ └── index.html # API docs homepage
├── tests/ # Test scripts and configurations
│ ├── test_multisite.sh # Multi-site test script
│ ├── test_headers.sh # Configurable headers test script
│ ├── test_load_balance.sh # Load balancing test script
│ ├── test_static_server.sh # Static website test script
│ ├── test_websocket_proxy.sh # WebSocket proxy test script
│ ├── test_websocket_client.py # WebSocket client test
│ ├── test_websocket_full.py # Full WebSocket test suite
│ ├── test_ws_upstream.py # WebSocket upstream server
│ ├── test_load_balancing.toml # Load balancing test configuration
│ ├── test_proxy_config.toml # Basic proxy test configuration
│ ├── test_websocket_config.toml # WebSocket proxy test configuration
│ └── config_test.toml # General test configuration
├── config.toml # Multi-site configuration with headers
└── README.md # This file
API Implementation Details
WebServerService
The main service implements the ProxyHttp trait from Pingora:
request_filter(): Routes incoming requests to appropriate handlersupstream_peer(): Returns error since we handle requests locally
Request Routing
The server intelligently routes requests based on URL patterns:
/→static/index.html/static/*→ Static assets with cache headers/*.html→ HTML files from static directory/api/*→ API endpoints- Everything else → 404 error
Request Handlers
handle_static_file(): Serves static files with proper MIME types and cache headershandle_health(): Returns JSON health statushandle_file_content(): Reads and returns file contentshandle_404(): Returns JSON error for unknown endpoints
Static File Features
- MIME Type Detection: Automatic content-type detection for:
- HTML, CSS, JavaScript
- Images (PNG, JPEG, GIF, SVG, ICO)
- Fonts (WOFF, WOFF2, TTF)
- Documents (PDF, XML, TXT)
- Cache Headers:
Cache-Control: public, max-age=3600for static assets - Error Handling: Graceful 404 responses for missing files
Features
- Content-Type Headers: Proper MIME types for all file types
- Content-Length: Accurate response size calculation
- Error Handling: Graceful error responses with helpful messages
- Query Parameter Parsing: Manual parsing for file path parameter
- Logging: Request logging with method and URI
Extending the Server
Adding New Static Endpoints
To add new static endpoints:
- Add a new pattern match in
request_filter() - Create a new handler method following the pattern of existing handlers
- Ensure proper error handling and response headers
Example:
"/api/new-endpoint" =>
Adding Reverse Proxy Features
BWS includes a comprehensive reverse proxy system. Key components:
- ProxyHandler: Main proxy logic with load balancing
- Load Balancing: Three algorithms (round-robin, weighted, least-connections)
- Connection Tracking: Atomic counters for least-connections algorithm
- Header Management: X-Forwarded-* and custom header support
- Path Transformation: URL rewriting and prefix stripping
- Error Handling: Graceful fallback and timeout handling
To extend proxy functionality:
- Modify
ProxyHandlerinsrc/handlers/proxy_handler.rs - Add new load balancing algorithms in the
select_*methods - Extend configuration in
src/config/site.rs - Update routing logic in
src/server/service.rs
Performance Characteristics
- Memory Efficient: Uses
Vec<u8>for response bodies to avoid borrowing issues - Async: Fully asynchronous request handling
- Zero-Copy: Efficient byte handling where possible
- Concurrent: Supports multiple simultaneous connections
Security Considerations
- File reading is currently unrestricted - consider adding path validation
- No authentication/authorization implemented
- Consider rate limiting for production use
- HTTPS support can be added through Pingora configuration
Security Status
The project uses automated security scanning via GitHub Actions. The current security status:
- ✅ Active Monitoring: Weekly security audits via
cargo audit - ✅ Dependency Review: Automated dependency review on pull requests
- ⚠️ Known Issue: One accepted vulnerability (RUSTSEC-2024-0437) - see
SECURITY.md
Security Documentation: See SECURITY.md for detailed security status and known issues.
Monitoring Script: Run ./scripts/monitor-deps.sh to check for dependency updates and security status.
Security Workflow: The CI pipeline automatically scans for new vulnerabilities while ignoring documented accepted risks.
📦 Publishing & Releases
BWS uses automated publishing to multiple platforms:
Automated Release Process
When you create a new version tag (e.g., v0.1.3), GitHub Actions automatically:
- 📦 Publishes to crates.io - Available via
cargo install bws-web-server - 🏗️ Builds cross-platform binaries - Linux, macOS, Windows
- 🐳 Publishes Docker images - To GitHub Container Registry
- 📝 Creates GitHub Release - With downloadable assets
Publishing to crates.io
Setup Required (one-time):
- Get API token from crates.io → Account Settings → API Tokens
- Add token as repository secret:
CARGO_REGISTRY_TOKEN
To publish a new version:
# 1. Update version in Cargo.toml
# 2. Commit and tag
Manual Publishing (if needed):
- Go to Actions → Publish to crates.io workflow
- Click Run workflow and choose dry-run option for testing
Release Artifacts
Each release includes:
- 📦 crates.io package -
cargo install bws-web-server - 🐧 Linux binaries - x86_64 (glibc + musl)
- 🍎 macOS binaries - x86_64 + ARM64 (Apple Silicon)
- 🪟 Windows binaries - x86_64 (no daemon support)
- 🐳 Docker images - Multi-arch (amd64/arm64)
For detailed setup instructions, see PUBLISHING.md.