BWS (Ben's Web Server)
A high-performance, multi-site web server built with Pingora, Cloudflare's battle-tested proxy framework.
🚀 Features
- Multi-Site Support: Host multiple websites on different ports with individual configurations
- Configurable Headers: Set custom HTTP headers per site via TOML configuration
- High Performance: Built on Pingora for enterprise-grade performance and reliability
- Health Monitoring: Built-in health check endpoints for monitoring
- Security Focused: Comprehensive security auditing and dependency management
- Easy Configuration: Simple TOML-based configuration system
📦 Installation
From crates.io
From Docker (Recommended for Production)
# Pull and run the latest version
From Source
🔧 Quick Start
- Create a configuration file (
bws_config.toml):
[]
= "BWS Multi-Site Server"
[[]]
= "main"
= "localhost"
= 8080
= "static"
= true
[]
= "BWS Main Site"
= "BWS/1.0"
= "main"
[[]]
= "api"
= "api.localhost"
= 8081
= "static-api"
= true
[]
= "v1"
= "api"
- Create static directories and files:
# Create directories for each site
# Add content to main site
# Add content to API site
- Run the server:
# Run with default config.toml
# Specify a custom config file
# Enable verbose logging
# Show help
# Show version
- Test your setup:
# Test main site
# Test API site
# Health check
💻 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
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 individual sites
# Test with virtual host headers
# Check sites configuration (includes header config)
# Test site-specific headers
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
│ └── lib.rs # Web server implementation with config support
├── 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
├── static-dev/ # Development site files
│ └── index.html # Dev homepage
├── config.toml # Multi-site configuration with headers
├── Cargo.toml # Project dependencies
├── test_multisite.sh # Multi-site test script
├── test_headers.sh # Configurable headers test script
├── test_static_server.sh # Static website test script
└── 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
To add new 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" =>
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.