Keyboard shortcuts

Press โ† or โ†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Installation

BWS can be installed in several ways. Choose the method that best fits your needs.

The easiest way to install BWS is using Cargo:

cargo install bws-web-server

This will install the latest stable version from crates.io. The package name is bws-web-server, but the installed binary is named bws.

Prerequisites

  • Rust: Version 1.70 or later
  • Cargo: Comes with Rust installation

Docker is the recommended deployment method for production environments:

# Pull and run the latest version
docker run -d -p 8080:8080 ghcr.io/benliao/bws:latest

# Or with custom configuration
docker run -d \
  -p 8080:8080 \
  -v $(pwd)/config.toml:/app/config.toml:ro \
  -v $(pwd)/static:/app/static:ro \
  ghcr.io/benliao/bws:latest

Available Docker Tags

  • latest - Latest stable release
  • v0.1.5 - Specific version (recommended for production)
  • main - Latest development build

From Source

For development or custom builds:

# Clone the repository
git clone https://github.com/benliao/bws.git
cd bws

# Build in debug mode
cargo build

# Build optimized release
cargo build --release

# The binary will be in target/release/bws

Pre-built Binaries

Download pre-built binaries from GitHub Releases:

Linux (x86_64)

wget https://github.com/benliao/bws/releases/latest/download/bws-linux-x86_64.tar.gz
tar -xzf bws-linux-x86_64.tar.gz
chmod +x bws

macOS (x86_64)

wget https://github.com/benliao/bws/releases/latest/download/bws-macos-x86_64.tar.gz
tar -xzf bws-macos-x86_64.tar.gz
chmod +x bws

macOS (ARM64/Apple Silicon)

wget https://github.com/benliao/bws/releases/latest/download/bws-macos-aarch64.tar.gz
tar -xzf bws-macos-aarch64.tar.gz
chmod +x bws

Windows (x86_64)

wget https://github.com/benliao/bws/releases/latest/download/bws-windows-x86_64.exe
# Note: Windows executable is directly usable

Verification

After installation, verify BWS is working:

# Check version
bws --version

# Display help
bws --help

Next Steps

Once installed, proceed to the Quick Start guide to set up your first BWS server!

Quick Start

Get BWS up and running in just a few minutes with both HTTP and HTTPS sites!

1. Create Configuration

Create a config.toml file with both HTTP and HTTPS sites:

[server]
name = "BWS Multi-Site Server"

# HTTP site
[[sites]]
name = "main"
hostname = "localhost"
port = 8080
static_dir = "static"
default = true

[sites.ssl]
enabled = false

[sites.headers]
"X-Site-Name" = "BWS Main Site"
"X-Powered-By" = "BWS/1.0"

# HTTPS site with automatic SSL
[[sites]]
name = "secure"
hostname = "secure.localhost"
port = 8443
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["secure.localhost", "ssl.localhost"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = true  # Use staging for testing
challenge_dir = "./acme-challenges"

[sites.headers]
"X-Site-Name" = "BWS Secure Site"
"X-Powered-By" = "BWS/1.0"
"Strict-Transport-Security" = "max-age=31536000"

2. Create Static Content

Create your static directory and add some content:

# Create directories
mkdir -p static acme-challenges

# Create a simple index.html
cat > static/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>Welcome to BWS</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        h1 { color: #333; }
        .secure { color: #28a745; }
    </style>
</head>
<body>
    <h1>๐Ÿš€ Welcome to BWS!</h1>
    <p>Your multi-site web server is running!</p>
    
    <h2>Available Sites:</h2>
    <ul>
        <li><a href="http://localhost:8080">Main Site (HTTP)</a></li>
        <li><a href="https://secure.localhost:8443" class="secure">Secure Site (HTTPS)</a></li>
    </ul>
    
    <h2>API Endpoints:</h2>
    <ul>
        <li><a href="/api/health">Health Check</a></li>
        <li><a href="/api/sites">Sites Info</a></li>
    </ul>
</body>
</html>
EOF

3. Run the Server

Start BWS with your configuration:

# Using cargo install
bws --config config.toml

# Using Docker
docker run -d \
  -p 8080:8080 \
  -v $(pwd)/config.toml:/app/config.toml:ro \
  -v $(pwd)/static:/app/static:ro \
  ghcr.io/benliao/bws:latest

# From source
cargo run -- --config config.toml

4. Test Your Server

Open your browser or use curl to test both HTTP and HTTPS sites:

# Main HTTP site
curl http://localhost:8080/

# Health check
curl http://localhost:8080/api/health

# Sites information
curl http://localhost:8080/api/sites

# Test HTTPS site (may need to add hostname to /etc/hosts)
curl -k https://secure.localhost:8443/

# Check SSL certificate (if ACME is working)
openssl s_client -connect localhost:8443 -servername secure.localhost

Setting up hostname resolution

For testing HTTPS sites with custom hostnames, add entries to /etc/hosts:

# Add to /etc/hosts
echo "127.0.0.1 secure.localhost" | sudo tee -a /etc/hosts
echo "127.0.0.1 ssl.localhost" | sudo tee -a /etc/hosts

ACME Certificate Notes

  • The example uses staging = true for Let's Encrypt staging environment
  • Staging certificates are not trusted by browsers but are good for testing
  • For production, set staging = false after testing
  • ACME certificates require your domain to be publicly accessible

You should see:

  • Your custom HTML page at http://localhost:8080/
  • Health status at http://localhost:8080/api/health
  • Site configuration at http://localhost:8080/api/sites
  • SSL-secured content at https://secure.localhost:8443/ (if configured)

5. Add WebSocket Proxy (Optional)

BWS can also proxy WebSocket connections with load balancing. Here's a simple example:

# Add to your existing configuration
[[sites]]
name = "websocket-proxy"
hostname = "ws.localhost"
port = 8090
static_dir = "static"

[sites.proxy]
enabled = true

# WebSocket upstream servers
[[sites.proxy.upstreams]]
name = "websocket_backend"
url = "http://localhost:3001"  # Will be converted to ws://localhost:3001
weight = 1

[[sites.proxy.upstreams]]
name = "websocket_backend"
url = "http://localhost:3002"  # Will be converted to ws://localhost:3002
weight = 1

# WebSocket routes
[[sites.proxy.routes]]
path = "/ws"
upstream = "websocket_backend"
strip_prefix = true
websocket = true  # Enable WebSocket proxying

# Load balancing for WebSocket connections
[sites.proxy.load_balancing]
method = "round_robin"

Test WebSocket proxying:

# Start simple WebSocket test servers (if you have Node.js)
npx ws ws://localhost:3001 &
npx ws ws://localhost:3002 &

# Connect through BWS proxy
# WebSocket connections to ws://ws.localhost:8090/ws will be load-balanced

7. Add More Sites (Optional)

Extend your configuration to host multiple sites with different SSL configurations:

[server]
name = "BWS Multi-Site Server"

# Main HTTP site
[[sites]]
name = "main"
hostname = "localhost"
port = 8080
static_dir = "static"
default = true

[sites.ssl]
enabled = false

[sites.headers]
"X-Site-Name" = "BWS Main Site"

# Blog site with auto SSL
[[sites]]
name = "blog"
hostname = "blog.localhost"
port = 8443
static_dir = "static-blog"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["blog.localhost"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = true
challenge_dir = "./acme-challenges"

[sites.headers]
"X-Site-Name" = "BWS Blog"
"X-Content-Type" = "blog-content"
"Strict-Transport-Security" = "max-age=31536000"

# API documentation with manual SSL
[[sites]]
name = "docs"
hostname = "docs.localhost"
port = 8444
static_dir = "static-docs"

[sites.ssl]
enabled = true
auto_cert = false
cert_file = "./certs/docs.localhost.crt"
key_file = "./certs/docs.localhost.key"

[sites.headers]
"X-Site-Name" = "BWS Documentation"
"Access-Control-Allow-Origin" = "*"
"Strict-Transport-Security" = "max-age=31536000"

Create the corresponding directories and certificates:

# Create directories
mkdir static-blog static-docs certs

# Add content
echo "<h1>Blog Site (HTTPS)</h1>" > static-blog/index.html
echo "<h1>Documentation Site (HTTPS)</h1>" > static-docs/index.html

# Generate self-signed certificate for docs site
openssl req -x509 -newkey rsa:4096 -keyout certs/docs.localhost.key -out certs/docs.localhost.crt -days 365 -nodes -subj "/CN=docs.localhost"
chmod 600 certs/docs.localhost.key

Restart BWS and access:

  • Main site: http://localhost:8080
  • Blog: https://blog.localhost:8443 (auto SSL)
  • Docs: https://docs.localhost:8444 (manual SSL)

Command Line Options

BWS supports several command line options:

# Specify config file
bws --config /path/to/config.toml

# Enable verbose logging
bws --verbose

# Run as daemon (Unix only)
bws --daemon

# Custom PID and log files for daemon mode
bws --daemon \
  --pid-file /var/run/bws.pid \
  --log-file /var/log/bws.log

Next Steps

Configuration

BWS uses TOML configuration files to define server behavior and site settings.

Configuration File Lkey_file = "./certs/manual.crt"


### Reverse Proxy Configuration

Each site can be configured as a reverse proxy with load balancing:

| Field | Type | Description | Default |
|-------|------|-------------|---------|
| `proxy.enabled` | Boolean | Enable reverse proxy for this site | `false` |
| `proxy.upstreams` | Array | Backend servers for proxying | `[]` |
| `proxy.upstreams.name` | String | Upstream group name | Required |
| `proxy.upstreams.url` | String | Backend server URL | Required |
| `proxy.upstreams.weight` | Integer | Server weight for load balancing | `1` |
| `proxy.routes` | Array | Proxy route configurations | `[]` |
| `proxy.routes.path` | String | Path pattern to match | Required |
| `proxy.routes.upstream` | String | Upstream group to proxy to | Required |
| `proxy.routes.strip_prefix` | Boolean | Remove path prefix when forwarding | `false` |
| `proxy.routes.websocket` | Boolean | Enable WebSocket proxying for this route | `false` |
| `proxy.load_balancing.method` | String | Load balancing algorithm | `"round_robin"` |
| `proxy.timeout.read` | Integer | Read timeout in seconds | `30` |
| `proxy.timeout.write` | Integer | Write timeout in seconds | `30` |
| `proxy.headers.add_x_forwarded` | Boolean | Add X-Forwarded-* headers | `true` |
| `proxy.headers.add_forwarded` | Boolean | Add Forwarded header | `true` |
| `proxy.headers.add` | Table | Custom headers to add | `{}` |
| `proxy.headers.remove` | Table | Headers to remove | `{}` |

### Example Proxy Configuration

```toml
# Reverse proxy site with load balancing
[[sites]]
name = "api"
hostname = "api.example.com"
port = 80

[sites.proxy]
enabled = true

# Multiple backend servers (same name for load balancing)
[[sites.proxy.upstreams]]
name = "api-servers"
url = "http://127.0.0.1:3001"
weight = 2

[[sites.proxy.upstreams]]
name = "api-servers"
url = "http://127.0.0.1:3002"
weight = 1

# Route configuration
[[sites.proxy.routes]]
path = "/v1/"
upstream = "api-servers"
strip_prefix = false

# Load balancing method (round_robin, weighted, least_connections)
[sites.proxy.load_balancing]
method = "weighted"

# Timeout configuration
[sites.proxy.timeout]
read = 30
write = 30

# Header management
[sites.proxy.headers]
add_x_forwarded = true
add_forwarded = true

[sites.proxy.headers.add]
"X-Proxy-Version" = "BWS/1.0"

[sites.proxy.headers.remove]
"X-Internal-Token" = true

key_file = "./certs/manual.key"ation

By default, BWS looks for config.toml in the current directory. You can specify a different location:

bws --config /path/to/your/config.toml

Basic Configuration Structure

[server]
name = "BWS Multi-Site Server"

[[sites]]
name = "example"
hostname = "localhost"
port = 8080
static_dir = "static"
default = true

[sites.headers]
"X-Custom-Header" = "value"

Server Section

The [server] section contains global server settings:

FieldTypeDescriptionDefault
nameStringServer identification name"BWS Server"
[server]
name = "My Production BWS Server"

Sites Configuration

Sites are defined using [[sites]] array tables. Each site represents a separate web service with its own SSL configuration.

Required Fields

FieldTypeDescription
nameStringUnique identifier for the site
hostnameStringHostname to bind to
portIntegerPort number to listen on
static_dirStringDirectory containing static files

Optional Fields

FieldTypeDescriptionDefault
defaultBooleanWhether this is the default sitefalse
api_onlyBooleanOnly serve API endpoints, no static filesfalse

SSL Configuration

Each site can have its own SSL/TLS configuration:

FieldTypeDescriptionDefault
ssl.enabledBooleanEnable SSL for this sitefalse
ssl.auto_certBooleanUse automatic certificates (ACME)false
ssl.domainsArrayAdditional domains for the certificate[]
ssl.cert_fileStringPath to certificate file (manual SSL)null
ssl.key_fileStringPath to private key file (manual SSL)null
ssl.acme.enabledBooleanEnable ACME certificate generationfalse
ssl.acme.emailStringEmail for ACME registrationnull
ssl.acme.stagingBooleanUse staging environmentfalse
ssl.acme.challenge_dirStringDirectory for ACME challenges"./acme-challenges"

Example Site Configuration

# HTTP Site
[[sites]]
name = "main"
hostname = "localhost"
port = 8080
static_dir = "static"
default = true

[sites.ssl]
enabled = false

# HTTPS Site with Auto SSL
[[sites]]
name = "secure"
hostname = "secure.localhost"
port = 8443
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["secure.localhost", "ssl.localhost"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

# HTTPS Site with Manual SSL
[[sites]]
name = "manual_ssl"
hostname = "manual.localhost"
port = 8444
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = false
cert_file = "./certs/manual.crt"
key_file = "./certs/manual.key"

Complete Example

Here's a comprehensive configuration example with SSL:

[server]
name = "BWS Production Server"

# Main website with HTTP
[[sites]]
name = "main"
hostname = "example.com"
port = 80
static_dir = "static"
default = true

[sites.ssl]
enabled = false

[sites.headers]
"X-Site-Name" = "Main Website"
"X-Powered-By" = "BWS/1.0"

# Main website with HTTPS (automatic SSL)
[[sites]]
name = "main_https"
hostname = "example.com"
port = 443
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["example.com", "www.example.com"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

[sites.headers]
"X-Site-Name" = "Main Website (HTTPS)"
"X-Powered-By" = "BWS/1.0"
"Strict-Transport-Security" = "max-age=31536000"

# Blog subdomain with manual SSL
[[sites]]
name = "blog"
hostname = "blog.example.com"
port = 443
static_dir = "blog-static"

[sites.ssl]
enabled = true
auto_cert = false
cert_file = "/etc/ssl/certs/blog.example.com.crt"
key_file = "/etc/ssl/private/blog.example.com.key"

[sites.headers]
"X-Site-Name" = "Blog"
"X-Content-Type" = "blog-content"
"Strict-Transport-Security" = "max-age=31536000"

Next Steps

Multi-Site Setup

BWS excels at hosting multiple websites on different ports with individual configurations. This guide shows you how to set up and manage multiple sites.

Basic Multi-Site Configuration

Here's a complete example with four different sites including SSL configurations:

[server]
name = "BWS Multi-Site Server"

# Main website (HTTP)
[[sites]]
name = "main"
hostname = "localhost"
port = 8080
static_dir = "static"
default = true

[sites.ssl]
enabled = false

[sites.headers]
"X-Site-Name" = "Main Website"
"X-Powered-By" = "BWS/1.0"
"X-Environment" = "production"

# Blog subdomain (HTTPS with auto SSL)
[[sites]]
name = "blog"
hostname = "blog.localhost"
port = 8443
static_dir = "static-blog"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["blog.localhost", "www.blog.localhost"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

[sites.headers]
"X-Site-Name" = "Blog"
"X-Content-Type" = "blog-content"
"X-Author" = "BWS Team"
"Strict-Transport-Security" = "max-age=31536000"

# API documentation (HTTPS with manual SSL)
[[sites]]
name = "docs"
hostname = "docs.localhost"
port = 8444
static_dir = "static-docs"

[sites.ssl]
enabled = true
auto_cert = false
cert_file = "./certs/docs.localhost.crt"
key_file = "./certs/docs.localhost.key"

[sites.headers]
"X-Site-Name" = "API Documentation"
"Access-Control-Allow-Origin" = "*"
"Access-Control-Allow-Methods" = "GET, OPTIONS"
"Strict-Transport-Security" = "max-age=31536000"

# Development environment (HTTP)
[[sites]]
name = "dev"
hostname = "localhost"
port = 8083
static_dir = "static-dev"

[sites.ssl]
enabled = false

[sites.headers]
"X-Site-Name" = "Development Environment"
"X-Environment" = "development"
"X-Debug-Mode" = "enabled"

Directory Structure

Create the corresponding directory structure including SSL certificate directories:

mkdir -p static static-blog static-docs static-dev acme-challenges certs

# Main site
cat > static/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head><title>Main Site</title></head>
<body>
    <h1>๐ŸŒ Main Website</h1>
    <p>Welcome to the main BWS site!</p>
    <nav>
        <a href="https://blog.localhost:8443">Blog (HTTPS)</a> |
        <a href="https://docs.localhost:8444">Docs (HTTPS)</a> |
        <a href="http://localhost:8083">Dev (HTTP)</a>
    </nav>
</body>
</html>
EOF

# Blog site
cat > static-blog/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head><title>BWS Blog</title></head>
<body>
    <h1>๐Ÿ“ BWS Blog (HTTPS)</h1>
    <p>Latest news and updates - Secured with SSL</p>
    <article>
        <h2>Welcome to BWS Blog</h2>
        <p>This is our blog powered by BWS multi-site hosting with automatic SSL.</p>
    </article>
</body>
</html>
EOF

# Documentation site
cat > static-docs/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head><title>BWS Documentation</title></head>
<body>
    <h1>๐Ÿ“š BWS Documentation (HTTPS)</h1>
    <p>Complete API and user documentation - Secured with manual SSL</p>
    <ul>
        <li><a href="/api/health">Health Check</a></li>
        <li><a href="/api/sites">Sites Info</a></li>
    </ul>
</body>
</html>
EOF

# Development site
cat > static-dev/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head><title>BWS Development</title></head>
<body>
    <h1>๐Ÿšง BWS Development</h1>
    <p>Development and testing environment (HTTP only)</p>
    <p><strong>Debug Mode:</strong> Enabled</p>
</body>
</html>
EOF

Site Types

Default Site

One site should be marked as default = true. This site handles requests that don't match other hostnames:

[[sites]]
name = "main"
hostname = "localhost"
port = 8080
static_dir = "static"
default = true  # This is the default site

[sites.ssl]
enabled = false

HTTPS Sites

Sites can be configured with SSL/TLS for secure connections:

# Automatic SSL with ACME (Let's Encrypt)
[[sites]]
name = "secure_auto"
hostname = "secure.example.com"
port = 443
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["secure.example.com", "www.secure.example.com"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

# Manual SSL certificates
[[sites]]
name = "secure_manual"
hostname = "manual.example.com"
port = 443
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = false
cert_file = "/etc/ssl/certs/manual.example.com.crt"
key_file = "/etc/ssl/private/manual.example.com.key"

API-Only Sites

For sites that only serve API endpoints without static files:

[[sites]]
name = "api"
hostname = "api.localhost"
port = 8084
static_dir = "api-static"
api_only = true  # Only serve /api/* endpoints

[sites.ssl]
enabled = true
auto_cert = true
domains = ["api.localhost"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

[sites.headers]
"Access-Control-Allow-Origin" = "*"
"Content-Type" = "application/json"

Hostname Patterns

BWS supports various hostname patterns:

# Localhost with different ports
[[sites]]
hostname = "localhost"
port = 8080

# Subdomain
[[sites]]
hostname = "blog.example.com"
port = 8081

# Different domain
[[sites]]
hostname = "api.myservice.com"
port = 8082

# IP address
[[sites]]
hostname = "192.168.1.100"
port = 8083

Load Balancing

You can run multiple BWS instances and use a load balancer:

# nginx.conf
upstream bws_main {
    server localhost:8080;
    server localhost:8090;  # Second BWS instance
}

upstream bws_blog {
    server localhost:8081;
    server localhost:8091;  # Second BWS instance
}

server {
    listen 80;
    server_name example.com;
    location / {
        proxy_pass http://bws_main;
    }
}

server {
    listen 80;
    server_name blog.example.com;
    location / {
        proxy_pass http://bws_blog;
    }
}

Testing Multi-Site Setup

  1. Start BWS:
bws --config config.toml
  1. Test each site:
# HTTP Main site
curl http://localhost:8080/

# HTTPS Blog (requires host header or /etc/hosts entry)
curl -k -H "Host: blog.localhost" https://localhost:8443/

# HTTPS Docs (manual SSL)
curl -k -H "Host: docs.localhost" https://localhost:8444/

# HTTP Dev site
curl http://localhost:8083/
  1. Check SSL certificates:
# Check auto SSL certificate
openssl s_client -connect localhost:8443 -servername blog.localhost

# Check manual SSL certificate
openssl s_client -connect localhost:8444 -servername docs.localhost
  1. Check site information:
curl http://localhost:8080/api/sites

Best Practices

Port Management

  • Use sequential ports for easy management
  • Document port assignments
  • Avoid common service ports (22, 80, 443, etc.)

Directory Organization

project/
โ”œโ”€โ”€ config.toml
โ”œโ”€โ”€ static/           # Main site
โ”œโ”€โ”€ static-blog/      # Blog content
โ”œโ”€โ”€ static-docs/      # Documentation
โ”œโ”€โ”€ static-api/       # API documentation
โ””โ”€โ”€ shared-assets/    # Common files (CSS, JS, images)

Security Considerations

  • Use different headers for different environments
  • Implement CORS properly for API sites
  • Consider IP restrictions for development sites

Monitoring

Each site can be monitored independently:

# Check health of each site
curl http://localhost:8080/api/health
curl http://localhost:8081/api/health
curl http://localhost:8082/api/health

Troubleshooting

Port Conflicts

# Check if port is in use
lsof -i :8080

# Kill process using port
kill $(lsof -t -i:8080)

Hostname Resolution

Add entries to /etc/hosts for testing:

127.0.0.1 blog.localhost
127.0.0.1 docs.localhost
127.0.0.1 api.localhost

Then access sites via:

  • http://localhost:8080 (HTTP main site)
  • https://blog.localhost:8443 (HTTPS blog with auto SSL)
  • https://docs.localhost:8444 (HTTPS docs with manual SSL)

SSL Certificate Setup

For manual SSL sites, generate test certificates:

# Create certificate directory
mkdir -p certs

# Generate self-signed certificate for docs.localhost
openssl req -x509 -newkey rsa:4096 -keyout certs/docs.localhost.key -out certs/docs.localhost.crt -days 365 -nodes -subj "/CN=docs.localhost"

# Set proper permissions
chmod 600 certs/docs.localhost.key
chmod 644 certs/docs.localhost.crt

Configuration Validation

BWS validates configuration on startup:

  • Duplicate site names โ†’ Error
  • Port conflicts โ†’ Error
  • Missing directories โ†’ Warning (created automatically)
  • Invalid hostnames โ†’ Error

Next Steps

SSL/TLS Configuration

BWS provides robust, production-ready SSL/TLS support with automatic certificate management, comprehensive error handling, and thread-safe operations. Each site can have its own HTTPS configuration, enabling mixed HTTP/HTTPS deployments with different certificates per domain.

Overview

BWS supports two types of SSL/TLS configuration:

  1. Automatic SSL Certificates - Using ACME (Let's Encrypt) with automatic renewal monitoring
  2. Manual SSL Certificates - Using your own SSL certificate files

Production-Ready Features

  • Automatic Certificate Renewal: Background monitoring service checks and renews certificates
  • Thread-Safe Operations: All SSL operations are safe for concurrent access
  • Comprehensive Error Handling: Graceful error propagation with detailed logging
  • Zero-Downtime Renewal: Certificates renewed without service interruption
  • Robust Monitoring: Certificate expiration tracking and proactive renewal

Automatic SSL Certificates (ACME)

Basic ACME Configuration

[[sites]]
name = "auto_ssl_site"
hostname = "example.com"
port = 443
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["example.com", "www.example.com"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

ACME Configuration Options

FieldTypeDescriptionDefault
enabledBooleanEnable ACME certificate generationfalse
emailStringEmail address for ACME registrationRequired
stagingBooleanUse Let's Encrypt staging environmentfalse
challenge_dirStringDirectory for ACME HTTP-01 challenges"./acme-challenges"

ACME Challenge Handling

BWS automatically handles ACME HTTP-01 challenges with robust error handling:

  1. Challenge Directory: Configure challenge_dir where ACME challenges will be served
  2. Automatic Routing: BWS automatically serves files from /.well-known/acme-challenge/
  3. Directory Creation: The challenge directory is created automatically if it doesn't exist
  4. Error Handling: Comprehensive error reporting for challenge failures
# Create challenge directory
mkdir -p ./acme-challenges

# BWS will automatically serve challenges from:
# http://yourdomain.com/.well-known/acme-challenge/TOKEN

Automatic Certificate Renewal

BWS includes a production-ready certificate monitoring system:

#![allow(unused)]
fn main() {
// Background service automatically monitors certificates
// - Checks certificate expiration every hour
// - Renews certificates when needed (before 30 days expiration)
// - Handles renewal failures gracefully with logging
// - Thread-safe operations prevent race conditions
}

Renewal Features:

  • Automatic Monitoring: Background service checks certificates hourly
  • Proactive Renewal: Renews certificates 30 days before expiration
  • Error Recovery: Comprehensive error handling with detailed logging
  • Zero Downtime: Renewals happen without service interruption
  • Thread Safety: All operations are safe for concurrent access

Production vs Staging

Staging Environment (staging = true):

  • Use for testing and development
  • Higher rate limits
  • Certificates are not trusted by browsers
  • Recommended for initial setup

Production Environment (staging = false):

  • Use for live websites
  • Lower rate limits (5 certificates per domain per week)
  • Certificates are trusted by browsers
  • Use only after testing with staging
# Testing configuration
[sites.ssl.acme]
enabled = true
email = "test@example.com"
staging = true  # Use staging environment
challenge_dir = "./acme-challenges"

# Production configuration
[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false  # Use production environment
challenge_dir = "./acme-challenges"

Manual SSL Certificates

Basic Manual SSL Configuration

[[sites]]
name = "manual_ssl_site"
hostname = "secure.example.com"
port = 443
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = false
cert_file = "/etc/ssl/certs/secure.example.com.crt"
key_file = "/etc/ssl/private/secure.example.com.key"

Certificate File Requirements

Certificate File (cert_file):

  • Must contain the SSL certificate in PEM format
  • Can include intermediate certificates (certificate chain)
  • File must be readable by the BWS process

Private Key File (key_file):

  • Must contain the private key in PEM format
  • Should be protected with appropriate file permissions (600)
  • Must correspond to the certificate

Certificate Generation

You can generate certificates using various methods:

Self-Signed Certificates (Development)

# Generate private key
openssl genrsa -out server.key 2048

# Generate certificate
openssl req -new -x509 -key server.key -out server.crt -days 365 -subj "/CN=localhost"

# Use in configuration
[sites.ssl]
enabled = true
auto_cert = false
cert_file = "./server.crt"
key_file = "./server.key"

Commercial SSL Certificates

# Generate private key
openssl genrsa -out example.com.key 2048

# Generate certificate signing request
openssl req -new -key example.com.key -out example.com.csr

# Submit CSR to certificate authority
# Download certificate and intermediate certificates

# Combine certificate with intermediate certificates
cat example.com.crt intermediate.crt > example.com-chain.crt

# Use in configuration
[sites.ssl]
enabled = true
auto_cert = false
cert_file = "/etc/ssl/certs/example.com-chain.crt"
key_file = "/etc/ssl/private/example.com.key"

Per-Site SSL Configuration

Configuration Structure

Each site has its own SSL configuration section:

[[sites]]
name = "site_name"
hostname = "example.com"
port = 443
static_dir = "static"

[sites.ssl]
enabled = true           # Enable SSL for this site
auto_cert = true         # Use automatic certificates
domains = ["example.com", "www.example.com"]  # Additional domains
cert_file = "path/to/cert.pem"    # Manual certificate file
key_file = "path/to/key.pem"      # Manual private key file

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

SSL Configuration Options

FieldTypeDescriptionRequired
enabledBooleanEnable SSL for this siteYes
auto_certBooleanUse ACME for automatic certificatesYes
domainsArrayAdditional domains for the certificateNo
cert_fileStringPath to certificate file (manual SSL)If auto_cert = false
key_fileStringPath to private key file (manual SSL)If auto_cert = false

Multi-Site SSL Examples

Mixed HTTP and HTTPS Sites

[server]
name = "Mixed Protocol Server"

# HTTP site on port 80
[[sites]]
name = "http_site"
hostname = "example.com"
port = 80
static_dir = "static"

[sites.ssl]
enabled = false

# HTTPS site on port 443 with auto SSL
[[sites]]
name = "https_site"
hostname = "example.com"
port = 443
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["example.com", "www.example.com"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

# API site with manual SSL
[[sites]]
name = "api_site"
hostname = "api.example.com"
port = 8443
static_dir = "api-static"

[sites.ssl]
enabled = true
auto_cert = false
cert_file = "/etc/ssl/certs/api.example.com.crt"
key_file = "/etc/ssl/private/api.example.com.key"

Different SSL Configurations per Site

# Main website with Let's Encrypt
[[sites]]
name = "main"
hostname = "example.com"
port = 443
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["example.com", "www.example.com"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

# Corporate subdomain with commercial certificate
[[sites]]
name = "corporate"
hostname = "corp.example.com"
port = 443
static_dir = "corp-static"

[sites.ssl]
enabled = true
auto_cert = false
cert_file = "/etc/ssl/certs/corp.example.com.crt"
key_file = "/etc/ssl/private/corp.example.com.key"

# Development site without SSL
[[sites]]
name = "dev"
hostname = "dev.example.com"
port = 8080
static_dir = "dev-static"

[sites.ssl]
enabled = false

Security Best Practices

File Permissions

Ensure proper file permissions for SSL files:

# Certificate files can be world-readable
chmod 644 /etc/ssl/certs/*.crt

# Private keys should be readable only by the owner
chmod 600 /etc/ssl/private/*.key

# Ensure BWS can read the files
chown bws:bws /etc/ssl/private/*.key

Security Headers

Use security headers with HTTPS sites:

[[sites]]
name = "secure_site"
hostname = "example.com"
port = 443
static_dir = "static"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["example.com"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

[sites.headers]
"Strict-Transport-Security" = "max-age=31536000; includeSubDomains; preload"
"X-Frame-Options" = "DENY"
"X-Content-Type-Options" = "nosniff"
"Referrer-Policy" = "strict-origin-when-cross-origin"
"Content-Security-Policy" = "default-src 'self'; script-src 'self' 'unsafe-inline'"

Certificate Monitoring

Monitor certificate expiration:

# Check certificate expiration
openssl x509 -in /etc/ssl/certs/example.com.crt -noout -dates

# For ACME certificates, BWS handles renewal automatically
# Check ACME certificate status in logs
tail -f /var/log/bws.log | grep -i acme

Troubleshooting

Common Issues

ACME Challenge Failures

# Ensure challenge directory is accessible
[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = true  # Use staging for debugging
challenge_dir = "./acme-challenges"

Check that:

  1. Domain resolves to your server
  2. Port 80 is accessible for HTTP-01 challenges
  3. Challenge directory exists and is writable
  4. No firewall blocking HTTP traffic

Certificate File Errors

# Verify certificate file format
openssl x509 -in cert.pem -text -noout

# Verify private key format
openssl rsa -in key.pem -check

# Check if certificate and key match
openssl x509 -noout -modulus -in cert.pem | openssl md5
openssl rsa -noout -modulus -in key.pem | openssl md5

Port Binding Issues

# Check if port is already in use
sudo lsof -i :443

# Ensure BWS has permission to bind to privileged ports
sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/bws

Debug Mode

Enable verbose logging for SSL debugging:

# Start BWS with verbose logging
RUST_LOG=debug bws --config config.toml --verbose

Validation

Test SSL configuration:

# Test HTTPS connectivity
curl -I https://example.com

# Check SSL certificate
openssl s_client -connect example.com:443 -servername example.com

# Test with specific protocol versions
curl --tlsv1.2 -I https://example.com
curl --tlsv1.3 -I https://example.com

Next Steps

Static File Serving

BWS provides efficient static file serving with automatic MIME type detection, caching headers, and subdirectory support.

How Static File Serving Works

BWS serves files from the static_dir configured for each site:

[[sites]]
name = "main"
hostname = "localhost"
port = 8080
static_dir = "static"  # Files served from this directory

Supported File Types

BWS automatically detects MIME types for common file formats:

Web Files

  • HTML: .html, .htm โ†’ text/html
  • CSS: .css โ†’ text/css
  • JavaScript: .js, .mjs โ†’ application/javascript
  • JSON: .json โ†’ application/json

Images

  • PNG: .png โ†’ image/png
  • JPEG: .jpg, .jpeg โ†’ image/jpeg
  • GIF: .gif โ†’ image/gif
  • SVG: .svg โ†’ image/svg+xml
  • WebP: .webp โ†’ image/webp
  • AVIF: .avif โ†’ image/avif
  • ICO: .ico โ†’ image/x-icon

Fonts

  • WOFF: .woff, .woff2 โ†’ font/woff
  • TTF: .ttf โ†’ font/ttf
  • OTF: .otf โ†’ font/otf
  • EOT: .eot โ†’ application/vnd.ms-fontobject

Media

  • MP4: .mp4 โ†’ video/mp4
  • WebM: .webm โ†’ video/webm
  • MP3: .mp3 โ†’ audio/mpeg
  • WAV: .wav โ†’ audio/wav
  • OGG: .ogg โ†’ audio/ogg

Documents

  • PDF: .pdf โ†’ application/pdf
  • XML: .xml โ†’ application/xml
  • Text: .txt โ†’ text/plain
  • Markdown: .md โ†’ text/markdown

Archives

  • ZIP: .zip โ†’ application/zip
  • Gzip: .gz โ†’ application/gzip
  • Tar: .tar โ†’ application/x-tar

Configuration

  • TOML: .toml โ†’ application/toml
  • YAML: .yaml, .yml โ†’ application/x-yaml

WebAssembly

  • WASM: .wasm โ†’ application/wasm

URL Patterns

BWS handles several URL patterns for static files:

Direct File Access

http://localhost:8080/index.html
http://localhost:8080/styles.css
http://localhost:8080/script.js

Static Directory Prefix

http://localhost:8080/static/css/main.css
http://localhost:8080/static/js/app.js
http://localhost:8080/static/images/logo.png

Subdirectory Support

http://localhost:8080/assets/css/main.css
http://localhost:8080/docs/api.html
http://localhost:8080/images/gallery/photo1.jpg

Index File Handling

BWS automatically serves index.html for directory requests:

http://localhost:8080/           โ†’ static/index.html
http://localhost:8080/docs/      โ†’ static/docs/index.html
http://localhost:8080/blog/      โ†’ static/blog/index.html

Directory Structure Examples

Basic Website

static/
โ”œโ”€โ”€ index.html          # Main page
โ”œโ”€โ”€ about.html          # About page
โ”œโ”€โ”€ styles.css          # Stylesheet
โ”œโ”€โ”€ script.js          # JavaScript
โ””โ”€โ”€ favicon.ico        # Site icon

Advanced Structure

static/
โ”œโ”€โ”€ index.html
โ”œโ”€โ”€ assets/
โ”‚   โ”œโ”€โ”€ css/
โ”‚   โ”‚   โ”œโ”€โ”€ main.css
โ”‚   โ”‚   โ”œโ”€โ”€ theme.css
โ”‚   โ”‚   โ””โ”€โ”€ responsive.css
โ”‚   โ”œโ”€โ”€ js/
โ”‚   โ”‚   โ”œโ”€โ”€ app.js
โ”‚   โ”‚   โ”œโ”€โ”€ utils.js
โ”‚   โ”‚   โ””โ”€โ”€ components/
โ”‚   โ”‚       โ”œโ”€โ”€ header.js
โ”‚   โ”‚       โ””โ”€โ”€ footer.js
โ”‚   โ”œโ”€โ”€ images/
โ”‚   โ”‚   โ”œโ”€โ”€ logo.svg
โ”‚   โ”‚   โ”œโ”€โ”€ hero.webp
โ”‚   โ”‚   โ””โ”€โ”€ gallery/
โ”‚   โ”‚       โ”œโ”€โ”€ photo1.jpg
โ”‚   โ”‚       โ””โ”€โ”€ photo2.jpg
โ”‚   โ””โ”€โ”€ fonts/
โ”‚       โ”œโ”€โ”€ Inter-Regular.woff2
โ”‚       โ””โ”€โ”€ Inter-Bold.woff2
โ”œโ”€โ”€ docs/
โ”‚   โ”œโ”€โ”€ index.html
โ”‚   โ”œโ”€โ”€ api.html
โ”‚   โ””โ”€โ”€ guide.html
โ””โ”€โ”€ downloads/
    โ”œโ”€โ”€ manual.pdf
    โ””โ”€โ”€ software.zip

Caching and Performance

BWS automatically adds caching headers:

Cache-Control: public, max-age=3600
Content-Type: text/css
Content-Length: 1234

Cache Control

  • Static files: 1 hour cache by default
  • HTML files: Shorter cache for dynamic content
  • Assets: Longer cache for images, fonts, etc.

Security Features

Path Traversal Protection

BWS prevents directory traversal attacks:

http://localhost:8080/../../../etc/passwd  โŒ Blocked
http://localhost:8080/..%2F..%2Fetc%2Fpasswd  โŒ Blocked

File Type Restrictions

Only serves files from the configured static_dir:

http://localhost:8080/config.toml  โŒ Not in static_dir
http://localhost:8080/.env         โŒ Hidden files blocked

Configuration Examples

Single Site

[[sites]]
name = "website"
hostname = "localhost"
port = 8080
static_dir = "public"

[sites.headers]
"Cache-Control" = "public, max-age=86400"
"X-Content-Type-Options" = "nosniff"

Multiple Asset Directories

# Main site
[[sites]]
name = "main"
hostname = "localhost"
port = 8080
static_dir = "dist"

# CDN-like asset server
[[sites]]
name = "assets"
hostname = "assets.localhost"
port = 8081
static_dir = "assets"

[sites.headers]
"Cache-Control" = "public, max-age=31536000"
"Access-Control-Allow-Origin" = "*"

Development vs Production

# Development
[[sites]]
name = "dev"
hostname = "localhost"
port = 8080
static_dir = "src"

[sites.headers]
"Cache-Control" = "no-cache, no-store, must-revalidate"
"X-Environment" = "development"

# Production
[[sites]]
name = "prod"
hostname = "example.com"
port = 8080
static_dir = "build"

[sites.headers]
"Cache-Control" = "public, max-age=31536000"
"X-Environment" = "production"

Testing Static Files

Basic File Serving

# Test HTML file
curl -I http://localhost:8080/index.html

# Test CSS file
curl -I http://localhost:8080/styles.css

# Test JavaScript
curl -I http://localhost:8080/app.js

MIME Type Verification

# Check MIME type headers
curl -I http://localhost:8080/image.png | grep "Content-Type"
curl -I http://localhost:8080/app.wasm | grep "Content-Type"

Subdirectory Access

# Test nested files
curl -I http://localhost:8080/assets/css/main.css
curl -I http://localhost:8080/docs/api.html

Index File Testing

# Directory with trailing slash
curl -I http://localhost:8080/docs/

# Directory without trailing slash
curl -I http://localhost:8080/docs

Troubleshooting

File Not Found (404)

  • Check file exists in static_dir
  • Verify file permissions (readable)
  • Check path spelling and case sensitivity

Wrong MIME Type

  • File extension not recognized
  • Add custom MIME type mapping if needed
  • Verify file extension is correct

Caching Issues

  • Clear browser cache
  • Check Cache-Control headers
  • Use browser dev tools to verify requests

Permission Errors

# Fix file permissions
chmod -R 644 static/*
chmod 755 static/

# Fix directory permissions
find static/ -type d -exec chmod 755 {} \;
find static/ -type f -exec chmod 644 {} \;

Best Practices

File Organization

  • Use descriptive directory names
  • Group related files together
  • Keep deep nesting to minimum (max 3-4 levels)

Performance

  • Optimize images (WebP, AVIF for modern browsers)
  • Minify CSS and JavaScript
  • Use appropriate file formats
  • Implement proper caching strategy

Security

  • Don't serve configuration files
  • Avoid exposing sensitive data in static files
  • Use proper file permissions
  • Regular security audits

Next Steps

Reverse Proxy Configuration

BWS now supports comprehensive Caddy-style reverse proxy functionality on a per-site basis. Each site can be configured to proxy specific routes to upstream servers with flexible routing, load balancing, and head๐Ÿš€ Future Enhancements:

  • Health check system with automatic failover
  • Connection pooling optimization
  • Circuit breaker pattern for failing upstreams
  • โœ… WebSocket proxy support - Real-time bidirectional communication proxying
  • Request body streaming for large payloads
  • Detailed metrics and monitoringgement.

Configuration Structure

Basic Proxy Configuration

[sites.proxy]
enabled = true

# Multiple backend servers (same name for load balancing)
[[sites.proxy.upstreams]]
name = "backend-pool"
url = "http://127.0.0.1:3001"
weight = 1

[[sites.proxy.upstreams]]
name = "backend-pool"
url = "http://127.0.0.1:3002"
weight = 2

# Route configuration
[[sites.proxy.routes]]
path = "/api/"
upstream = "backend-pool"
strip_prefix = false

# Load balancing configuration
[sites.proxy.load_balancing]
method = "round_robin"  # Options: round_robin, weighted, least_connections

# Timeout configuration
[sites.proxy.timeout]
read = 30
write = 30

# Header management
[sites.proxy.headers]
add_x_forwarded = true
add_forwarded = true

[sites.proxy.headers.add]
"X-Powered-By" = "BWS"

[sites.proxy.headers.remove]
"X-Internal-Header" = true

Load Balancing Algorithms

1. Round Robin (round_robin)

Distributes requests evenly across all available backend servers.

[sites.proxy.load_balancing]
method = "round_robin"
  • How it works: Cycles through servers in order
  • Best for: Servers with similar performance characteristics
  • Provides: Fair distribution when all servers have equal capacity

2. Weighted (weighted)

Distributes requests based on assigned weights.

[sites.proxy.load_balancing]
method = "weighted"

# Configure weights per server
[[sites.proxy.upstreams]]
name = "backend-pool"
url = "http://127.0.0.1:3001"
weight = 3  # Gets 3x traffic

[[sites.proxy.upstreams]]
name = "backend-pool"
url = "http://127.0.0.1:3002"
weight = 1  # Gets 1x traffic
  • How it works: Random selection weighted by server capacity
  • Best for: Servers with different capacities or performance
  • Provides: Performance-based load distribution

3. Least Connections (least_connections)

Routes requests to the server with the fewest active connections.

[sites.proxy.load_balancing]
method = "least_connections"
  • How it works: Tracks active connections per server using atomic counters
  • Best for: Long-running requests or varying response times
  • Provides: Optimal connection distribution

Features

Multiple Upstream Servers

Group multiple backend servers under the same upstream name for automatic load balancing.

Flexible Routing

  • Path-based routing: Route requests based on URL paths
  • Prefix stripping: Remove path prefixes before forwarding to upstream
  • Pattern matching: Match specific paths and route accordingly

Thread-Safe Load Balancing

  • Atomic Counters: Thread-safe request distribution
  • Connection Tracking: Real-time monitoring of active connections
  • Zero Locks: High-performance concurrent access

Header Management

  • Standard Proxy Headers: X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host
  • RFC 7239 Forwarded Header: Modern standard forwarded header support
  • Custom Headers: Add or remove custom headers per site
  • Header Preservation: Configure which headers to preserve or modify

Request/Response Handling

  • Full HTTP Support: All HTTP methods (GET, POST, PUT, DELETE, etc.)
  • Body Forwarding: Complete request and response body forwarding
  • Status Code Preservation: Maintains original response status codes
  • Error Handling: Graceful fallback with proper error responses

Timeout Configuration

  • Read Timeout: Configurable upstream read timeouts
  • Write Timeout: Configurable upstream write timeouts
  • Per-Site Settings: Individual timeout settings per site

Example Configurations

Basic API Proxy

[[sites]]
name = "api.example.com"
hostname = "api.example.com"
port = 80

[sites.proxy]
enabled = true

[[sites.proxy.upstreams]]
name = "api-backend"
url = "http://127.0.0.1:3000"

[[sites.proxy.routes]]
path = "/v1/"
upstream = "api-backend"

Load Balanced Application

[[sites]]
name = "app.example.com"
hostname = "app.example.com"
port = 80

[sites.proxy]
enabled = true

[[sites.proxy.upstreams]]
name = "app-server-1"
url = "http://10.0.1.10:8080"
weight = 2

[[sites.proxy.upstreams]]
name = "app-server-2"
url = "http://10.0.1.11:8080"
weight = 1

[[sites.proxy.routes]]
path = "/"
upstream = "app-servers"

[sites.proxy.load_balancing]
method = "weighted"

[sites.proxy.health_check]
enabled = true
interval_seconds = 15
path = "/health"

Mixed Static and Proxy

[[sites]]
name = "example.com"
hostname = "example.com"
port = 80
static_dir = "/var/www/example.com"

[sites.proxy]
enabled = true

[[sites.proxy.upstreams]]
name = "api"
url = "http://127.0.0.1:3000"

[[sites.proxy.upstreams]]
name = "admin"
url = "http://127.0.0.1:4000"

# Proxy API requests
[[sites.proxy.routes]]
path = "/api/"
upstream = "api"
strip_prefix = true

# Proxy admin interface
[[sites.proxy.routes]]
path = "/admin/"
upstream = "admin"
strip_prefix = false

# Static files are served for all other paths

Route Priority

When a request comes in, BWS checks routes in this order:

  1. API routes (/api/health, /api/config, etc.) - BWS internal APIs
  2. Proxy routes - Configured reverse proxy routes (most specific path first)
  3. Static files - Files from the site's static directory

Implementation Status

โœ… Fully Implemented:

  • โœ… Per-site proxy configuration - Complete TOML configuration parsing
  • โœ… Route detection and matching - Intelligent path-based routing
  • โœ… Full HTTP proxy implementation - Complete request/response forwarding using reqwest
  • โœ… Three load balancing algorithms - Round-robin, weighted, and least-connections
  • โœ… Connection tracking - Atomic counters for least-connections algorithm
  • โœ… Path transformation - Prefix stripping and URL rewriting
  • โœ… Header management - X-Forwarded-*, Forwarded, and custom headers
  • โœ… Error handling - Graceful fallback with 502 Bad Gateway responses
  • โœ… Response forwarding - Complete status code, header, and body forwarding
  • โœ… Timeout configuration - Configurable read/write timeouts
  • โœ… Thread safety - Concurrent request handling with atomic operations
  • โœ… Mixed mode operation - Static files and proxy routes work together

๏ฟฝ Future Enhancements:

  • Health check system with automatic failover
  • Connection pooling optimization
  • Circuit breaker pattern for failing upstreams
  • WebSocket proxy support
  • Request body streaming for large payloads
  • Detailed metrics and monitoring

WebSocket Proxy Support

BWS supports proxying WebSocket connections to upstream servers with the same load balancing capabilities as HTTP requests.

WebSocket Configuration

To enable WebSocket proxying for a route, set the websocket flag to true:

[[sites.proxy.routes]]
path = "/ws"
upstream = "websocket_backend"
strip_prefix = true
websocket = true  # Enable WebSocket proxying

WebSocket Features

  • Automatic Detection: BWS automatically detects WebSocket upgrade requests
  • Load Balancing: WebSocket connections are distributed using the same algorithms as HTTP requests
  • Bidirectional Communication: Full support for real-time message forwarding
  • Protocol Upgrade: Automatic handling of HTTP to WebSocket protocol upgrade
  • Header Forwarding: Proper forwarding of WebSocket-specific headers

Example WebSocket Configuration

[[sites]]
name = "websocket-app"
hostname = "ws.example.com" 
port = 8080
static_dir = "./static"

[sites.proxy]
enabled = true

# WebSocket upstream servers
[[sites.proxy.upstreams]]
name = "chat_servers"
url = "http://localhost:3001"  # Will be converted to ws://localhost:3001
weight = 1

[[sites.proxy.upstreams]]
name = "chat_servers"
url = "http://localhost:3002"  # Will be converted to ws://localhost:3002
weight = 1

# WebSocket routes
[[sites.proxy.routes]]
path = "/ws/chat"
upstream = "chat_servers"
strip_prefix = true
websocket = true

[[sites.proxy.routes]]
path = "/ws/notifications"
upstream = "chat_servers"
strip_prefix = false
websocket = true

# Load balancing for WebSocket connections
[sites.proxy.load_balancing]
method = "round_robin"  # or "weighted", "least_connections"

WebSocket URL Transformation

BWS automatically converts HTTP upstream URLs to WebSocket URLs:

  • http://localhost:3001 โ†’ ws://localhost:3001
  • https://localhost:3001 โ†’ wss://localhost:3001

Testing WebSocket Proxy

Use the included test script to verify WebSocket proxy functionality:

./tests/test_websocket_proxy.sh

This will:

  1. Start multiple WebSocket test servers
  2. Configure BWS with WebSocket proxy routes
  3. Provide a web interface for testing connections
  4. Demonstrate load balancing between upstream servers

Testing

The reverse proxy functionality is fully operational with comprehensive load balancing! Here's how to test it:

Quick Test

# 1. Start multiple backend servers
python3 -m http.server 3001 &
python3 -m http.server 3002 &
python3 -m http.server 3003 &

# 2. Start BWS with load balancing configuration
cargo run -- --config tests/test_load_balancing.toml

# 3. Test load balancing
curl http://localhost:8080/api/test  # Round-robin distribution
curl http://localhost:8081/         # Weighted distribution
curl http://localhost:8082/         # Least connections distribution

Comprehensive Load Balancing Test

Use the included test script to verify all load balancing algorithms:

./tests/test_load_balance.sh

This script will:

  • Start mock backend servers
  • Test round-robin distribution
  • Test weighted distribution (60%/40%)
  • Test least connections balancing
  • Verify proper request distribution

Manual Testing

# Test specific load balancing methods
curl -H "Host: roundrobin.example.com" http://localhost:8080/api/test
curl -H "Host: weighted.example.com" http://localhost:8081/
curl -H "Host: leastconn.example.com" http://localhost:8082/

# Test header forwarding
curl -v -H "Host: proxy.localhost" http://localhost:8080/api/data
# Look for X-Forwarded-For, X-Forwarded-Proto headers

# Test static file serving still works
curl http://localhost:8080/
# Returns: static HTML content from BWS

Verified Features:

  • โœ… Load Balancing: All three algorithms (round-robin, weighted, least-connections) working
  • โœ… Connection Tracking: Least-connections properly tracks active connections
  • โœ… Route Detection: Correctly identifies proxy vs static routes
  • โœ… Path Transformation: Prefix stripping and rewriting work as configured
  • โœ… HTTP Proxying: Full request/response proxying with all HTTP methods
  • โœ… Header Forwarding: Request and response headers properly forwarded
  • โœ… Error Handling: Returns 502 Bad Gateway when upstream is unavailable
  • โœ… Thread Safety: Concurrent requests handled safely with atomic operations
  • โœ… Timeouts: Configurable request timeouts prevent hanging
  • โœ… Mixed Mode: Static files and proxy routes work together seamlessly

Performance Characteristics

  • Round-Robin: O(1) selection complexity
  • Weighted: O(n) selection complexity where n = number of servers
  • Least Connections: O(n) selection complexity with atomic counters
  • Thread Safety: Lock-free operations using atomic primitives
  • Memory Efficiency: Minimal overhead with efficient data structures

This reverse proxy implementation makes BWS a complete web server solution, capable of serving static content, providing APIs, and proxying requests to backend services with enterprise-grade load balancing - just like Caddy!

Load Balancing in BWS

BWS reverse proxy includes comprehensive load balancing functionality similar to Caddy, with three different algorithms available for both HTTP and WebSocket connections.

Load Balancing Algorithms

1. Round Robin (round_robin)

Distributes requests evenly across all available backend servers in a circular manner.

How it works:

  • Maintains a counter for each upstream group
  • Increments counter for each request
  • Selects server based on counter % number_of_servers
  • Provides fair distribution when all servers have equal capacity

Best for:

  • Servers with similar performance characteristics
  • Simple, predictable load distribution
  • Development and testing environments
  • WebSocket chat applications with similar server capacity

2. Weighted (weighted)

Distributes requests based on assigned weights, allowing some servers to handle more traffic.

How it works:

  • Each server has a weight value (default: 1)
  • Random selection weighted by server capacity
  • Higher weight = more requests
  • Uses fast random number generation for selection

Best for:

  • Servers with different capacities
  • Gradual traffic migration
  • Performance-based load distribution
  • WebSocket servers with varying performance characteristics

3. Least Connections (least_connections)

Routes requests to the server with the fewest active connections.

How it works:

  • Tracks active connections per server using atomic counters
  • Increments counter when request starts
  • Decrements counter when request completes
  • Always routes to server with minimum connections

Best for:

  • Long-running requests
  • Servers with varying response times
  • Optimal connection distribution
  • WebSocket connections with persistent sessions

WebSocket Load Balancing

BWS extends all load balancing algorithms to support WebSocket connections with the same efficiency and reliability as HTTP requests.

WebSocket-Specific Features

  • Automatic Protocol Detection: BWS detects WebSocket upgrade requests and applies load balancing seamlessly
  • URL Transformation: HTTP upstream URLs are automatically converted to WebSocket URLs
    • http://localhost:3001 โ†’ ws://localhost:3001
    • https://localhost:3001 โ†’ wss://localhost:3001
  • Persistent Connection Tracking: WebSocket connections are tracked for least-connections algorithm
  • Same Algorithms: All three load balancing methods work identically for WebSocket connections

WebSocket Configuration Example

[[sites]]
name = "websocket-app"
hostname = "ws.example.com"
port = 8080

[sites.proxy]
enabled = true

# WebSocket upstream servers
[[sites.proxy.upstreams]]
name = "websocket_servers"
url = "http://localhost:3001"  # Automatically becomes ws://localhost:3001
weight = 1

[[sites.proxy.upstreams]]
name = "websocket_servers"  
url = "http://localhost:3002"  # Automatically becomes ws://localhost:3002
weight = 2  # Higher weight for better server

# WebSocket routes with load balancing
[[sites.proxy.routes]]
path = "/ws/chat"
upstream = "websocket_servers"
strip_prefix = true
websocket = true  # Enable WebSocket proxying

[[sites.proxy.routes]]
path = "/ws/notifications"
upstream = "websocket_servers"
strip_prefix = false
websocket = true

# Load balancing applies to WebSocket connections
[sites.proxy.load_balancing]
method = "least_connections"  # Ideal for persistent WebSocket connections

Use Cases by Algorithm

Round Robin for WebSocket:

  • Chat rooms with equal server capacity
  • Broadcasting services
  • Simple real-time APIs

Weighted for WebSocket:

  • Mixed server hardware configurations
  • Gradual migration to new WebSocket servers
  • Performance-based distribution

Least Connections for WebSocket:

  • Long-lived gaming connections
  • Persistent monitoring sessions
  • Real-time collaboration tools

Configuration

Basic Setup

# Site configuration
[[sites]]
name = "example.com"
hostname = "localhost"
port = 8080

[sites.proxy]
enabled = true

# Multiple servers with same upstream name
[[sites.proxy.upstreams]]
name = "backend-servers"
url = "http://127.0.0.1:3001"
weight = 1

[[sites.proxy.upstreams]]
name = "backend-servers"
url = "http://127.0.0.1:3002"
weight = 2  # This server gets 2x traffic in weighted mode

[[sites.proxy.upstreams]]
name = "backend-servers"
url = "http://127.0.0.1:3003"
weight = 1

# Route configuration
[[sites.proxy.routes]]
path = "/api/"
upstream = "backend-servers"

# Load balancing method
[sites.proxy.load_balancing]
method = "round_robin"  # or "weighted" or "least_connections"

Advanced Configuration

[sites.proxy]
enabled = true

# Request timeout
timeout = { read = 30, write = 30 }

# Header management
[sites.proxy.headers]
add_x_forwarded = true
add_forwarded = true

[sites.proxy.headers.add]
"X-Custom-Header" = "BWS-Proxy"

[sites.proxy.headers.remove]
"X-Internal-Header" = true

Testing Load Balancing

  1. Set up backend servers on different ports (3001, 3002, 3003)
  2. Configure BWS with the load balancing configuration
  3. Make multiple requests to see distribution
  4. Monitor logs to verify load balancing behavior

Use the included test script:

./tests/test_load_balance.sh

Implementation Details

Thread Safety

  • Round-robin counters use AtomicUsize for thread-safe access
  • Connection tracking uses atomic operations
  • No locks needed for load balancing decisions

Performance

  • O(1) complexity for round-robin selection
  • O(n) complexity for weighted selection (where n = number of servers)
  • O(n) complexity for least connections (where n = number of servers)
  • Minimal overhead with atomic operations

Reliability

  • Automatic failover if upstream server is unavailable
  • Connection tracking prevents memory leaks
  • Graceful handling of server addition/removal

Monitoring

BWS provides detailed logging for load balancing decisions:

INFO: Proxying request /api/users to upstream 'backend-servers'
INFO: Selected server http://127.0.0.1:3002 using round_robin
INFO: Successfully proxied request /api/users to http://127.0.0.1:3002

Connection counts and load balancing decisions are logged at debug level for troubleshooting.

Comparison with Caddy

BWS load balancing is designed to be compatible with Caddy's approach:

FeatureBWSCaddy
Round Robinโœ…โœ…
Weightedโœ…โœ…
Least Connectionsโœ…โœ…
Health Checks๐Ÿ”„ Plannedโœ…
Sticky Sessions๐Ÿ”„ Plannedโœ…
Circuit Breaker๐Ÿ”„ Plannedโœ…

Future Enhancements

  • Health Checks: Automatic detection of unhealthy servers
  • Sticky Sessions: Route requests from same client to same server
  • Circuit Breaker: Temporary removal of failing servers
  • Metrics: Detailed statistics on load balancing performance
  • Dynamic Configuration: Runtime modification of upstream servers

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

  1. Open DevTools (F12)
  2. Navigate to Network tab
  3. Reload page
  4. Click on any request
  5. 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

  1. Check TOML syntax in config file
  2. Restart BWS after configuration changes
  3. Verify header names are correct (case-sensitive)
  4. 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

  1. Start with permissive policy
  2. Use browser console to identify violations
  3. Gradually restrict policy
  4. 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

Health Monitoring

BWS provides built-in health monitoring endpoints and logging capabilities to help you monitor your server's status and performance.

Health Endpoints

BWS automatically provides health check endpoints for monitoring:

Basic Health Check

GET /health

Response:

{
  "status": "healthy",
  "timestamp": "2024-01-15T10:30:00Z",
  "version": "0.1.5",
  "uptime": 3600
}

Detailed Health Status

GET /health/detailed

Response:

{
  "status": "healthy",
  "timestamp": "2024-01-15T10:30:00Z",
  "version": "0.1.5",
  "uptime": 3600,
  "sites": [
    {
      "name": "main",
      "hostname": "localhost",
      "port": 8080,
      "status": "active",
      "requests_served": 1542,
      "last_request": "2024-01-15T10:29:45Z"
    }
  ],
  "system": {
    "memory_usage": "45.2 MB",
    "cpu_usage": "12.5%",
    "disk_usage": "78.3%"
  }
}

Monitoring Configuration

Health Check Settings

[monitoring]
enabled = true
health_endpoint = "/health"
detailed_endpoint = "/health/detailed"
metrics_endpoint = "/metrics"

Custom Health Checks

[monitoring.checks]
disk_threshold = 90    # Alert if disk usage > 90%
memory_threshold = 80  # Alert if memory usage > 80%
response_time_threshold = 1000  # Alert if response time > 1000ms

Logging Configuration

Basic Logging Setup

[logging]
level = "info"
format = "json"
output = "stdout"

File Logging

[logging]
level = "info"
format = "json"
output = "file"
file_path = "/var/log/bws/bws.log"
max_size = "100MB"
max_files = 10
compress = true

Structured Logging

[logging]
level = "debug"
format = "json"
include_fields = [
    "timestamp",
    "level",
    "message",
    "request_id",
    "client_ip",
    "user_agent",
    "response_time",
    "status_code"
]

Log Levels

Available Levels

  • ERROR: Error conditions and failures
  • WARN: Warning conditions
  • INFO: General informational messages
  • DEBUG: Detailed debugging information
  • TRACE: Very detailed tracing information

Log Level Examples

# Production
[logging]
level = "info"

# Development
[logging]
level = "debug"

# Troubleshooting
[logging]
level = "trace"

Metrics Collection

Basic Metrics

BWS automatically collects:

  • Request count
  • Response times
  • Error rates
  • Active connections
  • Memory usage
  • CPU usage

Prometheus Integration

[monitoring.prometheus]
enabled = true
endpoint = "/metrics"
port = 9090

Example metrics output:

# HELP bws_requests_total Total number of requests
# TYPE bws_requests_total counter
bws_requests_total{site="main",method="GET",status="200"} 1542

# HELP bws_response_time_seconds Response time in seconds
# TYPE bws_response_time_seconds histogram
bws_response_time_seconds_bucket{site="main",le="0.1"} 1200
bws_response_time_seconds_bucket{site="main",le="0.5"} 1500
bws_response_time_seconds_bucket{site="main",le="1.0"} 1540

Alerting

Health Check Monitoring

#!/bin/bash
# health_check.sh
HEALTH_URL="http://localhost:8080/health"
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_URL)

if [ $RESPONSE -eq 200 ]; then
    echo "BWS is healthy"
    exit 0
else
    echo "BWS health check failed: HTTP $RESPONSE"
    exit 1
fi

Uptime Monitoring Script

#!/bin/bash
# uptime_check.sh
while true; do
    if curl -f -s http://localhost:8080/health > /dev/null; then
        echo "$(date): BWS is running"
    else
        echo "$(date): BWS is DOWN" | mail -s "BWS Alert" admin@example.com
    fi
    sleep 60
done

System Integration

Systemd Integration

# /etc/systemd/system/bws.service
[Unit]
Description=BWS Web Server
After=network.target

[Service]
Type=simple
User=bws
ExecStart=/usr/local/bin/bws --config /etc/bws/config.toml
Restart=always
RestartSec=5

# Health check
ExecHealthCheck=/usr/local/bin/health_check.sh
HealthCheckInterval=30s

[Install]
WantedBy=multi-user.target

Docker Health Checks

# Dockerfile
FROM rust:1.89-slim

# ... build steps ...

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8080/health || exit 1

EXPOSE 8080
CMD ["bws", "--config", "/app/config.toml"]

Docker Compose Health Check

# docker-compose.yml
version: '3.8'
services:
  bws:
    build: .
    ports:
      - "8080:8080"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    restart: unless-stopped

Monitoring Tools Integration

Grafana Dashboard

{
  "dashboard": {
    "title": "BWS Monitoring",
    "panels": [
      {
        "title": "Request Rate",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(bws_requests_total[5m])"
          }
        ]
      },
      {
        "title": "Response Time",
        "type": "graph",
        "targets": [
          {
            "expr": "histogram_quantile(0.95, bws_response_time_seconds)"
          }
        ]
      }
    ]
  }
}

Nagios Check

#!/bin/bash
# check_bws.sh for Nagios
HOST="localhost"
PORT="8080"
WARNING_TIME=1000
CRITICAL_TIME=2000

RESPONSE_TIME=$(curl -o /dev/null -s -w "%{time_total}" http://$HOST:$PORT/health)
RESPONSE_TIME_MS=$(echo "$RESPONSE_TIME * 1000" | bc)

if (( $(echo "$RESPONSE_TIME_MS > $CRITICAL_TIME" | bc -l) )); then
    echo "CRITICAL - Response time: ${RESPONSE_TIME_MS}ms"
    exit 2
elif (( $(echo "$RESPONSE_TIME_MS > $WARNING_TIME" | bc -l) )); then
    echo "WARNING - Response time: ${RESPONSE_TIME_MS}ms"
    exit 1
else
    echo "OK - Response time: ${RESPONSE_TIME_MS}ms"
    exit 0
fi

Log Analysis

Log Parsing with jq

# Extract error logs
cat bws.log | jq 'select(.level == "ERROR")'

# Count requests by status code
cat bws.log | jq -r '.status_code' | sort | uniq -c

# Average response time
cat bws.log | jq -r '.response_time' | awk '{sum+=$1; count++} END {print sum/count}'

Log Aggregation

# Tail logs in real-time
tail -f /var/log/bws/bws.log | jq '.'

# Filter by log level
tail -f /var/log/bws/bws.log | jq 'select(.level == "ERROR" or .level == "WARN")'

# Monitor specific endpoints
tail -f /var/log/bws/bws.log | jq 'select(.path == "/api/users")'

Performance Monitoring

Request Tracking

[monitoring.requests]
track_response_times = true
track_status_codes = true
track_user_agents = true
track_client_ips = true
sample_rate = 1.0  # 100% sampling

Memory Monitoring

[monitoring.memory]
track_usage = true
alert_threshold = 80  # Alert at 80% usage
gc_metrics = true

Connection Monitoring

[monitoring.connections]
track_active = true
track_total = true
max_connections = 1000
timeout = 30  # seconds

Troubleshooting Health Issues

Common Health Check Failures

Service Unavailable

# Check if BWS is running
ps aux | grep bws

# Check port binding
netstat -tulpn | grep :8080

# Check configuration
bws --config-check

High Response Times

# Check system load
top
htop

# Check disk usage
df -h

# Check memory usage
free -h

Memory Leaks

# Monitor memory over time
while true; do
    ps -o pid,ppid,cmd,%mem,%cpu -p $(pgrep bws)
    sleep 10
done

# Generate memory dump (if available)
kill -USR1 $(pgrep bws)

Health Check Debugging

# Test health endpoint
curl -v http://localhost:8080/health

# Check detailed health
curl -s http://localhost:8080/health/detailed | jq '.'

# Monitor health over time
while true; do
    echo "$(date): $(curl -s http://localhost:8080/health | jq -r '.status')"
    sleep 30
done

Best Practices

Health Check Configuration

  • Set appropriate timeouts (3-5 seconds)
  • Use consistent intervals (30-60 seconds)
  • Include multiple health indicators
  • Monitor both application and system metrics

Logging Strategy

  • Use structured logging (JSON format)
  • Include correlation IDs for request tracking
  • Log at appropriate levels
  • Rotate logs to prevent disk space issues

Alerting Guidelines

  • Set realistic thresholds
  • Avoid alert fatigue
  • Include actionable information
  • Test alert mechanisms regularly

Monitoring Coverage

  • Monitor all critical endpoints
  • Track business metrics, not just technical
  • Set up both reactive and proactive monitoring
  • Document monitoring procedures

Next Steps

Docker Deployment

BWS provides comprehensive Docker support for easy deployment and containerization.

Docker Image

Official Docker Image

# Pull the latest image
docker pull ghcr.io/yourusername/bws:latest

# Pull a specific version
docker pull ghcr.io/yourusername/bws:0.1.5

Building from Source

# Clone the repository
git clone https://github.com/yourusername/bws.git
cd bws

# Build the Docker image
docker build -t bws:local .

Basic Usage

Simple Container

# Run BWS with default configuration
docker run -p 8080:8080 ghcr.io/yourusername/bws:latest

With Custom Configuration

# Run with custom config
docker run -p 8080:8080 \
  -v $(pwd)/config.toml:/app/config.toml \
  -v $(pwd)/static:/app/static \
  ghcr.io/yourusername/bws:latest

Background Execution

# Run as daemon
docker run -d \
  --name bws-server \
  -p 8080:8080 \
  --restart unless-stopped \
  -v $(pwd)/config.toml:/app/config.toml \
  -v $(pwd)/static:/app/static \
  ghcr.io/yourusername/bws:latest

Docker Compose

Basic Setup

# docker-compose.yml
version: '3.8'

services:
  bws:
    image: ghcr.io/yourusername/bws:latest
    ports:
      - "8080:8080"
    volumes:
      - ./config.toml:/app/config.toml
      - ./static:/app/static
      - ./logs:/app/logs
    environment:
      - RUST_LOG=info
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Multi-Site Setup

# docker-compose.yml
version: '3.8'

services:
  bws-main:
    image: ghcr.io/yourusername/bws:latest
    container_name: bws-main
    ports:
      - "8080:8080"
    volumes:
      - ./sites/main/config.toml:/app/config.toml
      - ./sites/main/static:/app/static
      - ./logs/main:/app/logs
    environment:
      - RUST_LOG=info
      - BWS_SITE_NAME=main
    restart: unless-stopped
    networks:
      - bws-network

  bws-api:
    image: ghcr.io/yourusername/bws:latest
    container_name: bws-api
    ports:
      - "8081:8080"
    volumes:
      - ./sites/api/config.toml:/app/config.toml
      - ./sites/api/static:/app/static
      - ./logs/api:/app/logs
    environment:
      - RUST_LOG=info
      - BWS_SITE_NAME=api
    restart: unless-stopped
    networks:
      - bws-network

networks:
  bws-network:
    driver: bridge

With Reverse Proxy

# docker-compose.yml
version: '3.8'

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/ssl:/etc/nginx/ssl
    depends_on:
      - bws
    networks:
      - web-network

  bws:
    image: ghcr.io/yourusername/bws:latest
    expose:
      - "8080"
    volumes:
      - ./config.toml:/app/config.toml
      - ./static:/app/static
      - ./logs:/app/logs
    environment:
      - RUST_LOG=info
    restart: unless-stopped
    networks:
      - web-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3

networks:
  web-network:
    driver: bridge

Environment Variables

Configuration via Environment

# Override configuration with environment variables
docker run -p 8080:8080 \
  -e BWS_CONFIG=/app/config.toml \
  -e BWS_LOG_FILE=/app/logs/bws.log \
  -e BWS_PID_FILE=/app/bws.pid \
  -e RUST_LOG=debug \
  ghcr.io/yourusername/bws:latest

Available Environment Variables

# Core settings
BWS_CONFIG=/app/config.toml          # Configuration file path
BWS_LOG_FILE=/app/logs/bws.log       # Log file path
BWS_PID_FILE=/app/bws.pid            # PID file path

# Logging
RUST_LOG=info                        # Log level
RUST_BACKTRACE=1                     # Enable backtraces

# Application
BWS_SITE_NAME=main                   # Site identifier
BWS_BIND_ADDRESS=0.0.0.0             # Bind address
BWS_PORT=8080                        # Default port

Volume Mounting

Essential Volumes

# Configuration and static files
docker run -p 8080:8080 \
  -v $(pwd)/config.toml:/app/config.toml:ro \
  -v $(pwd)/static:/app/static:ro \
  -v $(pwd)/logs:/app/logs \
  ghcr.io/yourusername/bws:latest

Development Setup

# Mount source for development
docker run -p 8080:8080 \
  -v $(pwd)/config.toml:/app/config.toml \
  -v $(pwd)/static:/app/static \
  -v $(pwd)/logs:/app/logs \
  -v $(pwd)/data:/app/data \
  ghcr.io/yourusername/bws:latest

Production Setup

# Production with named volumes
docker volume create bws-config
docker volume create bws-static
docker volume create bws-logs

docker run -p 8080:8080 \
  -v bws-config:/app/config \
  -v bws-static:/app/static \
  -v bws-logs:/app/logs \
  ghcr.io/yourusername/bws:latest

Health Checks

Docker Health Check

# Built into the image
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8080/health || exit 1

Custom Health Check Script

#!/bin/bash
# health-check.sh
curl -f -s http://localhost:8080/health > /dev/null
if [ $? -eq 0 ]; then
    exit 0
else
    exit 1
fi

Docker Compose Health Check

services:
  bws:
    image: ghcr.io/yourusername/bws:latest
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Networking

Bridge Network

# Create custom network
docker network create bws-network

# Run container on custom network
docker run --network bws-network \
  --name bws-server \
  -p 8080:8080 \
  ghcr.io/yourusername/bws:latest

Host Network

# Use host networking (Linux only)
docker run --network host \
  ghcr.io/yourusername/bws:latest

Internal Communication

# docker-compose.yml
services:
  bws:
    image: ghcr.io/yourusername/bws:latest
    networks:
      - internal
    # No ports exposed externally

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    networks:
      - internal
    depends_on:
      - bws

networks:
  internal:
    driver: bridge
    internal: true  # No external access

Security

Non-Root User

# Built into the image
USER bws
WORKDIR /app

Read-Only Root Filesystem

# Run with read-only root filesystem
docker run --read-only \
  --tmpfs /tmp \
  --tmpfs /app/logs \
  -v $(pwd)/config.toml:/app/config.toml:ro \
  -v $(pwd)/static:/app/static:ro \
  -p 8080:8080 \
  ghcr.io/yourusername/bws:latest

Security Options

# Enhanced security
docker run --security-opt=no-new-privileges \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  -p 8080:8080 \
  ghcr.io/yourusername/bws:latest

Docker Compose Security

services:
  bws:
    image: ghcr.io/yourusername/bws:latest
    read_only: true
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    tmpfs:
      - /tmp
      - /app/logs

Production Deployment

Resource Limits

# docker-compose.yml
services:
  bws:
    image: ghcr.io/yourusername/bws:latest
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3

Logging Configuration

services:
  bws:
    image: ghcr.io/yourusername/bws:latest
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        labels: "service=bws"

Monitoring Integration

services:
  bws:
    image: ghcr.io/yourusername/bws:latest
    labels:
      - "prometheus.io/scrape=true"
      - "prometheus.io/port=8080"
      - "prometheus.io/path=/metrics"

Docker Build Optimization

Multi-Stage Build

# Build stage
FROM rust:1.89-slim as builder
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
COPY src ./src
RUN cargo build --release

# Runtime stage
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y \
    ca-certificates \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Create non-root user
RUN useradd -r -s /bin/false bws

WORKDIR /app
COPY --from=builder /app/target/release/bws /usr/local/bin/
COPY --chown=bws:bws config.toml ./
COPY --chown=bws:bws static ./static

USER bws
EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8080/health || exit 1

CMD ["bws", "--config", "/app/config.toml"]

Build Arguments

ARG RUST_VERSION=1.89
ARG TARGET=x86_64-unknown-linux-gnu

FROM rust:${RUST_VERSION}-slim as builder
# ... build process ...
# Build with custom arguments
docker build --build-arg RUST_VERSION=1.89 -t bws:custom .

Troubleshooting

Container Won't Start

# Check container logs
docker logs bws-server

# Run interactively for debugging
docker run -it --entrypoint /bin/bash ghcr.io/yourusername/bws:latest

# Check configuration
docker run --rm -v $(pwd)/config.toml:/app/config.toml \
  ghcr.io/yourusername/bws:latest --config-check

Port Binding Issues

# Check if port is already in use
netstat -tulpn | grep :8080

# Use different port
docker run -p 8081:8080 ghcr.io/yourusername/bws:latest

Volume Mount Problems

# Check file permissions
ls -la config.toml static/

# Fix permissions
chmod 644 config.toml
chmod -R 644 static/

Health Check Failures

# Test health endpoint manually
docker exec bws-server curl -f http://localhost:8080/health

# Check health check logs
docker inspect bws-server | jq '.[0].State.Health'

Best Practices

Image Management

  • Use specific version tags, not latest
  • Regularly update base images
  • Scan images for vulnerabilities
  • Use multi-stage builds to reduce image size

Configuration

  • Use external configuration files
  • Store secrets securely (Docker secrets, environment variables)
  • Mount configuration as read-only
  • Validate configuration before deployment

Monitoring

  • Always include health checks
  • Monitor resource usage
  • Set up log aggregation
  • Use structured logging

Security

  • Run as non-root user
  • Use read-only filesystems when possible
  • Drop unnecessary capabilities
  • Regularly update dependencies

Next Steps

Daemon Mode Configuration

BWS can run as a system daemon (background service) for production deployments, providing automatic startup, monitoring, and management capabilities.

Daemon Overview

Running BWS as a daemon provides:

  • Automatic startup on system boot
  • Process monitoring and restart capabilities
  • Centralized logging and management
  • Integration with system monitoring tools
  • Proper signal handling and graceful shutdown

Systemd Configuration

Service File Creation

Create a systemd service file for BWS:

# /etc/systemd/system/bws.service
[Unit]
Description=BWS Multi-Site Web Server
Documentation=https://github.com/yourusername/bws
After=network.target
Wants=network.target

[Service]
Type=simple
User=bws
Group=bws
WorkingDirectory=/opt/bws
ExecStart=/usr/local/bin/bws --config /etc/bws/config.toml
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
TimeoutStartSec=60
TimeoutStopSec=30

# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/log/bws /var/lib/bws

# Resource limits
LimitNOFILE=65536
LimitNPROC=4096

# Environment
Environment=RUST_LOG=info
Environment=BWS_CONFIG=/etc/bws/config.toml
Environment=BWS_LOG_FILE=/var/log/bws/bws.log
Environment=BWS_PID_FILE=/var/run/bws.pid

[Install]
WantedBy=multi-user.target

Installing the Service

# Copy service file
sudo cp bws.service /etc/systemd/system/

# Reload systemd
sudo systemctl daemon-reload

# Enable service (auto-start on boot)
sudo systemctl enable bws

# Start service
sudo systemctl start bws

# Check status
sudo systemctl status bws

Service Management

# Start the service
sudo systemctl start bws

# Stop the service
sudo systemctl stop bws

# Restart the service
sudo systemctl restart bws

# Reload configuration
sudo systemctl reload bws

# Check service status
sudo systemctl status bws

# View logs
sudo journalctl -u bws -f

# Check if service is enabled
sudo systemctl is-enabled bws

User and Directory Setup

Creating BWS User

# Create system user for BWS
sudo useradd -r -s /bin/false -d /opt/bws bws

# Create necessary directories
sudo mkdir -p /opt/bws
sudo mkdir -p /etc/bws
sudo mkdir -p /var/log/bws
sudo mkdir -p /var/lib/bws

# Set ownership
sudo chown -R bws:bws /opt/bws
sudo chown -R bws:bws /var/log/bws
sudo chown -R bws:bws /var/lib/bws
sudo chown root:bws /etc/bws

# Set permissions
sudo chmod 755 /opt/bws
sudo chmod 750 /etc/bws
sudo chmod 755 /var/log/bws
sudo chmod 755 /var/lib/bws

File Structure

/opt/bws/                 # BWS home directory
โ”œโ”€โ”€ static/               # Static files
โ”œโ”€โ”€ sites/                # Multi-site configurations
โ””โ”€โ”€ bin/                  # BWS binary (optional)

/etc/bws/                 # Configuration directory
โ”œโ”€โ”€ config.toml           # Main configuration
โ”œโ”€โ”€ sites/                # Site-specific configs
โ””โ”€โ”€ ssl/                  # SSL certificates

/var/log/bws/             # Log directory
โ”œโ”€โ”€ bws.log               # Main log file
โ”œโ”€โ”€ access.log            # Access logs
โ””โ”€โ”€ error.log             # Error logs

/var/lib/bws/             # Runtime data
โ”œโ”€โ”€ cache/                # Cache files
โ””โ”€โ”€ temp/                 # Temporary files

Configuration Files

Main Configuration

# /etc/bws/config.toml
[daemon]
user = "bws"
group = "bws"
pid_file = "/var/run/bws.pid"
working_directory = "/opt/bws"

[logging]
level = "info"
output = "file"
file_path = "/var/log/bws/bws.log"
max_size = "100MB"
max_files = 10
compress = true

[[sites]]
name = "main"
hostname = "localhost"
port = 8080
static_dir = "/opt/bws/static"

[sites.headers]
"X-Served-By" = "BWS"
"Cache-Control" = "public, max-age=3600"

Environment Configuration

# /etc/bws/environment
BWS_CONFIG=/etc/bws/config.toml
BWS_LOG_FILE=/var/log/bws/bws.log
BWS_PID_FILE=/var/run/bws.pid
RUST_LOG=info
RUST_BACKTRACE=1

Process Management

Signal Handling

BWS responds to standard Unix signals:

# Graceful shutdown
sudo kill -TERM $(cat /var/run/bws.pid)

# Reload configuration
sudo kill -HUP $(cat /var/run/bws.pid)

# Force restart
sudo kill -USR1 $(cat /var/run/bws.pid)

# Force termination (last resort)
sudo kill -KILL $(cat /var/run/bws.pid)

Process Monitoring

# Check if BWS is running
pgrep -f bws

# Monitor BWS process
ps aux | grep bws

# Check open files
sudo lsof -p $(cat /var/run/bws.pid)

# Monitor resource usage
top -p $(cat /var/run/bws.pid)

Log Management

Log Rotation Configuration

# /etc/logrotate.d/bws
/var/log/bws/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    copytruncate
    postrotate
        systemctl reload bws
    endscript
}

Log Monitoring

# Follow main log
tail -f /var/log/bws/bws.log

# Follow with filtering
tail -f /var/log/bws/bws.log | grep ERROR

# Search logs
grep "error" /var/log/bws/bws.log

# Count log entries by level
grep -c "INFO\|WARN\|ERROR" /var/log/bws/bws.log

Monitoring and Health Checks

Health Check Script

#!/bin/bash
# /usr/local/bin/bws-health-check
BWS_PID_FILE="/var/run/bws.pid"
BWS_HEALTH_URL="http://localhost:8080/health"

# Check if PID file exists
if [ ! -f "$BWS_PID_FILE" ]; then
    echo "ERROR: PID file not found"
    exit 1
fi

# Check if process is running
PID=$(cat "$BWS_PID_FILE")
if ! kill -0 "$PID" 2>/dev/null; then
    echo "ERROR: BWS process not running"
    exit 1
fi

# Check health endpoint
if ! curl -f -s "$BWS_HEALTH_URL" > /dev/null; then
    echo "ERROR: Health check failed"
    exit 1
fi

echo "OK: BWS is healthy"
exit 0

Monitoring with Cron

# Add to crontab for user bws
*/5 * * * * /usr/local/bin/bws-health-check || /usr/bin/logger "BWS health check failed"

Systemd Timer for Health Checks

# /etc/systemd/system/bws-health.service
[Unit]
Description=BWS Health Check
After=bws.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/bws-health-check
User=bws
# /etc/systemd/system/bws-health.timer
[Unit]
Description=BWS Health Check Timer
Requires=bws-health.service

[Timer]
OnCalendar=*:0/5
Persistent=true

[Install]
WantedBy=timers.target

Auto-Recovery and Restart

Automatic Restart Configuration

# Enhanced systemd service with restart logic
[Service]
Type=simple
Restart=always
RestartSec=5
StartLimitInterval=60
StartLimitBurst=3

# Restart conditions
RestartPreventExitStatus=1 2 3 4 6 SIGTERM

Recovery Script

#!/bin/bash
# /usr/local/bin/bws-recovery
LOG_FILE="/var/log/bws/recovery.log"
PID_FILE="/var/run/bws.pid"

log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}

# Check if BWS is running
if [ -f "$PID_FILE" ] && kill -0 $(cat "$PID_FILE") 2>/dev/null; then
    if curl -f -s http://localhost:8080/health > /dev/null; then
        log_message "BWS is healthy"
        exit 0
    fi
fi

log_message "BWS appears to be down, attempting restart"

# Stop any existing processes
systemctl stop bws
sleep 5

# Clean up PID file if exists
[ -f "$PID_FILE" ] && rm -f "$PID_FILE"

# Start BWS
if systemctl start bws; then
    log_message "BWS restarted successfully"
    exit 0
else
    log_message "Failed to restart BWS"
    exit 1
fi

Security Considerations

Service Security

# Enhanced security in systemd service
[Service]
# Run as non-root user
User=bws
Group=bws

# Security restrictions
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/log/bws /var/lib/bws

# Capability restrictions
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE

# Network restrictions
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

# File system restrictions
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true

File Permissions

# Set secure permissions
chmod 600 /etc/bws/config.toml
chmod 755 /etc/bws
chmod 644 /usr/local/bin/bws
chmod 755 /usr/local/bin/bws

# Verify permissions
ls -la /etc/bws/
ls -la /var/log/bws/
ls -la /opt/bws/

Integration Examples

With Nginx

# /etc/nginx/sites-available/bws
upstream bws {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://bws;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /health {
        proxy_pass http://bws/health;
        access_log off;
    }
}

With Load Balancer

# HAProxy configuration
global
    daemon
    maxconn 4096

defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend web_frontend
    bind *:80
    default_backend bws_servers

backend bws_servers
    balance roundrobin
    option httpchk GET /health
    server bws1 127.0.0.1:8080 check
    server bws2 127.0.0.1:8081 check

Troubleshooting

Service Won't Start

# Check service status
systemctl status bws

# View detailed logs
journalctl -u bws -xe

# Check configuration
bws --config-check /etc/bws/config.toml

# Verify permissions
ls -la /etc/bws/config.toml
ls -la /usr/local/bin/bws

Permission Errors

# Fix ownership
sudo chown -R bws:bws /opt/bws /var/log/bws

# Fix permissions
sudo chmod 755 /opt/bws
sudo chmod 644 /etc/bws/config.toml

# Check SELinux (if applicable)
sestatus
setsebool -P httpd_can_network_connect 1

Performance Issues

# Check resource limits
systemctl show bws | grep Limit

# Monitor system resources
htop
iotop
netstat -tulpn

Best Practices

Configuration Management

  • Store configurations in version control
  • Use configuration templates for different environments
  • Validate configurations before deployment
  • Document all configuration changes

Monitoring

  • Set up comprehensive logging
  • Monitor service health continuously
  • Configure alerting for service failures
  • Regular log analysis and cleanup

Security

  • Run with minimal privileges
  • Regular security updates
  • Secure file permissions
  • Network security (firewall rules)

Maintenance

  • Regular backup of configurations
  • Monitor disk space for logs
  • Plan for service updates
  • Document operational procedures

Next Steps

Production Setup

This guide covers deploying BWS in production environments with security, performance, and reliability best practices.

Production Readiness

BWS has been significantly hardened for production use with comprehensive improvements:

Reliability Enhancements

  • Zero Panic Policy: All .unwrap() calls replaced with proper error handling
  • Comprehensive Error Handling: Graceful error propagation throughout the codebase
  • Thread-Safe Operations: Fixed all race conditions and concurrency issues
  • Automatic Certificate Renewal: Background monitoring service for SSL certificates
  • Memory Safety: Rust's ownership system prevents memory corruption and data races

Code Quality Assurance

  • Lint-Free Codebase: Passes all Clippy warnings for maximum code quality
  • Modern Rust Patterns: Updated to use latest async/await and error handling patterns
  • Resource Management: Proper cleanup of connections and certificate operations
  • Production-Grade Logging: Structured logging with comprehensive error documentation

Production Architecture

Internet โ†’ Load Balancer โ†’ Reverse Proxy โ†’ BWS Instances
                                       โ†“
                              Monitoring & Logging

High Availability Setup

                    Load Balancer (HAProxy/Nginx)
                           /              \
                    BWS Instance 1    BWS Instance 2
                         |                    |
                    Static Files        Static Files
                    (NFS/S3)           (NFS/S3)
                         |                    |
                    Health Monitor     Health Monitor

Security Configuration

SSL/TLS Termination

BWS is typically deployed behind a reverse proxy that handles SSL termination:

# /etc/nginx/sites-available/bws-production
server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    # SSL Configuration
    ssl_certificate /etc/ssl/certs/example.com.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # Security Headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-Frame-Options DENY always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Rate Limiting
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=static:10m rate=50r/s;

    location / {
        limit_req zone=static burst=20 nodelay;
        proxy_pass http://bws_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # Timeouts
        proxy_connect_timeout 5s;
        proxy_send_timeout 10s;
        proxy_read_timeout 10s;
    }

    location /api/ {
        limit_req zone=api burst=5 nodelay;
        proxy_pass http://bws_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /health {
        proxy_pass http://bws_backend/health;
        access_log off;
        allow 127.0.0.1;
        allow 10.0.0.0/8;
        deny all;
    }
}

upstream bws_backend {
    least_conn;
    server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8081 max_fails=3 fail_timeout=30s backup;
    keepalive 32;
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

Firewall Configuration

# UFW (Ubuntu Firewall) example
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 10.0.0.0/8 to any port 8080  # Internal BWS access
sudo ufw enable

# iptables example
iptables -A INPUT -p tcp --dport 22 -j ACCEPT    # SSH
iptables -A INPUT -p tcp --dport 80 -j ACCEPT    # HTTP
iptables -A INPUT -p tcp --dport 443 -j ACCEPT   # HTTPS
iptables -A INPUT -s 10.0.0.0/8 -p tcp --dport 8080 -j ACCEPT  # BWS internal
iptables -A INPUT -j DROP

Production Configuration

Optimized BWS Configuration

# /etc/bws/production.toml
[daemon]
user = "bws"
group = "bws"
pid_file = "/var/run/bws.pid"
working_directory = "/opt/bws"

[logging]
level = "info"
output = "file"
file_path = "/var/log/bws/bws.log"
max_size = "100MB"
max_files = 10
compress = true
format = "json"

[monitoring]
enabled = true
health_endpoint = "/health"
detailed_endpoint = "/health/detailed"
metrics_endpoint = "/metrics"

[monitoring.checks]
disk_threshold = 85
memory_threshold = 80
response_time_threshold = 1000

[performance]
max_connections = 10000
worker_threads = 8
keep_alive_timeout = 30
request_timeout = 30
max_request_size = "10MB"

# Production site
[[sites]]
name = "production"
hostname = "127.0.0.1"  # Behind reverse proxy
port = 8080
static_dir = "/opt/bws/static"

[sites.headers]
"Cache-Control" = "public, max-age=31536000"
"X-Content-Type-Options" = "nosniff"
"X-Frame-Options" = "DENY"
"X-Served-By" = "BWS-Production"
"Vary" = "Accept-Encoding"

# API site
[[sites]]
name = "api"
hostname = "127.0.0.1"
port = 8081
static_dir = "/opt/bws/api-docs"

[sites.headers]
"Cache-Control" = "no-cache, no-store, must-revalidate"
"Content-Type" = "application/json"
"Access-Control-Allow-Origin" = "https://example.com"
"X-API-Version" = "v1.0.0"

Environment Variables

# /etc/environment.d/bws.conf
BWS_CONFIG=/etc/bws/production.toml
BWS_LOG_FILE=/var/log/bws/bws.log
BWS_PID_FILE=/var/run/bws.pid
RUST_LOG=info
RUST_BACKTRACE=0
BWS_ENV=production

Performance Optimization

System Tuning

# /etc/sysctl.d/99-bws.conf
# Network performance
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 3

# File descriptor limits
fs.file-max = 1048576

# Apply settings
sysctl -p /etc/sysctl.d/99-bws.conf

System Limits

# /etc/security/limits.d/bws.conf
bws soft nofile 65536
bws hard nofile 65536
bws soft nproc 4096
bws hard nproc 4096

File System Optimization

# Mount options for static files (add to /etc/fstab)
/dev/sdb1 /opt/bws/static ext4 defaults,noatime,nodiratime 0 0

# For high-performance scenarios, consider tmpfs for cache
tmpfs /opt/bws/cache tmpfs defaults,size=1G,mode=755,uid=bws,gid=bws 0 0

Monitoring and Alerting

Prometheus Configuration

# /etc/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "bws_rules.yml"

scrape_configs:
  - job_name: 'bws'
    static_configs:
      - targets: ['localhost:8080', 'localhost:8081']
    metrics_path: '/metrics'
    scrape_interval: 5s

alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - alertmanager:9093

Alert Rules

# /etc/prometheus/bws_rules.yml
groups:
- name: bws.rules
  rules:
  - alert: BWS_Down
    expr: up{job="bws"} == 0
    for: 1m
    labels:
      severity: critical
    annotations:
      summary: "BWS instance is down"
      description: "BWS instance {{ $labels.instance }} has been down for more than 1 minute."

  - alert: BWS_HighResponseTime
    expr: histogram_quantile(0.95, bws_response_time_seconds) > 1
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "BWS high response time"
      description: "95th percentile response time is {{ $value }}s"

  - alert: BWS_HighErrorRate
    expr: rate(bws_requests_total{status=~"5.."}[5m]) > 0.1
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "BWS high error rate"
      description: "Error rate is {{ $value }} errors per second"

  - alert: BWS_HighMemoryUsage
    expr: bws_memory_usage_bytes / bws_memory_limit_bytes > 0.8
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "BWS high memory usage"
      description: "Memory usage is {{ $value }}%"

Grafana Dashboard

{
  "dashboard": {
    "id": null,
    "title": "BWS Production Dashboard",
    "tags": ["bws", "production"],
    "timezone": "browser",
    "panels": [
      {
        "id": 1,
        "title": "Request Rate",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(bws_requests_total[5m])",
            "legendFormat": "{{ instance }}"
          }
        ],
        "yAxes": [
          {
            "label": "Requests/sec",
            "min": 0
          }
        ]
      },
      {
        "id": 2,
        "title": "Response Time",
        "type": "graph",
        "targets": [
          {
            "expr": "histogram_quantile(0.50, bws_response_time_seconds)",
            "legendFormat": "50th percentile"
          },
          {
            "expr": "histogram_quantile(0.95, bws_response_time_seconds)",
            "legendFormat": "95th percentile"
          }
        ]
      },
      {
        "id": 3,
        "title": "Error Rate",
        "type": "singlestat",
        "targets": [
          {
            "expr": "rate(bws_requests_total{status=~\"5..\"}[5m])",
            "legendFormat": "5xx errors/sec"
          }
        ]
      }
    ]
  }
}

Backup and Disaster Recovery

Configuration Backup

#!/bin/bash
# /usr/local/bin/backup-bws-config.sh
BACKUP_DIR="/backup/bws"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="bws-config-$DATE.tar.gz"

mkdir -p "$BACKUP_DIR"

# Backup configuration
tar -czf "$BACKUP_DIR/$BACKUP_FILE" \
    /etc/bws/ \
    /opt/bws/static/ \
    /var/log/bws/ \
    /etc/systemd/system/bws.service

# Keep only last 30 backups
find "$BACKUP_DIR" -name "bws-config-*.tar.gz" -mtime +30 -delete

echo "Backup completed: $BACKUP_DIR/$BACKUP_FILE"

Log Backup and Rotation

# /etc/logrotate.d/bws
/var/log/bws/*.log {
    daily
    missingok
    rotate 90
    compress
    delaycompress
    notifempty
    copytruncate
    postrotate
        systemctl reload bws
        # Archive to S3 or backup system
        aws s3 cp /var/log/bws/bws.log.1.gz s3://backup-bucket/logs/bws/$(date +%Y/%m/%d)/
    endscript
}

Health Check and Recovery

#!/bin/bash
# /usr/local/bin/bws-recovery.sh
BWS_HEALTH_URL="http://localhost:8080/health"
LOG_FILE="/var/log/bws/recovery.log"
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"

log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

send_alert() {
    curl -X POST -H 'Content-type: application/json' \
        --data "{\"text\":\"BWS Alert: $1\"}" \
        "$SLACK_WEBHOOK"
}

# Check BWS health
if ! curl -f -s "$BWS_HEALTH_URL" > /dev/null; then
    log_message "BWS health check failed, attempting recovery"
    send_alert "BWS is down, attempting automatic recovery"
    
    # Try graceful restart
    systemctl restart bws
    sleep 10
    
    # Check if restart was successful
    if curl -f -s "$BWS_HEALTH_URL" > /dev/null; then
        log_message "BWS recovered successfully"
        send_alert "BWS recovery successful"
    else
        log_message "BWS recovery failed"
        send_alert "BWS recovery FAILED - manual intervention required"
        exit 1
    fi
else
    log_message "BWS is healthy"
fi

Deployment Strategies

Blue-Green Deployment

#!/bin/bash
# /usr/local/bin/deploy-bws.sh
BLUE_PORT=8080
GREEN_PORT=8081
HEALTH_CHECK_URL="http://localhost"

deploy_to_port() {
    local PORT=$1
    local VERSION=$2
    
    echo "Deploying BWS $VERSION to port $PORT"
    
    # Stop existing service
    systemctl stop bws-$PORT
    
    # Update binary
    cp /tmp/bws-$VERSION /usr/local/bin/bws-$PORT
    
    # Update configuration
    sed "s/port = .*/port = $PORT/" /etc/bws/config.toml > /etc/bws/config-$PORT.toml
    
    # Start service
    systemctl start bws-$PORT
    
    # Health check
    sleep 5
    if curl -f -s "$HEALTH_CHECK_URL:$PORT/health" > /dev/null; then
        echo "Deployment to port $PORT successful"
        return 0
    else
        echo "Deployment to port $PORT failed"
        return 1
    fi
}

# Get current active port from load balancer
CURRENT_PORT=$(nginx -T 2>/dev/null | grep "server 127.0.0.1:" | head -1 | awk '{print $2}' | cut -d: -f2)

if [ "$CURRENT_PORT" = "$BLUE_PORT" ]; then
    DEPLOY_PORT=$GREEN_PORT
    SWITCH_FROM=$BLUE_PORT
else
    DEPLOY_PORT=$BLUE_PORT
    SWITCH_FROM=$GREEN_PORT
fi

echo "Deploying to $DEPLOY_PORT (current: $SWITCH_FROM)"

# Deploy to inactive port
if deploy_to_port $DEPLOY_PORT $1; then
    # Switch load balancer
    sed -i "s/server 127.0.0.1:$SWITCH_FROM/server 127.0.0.1:$DEPLOY_PORT/" /etc/nginx/sites-available/bws-production
    nginx -s reload
    
    echo "Switched load balancer to port $DEPLOY_PORT"
    
    # Stop old instance after delay
    sleep 30
    systemctl stop bws-$SWITCH_FROM
    
    echo "Deployment completed successfully"
else
    echo "Deployment failed"
    exit 1
fi

Rolling Updates

#!/bin/bash
# /usr/local/bin/rolling-update.sh
INSTANCES=("server1" "server2" "server3")
VERSION=$1

for instance in "${INSTANCES[@]}"; do
    echo "Updating $instance..."
    
    # Remove from load balancer
    ssh $instance "nginx -s reload"  # Remove from upstream
    
    # Wait for connections to drain
    sleep 30
    
    # Deploy new version
    ssh $instance "systemctl stop bws && cp /tmp/bws-$VERSION /usr/local/bin/bws && systemctl start bws"
    
    # Health check
    if ssh $instance "curl -f -s http://localhost:8080/health"; then
        echo "$instance updated successfully"
        # Add back to load balancer
        ssh $instance "nginx -s reload"  # Add to upstream
    else
        echo "Update failed on $instance"
        exit 1
    fi
    
    sleep 10
done

echo "Rolling update completed"

Security Best Practices

Access Control

# Restrict access to BWS configuration
chmod 600 /etc/bws/config.toml
chown root:bws /etc/bws/config.toml

# Secure log files
chmod 640 /var/log/bws/*.log
chown bws:adm /var/log/bws/*.log

# Secure binary
chmod 755 /usr/local/bin/bws
chown root:root /usr/local/bin/bws

Network Security

# Disable unnecessary services
systemctl disable telnet
systemctl disable ftp
systemctl disable rsh

# Configure fail2ban for SSH protection
cat > /etc/fail2ban/jail.local << EOF
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
EOF

systemctl enable fail2ban
systemctl start fail2ban

Regular Security Updates

#!/bin/bash
# /usr/local/bin/security-updates.sh
# Run via cron: 0 2 * * 0 /usr/local/bin/security-updates.sh

# Update system packages
apt update && apt upgrade -y

# Update BWS if new version available
CURRENT_VERSION=$(bws --version | awk '{print $2}')
LATEST_VERSION=$(curl -s https://api.github.com/repos/yourusername/bws/releases/latest | jq -r .tag_name)

if [ "$CURRENT_VERSION" != "$LATEST_VERSION" ]; then
    echo "BWS update available: $CURRENT_VERSION -> $LATEST_VERSION"
    # Implement update process
fi

# Restart services if needed
if [ -f /var/run/reboot-required ]; then
    echo "Reboot required after updates"
    # Schedule maintenance window reboot
fi

Troubleshooting Production Issues

Common Issues and Solutions

High CPU Usage

# Monitor CPU usage
top -p $(pgrep bws)
htop -p $(pgrep bws)

# Check system load
uptime
iostat 1

# Review configuration
grep -E "worker_threads|max_connections" /etc/bws/config.toml

Memory Leaks

# Monitor memory usage over time
while true; do
    ps -o pid,ppid,cmd,%mem,%cpu -p $(pgrep bws)
    sleep 60
done > /tmp/bws-memory.log

# Check for memory leaks
valgrind --tool=memcheck --leak-check=full /usr/local/bin/bws

Network Issues

# Check port bindings
netstat -tulpn | grep bws

# Monitor connections
ss -tuln | grep :8080
lsof -i :8080

# Check network performance
iftop
nethogs

Disk Space Issues

# Check disk usage
df -h
du -sh /var/log/bws/
du -sh /opt/bws/

# Clean up logs
journalctl --vacuum-time=7d
logrotate -f /etc/logrotate.d/bws

Maintenance Procedures

Regular Maintenance Tasks

#!/bin/bash
# /usr/local/bin/bws-maintenance.sh
# Run weekly via cron

LOG_FILE="/var/log/bws/maintenance.log"

log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

log_message "Starting BWS maintenance"

# Check disk space
DISK_USAGE=$(df /opt/bws | tail -1 | awk '{print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -gt 85 ]; then
    log_message "WARNING: Disk usage is ${DISK_USAGE}%"
fi

# Rotate logs
logrotate -f /etc/logrotate.d/bws

# Check configuration
if bws --config-check /etc/bws/config.toml; then
    log_message "Configuration is valid"
else
    log_message "ERROR: Configuration validation failed"
fi

# Update file permissions
chown -R bws:bws /opt/bws/static/
chmod -R 644 /opt/bws/static/*

# Clean temporary files
find /tmp -name "bws-*" -mtime +7 -delete

# Backup configuration
/usr/local/bin/backup-bws-config.sh

log_message "BWS maintenance completed"

Update Procedures

#!/bin/bash
# /usr/local/bin/update-bws.sh
NEW_VERSION=$1

if [ -z "$NEW_VERSION" ]; then
    echo "Usage: $0 <version>"
    exit 1
fi

echo "Updating BWS to version $NEW_VERSION"

# Backup current version
cp /usr/local/bin/bws /usr/local/bin/bws.backup

# Download new version
wget "https://github.com/yourusername/bws/releases/download/$NEW_VERSION/bws-linux-amd64" -O /tmp/bws-$NEW_VERSION

# Verify checksum (if available)
# wget "https://github.com/yourusername/bws/releases/download/$NEW_VERSION/checksums.txt" -O /tmp/checksums.txt
# sha256sum -c /tmp/checksums.txt

# Test new version
chmod +x /tmp/bws-$NEW_VERSION
if /tmp/bws-$NEW_VERSION --version; then
    echo "New version validated"
else
    echo "New version validation failed"
    exit 1
fi

# Deploy using blue-green strategy
/usr/local/bin/deploy-bws.sh $NEW_VERSION

echo "BWS updated to version $NEW_VERSION"

Best Practices Summary

Configuration

  • Use environment-specific configuration files
  • Store sensitive data in environment variables or secret management systems
  • Regularly validate configuration syntax
  • Version control all configuration changes

Security

  • Run BWS behind a reverse proxy with SSL termination
  • Implement proper firewall rules
  • Regular security updates and patches
  • Monitor for security vulnerabilities
  • Use non-root user for BWS process

Performance

  • Tune system parameters for high-performance workloads
  • Monitor resource usage continuously
  • Implement proper caching strategies
  • Use CDN for static assets when possible

Reliability

  • Implement comprehensive health checks
  • Set up automated monitoring and alerting
  • Use deployment strategies that minimize downtime
  • Regular backups of configuration and data
  • Document incident response procedures

Monitoring

  • Monitor both technical and business metrics
  • Set up alerting with appropriate thresholds
  • Regular review of logs and metrics
  • Performance trend analysis
  • Capacity planning based on growth projections

Next Steps

Performance Tuning

This guide covers optimizing BWS for maximum performance, throughput, and efficiency in production environments.

Performance Overview

BWS is built on Pingora, providing excellent performance characteristics:

  • High-performance async I/O
  • Minimal memory footprint
  • Efficient connection handling
  • Built-in caching capabilities
  • Horizontal scaling support

System-Level Optimization

Operating System Tuning

Network Stack Optimization

# /etc/sysctl.d/99-bws-performance.conf

# TCP/IP stack tuning
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_max_tw_buckets = 1440000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 15

# Buffer sizes
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# Connection tracking
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 300

# Apply settings
sysctl -p /etc/sysctl.d/99-bws-performance.conf

File Descriptor Limits

# /etc/security/limits.d/bws-performance.conf
bws soft nofile 1048576
bws hard nofile 1048576
bws soft nproc 32768
bws hard nproc 32768

# For systemd services
# /etc/systemd/system/bws.service.d/limits.conf
[Service]
LimitNOFILE=1048576
LimitNPROC=32768

CPU and Memory Optimization

# CPU governor for performance
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

# Disable swap for consistent performance
swapoff -a
# Comment out swap in /etc/fstab

# NUMA optimization (for multi-socket systems)
echo 0 > /proc/sys/kernel/numa_balancing

Storage Optimization

File System Tuning

# Mount options for static files (add to /etc/fstab)
/dev/sdb1 /opt/bws/static ext4 defaults,noatime,nodiratime,data=writeback 0 0

# For high-performance scenarios
/dev/nvme0n1 /opt/bws/cache xfs defaults,noatime,largeio,inode64 0 0

# Temporary files in memory
tmpfs /tmp tmpfs defaults,size=2G,mode=1777 0 0
tmpfs /var/tmp tmpfs defaults,size=1G,mode=1777 0 0

I/O Scheduler Optimization

# For SSDs
echo noop > /sys/block/sda/queue/scheduler

# For HDDs
echo deadline > /sys/block/sda/queue/scheduler

# Make persistent (add to /etc/rc.local or systemd service)
echo 'noop' > /sys/block/sda/queue/scheduler

BWS Configuration Optimization

Performance-Focused Configuration

# /etc/bws/performance.toml
[performance]
# Worker thread configuration
worker_threads = 16  # 2x CPU cores for I/O bound workloads
max_blocking_threads = 512

# Connection settings
max_connections = 100000
keep_alive_timeout = 60
request_timeout = 30
response_timeout = 30

# Buffer sizes
read_buffer_size = "64KB"
write_buffer_size = "64KB"
max_request_size = "10MB"

# Connection pooling
connection_pool_size = 1000
connection_pool_idle_timeout = 300

[caching]
enabled = true
max_memory = "1GB"
ttl_default = 3600
ttl_static = 86400

[compression]
enabled = true
level = 6  # Balance between CPU and compression ratio
min_size = 1024  # Don't compress small files

[[sites]]
name = "high-performance"
hostname = "0.0.0.0"
port = 8080
static_dir = "/opt/bws/static"

# Optimized headers for caching
[sites.headers]
"Cache-Control" = "public, max-age=31536000, immutable"
"Vary" = "Accept-Encoding"
"X-Content-Type-Options" = "nosniff"

Memory Management

[memory]
# Garbage collection tuning
gc_threshold = 0.8  # Trigger GC at 80% memory usage
max_heap_size = "4GB"

# Buffer pool settings
buffer_pool_size = "512MB"
buffer_pool_max_buffers = 10000

# Static file caching
file_cache_size = "2GB"
file_cache_max_files = 100000

CPU Optimization

[cpu]
# Thread affinity (if supported)
pin_threads = true
cpu_affinity = [0, 1, 2, 3, 4, 5, 6, 7]  # Pin to specific cores

# Async runtime tuning
io_uring = true  # Use io_uring if available (Linux 5.1+)
event_loop_threads = 4

Load Testing and Benchmarking

Benchmarking Tools

wrk - HTTP Benchmarking

# Install wrk
sudo apt install wrk

# Basic load test
wrk -t12 -c400 -d30s --latency http://localhost:8080/

# Custom script for complex scenarios
cat > test-script.lua << 'EOF'
wrk.method = "GET"
wrk.headers["User-Agent"] = "wrk-benchmark"

request = function()
    local path = "/static/file" .. math.random(1, 1000) .. ".jpg"
    return wrk.format(nil, path)
end
EOF

wrk -t12 -c400 -d30s -s test-script.lua http://localhost:8080/

Apache Bench (ab)

# Simple test
ab -n 10000 -c 100 http://localhost:8080/

# With keep-alive
ab -n 10000 -c 100 -k http://localhost:8080/

# POST requests
ab -n 1000 -c 10 -p post_data.json -T application/json http://localhost:8080/api/test

hey - Modern Load Testing

# Install hey
go install github.com/rakyll/hey@latest

# Basic test
hey -n 10000 -c 100 http://localhost:8080/

# With custom headers
hey -n 10000 -c 100 -H "Accept: application/json" http://localhost:8080/api/health

# Rate limited test
hey -n 10000 -q 100 http://localhost:8080/

Performance Testing Strategy

Baseline Testing

#!/bin/bash
# performance-baseline.sh

SERVER_URL="http://localhost:8080"
RESULTS_DIR="/tmp/performance-results"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p "$RESULTS_DIR"

echo "Running BWS performance baseline tests - $DATE"

# Test 1: Static file serving
echo "Testing static file serving..."
wrk -t4 -c50 -d60s --latency "$SERVER_URL/static/test.html" > "$RESULTS_DIR/static-$DATE.log"

# Test 2: API endpoints
echo "Testing API endpoints..."
wrk -t4 -c50 -d60s --latency "$SERVER_URL/health" > "$RESULTS_DIR/api-$DATE.log"

# Test 3: High concurrency
echo "Testing high concurrency..."
wrk -t12 -c1000 -d60s --latency "$SERVER_URL/" > "$RESULTS_DIR/concurrency-$DATE.log"

# Test 4: Sustained load
echo "Testing sustained load..."
wrk -t8 -c200 -d300s --latency "$SERVER_URL/" > "$RESULTS_DIR/sustained-$DATE.log"

echo "Performance tests completed. Results in $RESULTS_DIR"

Stress Testing

#!/bin/bash
# stress-test.sh

# Gradually increase load
for connections in 100 500 1000 2000 5000; do
    echo "Testing with $connections connections..."
    wrk -t12 -c$connections -d30s --latency http://localhost:8080/ > "stress-$connections.log"
    
    # Check if server is still responsive
    if ! curl -f -s http://localhost:8080/health > /dev/null; then
        echo "Server failed at $connections connections"
        break
    fi
    
    # Cool down period
    sleep 10
done

Performance Monitoring

Real-time Monitoring Script

#!/bin/bash
# monitor-performance.sh

LOG_FILE="/var/log/bws/performance.log"
INTERVAL=5

log_metrics() {
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
    local memory_usage=$(free | grep Mem | awk '{printf "%.1f", $3/$2 * 100.0}')
    local connections=$(ss -tuln | grep :8080 | wc -l)
    local load_avg=$(uptime | awk -F'load average:' '{print $2}' | cut -d',' -f1 | xargs)
    
    echo "$timestamp,CPU:$cpu_usage%,Memory:$memory_usage%,Connections:$connections,Load:$load_avg" >> "$LOG_FILE"
}

echo "Starting performance monitoring (interval: ${INTERVAL}s)"
echo "Timestamp,CPU,Memory,Connections,LoadAvg" > "$LOG_FILE"

while true; do
    log_metrics
    sleep $INTERVAL
done

Performance Dashboard Script

#!/bin/bash
# performance-dashboard.sh

# Real-time performance dashboard
watch -n 1 '
echo "=== BWS Performance Dashboard ==="
echo "Time: $(date)"
echo ""
echo "=== System Resources ==="
echo "CPU Usage: $(top -bn1 | grep "Cpu(s)" | awk "{print \$2}")"
echo "Memory: $(free -h | grep Mem | awk "{printf \"Used: %s/%s (%.1f%%)\", \$3, \$2, \$3/\$2*100}")"
echo "Load Average: $(uptime | awk -F"load average:" "{print \$2}")"
echo ""
echo "=== Network ==="
echo "Active Connections: $(ss -tuln | grep :8080 | wc -l)"
echo "TCP Connections: $(ss -s | grep TCP | head -1)"
echo ""
echo "=== BWS Process ==="
BWS_PID=$(pgrep bws)
if [ ! -z "$BWS_PID" ]; then
    echo "Process ID: $BWS_PID"
    echo "Memory Usage: $(ps -o pid,ppid,cmd,%mem,%cpu -p $BWS_PID | tail -1)"
    echo "File Descriptors: $(lsof -p $BWS_PID | wc -l)"
else
    echo "BWS process not found"
fi
'

Optimization Strategies

Static File Optimization

File Compression

#!/bin/bash
# precompress-static-files.sh

STATIC_DIR="/opt/bws/static"

# Pre-compress static files
find "$STATIC_DIR" -type f \( -name "*.css" -o -name "*.js" -o -name "*.html" -o -name "*.svg" \) | while read file; do
    # Gzip compression
    if [ ! -f "$file.gz" ] || [ "$file" -nt "$file.gz" ]; then
        gzip -k -9 "$file"
        echo "Compressed: $file"
    fi
    
    # Brotli compression (if available)
    if command -v brotli > /dev/null; then
        if [ ! -f "$file.br" ] || [ "$file" -nt "$file.br" ]; then
            brotli -k -q 11 "$file"
            echo "Brotli compressed: $file"
        fi
    fi
done

# Optimize images
find "$STATIC_DIR" -name "*.jpg" -o -name "*.jpeg" | while read file; do
    if command -v jpegoptim > /dev/null; then
        jpegoptim --strip-all --max=85 "$file"
    fi
done

find "$STATIC_DIR" -name "*.png" | while read file; do
    if command -v optipng > /dev/null; then
        optipng -o2 "$file"
    fi
done

CDN Integration

# Configure BWS for CDN usage
[[sites]]
name = "cdn-optimized"
hostname = "localhost"
port = 8080
static_dir = "/opt/bws/static"

[sites.headers]
"Cache-Control" = "public, max-age=31536000, immutable"
"Access-Control-Allow-Origin" = "*"
"Vary" = "Accept-Encoding"
"X-CDN-Cache" = "MISS"

# Separate configuration for CDN edge
[[sites]]
name = "edge"
hostname = "edge.example.com"
port = 8081
static_dir = "/opt/bws/edge-cache"

[sites.headers]
"Cache-Control" = "public, max-age=604800"  # 1 week for edge cache
"X-CDN-Cache" = "HIT"

Database and Cache Optimization

Redis Integration (if using caching)

# Redis performance tuning
# /etc/redis/redis.conf

# Memory settings
maxmemory 2gb
maxmemory-policy allkeys-lru

# Persistence settings (adjust based on needs)
save 900 1
save 300 10
save 60 10000

# Network settings
tcp-keepalive 60
timeout 0

# Performance settings
tcp-backlog 511
databases 16

Memcached Configuration

# /etc/memcached.conf
-m 1024  # 1GB memory
-c 1024  # Max connections
-t 4     # Number of threads
-l 127.0.0.1  # Listen address
-p 11211 # Port

Reverse Proxy Optimization

Nginx Performance Configuration

# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
worker_rlimit_nofile 100000;

events {
    worker_connections 4000;
    use epoll;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 30;
    keepalive_requests 100000;
    reset_timedout_connection on;
    client_body_timeout 10;
    send_timeout 2;
    
    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml+rss
        application/atom+xml
        image/svg+xml;
    
    # Buffer sizes
    client_max_body_size 10m;
    client_body_buffer_size 128k;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 4k;
    output_buffers 1 32k;
    postpone_output 1460;
    
    # Proxy settings
    proxy_buffering on;
    proxy_buffer_size 128k;
    proxy_buffers 4 256k;
    proxy_busy_buffers_size 256k;
    
    upstream bws_backend {
        least_conn;
        server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
        server 127.0.0.1:8081 max_fails=3 fail_timeout=30s;
        keepalive 300;
    }
    
    server {
        listen 80 default_server;
        
        location / {
            proxy_pass http://bws_backend;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            
            # Caching
            proxy_cache_valid 200 1h;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
        }
    }
}

Performance Monitoring and Analysis

Key Performance Metrics

Response Time Monitoring

#!/bin/bash
# response-time-monitor.sh

URL="http://localhost:8080"
LOG_FILE="/var/log/bws/response-times.log"

while true; do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    RESPONSE_TIME=$(curl -o /dev/null -s -w "%{time_total}" "$URL/health")
    RESPONSE_CODE=$(curl -o /dev/null -s -w "%{http_code}" "$URL/health")
    
    echo "$TIMESTAMP,$RESPONSE_TIME,$RESPONSE_CODE" >> "$LOG_FILE"
    sleep 1
done

Throughput Measurement

#!/bin/bash
# throughput-monitor.sh

# Monitor requests per second
LOG_FILE="/var/log/bws/throughput.log"
ACCESS_LOG="/var/log/nginx/access.log"

while true; do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    RPS=$(tail -60 "$ACCESS_LOG" | grep "$(date '+%d/%b/%Y:%H:%M')" | wc -l)
    
    echo "$TIMESTAMP,$RPS" >> "$LOG_FILE"
    sleep 60
done

Performance Analysis Tools

Log Analysis

#!/bin/bash
# analyze-performance.sh

LOG_FILE="/var/log/nginx/access.log"
OUTPUT_DIR="/tmp/performance-analysis"
DATE=$(date +%Y%m%d)

mkdir -p "$OUTPUT_DIR"

echo "Analyzing performance for $DATE"

# Top requested URLs
echo "=== Top Requested URLs ===" > "$OUTPUT_DIR/top-urls-$DATE.txt"
awk '{print $7}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -20 >> "$OUTPUT_DIR/top-urls-$DATE.txt"

# Response codes distribution
echo "=== Response Codes ===" > "$OUTPUT_DIR/response-codes-$DATE.txt"
awk '{print $9}' "$LOG_FILE" | sort | uniq -c | sort -rn >> "$OUTPUT_DIR/response-codes-$DATE.txt"

# Response time analysis (if logged)
echo "=== Response Time Analysis ===" > "$OUTPUT_DIR/response-times-$DATE.txt"
awk '{print $NF}' "$LOG_FILE" | grep -E '^[0-9]+\.[0-9]+$' | \
awk '{
    sum += $1
    count++
    if ($1 > max) max = $1
    if (min == 0 || $1 < min) min = $1
}
END {
    print "Average:", sum/count
    print "Min:", min
    print "Max:", max
}' >> "$OUTPUT_DIR/response-times-$DATE.txt"

# Hourly request distribution
echo "=== Hourly Request Distribution ===" > "$OUTPUT_DIR/hourly-requests-$DATE.txt"
awk '{print substr($4, 14, 2)}' "$LOG_FILE" | sort | uniq -c >> "$OUTPUT_DIR/hourly-requests-$DATE.txt"

echo "Analysis complete. Results in $OUTPUT_DIR"
#!/bin/bash
# resource-trends.sh

DURATION=${1:-3600}  # Default 1 hour
INTERVAL=10
SAMPLES=$((DURATION / INTERVAL))

echo "Collecting resource usage data for $DURATION seconds..."
echo "timestamp,cpu_percent,memory_mb,connections,load_avg" > resource-usage.csv

for i in $(seq 1 $SAMPLES); do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    CPU_PERCENT=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
    MEMORY_MB=$(ps -o pid,rss -p $(pgrep bws) | tail -1 | awk '{print $2/1024}')
    CONNECTIONS=$(ss -tuln | grep :8080 | wc -l)
    LOAD_AVG=$(uptime | awk -F'load average:' '{print $2}' | cut -d',' -f1 | xargs)
    
    echo "$TIMESTAMP,$CPU_PERCENT,$MEMORY_MB,$CONNECTIONS,$LOAD_AVG" >> resource-usage.csv
    
    sleep $INTERVAL
done

echo "Resource usage data collected in resource-usage.csv"

Optimization Recommendations

Hardware Recommendations

CPU Optimization

  • Use modern CPUs with high single-thread performance
  • Consider NUMA topology for multi-socket systems
  • Enable CPU turbo boost for peak performance
  • Pin BWS processes to specific CPU cores for consistency

Memory Optimization

  • Use ECC RAM for data integrity
  • Ensure sufficient RAM for file caching
  • Consider NUMA-aware memory allocation
  • Monitor for memory leaks and fragmentation

Storage Optimization

  • Use NVMe SSDs for static file storage
  • Implement RAID for redundancy without performance penalty
  • Consider separate storage for logs and static files
  • Use tmpfs for temporary files and cache

Network Optimization

  • Use 10Gbps+ network interfaces for high-traffic scenarios
  • Implement network bonding for redundancy
  • Optimize network driver settings
  • Consider SR-IOV for virtualized environments

Application-Level Optimization

Code Optimization

#![allow(unused)]
fn main() {
// Example optimizations in BWS configuration
use pingora::prelude::*;
use tokio::runtime::Builder;

// Custom runtime configuration
let runtime = Builder::new_multi_thread()
    .worker_threads(num_cpus::get() * 2)
    .max_blocking_threads(512)
    .thread_keep_alive(Duration::from_secs(60))
    .enable_all()
    .build()
    .unwrap();

// Connection pooling optimization
let pool_config = ConnectionPoolConfig {
    max_connections_per_host: 100,
    idle_timeout: Duration::from_secs(300),
    connect_timeout: Duration::from_secs(10),
};
}

Memory Pool Configuration

[memory_pool]
small_buffer_size = "4KB"
medium_buffer_size = "64KB"
large_buffer_size = "1MB"
pool_size = 1000

Scaling Strategies

Horizontal Scaling

# Kubernetes deployment example
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bws-deployment
spec:
  replicas: 6
  selector:
    matchLabels:
      app: bws
  template:
    metadata:
      labels:
        app: bws
    spec:
      containers:
      - name: bws
        image: ghcr.io/yourusername/bws:latest
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: bws-service
spec:
  selector:
    app: bws
  ports:
  - port: 80
    targetPort: 8080
  type: LoadBalancer

Vertical Scaling

# Automatic resource scaling script
#!/bin/bash
# auto-scale.sh

CPU_THRESHOLD=80
MEMORY_THRESHOLD=80
CHECK_INTERVAL=60

while true; do
    CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
    MEMORY_USAGE=$(free | grep Mem | awk '{printf "%.0f", $3/$2 * 100.0}')
    
    if (( $(echo "$CPU_USAGE > $CPU_THRESHOLD" | bc -l) )); then
        echo "High CPU usage detected: $CPU_USAGE%"
        # Scale up logic here
    fi
    
    if (( MEMORY_USAGE > MEMORY_THRESHOLD )); then
        echo "High memory usage detected: $MEMORY_USAGE%"
        # Scale up logic here
    fi
    
    sleep $CHECK_INTERVAL
done

Performance Best Practices

Configuration Best Practices

  1. Right-size worker threads: 2x CPU cores for I/O-bound workloads
  2. Optimize buffer sizes: Match your typical request/response sizes
  3. Enable compression: For text-based content
  4. Use connection pooling: Reuse connections for better performance
  5. Configure appropriate timeouts: Balance responsiveness and resource usage

Monitoring Best Practices

  1. Monitor key metrics: Response time, throughput, error rate, resource usage
  2. Set up alerting: For performance degradation
  3. Regular performance testing: Catch regressions early
  4. Capacity planning: Monitor trends and plan for growth
  5. Document baselines: Know your normal performance characteristics

Deployment Best Practices

  1. Load testing: Test under realistic load before production
  2. Gradual rollouts: Use blue-green or canary deployments
  3. Performance regression testing: Automated checks for performance changes
  4. Resource monitoring: Continuous monitoring of system resources
  5. Regular optimization: Periodic performance reviews and tuning

Next Steps

REST API

BWS provides a REST API for monitoring and management.

Endpoints

Health Check

GET /api/health

Returns the server health status.

Response:

{
  "status": "healthy",
  "timestamp": "2025-08-23T12:00:00Z",
  "version": "0.1.5",
  "uptime_seconds": 3600
}

Example:

curl http://localhost:8080/api/health

Sites Information

GET /api/sites

Returns information about all configured sites.

Response:

{
  "sites": [
    {
      "name": "main",
      "hostname": "localhost",
      "port": 8080,
      "static_dir": "static",
      "default": true,
      "headers": {
        "X-Site-Name": "BWS Main Site",
        "X-Powered-By": "BWS/1.0"
      }
    }
  ],
  "total_sites": 1
}

Example:

curl http://localhost:8080/api/sites

Response Headers

All API responses include these headers:

  • Content-Type: application/json
  • X-Powered-By: BWS/1.0
  • Site-specific custom headers (if configured)

Error Responses

API endpoints return standard HTTP status codes:

  • 200 OK - Successful request
  • 404 Not Found - Endpoint not found
  • 500 Internal Server Error - Server error

Error Format:

{
  "error": "Not Found",
  "message": "The requested endpoint does not exist",
  "available_endpoints": ["/", "/api/health", "/api/sites"]
}

Configuration Schema

This document provides a complete reference for all BWS configuration options in the config.toml file.

Configuration File Structure

BWS uses TOML format for configuration. The basic structure is:

# Global settings
[daemon]
# Daemon configuration

[logging]
# Logging configuration

[performance]
# Performance tuning

[monitoring]
# Health monitoring

# Site definitions
[[sites]]
# First site configuration

[[sites]]
# Second site configuration

Global Configuration Sections

Daemon Configuration

Controls how BWS runs as a daemon process.

[daemon]
user = "bws"                           # User to run as (string)
group = "bws"                          # Group to run as (string)
pid_file = "/var/run/bws.pid"          # PID file location (string)
working_directory = "/opt/bws"         # Working directory (string)
daemonize = true                       # Run as daemon (boolean)

Parameters:

  • user (string, optional): System user to run BWS as. Default: current user
  • group (string, optional): System group to run BWS as. Default: current user's group
  • pid_file (string, optional): Path to store process ID file. Default: no PID file
  • working_directory (string, optional): Change to this directory on startup
  • daemonize (boolean, optional): Fork and run in background. Default: false

Logging Configuration

Controls logging behavior and output.

[logging]
level = "info"                         # Log level (string)
output = "stdout"                      # Output destination (string)
format = "json"                        # Log format (string)
file_path = "/var/log/bws/bws.log"    # Log file path (string)
max_size = "100MB"                     # Maximum log file size (string)
max_files = 10                         # Number of log files to keep (integer)
compress = true                        # Compress rotated logs (boolean)
include_fields = [                     # Fields to include in logs (array)
    "timestamp",
    "level", 
    "message",
    "request_id"
]

Parameters:

  • level (string, optional): Log level. Values: trace, debug, info, warn, error. Default: info
  • output (string, optional): Where to send logs. Values: stdout, stderr, file. Default: stdout
  • format (string, optional): Log format. Values: text, json. Default: text
  • file_path (string, required if output="file"): Path to log file
  • max_size (string, optional): Maximum size before rotation. Examples: 10MB, 1GB. Default: 100MB
  • max_files (integer, optional): Number of rotated files to keep. Default: 10
  • compress (boolean, optional): Compress rotated log files. Default: true
  • include_fields (array, optional): Fields to include in structured logs

Performance Configuration

Tuning parameters for performance optimization.

[performance]
worker_threads = 8                     # Number of worker threads (integer)
max_blocking_threads = 512             # Max blocking threads (integer)
max_connections = 10000                # Maximum concurrent connections (integer)
keep_alive_timeout = 60                # Keep-alive timeout in seconds (integer)
request_timeout = 30                   # Request timeout in seconds (integer)
response_timeout = 30                  # Response timeout in seconds (integer)
read_buffer_size = "64KB"              # Read buffer size (string)
write_buffer_size = "64KB"             # Write buffer size (string)
max_request_size = "10MB"              # Maximum request size (string)
connection_pool_size = 1000            # Connection pool size (integer)
connection_pool_idle_timeout = 300     # Pool idle timeout in seconds (integer)

Parameters:

  • worker_threads (integer, optional): Number of async worker threads. Default: number of CPU cores
  • max_blocking_threads (integer, optional): Maximum blocking threads for file I/O. Default: 512
  • max_connections (integer, optional): Maximum concurrent connections. Default: 10000
  • keep_alive_timeout (integer, optional): HTTP keep-alive timeout in seconds. Default: 60
  • request_timeout (integer, optional): Request processing timeout in seconds. Default: 30
  • response_timeout (integer, optional): Response sending timeout in seconds. Default: 30
  • read_buffer_size (string, optional): Buffer size for reading requests. Default: 8KB
  • write_buffer_size (string, optional): Buffer size for writing responses. Default: 8KB
  • max_request_size (string, optional): Maximum allowed request size. Default: 1MB
  • connection_pool_size (integer, optional): Size of connection pool. Default: 100
  • connection_pool_idle_timeout (integer, optional): Idle timeout for pooled connections. Default: 300

Monitoring Configuration

Health monitoring and metrics collection.

[monitoring]
enabled = true                         # Enable monitoring (boolean)
health_endpoint = "/health"            # Health check endpoint (string)
detailed_endpoint = "/health/detailed" # Detailed health endpoint (string)
metrics_endpoint = "/metrics"          # Metrics endpoint for Prometheus (string)

[monitoring.checks]
disk_threshold = 90                    # Disk usage alert threshold (integer)
memory_threshold = 80                  # Memory usage alert threshold (integer)
response_time_threshold = 1000         # Response time alert threshold in ms (integer)

[monitoring.prometheus]
enabled = true                         # Enable Prometheus metrics (boolean)
endpoint = "/metrics"                  # Metrics endpoint path (string)
port = 9090                           # Metrics server port (integer)

Parameters:

  • enabled (boolean, optional): Enable health monitoring. Default: true
  • health_endpoint (string, optional): Path for basic health checks. Default: /health
  • detailed_endpoint (string, optional): Path for detailed health info. Default: /health/detailed
  • metrics_endpoint (string, optional): Path for Prometheus metrics. Default: /metrics

Monitoring Checks:

  • disk_threshold (integer, optional): Alert when disk usage exceeds this percentage. Default: 90
  • memory_threshold (integer, optional): Alert when memory usage exceeds this percentage. Default: 80
  • response_time_threshold (integer, optional): Alert when response time exceeds this value in milliseconds. Default: 1000

Prometheus Integration:

  • enabled (boolean, optional): Enable Prometheus metrics export. Default: false
  • endpoint (string, optional): Metrics endpoint path. Default: /metrics
  • port (integer, optional): Port for metrics server. Default: same as main site

Caching Configuration

Configure caching behavior for static files.

[caching]
enabled = true                         # Enable caching (boolean)
max_memory = "1GB"                     # Maximum memory for cache (string)
ttl_default = 3600                     # Default TTL in seconds (integer)
ttl_static = 86400                     # TTL for static files (integer)
max_file_size = "10MB"                 # Maximum cacheable file size (string)
cache_control_override = false         # Override Cache-Control headers (boolean)

Parameters:

  • enabled (boolean, optional): Enable response caching. Default: false
  • max_memory (string, optional): Maximum memory to use for cache. Default: 100MB
  • ttl_default (integer, optional): Default cache TTL in seconds. Default: 3600
  • ttl_static (integer, optional): TTL for static files in seconds. Default: 86400
  • max_file_size (string, optional): Maximum size of files to cache. Default: 1MB
  • cache_control_override (boolean, optional): Override existing Cache-Control headers. Default: false

Compression Configuration

Configure response compression.

[compression]
enabled = true                         # Enable compression (boolean)
level = 6                              # Compression level 1-9 (integer)
min_size = 1024                        # Minimum size to compress (integer)
algorithms = ["gzip", "deflate"]       # Compression algorithms (array)
types = [                              # MIME types to compress (array)
    "text/html",
    "text/css",
    "application/javascript",
    "application/json"
]

Parameters:

  • enabled (boolean, optional): Enable response compression. Default: false
  • level (integer, optional): Compression level (1-9, higher = better compression). Default: 6
  • min_size (integer, optional): Minimum response size to compress in bytes. Default: 1024
  • algorithms (array, optional): Supported compression algorithms. Default: ["gzip"]
  • types (array, optional): MIME types to compress. Default: common text types

Site Configuration

Each [[sites]] section defines a virtual host or site.

Basic Site Configuration

[[sites]]
name = "example"                       # Site identifier (string)
hostname = "localhost"                 # Hostname to bind to (string)
port = 8080                           # Port to listen on (integer)
static_dir = "static"                 # Directory for static files (string)
index_file = "index.html"             # Default index file (string)

Required Parameters:

  • name (string): Unique identifier for this site
  • hostname (string): Hostname or IP address to bind to
  • port (integer): TCP port number to listen on
  • static_dir (string): Path to directory containing static files

Optional Parameters:

  • index_file (string, optional): Default file to serve for directory requests. Default: index.html

Advanced Site Configuration

[[sites]]
name = "advanced"
hostname = "example.com"
port = 8080
static_dir = "/var/www/example"
index_file = "index.html"
enable_directory_listing = false      # Allow directory browsing (boolean)
follow_symlinks = false               # Follow symbolic links (boolean)
case_sensitive = true                 # Case-sensitive file matching (boolean)
max_age = 3600                        # Default cache max-age (integer)
cors_enabled = true                   # Enable CORS headers (boolean)

Additional Parameters:

  • enable_directory_listing (boolean, optional): Allow browsing directories without index files. Default: false
  • follow_symlinks (boolean, optional): Follow symbolic links when serving files. Default: false
  • case_sensitive (boolean, optional): Case-sensitive URL matching. Default: true
  • max_age (integer, optional): Default Cache-Control max-age in seconds. Default: 3600
  • cors_enabled (boolean, optional): Enable CORS headers for cross-origin requests. Default: false

Site Headers Configuration

Custom HTTP headers for responses from a site.

[[sites]]
name = "example"
hostname = "localhost"
port = 8080
static_dir = "static"

[sites.headers]
"Cache-Control" = "public, max-age=3600"
"X-Content-Type-Options" = "nosniff"
"X-Frame-Options" = "DENY"
"X-XSS-Protection" = "1; mode=block"
"Strict-Transport-Security" = "max-age=31536000"
"Content-Security-Policy" = "default-src 'self'"
"Referrer-Policy" = "strict-origin-when-cross-origin"
"Access-Control-Allow-Origin" = "*"
"Access-Control-Allow-Methods" = "GET, POST, PUT, DELETE"
"X-Custom-Header" = "custom-value"

Header Configuration:

  • Any valid HTTP header name can be used as a key
  • Header values must be strings
  • Headers are added to all responses from the site
  • Case-insensitive header names (will be normalized)

Site SSL/TLS Configuration

Configure SSL/TLS for HTTPS sites with automatic or manual certificates.

[[sites]]
name = "secure"
hostname = "secure.example.com"
port = 443
static_dir = "static"

[sites.ssl]
enabled = true                         # Enable SSL/TLS (boolean)
auto_cert = true                       # Use automatic certificates (boolean)
domains = ["secure.example.com", "www.secure.example.com"] # Additional domains (array)
cert_file = "/etc/ssl/certs/site.crt" # Certificate file path (string)
key_file = "/etc/ssl/private/site.key" # Private key file path (string)

[sites.ssl.acme]
enabled = true                         # Enable ACME certificate generation (boolean)
email = "admin@example.com"            # Email for ACME registration (string)
staging = false                        # Use staging environment (boolean)
challenge_dir = "./acme-challenges"    # ACME challenge directory (string)

SSL Parameters:

  • enabled (boolean, optional): Enable SSL/TLS for this site. Default: false
  • auto_cert (boolean, optional): Use automatic certificate generation via ACME. Default: false
  • domains (array, optional): Additional domains for the SSL certificate. Default: []
  • cert_file (string, required if auto_cert=false): Path to SSL certificate file
  • key_file (string, required if auto_cert=false): Path to SSL private key file

ACME Configuration:

  • enabled (boolean, optional): Enable ACME certificate generation. Default: false
  • email (string, required if enabled): Email address for ACME registration
  • staging (boolean, optional): Use Let's Encrypt staging environment for testing. Default: false
  • challenge_dir (string, optional): Directory for HTTP-01 challenge files. Default: "./acme-challenges"

SSL Configuration Examples:

Automatic SSL with ACME (Let's Encrypt):

[sites.ssl]
enabled = true
auto_cert = true
domains = ["example.com", "www.example.com"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "./acme-challenges"

Manual SSL with custom certificates:

[sites.ssl]
enabled = true
auto_cert = false
cert_file = "/etc/ssl/certs/example.com.crt"
key_file = "/etc/ssl/private/example.com.key"

Site Rate Limiting

Configure rate limiting for requests.

[[sites]]
name = "rate-limited"
hostname = "api.example.com"
port = 8080
static_dir = "static"

[sites.rate_limit]
enabled = true                         # Enable rate limiting (boolean)
requests_per_minute = 60              # Requests per minute per IP (integer)
burst_size = 10                       # Burst allowance (integer)
block_duration = 300                  # Block duration in seconds (integer)
whitelist = ["127.0.0.1", "10.0.0.0/8"] # IP whitelist (array)
blacklist = ["192.168.1.100"]        # IP blacklist (array)

Rate Limiting Parameters:

  • enabled (boolean, optional): Enable rate limiting. Default: false
  • requests_per_minute (integer, optional): Maximum requests per minute per IP. Default: 60
  • burst_size (integer, optional): Allow burst of requests above the rate. Default: 10
  • block_duration (integer, optional): How long to block an IP after rate limit exceeded. Default: 300
  • whitelist (array, optional): IP addresses or CIDR blocks to exempt from rate limiting
  • blacklist (array, optional): IP addresses or CIDR blocks to always block

Site Access Control

Configure access control and authentication.

[[sites]]
name = "protected"
hostname = "internal.example.com"
port = 8080
static_dir = "static"

[sites.access]
allow_ips = ["10.0.0.0/8", "192.168.0.0/16"] # Allowed IP ranges (array)
deny_ips = ["192.168.1.100"]          # Denied IP addresses (array)
require_auth = true                    # Require authentication (boolean)
auth_type = "basic"                    # Authentication type (string)
auth_realm = "Protected Area"          # Basic auth realm (string)
auth_file = "/etc/bws/htpasswd"       # Password file for basic auth (string)

Access Control Parameters:

  • allow_ips (array, optional): IP addresses or CIDR blocks allowed access
  • deny_ips (array, optional): IP addresses or CIDR blocks denied access
  • require_auth (boolean, optional): Require authentication for access. Default: false
  • auth_type (string, optional): Authentication method. Values: basic, digest. Default: basic
  • auth_realm (string, optional): Realm name for HTTP authentication. Default: BWS
  • auth_file (string, required if require_auth=true): Path to password file

Complete Configuration Example

# BWS Complete Configuration Example

# Daemon configuration
[daemon]
user = "bws"
group = "bws"
pid_file = "/var/run/bws.pid"
working_directory = "/opt/bws"

# Logging configuration
[logging]
level = "info"
output = "file"
format = "json"
file_path = "/var/log/bws/bws.log"
max_size = "100MB"
max_files = 10
compress = true

# Performance tuning
[performance]
worker_threads = 8
max_connections = 10000
keep_alive_timeout = 60
request_timeout = 30
read_buffer_size = "64KB"
write_buffer_size = "64KB"

# Monitoring
[monitoring]
enabled = true
health_endpoint = "/health"
detailed_endpoint = "/health/detailed"

[monitoring.checks]
disk_threshold = 90
memory_threshold = 80
response_time_threshold = 1000

# Caching
[caching]
enabled = true
max_memory = "1GB"
ttl_default = 3600
ttl_static = 86400

# Compression
[compression]
enabled = true
level = 6
min_size = 1024
types = ["text/html", "text/css", "application/javascript"]

# Main website (HTTP)
[[sites]]
name = "main"
hostname = "example.com"
port = 80
static_dir = "/var/www/main"
index_file = "index.html"

[sites.ssl]
enabled = false

[sites.headers]
"Cache-Control" = "public, max-age=3600"
"X-Content-Type-Options" = "nosniff"
"X-Frame-Options" = "SAMEORIGIN"

# Main website (HTTPS with auto SSL)
[[sites]]
name = "main_https"
hostname = "example.com"
port = 443
static_dir = "/var/www/main"
index_file = "index.html"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["example.com", "www.example.com"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
staging = false
challenge_dir = "/var/www/acme-challenges"

[sites.headers]
"Cache-Control" = "public, max-age=3600"
"X-Content-Type-Options" = "nosniff"
"X-Frame-Options" = "SAMEORIGIN"
"Strict-Transport-Security" = "max-age=31536000"

# API server (HTTPS with manual SSL)
[[sites]]
name = "api"
hostname = "api.example.com"
port = 443
static_dir = "/var/www/api-docs"

[sites.ssl]
enabled = true
auto_cert = false
cert_file = "/etc/ssl/certs/api.example.com.crt"
key_file = "/etc/ssl/private/api.example.com.key"

[sites.headers]
"Content-Type" = "application/json"
"Access-Control-Allow-Origin" = "https://example.com"
"Cache-Control" = "no-cache"
"Strict-Transport-Security" = "max-age=31536000"

[sites.rate_limit]
enabled = true
requests_per_minute = 100
burst_size = 20

# Secure admin interface
[[sites]]
name = "admin"
hostname = "admin.example.com"
port = 8443
static_dir = "/var/www/admin"

[sites.ssl]
enabled = true
cert_file = "/etc/ssl/certs/admin.crt"
key_file = "/etc/ssl/private/admin.key"

[sites.access]
allow_ips = ["10.0.0.0/8"]
require_auth = true
auth_file = "/etc/bws/admin.htpasswd"

[sites.headers]
"Strict-Transport-Security" = "max-age=31536000"
"X-Frame-Options" = "DENY"

Data Types and Formats

String Values

  • Quoted strings: "value"
  • Raw strings: 'value' (no escape sequences)
  • Multi-line strings: """value"""

Size Values

Size values can use suffixes:

  • B - bytes
  • KB - kilobytes (1024 bytes)
  • MB - megabytes (1024 KB)
  • GB - gigabytes (1024 MB)

Examples: "1MB", "512KB", "2GB"

Duration Values

Duration values are integers representing seconds unless otherwise specified.

Arrays

Arrays use square brackets: ["item1", "item2"]

IP Addresses and CIDR

  • IPv4: "192.168.1.1"
  • IPv6: "2001:db8::1"
  • CIDR notation: "192.168.0.0/16", "10.0.0.0/8"

Configuration Validation

BWS validates configuration on startup. Common validation errors:

Syntax Errors

# Invalid: missing quotes
name = value  # Should be name = "value"

# Invalid: missing comma in array
ports = [8080 8081]  # Should be ports = [8080, 8081]

Type Errors

# Invalid: string instead of integer
port = "8080"  # Should be port = 8080

# Invalid: integer instead of boolean
enabled = 1  # Should be enabled = true

Logical Errors

# Invalid: duplicate site names
[[sites]]
name = "main"

[[sites]]
name = "main"  # Error: duplicate name

# Invalid: missing required fields
[[sites]]
hostname = "localhost"  # Error: missing port and static_dir

Environment Variable Overrides

Some configuration values can be overridden with environment variables:

BWS_CONFIG=/path/to/config.toml       # Configuration file path
BWS_LOG_FILE=/path/to/log/file        # Override logging.file_path
BWS_PID_FILE=/path/to/pid/file        # Override daemon.pid_file
BWS_STATIC_DIR=/path/to/static        # Override sites.static_dir (first site)
BWS_PORT=8080                         # Override sites.port (first site)
BWS_HOSTNAME=localhost                # Override sites.hostname (first site)
RUST_LOG=debug                        # Override logging.level

Configuration Best Practices

Security

  • Set appropriate file permissions (600) for configuration files
  • Use separate configuration files for different environments
  • Store sensitive data in environment variables or external secret management
  • Regularly review and audit configuration changes

Performance

  • Tune worker threads based on workload characteristics
  • Configure appropriate timeouts for your use case
  • Enable compression for text-based content
  • Use caching for frequently accessed static files

Monitoring

  • Enable health endpoints for monitoring
  • Configure appropriate thresholds for alerts
  • Use structured logging for better analysis
  • Monitor resource usage trends

Maintenance

  • Use version control for configuration files
  • Document configuration changes
  • Test configuration changes in non-production environments
  • Implement configuration validation in CI/CD pipelines

Next Steps

Contributing to BWS

Thank you for your interest in contributing to BWS! This guide will help you get started with contributing to the project.

Getting Started

Prerequisites

Before contributing, ensure you have:

  • Rust: Version 1.89 or later
  • Git: For version control
  • GitHub Account: For submitting pull requests
  • Basic Rust Knowledge: Understanding of Rust syntax and concepts

Development Environment Setup

  1. Fork the Repository

    # Fork the repository on GitHub, then clone your fork
    git clone https://github.com/yourusername/bws.git
    cd bws
    
    # Add upstream remote
    git remote add upstream https://github.com/benliao/bws.git
    
  2. Install Dependencies

    # Install Rust if not already installed
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    source ~/.cargo/env
    
    # Install required tools
    cargo install cargo-fmt
    cargo install cargo-clippy
    cargo install cargo-audit
    
  3. Build the Project

    # Build in debug mode
    cargo build
    
    # Run tests
    cargo test
    
    # Check formatting and linting
    cargo fmt --check
    cargo clippy -- -D warnings
    

Development Workflow

1. Creating a Feature Branch

# Sync with upstream
git fetch upstream
git checkout main
git merge upstream/main

# Create feature branch
git checkout -b feature/your-feature-name

2. Making Changes

Follow these guidelines when making changes:

Code Style

  • Follow Rust standard formatting (cargo fmt)
  • Use meaningful variable and function names
  • Add documentation for public APIs
  • Include unit tests for new functionality

Commit Messages

Use conventional commit format:

type(scope): description

body (optional)

footer (optional)

Examples:

git commit -m "feat(server): add HTTP/2 support"
git commit -m "fix(config): handle missing static directory"
git commit -m "docs(readme): update installation instructions"

Commit Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting, etc.)
  • refactor: Code refactoring
  • test: Adding or updating tests
  • chore: Maintenance tasks

3. Testing Your Changes

# Run all tests
cargo test

# Run specific test
cargo test test_name

# Run tests with output
cargo test -- --nocapture

# Run integration tests
cargo test --test integration

# Check for memory leaks (if available)
cargo valgrind test

4. Code Quality Checks

# Format code
cargo fmt

# Check formatting
cargo fmt --check

# Run linter
cargo clippy

# Check for security vulnerabilities
cargo audit

# Check documentation
cargo doc --no-deps

Contributing Guidelines

Code Organization

src/
โ”œโ”€โ”€ lib.rs          # Main library entry point
โ”œโ”€โ”€ bin/
โ”‚   โ””โ”€โ”€ main.rs     # Binary entry point
โ”œโ”€โ”€ config/         # Configuration handling
โ”œโ”€โ”€ server/         # Server implementation
โ”œโ”€โ”€ handlers/       # Request handlers
โ”œโ”€โ”€ utils/          # Utility functions
โ””โ”€โ”€ tests/          # Integration tests

tests/              # Integration tests
docs/               # Documentation
examples/           # Example configurations

Writing Good Code

1. Error Handling

#![allow(unused)]
fn main() {
use anyhow::{Context, Result};

fn read_config_file(path: &str) -> Result<Config> {
    let content = std::fs::read_to_string(path)
        .with_context(|| format!("Failed to read config file: {}", path))?;
    
    toml::from_str(&content)
        .with_context(|| "Failed to parse config file")
}
}

2. Logging

#![allow(unused)]
fn main() {
use tracing::{info, warn, error, debug};

fn start_server(config: &Config) -> Result<()> {
    info!("Starting BWS server on {}:{}", config.hostname, config.port);
    
    match bind_server(&config) {
        Ok(server) => {
            info!("Server started successfully");
            server.run()
        }
        Err(e) => {
            error!("Failed to start server: {}", e);
            Err(e)
        }
    }
}
}

3. Documentation

#![allow(unused)]
fn main() {
/// Handles HTTP requests for static file serving
/// 
/// # Arguments
/// 
/// * `request` - The incoming HTTP request
/// * `static_dir` - Path to the directory containing static files
/// 
/// # Returns
/// 
/// Returns a `Result` containing the HTTP response or an error
/// 
/// # Examples
/// 
/// ```rust
/// let response = handle_static_request(&request, "/var/www/static")?;
/// ```
pub fn handle_static_request(
    request: &HttpRequest, 
    static_dir: &str
) -> Result<HttpResponse> {
    // Implementation here
}
}

4. Testing

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_config_parsing() {
        let config_str = r#"
            [[sites]]
            name = "test"
            hostname = "localhost"
            port = 8080
            static_dir = "static"
        "#;
        
        let config: Config = toml::from_str(config_str).unwrap();
        assert_eq!(config.sites.len(), 1);
        assert_eq!(config.sites[0].name, "test");
    }
    
    #[tokio::test]
    async fn test_server_startup() {
        let config = Config::default();
        let result = start_server(&config).await;
        assert!(result.is_ok());
    }
}
}

Pull Request Process

1. Before Submitting

  • Code follows project style guidelines
  • All tests pass (cargo test)
  • Code is properly formatted (cargo fmt)
  • No clippy warnings (cargo clippy)
  • Documentation is updated if needed
  • CHANGELOG.md is updated for user-facing changes

2. Pull Request Template

## Description
Brief description of changes made.

## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update

## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing performed

## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Tests pass
- [ ] Documentation updated
- [ ] CHANGELOG.md updated

3. Review Process

  1. Automated Checks: CI/CD pipeline runs automatically
  2. Code Review: Maintainers review the changes
  3. Feedback: Address any requested changes
  4. Approval: Once approved, the PR will be merged

Issue Reporting

Bug Reports

Use the bug report template:

**Bug Description**
A clear description of the bug.

**Steps to Reproduce**
1. Step 1
2. Step 2
3. Step 3

**Expected Behavior**
What you expected to happen.

**Actual Behavior**
What actually happened.

**Environment**
- OS: [e.g., Ubuntu 20.04]
- Rust version: [e.g., 1.89.0]
- BWS version: [e.g., 0.1.5]

**Configuration**
```toml
# Include relevant configuration

Logs

Include relevant log output

#### Feature Requests

Use the feature request template:

```markdown
**Feature Description**
Clear description of the proposed feature.

**Use Case**
Explain why this feature would be useful.

**Proposed Solution**
Describe how you envision this feature working.

**Alternatives Considered**
Any alternative solutions you've considered.

**Additional Context**
Any other context about the feature request.

Development Best Practices

Code Review Guidelines

When reviewing code:

  1. Functionality: Does the code work correctly?
  2. Style: Does it follow project conventions?
  3. Performance: Are there performance implications?
  4. Security: Are there security concerns?
  5. Maintainability: Is the code easy to understand and maintain?
  6. Testing: Are there adequate tests?

Performance Considerations

  • Use cargo bench for performance testing
  • Profile with cargo flamegraph when needed
  • Consider memory allocation patterns
  • Benchmark critical paths
  • Document performance characteristics

Security Guidelines

  • Validate all user inputs
  • Use secure defaults
  • Follow principle of least privilege
  • Regular security audits with cargo audit
  • Handle sensitive data carefully
  • Document security assumptions

Development Tools

# Essential tools
cargo install cargo-watch      # Auto-rebuild on changes
cargo install cargo-expand     # Expand macros
cargo install cargo-tree       # Dependency tree
cargo install cargo-outdated   # Check for outdated dependencies

# Development helpers
cargo install cargo-edit       # Add/remove dependencies easily
cargo install cargo-release    # Release management
cargo install cargo-benchcmp   # Compare benchmarks

IDE Setup

VS Code

Recommended extensions:

  • rust-analyzer
  • CodeLLDB (debugging)
  • Better TOML
  • GitLens

Settings

{
    "rust-analyzer.checkOnSave.command": "clippy",
    "rust-analyzer.cargo.features": "all",
    "editor.formatOnSave": true
}

Debugging

# Debug build
cargo build

# Run with debugger
rust-gdb target/debug/bws

# Or with lldb
rust-lldb target/debug/bws

# Environment variables for debugging
RUST_BACKTRACE=1 cargo run
RUST_LOG=debug cargo run

Release Process

Version Numbering

BWS follows Semantic Versioning:

  • MAJOR: Breaking changes
  • MINOR: New features (backward compatible)
  • PATCH: Bug fixes (backward compatible)

Release Checklist

  1. Update Version Numbers

    # Update Cargo.toml
    version = "0.2.0"
    
    # Update documentation references
    
  2. Update CHANGELOG.md

    ## [0.2.0] - 2024-01-15
    
    ### Added
    - New feature descriptions
    
    ### Changed
    - Changed feature descriptions
    
    ### Fixed
    - Bug fix descriptions
    
  3. Run Full Test Suite

    cargo test --all-features
    cargo clippy --all-targets --all-features
    cargo fmt --check
    cargo audit
    
  4. Update Documentation

    cargo doc --no-deps
    mdbook build docs/
    
  5. Create Release Tag

    git tag -a v0.2.0 -m "Release version 0.2.0"
    git push origin v0.2.0
    

Community Guidelines

Code of Conduct

We follow the Rust Code of Conduct:

  • Be friendly and welcoming
  • Be patient
  • Be respectful
  • Be constructive
  • Choose your words carefully

Communication Channels

  • GitHub Issues: Bug reports and feature requests
  • GitHub Discussions: General questions and discussions
  • Pull Requests: Code contributions and reviews

Getting Help

If you need help:

  1. Check existing documentation
  2. Search GitHub issues
  3. Ask in GitHub Discussions
  4. Ping maintainers in issues/PRs if urgent

Recognition

Contributors are recognized in:

  • CONTRIBUTORS.md file
  • Release notes
  • GitHub contributor graphs
  • Special thanks in documentation

Advanced Topics

Adding New Features

1. Design Document

For significant features, create a design document:

# Feature: HTTP/2 Support

## Overview
Add HTTP/2 support to BWS for improved performance.

## Motivation
- Better multiplexing
- Reduced latency
- Industry standard

## Design
- Use hyper's HTTP/2 implementation
- Maintain backward compatibility
- Configuration options for HTTP/2 settings

## Implementation Plan
1. Update dependencies
2. Add configuration options
3. Implement HTTP/2 handling
4. Add tests
5. Update documentation

## Testing Strategy
- Unit tests for new code
- Integration tests with HTTP/2 clients
- Performance benchmarks
- Compatibility testing

## Documentation Updates
- Configuration reference
- Performance guide
- Migration guide

2. Implementation Steps

  1. Create feature branch
  2. Add configuration options
  3. Implement core functionality
  4. Add comprehensive tests
  5. Update documentation
  6. Submit pull request

Performance Optimization

When optimizing performance:

  1. Measure First: Use benchmarks to identify bottlenecks
  2. Profile: Use profiling tools to understand behavior
  3. Optimize: Make targeted improvements
  4. Verify: Confirm improvements with benchmarks
  5. Document: Update performance documentation

Dependency Management

# Add dependency
cargo add tokio --features full

# Add dev dependency
cargo add --dev criterion

# Update dependencies
cargo update

# Check for outdated dependencies
cargo outdated

# Audit for security issues
cargo audit

Troubleshooting Development Issues

Common Issues

1. Build Failures

# Clean and rebuild
cargo clean
cargo build

# Check for dependency issues
cargo tree
cargo update

2. Test Failures

# Run specific test
cargo test test_name -- --nocapture

# Run ignored tests
cargo test -- --ignored

# Run tests in single thread
cargo test -- --test-threads=1

3. Formatting Issues

# Format all code
cargo fmt

# Check specific file
rustfmt src/lib.rs

4. Linting Issues

# Run clippy with all targets
cargo clippy --all-targets

# Allow specific lints
#[allow(clippy::too_many_arguments)]

Resources

Learning Resources

Tools and Libraries

Similar Projects

  • nginx - High-performance web server
  • caddy - Modern web server
  • traefik - Cloud-native application proxy

Thank you for contributing to BWS! Your contributions help make the project better for everyone.

Building from Source

This guide covers building BWS from source code, including development setup, build options, and cross-compilation.

Prerequisites

System Requirements

Minimum Requirements

  • RAM: 2GB available memory
  • Disk Space: 1GB free space for build artifacts
  • CPU: Any modern x64 or ARM64 processor

Supported Platforms

  • Linux: Ubuntu 18.04+, Debian 10+, RHEL 8+, Alpine Linux
  • macOS: 10.15+ (Catalina)
  • Windows: Windows 10+ (with WSL2 recommended)
  • FreeBSD: 12.0+

Dependencies

Rust Toolchain

# Install Rust via rustup (recommended)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# Verify installation
rustc --version
cargo --version

# Update to latest stable
rustup update stable

System Dependencies

Ubuntu/Debian:

sudo apt update
sudo apt install -y \
    build-essential \
    pkg-config \
    libssl-dev \
    cmake \
    git \
    curl

CentOS/RHEL/Fedora:

sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y \
    pkg-config \
    openssl-devel \
    cmake \
    git \
    curl

macOS:

# Install Xcode command line tools
xcode-select --install

# Or install via Homebrew
brew install cmake pkg-config openssl

Windows (WSL2):

# In WSL2 Ubuntu
sudo apt update
sudo apt install -y \
    build-essential \
    pkg-config \
    libssl-dev \
    cmake \
    git \
    curl

Optional Dependencies

# For enhanced compression support
sudo apt install -y libbrotli-dev zlib1g-dev

# For performance profiling
cargo install cargo-flamegraph

# For security auditing
cargo install cargo-audit

# For benchmarking
cargo install cargo-bench

Getting the Source Code

Clone Repository

# Clone the main repository
git clone https://github.com/benliao/bws.git
cd bws

# Or clone your fork
git clone https://github.com/yourusername/bws.git
cd bws

# Check available branches/tags
git branch -a
git tag -l

Download Source Archive

# Download specific version
wget https://github.com/benliao/bws/archive/refs/tags/v0.1.5.tar.gz
tar -xzf v0.1.5.tar.gz
cd bws-0.1.5

Build Configuration

Cargo.toml Overview

[package]
name = "bws"
version = "0.1.5"
edition = "2021"
rust-version = "1.89"

[dependencies]
pingora = "0.6.0"
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
toml = "0.8"
anyhow = "1.0"
tracing = "0.1"

[features]
default = ["compression", "metrics"]
compression = ["brotli", "gzip"]
metrics = ["prometheus"]
tls = ["openssl"]
jemalloc = ["jemallocator"]

[profile.release]
opt-level = 3
lto = true
codegen-units = 1
panic = "abort"

Feature Flags

Available Features

  • compression: Enable response compression (gzip, brotli)
  • metrics: Enable Prometheus metrics export
  • tls: Enable TLS/SSL support
  • jemalloc: Use jemalloc allocator for better performance
  • mimalloc: Use mimalloc allocator (alternative to jemalloc)

Building with Specific Features

# Build with all features
cargo build --all-features

# Build with specific features
cargo build --features "compression,metrics"

# Build without default features
cargo build --no-default-features

# Build with custom feature combination
cargo build --no-default-features --features "compression,tls"

Build Commands

Development Build

# Standard debug build
cargo build

# With specific features
cargo build --features "compression,metrics"

# With verbose output
cargo build --verbose

# Check without building
cargo check

Release Build

# Optimized release build
cargo build --release

# Release with all features
cargo build --release --all-features

# Strip debug symbols
cargo build --release
strip target/release/bws  # Linux/macOS

Custom Profiles

Performance Profile

# Add to Cargo.toml
[profile.performance]
inherits = "release"
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "abort"
# Build with performance profile
cargo build --profile performance

Size-Optimized Profile

[profile.min-size]
inherits = "release"
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
strip = true
# Build for minimum size
cargo build --profile min-size

Build Optimization

Rust Compiler Flags

Environment Variables

# Enable link-time optimization
export RUSTFLAGS="-C link-arg=-s"

# Use specific target CPU
export RUSTFLAGS="-C target-cpu=native"

# Optimize for size
export RUSTFLAGS="-C opt-level=z"

# Build with optimizations
cargo build --release

Target-Specific Optimization

# Build for specific CPU architecture
RUSTFLAGS="-C target-cpu=skylake" cargo build --release

# Build with all CPU features
RUSTFLAGS="-C target-cpu=native" cargo build --release

# Build for compatibility
RUSTFLAGS="-C target-cpu=x86-64" cargo build --release

Memory Allocator Optimization

Using jemalloc

# Add to Cargo.toml
[dependencies]
jemallocator = "0.5"

# Add to src/main.rs
#[global_allocator]
static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;

Using mimalloc

# Add to Cargo.toml
[dependencies]
mimalloc = { version = "0.1", default-features = false }

# Add to src/main.rs
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
# Cargo.toml release profile
[profile.release]
lto = true              # Enable LTO
codegen-units = 1       # Use single codegen unit
opt-level = 3           # Maximum optimization

Cross-Compilation

Setup Cross-Compilation Targets

# Add common targets
rustup target add x86_64-unknown-linux-gnu
rustup target add x86_64-unknown-linux-musl
rustup target add aarch64-unknown-linux-gnu
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
rustup target add x86_64-pc-windows-gnu

# List installed targets
rustup target list --installed

Cross-Compilation Examples

Linux to musl (static linking)

# Install musl target
rustup target add x86_64-unknown-linux-musl

# Install musl tools (Ubuntu/Debian)
sudo apt install musl-tools

# Build static binary
cargo build --release --target x86_64-unknown-linux-musl

# Verify static linking
ldd target/x86_64-unknown-linux-musl/release/bws
# Should show "not a dynamic executable"

Linux to ARM64

# Install ARM64 target
rustup target add aarch64-unknown-linux-gnu

# Install cross-compilation tools
sudo apt install gcc-aarch64-linux-gnu

# Set up linker
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc

# Build for ARM64
cargo build --release --target aarch64-unknown-linux-gnu

macOS Universal Binary

# Install both targets
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin

# Build for both architectures
cargo build --release --target x86_64-apple-darwin
cargo build --release --target aarch64-apple-darwin

# Create universal binary
lipo -create \
    target/x86_64-apple-darwin/release/bws \
    target/aarch64-apple-darwin/release/bws \
    -output target/release/bws-universal

Windows Cross-Compilation (from Linux)

# Install Windows target
rustup target add x86_64-pc-windows-gnu

# Install MinGW
sudo apt install mingw-w64

# Build for Windows
cargo build --release --target x86_64-pc-windows-gnu

Using cross Tool

# Install cross
cargo install cross

# Build for different targets using Docker
cross build --release --target aarch64-unknown-linux-gnu
cross build --release --target x86_64-unknown-linux-musl
cross build --release --target armv7-unknown-linux-gnueabihf

Build Scripts and Automation

Makefile

# Makefile
.PHONY: build build-release test clean install

# Default target
all: build

# Development build
build:
	cargo build

# Release build
build-release:
	cargo build --release

# Build with all features
build-all:
	cargo build --release --all-features

# Run tests
test:
	cargo test

# Clean build artifacts
clean:
	cargo clean

# Install locally
install:
	cargo install --path .

# Cross-compilation targets
build-linux-musl:
	cargo build --release --target x86_64-unknown-linux-musl

build-arm64:
	cargo build --release --target aarch64-unknown-linux-gnu

build-windows:
	cargo build --release --target x86_64-pc-windows-gnu

# All targets
build-all-targets: build-linux-musl build-arm64 build-windows

# Package release
package:
	mkdir -p dist
	cp target/release/bws dist/
	cp README.md LICENSE dist/
	tar -czf dist/bws-$(shell cargo pkgid | cut -d'#' -f2).tar.gz -C dist .

Build Script

#!/bin/bash
# build.sh

set -e

echo "Building BWS from source..."

# Check Rust installation
if ! command -v cargo &> /dev/null; then
    echo "Error: Rust/Cargo not found. Please install Rust first."
    exit 1
fi

# Get version
VERSION=$(cargo pkgid | cut -d'#' -f2)
echo "Building BWS version $VERSION"

# Clean previous builds
echo "Cleaning previous builds..."
cargo clean

# Build release version
echo "Building release version..."
cargo build --release --all-features

# Run tests
echo "Running tests..."
cargo test --release

# Check binary
if [ -f "target/release/bws" ]; then
    echo "Build successful!"
    echo "Binary location: target/release/bws"
    echo "Binary size: $(du -h target/release/bws | cut -f1)"
    
    # Test the binary
    ./target/release/bws --version
else
    echo "Build failed: Binary not found"
    exit 1
fi

echo "Build completed successfully!"

GitHub Actions Build

# .github/workflows/build.yml
name: Build

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    name: Build
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        rust: [stable, beta]

    steps:
    - uses: actions/checkout@v4

    - name: Install Rust
      uses: dtolnay/rust-toolchain@master
      with:
        toolchain: ${{ matrix.rust }}

    - name: Cache dependencies
      uses: actions/cache@v3
      with:
        path: |
          ~/.cargo/registry
          ~/.cargo/git
          target
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

    - name: Build
      run: cargo build --release --all-features

    - name: Run tests
      run: cargo test --release

    - name: Upload artifacts
      uses: actions/upload-artifact@v3
      with:
        name: bws-${{ matrix.os }}
        path: target/release/bws*

Testing the Build

Unit Tests

# Run all tests
cargo test

# Run specific test
cargo test test_config

# Run tests with output
cargo test -- --nocapture

# Run tests in single thread
cargo test -- --test-threads=1

# Run ignored tests
cargo test -- --ignored

Integration Tests

# Run integration tests only
cargo test --test integration

# Run specific integration test
cargo test --test integration -- test_server_startup

Benchmarks

# Install criterion for benchmarking
cargo install criterion

# Run benchmarks
cargo bench

# Run specific benchmark
cargo bench bench_name

Manual Testing

# Build and test the binary
cargo build --release

# Test basic functionality
./target/release/bws --version
./target/release/bws --help

# Test with sample configuration
echo '
[[sites]]
name = "test"
hostname = "127.0.0.1"
port = 8080
static_dir = "static"
' > test-config.toml

mkdir -p static
echo "Hello, World!" > static/index.html

# Start server in background
./target/release/bws --config test-config.toml &
SERVER_PID=$!

# Test HTTP request
sleep 2
curl http://127.0.0.1:8080/

# Clean up
kill $SERVER_PID
rm -rf test-config.toml static/

Troubleshooting Build Issues

Common Build Errors

1. Linker Errors

# Error: linker `cc` not found
sudo apt install build-essential  # Ubuntu/Debian
sudo dnf groupinstall "Development Tools"  # RHEL/Fedora

# Error: could not find system library 'openssl'
sudo apt install libssl-dev pkg-config  # Ubuntu/Debian
sudo dnf install openssl-devel pkgconf  # RHEL/Fedora

2. Memory Issues

# Reduce parallel builds if running out of memory
cargo build --jobs 1

# Or set permanently
echo 'jobs = 1' >> ~/.cargo/config.toml

3. Network Issues

# Use git instead of HTTPS for dependencies
git config --global url."git://github.com/".insteadOf "https://github.com/"

# Or use offline mode with vendored dependencies
cargo vendor
cargo build --offline

4. Permission Issues

# Fix cargo directory permissions
sudo chown -R $(whoami) ~/.cargo

# Clean and rebuild
cargo clean
cargo build

Debugging Build Issues

Verbose Output

# Build with verbose output
cargo build --verbose

# Show build timing
cargo build --timings

# Show why dependencies are being rebuilt
cargo build --verbose --explain

Environment Debugging

# Show cargo configuration
cargo config list

# Show target information
rustc --print target-list
rustc --print cfg

# Show toolchain information
rustup show

Installation

Local Installation

# Install from current directory
cargo install --path .

# Install with specific features
cargo install --path . --features "compression,metrics"

# Force reinstall
cargo install --path . --force

System-Wide Installation

# Copy binary to system path
sudo cp target/release/bws /usr/local/bin/

# Make executable
sudo chmod +x /usr/local/bin/bws

# Verify installation
bws --version

Package Creation

DEB Package (Ubuntu/Debian)

# Install cargo-deb
cargo install cargo-deb

# Add metadata to Cargo.toml
[package.metadata.deb]
maintainer = "Your Name <your.email@example.com>"
copyright = "2024, Your Name <your.email@example.com>"
license-file = ["LICENSE", "5"]
extended-description = "BWS is a high-performance multi-site web server"
depends = "$auto"
section = "utility"
priority = "optional"
assets = [
    ["target/release/bws", "usr/bin/", "755"],
    ["README.md", "usr/share/doc/bws/README", "644"],
]

# Build DEB package
cargo deb

RPM Package (RHEL/Fedora)

# Install cargo-rpm
cargo install cargo-rpm

# Initialize RPM spec
cargo rpm init

# Build RPM package
cargo rpm build

Windows Installer

# Install cargo-wix
cargo install cargo-wix

# Initialize WiX configuration
cargo wix init

# Build MSI installer
cargo wix

Optimization Tips

Build Performance

  • Use cargo check during development instead of cargo build
  • Enable incremental compilation
  • Use sccache for shared build cache
  • Consider using mold linker on Linux for faster linking

Binary Size Optimization

[profile.release]
opt-level = "z"      # Optimize for size
lto = true           # Link-time optimization
strip = true         # Strip symbols
panic = "abort"      # Smaller panic handling

Runtime Performance

[profile.release]
opt-level = 3        # Maximum optimization
lto = "fat"          # Full LTO
codegen-units = 1    # Single codegen unit
panic = "abort"      # Abort on panic

Next Steps

After building BWS:

  1. Read the Configuration Guide to set up your server
  2. Follow the Quick Start to get running
  3. Check Performance Tuning for optimization
  4. Review Production Setup for deployment

For development:

  1. Read the Contributing Guide
  2. Set up your development environment
  3. Run the test suite
  4. Start contributing!

Testing

This guide covers testing strategies, tools, and best practices for BWS development and deployment.

Testing Overview

BWS includes multiple layers of testing:

  • Unit Tests: Test individual functions and modules
  • Integration Tests: Test component interactions
  • End-to-End Tests: Test complete workflows
  • Performance Tests: Measure performance characteristics
  • Security Tests: Validate security measures

Running Tests

Basic Test Commands

# Run all tests
cargo test

# Run tests with output
cargo test -- --nocapture

# Run specific test
cargo test test_config_parsing

# Run tests matching pattern
cargo test config

# Run ignored tests
cargo test -- --ignored

# Run tests in single thread (for debugging)
cargo test -- --test-threads=1

Test Categories

# Run only unit tests
cargo test --lib

# Run only integration tests
cargo test --test integration

# Run only documentation tests
cargo test --doc

# Run tests for specific package
cargo test -p bws-core

Test with Features

# Test with all features
cargo test --all-features

# Test with specific features
cargo test --features "compression,metrics"

# Test without default features
cargo test --no-default-features

Unit Testing

Basic Unit Tests

#![allow(unused)]
fn main() {
// src/config.rs
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_config_default() {
        let config = Config::default();
        assert_eq!(config.sites.len(), 0);
    }

    #[test]
    fn test_config_parsing() {
        let toml_str = r#"
            [[sites]]
            name = "test"
            hostname = "localhost"
            port = 8080
            static_dir = "static"
        "#;

        let config: Config = toml::from_str(toml_str).unwrap();
        assert_eq!(config.sites.len(), 1);
        assert_eq!(config.sites[0].name, "test");
        assert_eq!(config.sites[0].port, 8080);
    }

    #[test]
    #[should_panic(expected = "Invalid port")]
    fn test_invalid_port() {
        let site = Site {
            name: "test".to_string(),
            hostname: "localhost".to_string(),
            port: 0, // Invalid port
            static_dir: "static".to_string(),
            ..Default::default()
        };
        site.validate().unwrap();
    }
}
}

Testing Error Conditions

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;
    use anyhow::Result;

    #[test]
    fn test_file_not_found() {
        let result = read_config_file("nonexistent.toml");
        assert!(result.is_err());
        
        let error = result.unwrap_err();
        assert!(error.to_string().contains("No such file"));
    }

    #[test]
    fn test_invalid_toml() {
        let invalid_toml = "invalid toml content [[[";
        let result = parse_config(invalid_toml);
        assert!(result.is_err());
    }

    #[test]
    fn test_missing_required_field() {
        let toml_str = r#"
            [[sites]]
            name = "test"
            Missing hostname, port, static_dir
        "#;
        
        let result: Result<Config, _> = toml::from_str(toml_str);
        assert!(result.is_err());
    }
}
}

Mocking and Test Doubles

#![allow(unused)]
fn main() {
// Use mockall for mocking
use mockall::predicate::*;
use mockall::mock;

mock! {
    FileSystem {
        fn read_file(&self, path: &str) -> Result<String>;
        fn file_exists(&self, path: &str) -> bool;
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_config_loading_with_mock() {
        let mut mock_fs = MockFileSystem::new();
        mock_fs
            .expect_read_file()
            .with(eq("config.toml"))
            .times(1)
            .returning(|_| Ok(r#"
                [[sites]]
                name = "test"
                hostname = "localhost"
                port = 8080
                static_dir = "static"
            "#.to_string()));

        let config = load_config_with_fs(&mock_fs, "config.toml").unwrap();
        assert_eq!(config.sites.len(), 1);
    }
}
}

Integration Testing

Test Structure

#![allow(unused)]
fn main() {
// tests/integration/server_tests.rs
use bws::{Config, Server};
use std::time::Duration;
use tokio::time::sleep;

#[tokio::test]
async fn test_server_startup_shutdown() {
    let config = test_config();
    let server = Server::new(config).await.unwrap();
    
    // Start server in background
    let handle = tokio::spawn(async move {
        server.run().await
    });
    
    // Give server time to start
    sleep(Duration::from_millis(100)).await;
    
    // Test server is responding
    let response = reqwest::get("http://127.0.0.1:8080/health").await.unwrap();
    assert_eq!(response.status(), 200);
    
    // Shutdown server
    handle.abort();
}

#[tokio::test]
async fn test_static_file_serving() {
    let temp_dir = setup_test_static_files().await;
    let config = Config {
        sites: vec![Site {
            name: "test".to_string(),
            hostname: "127.0.0.1".to_string(),
            port: 8081,
            static_dir: temp_dir.path().to_string_lossy().to_string(),
            ..Default::default()
        }],
        ..Default::default()
    };
    
    let server = Server::new(config).await.unwrap();
    let handle = tokio::spawn(async move {
        server.run().await
    });
    
    sleep(Duration::from_millis(100)).await;
    
    // Test serving static file
    let response = reqwest::get("http://127.0.0.1:8081/test.html").await.unwrap();
    assert_eq!(response.status(), 200);
    assert_eq!(response.text().await.unwrap(), "<h1>Test</h1>");
    
    handle.abort();
    cleanup_test_files(temp_dir).await;
}

fn test_config() -> Config {
    Config {
        sites: vec![Site {
            name: "test".to_string(),
            hostname: "127.0.0.1".to_string(),
            port: 8080,
            static_dir: "test_static".to_string(),
            ..Default::default()
        }],
        ..Default::default()
    }
}

async fn setup_test_static_files() -> tempfile::TempDir {
    let temp_dir = tempfile::tempdir().unwrap();
    
    tokio::fs::write(
        temp_dir.path().join("test.html"),
        "<h1>Test</h1>"
    ).await.unwrap();
    
    tokio::fs::write(
        temp_dir.path().join("index.html"),
        "<h1>Index</h1>"
    ).await.unwrap();
    
    temp_dir
}
}

HTTP Client Testing

#![allow(unused)]
fn main() {
// tests/integration/http_tests.rs
use reqwest::Client;
use serde_json::Value;

#[tokio::test]
async fn test_health_endpoint() {
    let client = Client::new();
    let response = client
        .get("http://127.0.0.1:8080/health")
        .send()
        .await
        .unwrap();
    
    assert_eq!(response.status(), 200);
    assert_eq!(response.headers().get("content-type").unwrap(), "application/json");
    
    let body: Value = response.json().await.unwrap();
    assert_eq!(body["status"], "healthy");
}

#[tokio::test]
async fn test_custom_headers() {
    let client = Client::new();
    let response = client
        .get("http://127.0.0.1:8080/")
        .send()
        .await
        .unwrap();
    
    // Check custom headers are present
    assert!(response.headers().contains_key("x-served-by"));
    assert_eq!(response.headers()["cache-control"], "public, max-age=3600");
}

#[tokio::test]
async fn test_cors_headers() {
    let client = Client::new();
    let response = client
        .options("http://127.0.0.1:8080/")
        .header("Origin", "https://example.com")
        .header("Access-Control-Request-Method", "GET")
        .send()
        .await
        .unwrap();
    
    assert_eq!(response.status(), 200);
    assert!(response.headers().contains_key("access-control-allow-origin"));
}
}

Database Integration Tests

#![allow(unused)]
fn main() {
// tests/integration/database_tests.rs (if BWS had database features)
use sqlx::PgPool;

#[tokio::test]
async fn test_database_connection() {
    let pool = setup_test_database().await;
    
    let config = Config {
        database_url: Some(pool.connect_options().to_url_lossy().to_string()),
        ..test_config()
    };
    
    let server = Server::new(config).await.unwrap();
    
    // Test database-dependent endpoints
    let response = reqwest::get("http://127.0.0.1:8080/api/data").await.unwrap();
    assert_eq!(response.status(), 200);
    
    cleanup_test_database(pool).await;
}

async fn setup_test_database() -> PgPool {
    // Set up test database
    PgPool::connect("postgres://test:test@localhost/bws_test")
        .await
        .unwrap()
}
}

End-to-End Testing

Test Scenarios

#![allow(unused)]
fn main() {
// tests/e2e/scenarios.rs
use std::process::{Command, Stdio};
use std::time::Duration;
use tokio::time::sleep;

#[tokio::test]
async fn test_complete_deployment_scenario() {
    // 1. Create test configuration
    let config_content = r#"
        [daemon]
        pid_file = "/tmp/bws-test.pid"
        
        [logging]
        level = "info"
        output = "file"
        file_path = "/tmp/bws-test.log"
        
        [[sites]]
        name = "main"
        hostname = "127.0.0.1"
        port = 8080
        static_dir = "test_static"
        
        [sites.headers]
        "Cache-Control" = "public, max-age=3600"
    "#;
    
    std::fs::write("test-config.toml", config_content).unwrap();
    
    // 2. Create static files
    std::fs::create_dir_all("test_static").unwrap();
    std::fs::write("test_static/index.html", "<h1>Welcome to BWS</h1>").unwrap();
    std::fs::write("test_static/style.css", "body { color: blue; }").unwrap();
    
    // 3. Start BWS server
    let mut child = Command::new("target/release/bws")
        .arg("--config")
        .arg("test-config.toml")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn()
        .unwrap();
    
    // 4. Wait for server to start
    sleep(Duration::from_secs(2)).await;
    
    // 5. Run tests
    test_homepage().await;
    test_static_files().await;
    test_health_check().await;
    test_performance().await;
    
    // 6. Cleanup
    child.kill().unwrap();
    std::fs::remove_file("test-config.toml").unwrap();
    std::fs::remove_dir_all("test_static").unwrap();
    std::fs::remove_file("/tmp/bws-test.log").ok();
    std::fs::remove_file("/tmp/bws-test.pid").ok();
}

async fn test_homepage() {
    let response = reqwest::get("http://127.0.0.1:8080/").await.unwrap();
    assert_eq!(response.status(), 200);
    assert!(response.text().await.unwrap().contains("Welcome to BWS"));
}

async fn test_static_files() {
    let response = reqwest::get("http://127.0.0.1:8080/style.css").await.unwrap();
    assert_eq!(response.status(), 200);
    assert_eq!(response.headers()["content-type"], "text/css");
    assert!(response.text().await.unwrap().contains("color: blue"));
}

async fn test_health_check() {
    let response = reqwest::get("http://127.0.0.1:8080/health").await.unwrap();
    assert_eq!(response.status(), 200);
    
    let health: serde_json::Value = response.json().await.unwrap();
    assert_eq!(health["status"], "healthy");
}

async fn test_performance() {
    use std::time::Instant;
    
    let start = Instant::now();
    
    // Make 100 concurrent requests
    let futures: Vec<_> = (0..100)
        .map(|_| reqwest::get("http://127.0.0.1:8080/"))
        .collect();
    
    let responses = futures::future::join_all(futures).await;
    let duration = start.elapsed();
    
    // All requests should succeed
    for response in responses {
        assert_eq!(response.unwrap().status(), 200);
    }
    
    // Should complete in reasonable time
    assert!(duration < Duration::from_secs(5));
    println!("100 requests completed in {:?}", duration);
}
}

Multi-Site Testing

#![allow(unused)]
fn main() {
#[tokio::test]
async fn test_multi_site_configuration() {
    let config_content = r#"
        [[sites]]
        name = "main"
        hostname = "127.0.0.1"
        port = 8080
        static_dir = "main_static"
        
        [[sites]]
        name = "api"
        hostname = "127.0.0.1"
        port = 8081
        static_dir = "api_static"
        
        [sites.headers]
        "Content-Type" = "application/json"
    "#;
    
    // Setup and test both sites
    setup_multi_site_files();
    
    let mut child = start_bws_server("multi-site-config.toml");
    sleep(Duration::from_secs(2)).await;
    
    // Test main site
    let response = reqwest::get("http://127.0.0.1:8080/").await.unwrap();
    assert_eq!(response.status(), 200);
    
    // Test API site
    let response = reqwest::get("http://127.0.0.1:8081/").await.unwrap();
    assert_eq!(response.status(), 200);
    assert_eq!(response.headers()["content-type"], "application/json");
    
    cleanup_multi_site_test(child);
}
}

WebSocket Proxy Testing

#![allow(unused)]
fn main() {
// tests/integration/websocket_tests.rs
use tokio_tungstenite::{connect_async, tungstenite::Message};

#[tokio::test]
async fn test_websocket_proxy_configuration() {
    let config_content = r#"
        [[sites]]
        name = "websocket-proxy"
        hostname = "127.0.0.1"
        port = 8090
        static_dir = "static"
        
        [sites.proxy]
        enabled = true
        
        [[sites.proxy.upstreams]]
        name = "websocket_backend"
        url = "http://127.0.0.1:3001"
        weight = 1
        
        [[sites.proxy.upstreams]]
        name = "websocket_backend"
        url = "http://127.0.0.1:3002"
        weight = 1
        
        [[sites.proxy.routes]]
        path = "/ws"
        upstream = "websocket_backend"
        strip_prefix = true
        websocket = true
        
        [sites.proxy.load_balancing]
        method = "round_robin"
    "#;
    
    // Start mock WebSocket servers
    let server1 = start_mock_websocket_server(3001).await;
    let server2 = start_mock_websocket_server(3002).await;
    
    // Start BWS with WebSocket proxy config
    let bws_server = start_bws_server_with_config(config_content).await;
    
    // Test WebSocket upgrade detection
    test_websocket_upgrade_detection().await;
    
    // Test WebSocket proxy connection
    test_websocket_proxy_connection().await;
    
    // Test load balancing
    test_websocket_load_balancing().await;
    
    // Cleanup
    cleanup_websocket_test(bws_server, server1, server2).await;
}

async fn test_websocket_upgrade_detection() {
    // Test that BWS properly detects WebSocket upgrade requests
    let client = reqwest::Client::new();
    let response = client
        .get("http://127.0.0.1:8090/ws")
        .header("Upgrade", "websocket")
        .header("Connection", "Upgrade")
        .header("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==")
        .header("Sec-WebSocket-Version", "13")
        .send()
        .await
        .unwrap();
    
    // Should attempt WebSocket upgrade (not 404)
    assert_ne!(response.status(), 404);
}

async fn test_websocket_proxy_connection() {
    // Note: This test demonstrates the framework
    // Full implementation requires additional Pingora integration
    
    // Attempt WebSocket connection through proxy
    let ws_url = "ws://127.0.0.1:8090/ws";
    
    // In a complete implementation, this would succeed
    match connect_async(ws_url).await {
        Ok((mut ws_stream, _)) => {
            // Send test message
            ws_stream.send(Message::Text("test".to_string())).await.unwrap();
            
            // Receive response
            if let Some(msg) = ws_stream.next().await {
                let msg = msg.unwrap();
                assert!(msg.is_text());
                println!("Received: {}", msg.to_text().unwrap());
            }
        }
        Err(e) => {
            // Expected in current implementation
            println!("WebSocket connection failed (expected): {}", e);
        }
    }
}

async fn test_websocket_load_balancing() {
    // Test that WebSocket connections are load balanced
    let mut server_responses = std::collections::HashMap::new();
    
    // Make multiple connections
    for i in 0..10 {
        let ws_url = format!("ws://127.0.0.1:8090/ws?test={}", i);
        
        // In full implementation, track which server responds
        // Current implementation provides detection framework
        match connect_async(&ws_url).await {
            Ok((mut ws_stream, _)) => {
                ws_stream.send(Message::Text("ping".to_string())).await.unwrap();
                
                if let Some(msg) = ws_stream.next().await {
                    let response = msg.unwrap().to_text().unwrap();
                    *server_responses.entry(response.to_string()).or_insert(0) += 1;
                }
            }
            Err(_) => {
                // Expected in current framework implementation
            }
        }
    }
    
    // In full implementation, verify load balancing distribution
    println!("Server response distribution: {:?}", server_responses);
}

async fn start_mock_websocket_server(port: u16) -> tokio::task::JoinHandle<()> {
    tokio::spawn(async move {
        use tokio_tungstenite::{accept_async, tungstenite::Message};
        use tokio::net::{TcpListener, TcpStream};
        
        let listener = TcpListener::bind(format!("127.0.0.1:{}", port)).await.unwrap();
        println!("Mock WebSocket server listening on port {}", port);
        
        while let Ok((stream, _)) = listener.accept().await {
            tokio::spawn(handle_websocket_connection(stream, port));
        }
    })
}

async fn handle_websocket_connection(stream: TcpStream, port: u16) {
    match accept_async(stream).await {
        Ok(mut websocket) => {
            while let Some(msg) = websocket.next().await {
                match msg {
                    Ok(Message::Text(text)) => {
                        let response = format!("Echo from server {}: {}", port, text);
                        websocket.send(Message::Text(response)).await.unwrap();
                    }
                    Ok(Message::Close(_)) => break,
                    Err(e) => {
                        println!("WebSocket error: {}", e);
                        break;
                    }
                    _ => {}
                }
            }
        }
        Err(e) => println!("WebSocket handshake failed: {}", e),
    }
}
}

WebSocket Test Script

#!/bin/bash
# Run the WebSocket proxy test script
./tests/test_websocket_proxy.sh

This script will:

  • Start multiple WebSocket test servers
  • Configure BWS with WebSocket proxy routes
  • Provide a web interface for manual testing
  • Demonstrate load balancing between upstream servers

Performance Testing

Load Testing with wrk

#!/bin/bash
# scripts/load-test.sh

BWS_PID=""

setup_test_server() {
    echo "Setting up test server..."
    
    # Create test configuration
    cat > test-load-config.toml << EOF
[[sites]]
name = "load-test"
hostname = "127.0.0.1"
port = 8080
static_dir = "load_test_static"

[sites.headers]
"Cache-Control" = "public, max-age=3600"
EOF

    # Create test files
    mkdir -p load_test_static
    echo "<h1>Load Test Page</h1>" > load_test_static/index.html
    
    # Generate test files of various sizes
    dd if=/dev/zero of=load_test_static/1kb.txt bs=1024 count=1 2>/dev/null
    dd if=/dev/zero of=load_test_static/10kb.txt bs=1024 count=10 2>/dev/null
    dd if=/dev/zero of=load_test_static/100kb.txt bs=1024 count=100 2>/dev/null
    
    # Start BWS
    ./target/release/bws --config test-load-config.toml &
    BWS_PID=$!
    
    sleep 2
}

run_load_tests() {
    echo "Running load tests..."
    
    # Test 1: Basic load test
    echo "=== Basic Load Test ==="
    wrk -t4 -c50 -d30s --latency http://127.0.0.1:8080/
    
    # Test 2: High concurrency
    echo "=== High Concurrency Test ==="
    wrk -t8 -c200 -d30s --latency http://127.0.0.1:8080/
    
    # Test 3: Different file sizes
    echo "=== 1KB File Test ==="
    wrk -t4 -c50 -d15s http://127.0.0.1:8080/1kb.txt
    
    echo "=== 10KB File Test ==="
    wrk -t4 -c50 -d15s http://127.0.0.1:8080/10kb.txt
    
    echo "=== 100KB File Test ==="
    wrk -t4 -c50 -d15s http://127.0.0.1:8080/100kb.txt
    
    # Test 4: Sustained load
    echo "=== Sustained Load Test (5 minutes) ==="
    wrk -t4 -c100 -d300s --latency http://127.0.0.1:8080/
}

cleanup_test() {
    echo "Cleaning up..."
    if [ ! -z "$BWS_PID" ]; then
        kill $BWS_PID 2>/dev/null
    fi
    rm -rf load_test_static test-load-config.toml
}

# Trap cleanup on script exit
trap cleanup_test EXIT

setup_test_server
run_load_tests

Benchmark Tests

#![allow(unused)]
fn main() {
// benches/server_benchmark.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use bws::{Config, Server};

fn bench_config_parsing(c: &mut Criterion) {
    let config_str = r#"
        [[sites]]
        name = "bench"
        hostname = "127.0.0.1"
        port = 8080
        static_dir = "static"
        
        [sites.headers]
        "Cache-Control" = "public, max-age=3600"
        "X-Content-Type-Options" = "nosniff"
    "#;
    
    c.bench_function("parse config", |b| {
        b.iter(|| {
            let _config: Config = toml::from_str(black_box(config_str)).unwrap();
        })
    });
}

fn bench_static_file_resolution(c: &mut Criterion) {
    let config = test_config();
    
    c.bench_function("resolve static file", |b| {
        b.iter(|| {
            let _path = resolve_static_file(
                black_box("/assets/css/main.css"),
                black_box(&config.sites[0])
            );
        })
    });
}

criterion_group!(benches, bench_config_parsing, bench_static_file_resolution);
criterion_main!(benches);
}

Memory Testing

#![allow(unused)]
fn main() {
// tests/memory_tests.rs
#[test]
fn test_memory_usage() {
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};
    
    let memory_counter = Arc::new(AtomicUsize::new(0));
    
    // Custom allocator to track memory usage
    #[global_allocator]
    static GLOBAL: TrackingAllocator = TrackingAllocator;
    
    let initial_memory = get_memory_usage();
    
    // Create large number of configs
    let configs: Vec<Config> = (0..1000)
        .map(|i| Config {
            sites: vec![Site {
                name: format!("site_{}", i),
                hostname: "127.0.0.1".to_string(),
                port: 8080 + i,
                static_dir: format!("static_{}", i),
                ..Default::default()
            }],
            ..Default::default()
        })
        .collect();
    
    let peak_memory = get_memory_usage();
    drop(configs);
    
    // Force garbage collection
    std::hint::black_box(());
    
    let final_memory = get_memory_usage();
    
    println!("Initial memory: {} KB", initial_memory / 1024);
    println!("Peak memory: {} KB", peak_memory / 1024);
    println!("Final memory: {} KB", final_memory / 1024);
    
    // Memory should be released
    assert!(final_memory < peak_memory);
}
}

Security Testing

Input Validation Tests

#![allow(unused)]
fn main() {
#[tokio::test]
async fn test_path_traversal_protection() {
    // Test various path traversal attempts
    let malicious_paths = vec![
        "../../../etc/passwd",
        "..%2F..%2F..%2Fetc%2Fpasswd",
        "....//....//....//etc//passwd",
        "%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd",
    ];
    
    for path in malicious_paths {
        let response = reqwest::get(&format!("http://127.0.0.1:8080/{}", path))
            .await
            .unwrap();
        
        // Should return 404 or 403, not 200
        assert_ne!(response.status(), 200);
    }
}

#[tokio::test]
async fn test_request_size_limits() {
    let client = reqwest::Client::new();
    
    // Test large request body
    let large_body = "x".repeat(10 * 1024 * 1024); // 10MB
    
    let response = client
        .post("http://127.0.0.1:8080/")
        .body(large_body)
        .send()
        .await
        .unwrap();
    
    // Should reject large requests
    assert_eq!(response.status(), 413); // Payload Too Large
}

#[tokio::test]
async fn test_header_injection() {
    let client = reqwest::Client::new();
    
    // Test header injection attempts
    let response = client
        .get("http://127.0.0.1:8080/")
        .header("X-Forwarded-For", "malicious\r\nContent-Type: text/html")
        .send()
        .await
        .unwrap();
    
    // Response should not contain injected header
    assert!(!response.headers().contains_key("content-type"));
}
}

Rate Limiting Tests

#![allow(unused)]
fn main() {
#[tokio::test]
async fn test_rate_limiting() {
    let client = reqwest::Client::new();
    
    // Make requests rapidly
    let mut success_count = 0;
    let mut rate_limited_count = 0;
    
    for _ in 0..100 {
        let response = client
            .get("http://127.0.0.1:8080/")
            .send()
            .await
            .unwrap();
        
        match response.status().as_u16() {
            200 => success_count += 1,
            429 => rate_limited_count += 1, // Too Many Requests
            _ => {}
        }
    }
    
    // Should have some rate limited responses
    assert!(rate_limited_count > 0);
    println!("Success: {}, Rate Limited: {}", success_count, rate_limited_count);
}
}

Test Utilities and Helpers

Test Configuration Factory

#![allow(unused)]
fn main() {
// tests/common/mod.rs
pub fn test_config() -> Config {
    Config {
        daemon: DaemonConfig::default(),
        logging: LoggingConfig {
            level: "debug".to_string(),
            output: "stdout".to_string(),
            ..Default::default()
        },
        sites: vec![Site {
            name: "test".to_string(),
            hostname: "127.0.0.1".to_string(),
            port: 8080,
            static_dir: "test_static".to_string(),
            ..Default::default()
        }],
        ..Default::default()
    }
}

pub fn test_config_with_port(port: u16) -> Config {
    let mut config = test_config();
    config.sites[0].port = port;
    config
}

pub fn test_config_multi_site() -> Config {
    Config {
        sites: vec![
            Site {
                name: "main".to_string(),
                hostname: "127.0.0.1".to_string(),
                port: 8080,
                static_dir: "main_static".to_string(),
                ..Default::default()
            },
            Site {
                name: "api".to_string(),
                hostname: "127.0.0.1".to_string(),
                port: 8081,
                static_dir: "api_static".to_string(),
                ..Default::default()
            },
        ],
        ..Default::default()
    }
}
}

Test Server Management

#![allow(unused)]
fn main() {
use std::sync::Once;
use tokio::sync::Mutex;

static INIT: Once = Once::new();
static TEST_SERVER: Mutex<Option<TestServer>> = Mutex::const_new(None);

pub struct TestServer {
    pub port: u16,
    handle: tokio::task::JoinHandle<()>,
}

impl TestServer {
    pub async fn start(config: Config) -> Self {
        let port = config.sites[0].port;
        let server = Server::new(config).await.unwrap();
        
        let handle = tokio::spawn(async move {
            server.run().await.unwrap();
        });
        
        // Wait for server to start
        tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
        
        TestServer { port, handle }
    }
    
    pub fn url(&self) -> String {
        format!("http://127.0.0.1:{}", self.port)
    }
}

impl Drop for TestServer {
    fn drop(&mut self) {
        self.handle.abort();
    }
}

// Global test server for shared tests
pub async fn get_test_server() -> &'static TestServer {
    let mut server = TEST_SERVER.lock().await;
    if server.is_none() {
        *server = Some(TestServer::start(test_config()).await);
    }
    server.as_ref().unwrap()
}
}

Test File Management

#![allow(unused)]
fn main() {
use tempfile::{TempDir, NamedTempFile};

pub struct TestStaticFiles {
    pub temp_dir: TempDir,
    pub index_file: PathBuf,
    pub css_file: PathBuf,
    pub js_file: PathBuf,
}

impl TestStaticFiles {
    pub async fn new() -> Self {
        let temp_dir = TempDir::new().unwrap();
        
        let index_file = temp_dir.path().join("index.html");
        tokio::fs::write(&index_file, "<h1>Test Index</h1>").await.unwrap();
        
        let css_file = temp_dir.path().join("style.css");
        tokio::fs::write(&css_file, "body { color: red; }").await.unwrap();
        
        let js_file = temp_dir.path().join("script.js");
        tokio::fs::write(&js_file, "console.log('test');").await.unwrap();
        
        TestStaticFiles {
            temp_dir,
            index_file,
            css_file,
            js_file,
        }
    }
    
    pub fn path(&self) -> &Path {
        self.temp_dir.path()
    }
}
}

Continuous Integration Testing

GitHub Actions Test Workflow

# .github/workflows/test.yml
name: Tests

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    name: Test Suite
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        rust: [stable, beta]
        
    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust
      uses: dtolnay/rust-toolchain@master
      with:
        toolchain: ${{ matrix.rust }}
        components: rustfmt, clippy
    
    - name: Cache dependencies
      uses: actions/cache@v3
      with:
        path: |
          ~/.cargo/registry
          ~/.cargo/git
          target
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
    
    - name: Check formatting
      run: cargo fmt --all -- --check
    
    - name: Run clippy
      run: cargo clippy --all-targets --all-features -- -D warnings
    
    - name: Run tests
      run: cargo test --all-features --verbose
    
    - name: Run integration tests
      run: cargo test --test integration --all-features
    
    - name: Run benchmarks (check only)
      run: cargo bench --no-run

Test Coverage

# Add to GitHub Actions
- name: Install coverage tools
  run: |
    cargo install cargo-tarpaulin

- name: Generate test coverage
  run: |
    cargo tarpaulin --verbose --all-features --workspace --timeout 120 --out Xml

- name: Upload coverage to Codecov
  uses: codecov/codecov-action@v3
  with:
    file: ./cobertura.xml

Testing Best Practices

Test Organization

  • Group related tests in modules
  • Use descriptive test names
  • Follow AAA pattern (Arrange, Act, Assert)
  • Test both happy path and error cases
  • Use test fixtures for common setup

Test Data Management

  • Use temporary directories for file operations
  • Clean up resources in test teardown
  • Use factories for creating test objects
  • Avoid hardcoded values, use constants

Performance Testing

  • Run performance tests in isolated environment
  • Use consistent hardware for benchmarks
  • Monitor for performance regressions
  • Set reasonable performance thresholds

Security Testing

  • Test all input validation
  • Check authentication and authorization
  • Verify secure defaults
  • Test rate limiting and DOS protection

Test Maintenance

  • Keep tests up to date with code changes
  • Remove or update obsolete tests
  • Refactor duplicated test code
  • Document complex test scenarios

Next Steps

Troubleshooting

This guide helps you diagnose and resolve common issues with BWS installation, configuration, and operation.

Common Issues

Installation Problems

Rust Installation Issues

Problem: cargo command not found

cargo: command not found

Solution:

# Install Rust via rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# Or add to shell profile
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

Problem: Outdated Rust version

error: package `bws v0.1.5` cannot be built because it requires rustc 1.89 or newer

Solution:

# Update Rust toolchain
rustup update stable
rustc --version  # Should show 1.89 or newer

Compilation Errors

Problem: Missing system dependencies

error: failed to run custom build command for `openssl-sys v0.9.xx`

Solution:

# Ubuntu/Debian
sudo apt update
sudo apt install -y pkg-config libssl-dev build-essential

# CentOS/RHEL/Fedora
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y pkg-config openssl-devel

# macOS
brew install openssl pkg-config

Problem: Linker errors

error: linking with `cc` failed: exit status: 1
note: /usr/bin/ld: cannot find -lssl

Solution:

# Ubuntu/Debian
sudo apt install -y libssl-dev

# Set environment variables if needed
export PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig"
export OPENSSL_DIR="/usr"

Configuration Issues

Invalid TOML Syntax

Problem: Configuration file parsing errors

Error: failed to parse config file
Caused by: invalid TOML syntax at line 5, column 10

Solution:

# Check TOML syntax
# Common issues:
# 1. Missing quotes around strings
name = example     # Wrong
name = "example"   # Correct

# 2. Incorrect array syntax
ports = [8080 8081]     # Wrong (missing comma)
ports = [8080, 8081]    # Correct

# 3. Misplaced sections
[[sites]]
name = "test"
[daemon]           # Wrong (should be before [[sites]])

# Validate TOML syntax online: https://www.toml-lint.com/

Missing Required Fields

Problem: Configuration validation errors

Error: missing required field `port` for site 'example'

Solution:

# Ensure all required fields are present
[[sites]]
name = "example"      # Required
hostname = "localhost" # Required
port = 8080           # Required
static_dir = "static" # Required

Port Binding Issues

Problem: Address already in use

Error: failed to bind to 127.0.0.1:8080
Caused by: Address already in use (os error 98)

Solution:

# Check what's using the port
lsof -i :8080
netstat -tulpn | grep :8080

# Kill the process using the port
kill -9 $(lsof -ti:8080)

# Or use a different port
[[sites]]
name = "example"
hostname = "localhost"
port = 8081  # Use different port
static_dir = "static"

File Permission Issues

Problem: Cannot access static files

Error: Permission denied (os error 13)

Solution:

# Check file permissions
ls -la static/

# Fix permissions
chmod 755 static/
chmod 644 static/*
find static/ -type d -exec chmod 755 {} \;
find static/ -type f -exec chmod 644 {} \;

# Check directory ownership
sudo chown -R $USER:$USER static/

Runtime Issues

BWS Won't Start

Problem: Server fails to start silently

# No output, process exits immediately

Solution:

# Enable debug logging
RUST_LOG=debug ./target/release/bws --config config.toml

# Check configuration
./target/release/bws --config config.toml --validate

# Check system resources
df -h        # Disk space
free -h      # Memory
ulimit -n    # File descriptors

High Memory Usage

Problem: BWS consuming excessive memory

# Process using > 1GB RAM for simple static serving

Solution:

# Monitor memory usage
ps aux | grep bws
top -p $(pgrep bws)

# Check for memory leaks
valgrind --tool=memcheck --leak-check=full ./target/release/bws

# Optimize configuration
[performance]
max_connections = 1000      # Reduce if too high
worker_threads = 4          # Match CPU cores
connection_pool_size = 100  # Reduce pool size

[caching]
max_memory = "100MB"        # Limit cache size

High CPU Usage

Problem: BWS using 100% CPU

# CPU usage constantly high even with low traffic

Solution:

# Profile CPU usage
perf record -g ./target/release/bws --config config.toml
perf report

# Check configuration
[performance]
worker_threads = 4  # Don't exceed CPU cores
keep_alive_timeout = 30  # Reduce timeout

# Monitor system load
htop
iostat 1

Connection Issues

Problem: Cannot connect to BWS

curl: (7) Failed to connect to localhost port 8080: Connection refused

Solution:

# Check if BWS is running
ps aux | grep bws
systemctl status bws  # If using systemd

# Check port binding
netstat -tulpn | grep :8080
ss -tulpn | grep :8080

# Check firewall
sudo ufw status
sudo iptables -L

# Test locally first
curl -v http://127.0.0.1:8080/

Performance Issues

Slow Response Times

Problem: High latency for static file serving

# Response times > 1 second for small files

Solution:

# Check disk I/O
iostat -x 1
iotop

# Optimize storage
# Use SSD for static files
# Enable file system caching
mount -o remount,noatime /path/to/static

# Tune BWS configuration
[performance]
read_buffer_size = "64KB"   # Increase buffer size
write_buffer_size = "64KB"
worker_threads = 8          # Increase workers

[caching]
enabled = true
max_memory = "1GB"          # Enable caching

Low Throughput

Problem: Cannot handle expected load

# Failing under moderate load (< 1000 req/s)

Solution:

# Increase system limits
# /etc/security/limits.conf
bws soft nofile 65536
bws hard nofile 65536

# /etc/sysctl.conf
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# Tune BWS
[performance]
max_connections = 10000
worker_threads = 16         # 2x CPU cores
keep_alive_timeout = 60

# Use load balancer for scaling

Network Issues

Timeout Errors

Problem: Requests timing out

curl: (28) Operation timed out after 30000 milliseconds

Solution:

# Check network connectivity
ping hostname
traceroute hostname

# Increase timeouts
[performance]
request_timeout = 60      # Increase from 30
response_timeout = 60
keep_alive_timeout = 120

# Check for network congestion
iftop
nethogs

DNS Resolution Issues

Problem: Cannot resolve hostname

curl: (6) Could not resolve host: example.com

Solution:

# Test DNS resolution
nslookup example.com
dig example.com

# Check /etc/hosts
grep example.com /etc/hosts

# Use IP address instead
[[sites]]
name = "example"
hostname = "192.168.1.100"  # Use IP instead of hostname
port = 8080
static_dir = "static"

SSL/TLS Issues

Certificate Problems

Problem: SSL certificate errors

Error: SSL certificate verification failed

Solution:

# Check certificate validity
openssl x509 -in cert.pem -text -noout
openssl verify -CAfile ca.pem cert.pem

# Check certificate permissions
ls -la /etc/ssl/certs/
chmod 644 /etc/ssl/certs/cert.pem
chmod 600 /etc/ssl/private/key.pem

# Verify certificate chain
openssl s_client -connect example.com:443 -showcerts

TLS Handshake Failures

Problem: TLS handshake errors

Error: TLS handshake failed

Solution:

# Check TLS configuration
[sites.ssl]
enabled = true
protocols = ["TLSv1.2", "TLSv1.3"]  # Ensure modern protocols
cert_file = "/path/to/cert.pem"
key_file = "/path/to/key.pem"

# Test TLS connection
openssl s_client -connect localhost:8443 -tls1_2

Docker Issues

Container Won't Start

Problem: Docker container exits immediately

docker run bws:latest
# Container exits with code 1

Solution:

# Check container logs
docker logs container_id

# Run interactively for debugging
docker run -it --entrypoint /bin/bash bws:latest

# Check file permissions in container
docker run --rm bws:latest ls -la /app/

# Mount configuration correctly
docker run -v $(pwd)/config.toml:/app/config.toml bws:latest

Volume Mount Issues

Problem: Cannot access mounted files

Error: No such file or directory: /app/static/index.html

Solution:

# Check volume mount syntax
docker run -v $(pwd)/static:/app/static bws:latest

# Verify host path exists
ls -la $(pwd)/static/

# Check file permissions
chmod -R 644 static/
chmod 755 static/

# Use absolute paths
docker run -v /full/path/to/static:/app/static bws:latest

Diagnostic Commands

System Information

#!/bin/bash
# diagnostic.sh - System diagnostic script

echo "=== BWS Diagnostic Information ==="
echo "Date: $(date)"
echo "Host: $(hostname)"
echo

echo "=== System Information ==="
uname -a
cat /etc/os-release 2>/dev/null || cat /etc/redhat-release 2>/dev/null
echo

echo "=== Resource Usage ==="
echo "CPU cores: $(nproc)"
echo "Memory:"
free -h
echo "Disk:"
df -h
echo "Load average:"
uptime
echo

echo "=== Network Configuration ==="
ip addr show
echo
netstat -tulpn | grep -E ":(8080|8081|8082|8083)"
echo

echo "=== BWS Process Information ==="
if pgrep -f bws > /dev/null; then
    echo "BWS is running:"
    ps aux | grep -v grep | grep bws
    echo
    echo "Open files:"
    lsof -p $(pgrep bws) | head -20
else
    echo "BWS is not running"
fi
echo

echo "=== Configuration Files ==="
find . -name "*.toml" -exec echo "File: {}" \; -exec head -20 {} \; -exec echo \;

echo "=== Log Files ==="
find /var/log -name "*bws*" 2>/dev/null | while read log; do
    echo "=== $log ==="
    tail -20 "$log" 2>/dev/null
    echo
done

echo "=== Recent System Logs ==="
journalctl -u bws --no-pager -n 20 2>/dev/null || echo "No systemd logs found"

Network Diagnostics

#!/bin/bash
# network-test.sh - Network connectivity test

HOST=${1:-localhost}
PORT=${2:-8080}

echo "Testing connectivity to $HOST:$PORT"

# Test basic connectivity
echo "=== Ping Test ==="
ping -c 3 $HOST

echo "=== Port Test ==="
nc -zv $HOST $PORT 2>&1

echo "=== HTTP Test ==="
curl -v http://$HOST:$PORT/ 2>&1 | head -20

echo "=== DNS Resolution ==="
nslookup $HOST

echo "=== Route Trace ==="
traceroute $HOST 2>/dev/null | head -10

Performance Monitoring

#!/bin/bash
# monitor.sh - Real-time BWS monitoring

BWS_PID=$(pgrep bws)

if [ -z "$BWS_PID" ]; then
    echo "BWS process not found"
    exit 1
fi

echo "Monitoring BWS process $BWS_PID"
echo "Press Ctrl+C to stop"

while true; do
    clear
    echo "=== BWS Monitoring - $(date) ==="
    echo
    
    # Process information
    echo "=== Process Information ==="
    ps -o pid,ppid,cmd,%mem,%cpu,time -p $BWS_PID
    echo
    
    # Memory usage
    echo "=== Memory Usage ==="
    cat /proc/$BWS_PID/status | grep -E "VmSize|VmRSS|VmData|VmStk"
    echo
    
    # Network connections
    echo "=== Network Connections ==="
    ss -tuln | grep ":8080\|:8081\|:8082\|:8083" | wc -l | xargs echo "Active connections:"
    echo
    
    # File descriptors
    echo "=== File Descriptors ==="
    ls /proc/$BWS_PID/fd/ | wc -l | xargs echo "Open file descriptors:"
    echo
    
    # System load
    echo "=== System Load ==="
    uptime
    
    sleep 5
done

Log Analysis

Error Log Patterns

# Common error patterns to look for

# Configuration errors
grep -i "config\|parse\|invalid" /var/log/bws/bws.log

# Network errors
grep -i "bind\|connection\|timeout" /var/log/bws/bws.log

# File system errors
grep -i "permission\|not found\|access" /var/log/bws/bws.log

# Performance issues
grep -i "slow\|timeout\|overload" /var/log/bws/bws.log

# Security issues
grep -i "attack\|malicious\|blocked" /var/log/bws/bws.log

Log Analysis Script

#!/bin/bash
# analyze-logs.sh - BWS log analysis

LOG_FILE=${1:-/var/log/bws/bws.log}

if [ ! -f "$LOG_FILE" ]; then
    echo "Log file not found: $LOG_FILE"
    exit 1
fi

echo "Analyzing BWS logs: $LOG_FILE"
echo "Log file size: $(du -h $LOG_FILE | cut -f1)"
echo "Total lines: $(wc -l < $LOG_FILE)"
echo

echo "=== Error Summary ==="
grep -i error "$LOG_FILE" | wc -l | xargs echo "Total errors:"
grep -i warn "$LOG_FILE" | wc -l | xargs echo "Total warnings:"
echo

echo "=== Recent Errors ==="
grep -i error "$LOG_FILE" | tail -10
echo

echo "=== Top Error Messages ==="
grep -i error "$LOG_FILE" | sort | uniq -c | sort -rn | head -10
echo

echo "=== Request Statistics ==="
if grep -q "request" "$LOG_FILE"; then
    grep "request" "$LOG_FILE" | wc -l | xargs echo "Total requests:"
    
    # Status code distribution
    echo "Status codes:"
    grep -o '"status":[0-9]*' "$LOG_FILE" | cut -d: -f2 | sort | uniq -c | sort -rn
fi

Recovery Procedures

Service Recovery

#!/bin/bash
# recover-bws.sh - BWS service recovery

echo "Starting BWS recovery procedure..."

# Stop any running instances
echo "Stopping BWS..."
systemctl stop bws 2>/dev/null || pkill -f bws

# Clean up PID files
rm -f /var/run/bws.pid

# Check configuration
echo "Validating configuration..."
if ! bws --config /etc/bws/config.toml --validate; then
    echo "Configuration invalid, please fix and retry"
    exit 1
fi

# Check file permissions
echo "Checking file permissions..."
if [ ! -r /etc/bws/config.toml ]; then
    echo "Configuration file not readable"
    chmod 644 /etc/bws/config.toml
fi

# Check static directory
STATIC_DIR=$(grep static_dir /etc/bws/config.toml | head -1 | cut -d'"' -f2)
if [ ! -d "$STATIC_DIR" ]; then
    echo "Creating static directory: $STATIC_DIR"
    mkdir -p "$STATIC_DIR"
    echo "<h1>BWS Recovery Page</h1>" > "$STATIC_DIR/index.html"
fi

# Start service
echo "Starting BWS..."
if systemctl start bws; then
    echo "BWS started successfully"
    systemctl status bws
else
    echo "Failed to start BWS, check logs:"
    journalctl -u bws --no-pager -n 20
fi

Database Recovery (if applicable)

#!/bin/bash
# recover-database.sh - Database recovery for BWS

echo "Database recovery procedure..."

# Check database connection
if ! pg_isready -h localhost -p 5432; then
    echo "Database not accessible"
    exit 1
fi

# Backup current database
pg_dump bws > /backup/bws-recovery-$(date +%Y%m%d).sql

# Run database maintenance
psql bws -c "VACUUM ANALYZE;"
psql bws -c "REINDEX DATABASE bws;"

echo "Database recovery completed"

Prevention Strategies

Monitoring Setup

# Set up basic monitoring
crontab -e

# Add monitoring jobs
*/5 * * * * /usr/local/bin/bws-health-check || /usr/bin/logger "BWS health check failed"
0 */6 * * * /usr/local/bin/cleanup-logs
0 2 * * * /usr/local/bin/backup-bws-config

Automated Backups

#!/bin/bash
# backup-bws.sh - Automated BWS backup

BACKUP_DIR="/backup/bws"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p "$BACKUP_DIR"

# Backup configuration
tar -czf "$BACKUP_DIR/config-$DATE.tar.gz" /etc/bws/

# Backup static files
tar -czf "$BACKUP_DIR/static-$DATE.tar.gz" /var/www/

# Backup logs
tar -czf "$BACKUP_DIR/logs-$DATE.tar.gz" /var/log/bws/

# Clean old backups (keep 30 days)
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete

echo "Backup completed: $BACKUP_DIR"

Health Monitoring

#!/bin/bash
# health-monitor.sh - Continuous health monitoring

ALERT_EMAIL="admin@example.com"
ALERT_WEBHOOK="https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"

check_health() {
    if ! curl -f -s http://localhost:8080/health > /dev/null; then
        return 1
    fi
    return 0
}

send_alert() {
    local message="$1"
    
    # Email alert
    echo "$message" | mail -s "BWS Alert" "$ALERT_EMAIL"
    
    # Slack alert
    curl -X POST -H 'Content-type: application/json' \
        --data "{\"text\":\"$message\"}" \
        "$ALERT_WEBHOOK"
}

# Main monitoring loop
while true; do
    if ! check_health; then
        send_alert "BWS health check failed at $(date)"
        
        # Attempt recovery
        systemctl restart bws
        sleep 30
        
        if check_health; then
            send_alert "BWS recovered successfully at $(date)"
        else
            send_alert "BWS recovery failed - manual intervention required"
        fi
    fi
    
    sleep 60
done

Getting Help

Information to Collect

When reporting issues, include:

  1. System Information

    • Operating system and version
    • Rust version (rustc --version)
    • BWS version (bws --version)
  2. Configuration

    • Configuration file content (sanitized)
    • Command line arguments used
  3. Error Information

    • Complete error messages
    • Stack traces if available
    • Log file contents
  4. Environment

    • Available memory and disk space
    • Network configuration
    • Other running services

Support Channels

  • GitHub Issues: Report bugs and request features
  • GitHub Discussions: Ask questions and get help
  • Documentation: Check existing documentation
  • Community: Join discussions with other users

Before Reporting

  1. Search existing issues
  2. Try the latest version
  3. Check documentation
  4. Provide minimal reproduction case
  5. Include diagnostic information

Next Steps

After resolving issues:

  1. Update your monitoring setup
  2. Review Performance Tuning
  3. Check Security Best Practices
  4. Consider High Availability Setup

Frequently Asked Questions (FAQ)

General Questions

What is BWS?

BWS (Basic Web Server) is a high-performance, multi-site web server built with Rust and powered by Cloudflare's Pingora framework. It's designed for serving static files and provides enterprise-grade features including multi-site hosting, SSL/TLS support, and comprehensive monitoring.

Why use BWS over other web servers?

Performance: Built on Pingora, BWS offers exceptional performance and low latency.

Safety: Written in Rust, BWS provides memory safety and prevents common security vulnerabilities.

Simplicity: Easy configuration through TOML files and straightforward deployment.

Multi-tenancy: Native support for hosting multiple sites from a single instance.

Modern Features: Built-in support for WASM, comprehensive MIME types, and modern web standards.

What are the system requirements?

Minimum Requirements:

  • CPU: 1 core (x86_64 or ARM64)
  • RAM: 256MB
  • Storage: 100MB for binary + static content
  • OS: Linux, macOS, or Windows

Recommended for Production:

  • CPU: 4+ cores
  • RAM: 2GB+
  • Storage: SSD with sufficient space for content
  • OS: Linux (Ubuntu 20.04+, CentOS 8+, RHEL 8+)

Is BWS production-ready?

Yes, BWS is production-ready. It's built on Cloudflare's battle-tested Pingora framework and includes:

  • Comprehensive error handling
  • Security hardening
  • Performance optimization
  • Monitoring and logging
  • Automated testing
  • Documentation and support

Installation & Setup

How do I install BWS?

You have several options:

From pre-built binaries:

# Download from GitHub releases
wget https://github.com/yourusername/bws/releases/latest/download/bws-linux-x86_64.tar.gz
tar -xzf bws-linux-x86_64.tar.gz

From source:

git clone https://github.com/yourusername/bws.git
cd bws
cargo build --release

Using Docker:

docker pull ghcr.io/yourusername/bws:latest

See the Installation Guide for detailed instructions.

Do I need root privileges to run BWS?

No, BWS can run as a non-root user. However:

  • Ports < 1024: Require root privileges or CAP_NET_BIND_SERVICE capability
  • File access: Ensure the user can read configuration and static files
  • Log files: Ensure the user can write to log directories

Best practice: Run as a dedicated user with minimal privileges:

useradd -r -s /bin/false bws
sudo -u bws ./bws --config config.toml

Can I run BWS on Windows?

Yes, BWS supports Windows. However, some features may behave differently:

  • Use Windows paths (C:\path o\files)
  • Service management differs from Linux
  • Performance may vary compared to Linux

For production, Linux is recommended.

Configuration

How do I configure multiple sites?

Use the [[sites]] array in your configuration:

[[sites]]
name = "main"
hostname = "example.com"
port = 8080
static_dir = "/var/www/main"

[[sites]]
name = "blog"
hostname = "blog.example.com"
port = 8080
static_dir = "/var/www/blog"

[[sites]]
name = "api"
hostname = "api.example.com"
port = 8081
static_dir = "/var/www/api"

Each site can have different configurations while sharing the same BWS instance.

Can I use environment variables in configuration?

Currently, BWS doesn't support environment variable substitution in TOML files. However, you can:

  1. Generate configuration programmatically:
envsubst < config.template.toml > config.toml
  1. Use multiple config files:
bws --config config-${ENVIRONMENT}.toml
  1. Override specific settings via command line (if supported in your version)

How do I enable SSL/TLS?

Add SSL configuration to your site:

[[sites]]
name = "secure"
hostname = "example.com"
port = 8443
static_dir = "/var/www/secure"

[sites.ssl]
enabled = true
cert_file = "/etc/ssl/certs/example.com.pem"
key_file = "/etc/ssl/private/example.com.key"
protocols = ["TLSv1.2", "TLSv1.3"]

See SSL/TLS Configuration for details.

What's the difference between hostname and domain?

  • hostname: The network interface and host header to match
  • domain: An alias for hostname (legacy compatibility)

Both fields serve the same purpose. Use hostname for new configurations.

How do I serve files from subdirectories?

BWS automatically serves files from subdirectories. For example, with:

static_dir = "/var/www/html"

These URLs work automatically:

  • http://example.com/ โ†’ /var/www/html/index.html
  • http://example.com/about/ โ†’ /var/www/html/about/index.html
  • http://example.com/assets/style.css โ†’ /var/www/html/assets/style.css

Performance

How many concurrent connections can BWS handle?

BWS can handle thousands of concurrent connections. The exact number depends on:

  • System resources: CPU cores, RAM, file descriptors
  • Configuration: max_connections, worker_threads
  • Content type: Static files vs. dynamic content
  • Network conditions: Latency, bandwidth

Typical performance:

  • Small VPS (2 cores, 2GB RAM): 1,000-5,000 concurrent connections
  • Medium server (8 cores, 16GB RAM): 10,000-50,000 concurrent connections
  • Large server (32 cores, 64GB RAM): 100,000+ concurrent connections

How do I optimize BWS performance?

Configuration tuning:

[performance]
worker_threads = 8           # Match CPU cores * 2
max_connections = 10000      # Based on system capacity
read_buffer_size = "64KB"    # Larger for big files
write_buffer_size = "64KB"   # Larger for throughput

[caching]
enabled = true
max_memory = "1GB"           # Adjust based on available RAM

System tuning:

# Increase file descriptor limits
echo "bws soft nofile 65536" >> /etc/security/limits.conf
echo "bws hard nofile 65536" >> /etc/security/limits.conf

# Tune kernel parameters
echo "net.core.somaxconn = 65535" >> /etc/sysctl.conf
echo "net.ipv4.tcp_max_syn_backlog = 65535" >> /etc/sysctl.conf
sysctl -p

See Performance Tuning for comprehensive optimization.

Does BWS support caching?

Yes, BWS includes built-in caching:

[caching]
enabled = true
max_memory = "512MB"         # Memory limit for cache
ttl = 3600                   # Time-to-live in seconds
compression = true           # Enable gzip compression

Caching improves performance by:

  • Reducing disk I/O
  • Enabling content compression
  • Serving frequently requested files from memory

Can BWS serve WASM files?

Yes, BWS includes native WASM support with proper MIME types:

  • .wasm files are served with application/wasm
  • Supports WebAssembly streaming compilation
  • Enables modern web applications

No additional configuration required - WASM support is built-in.

Security

Is BWS secure?

BWS implements multiple security layers:

Language Safety: Written in Rust, preventing memory safety vulnerabilities.

Input Validation: Strict validation of requests and configuration.

Path Traversal Protection: Prevents access to files outside static directories.

Security Headers: Configurable security headers.

Regular Updates: Dependencies are regularly updated for security fixes.

How do I secure BWS in production?

Basic security:

[security]
hide_server_header = true    # Don't reveal server information
max_request_size = "10MB"    # Prevent large request attacks

[headers]
"X-Frame-Options" = "DENY"
"X-Content-Type-Options" = "nosniff"
"X-XSS-Protection" = "1; mode=block"
"Strict-Transport-Security" = "max-age=31536000; includeSubDomains"

Additional measures:

  • Run as non-root user
  • Use firewall to restrict access
  • Enable SSL/TLS with strong ciphers
  • Regular security updates
  • Monitor logs for suspicious activity

See Security Best Practices for comprehensive guidance.

Does BWS log sensitive information?

BWS is designed to avoid logging sensitive information:

  • Passwords and API keys are not logged
  • Request bodies are not logged by default
  • IP addresses are logged for legitimate monitoring

Log configuration:

[logging]
level = "info"               # Avoid "debug" in production
access_log = "/var/log/bws/access.log"
error_log = "/var/log/bws/error.log"

Always review logs before sharing for troubleshooting.

Can I restrict access to certain files?

Currently, BWS serves all files from the static directory. For access control:

File system permissions:

# Remove read permissions for sensitive files
chmod 600 sensitive-file.txt

Reverse proxy approach: Use nginx or Apache as a reverse proxy for advanced access control:

location /admin/ {
    auth_basic "Admin Area";
    auth_basic_user_file /etc/nginx/.htpasswd;
    proxy_pass http://localhost:8080;
}

Separate directories: Use different BWS sites for different access levels.

Deployment

How do I deploy BWS in production?

Systemd service (recommended for Linux):

# Create service file
sudo tee /etc/systemd/system/bws.service > /dev/null <<EOF
[Unit]
Description=BWS Web Server
After=network.target

[Service]
Type=simple
User=bws
ExecStart=/usr/local/bin/bws --config /etc/bws/config.toml
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

# Enable and start service
sudo systemctl enable bws
sudo systemctl start bws

Docker deployment:

docker run -d 
  --name bws 
  -p 8080:8080 
  -v /path/to/config.toml:/app/config.toml:ro 
  -v /path/to/static:/app/static:ro 
  ghcr.io/yourusername/bws:latest

See Production Deployment for complete instructions.

Can I use BWS with a reverse proxy?

Yes, BWS works well behind reverse proxies:

Nginx example:

upstream bws {
    server 127.0.0.1:8080;
}

server {
    listen 80;
    server_name example.com;
    
    location / {
        proxy_pass http://bws;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Benefits:

  • SSL termination at proxy
  • Load balancing across multiple BWS instances
  • Advanced routing and caching
  • Security filtering

How do I update BWS?

Binary updates:

# Stop service
sudo systemctl stop bws

# Backup current binary
cp /usr/local/bin/bws /usr/local/bin/bws.backup

# Replace binary
wget https://github.com/yourusername/bws/releases/latest/download/bws-linux-x86_64.tar.gz
tar -xzf bws-linux-x86_64.tar.gz
sudo cp bws /usr/local/bin/

# Restart service
sudo systemctl start bws

Docker updates:

# Pull new image
docker pull ghcr.io/yourusername/bws:latest

# Restart with new image
docker-compose down
docker-compose up -d

Source updates:

git pull origin main
cargo build --release
sudo cp target/release/bws /usr/local/bin/
sudo systemctl restart bws

Can I run multiple BWS instances?

Yes, you can run multiple BWS instances:

Same machine, different ports:

# Instance 1: config1.toml
[[sites]]
name = "site1"
hostname = "localhost"
port = 8080
static_dir = "/var/www/site1"

# Instance 2: config2.toml
[[sites]]
name = "site2"
hostname = "localhost"
port = 8081
static_dir = "/var/www/site2"

Load balancing: Use a load balancer to distribute traffic across instances.

Different machines: Deploy separate BWS instances on different servers for horizontal scaling.

Troubleshooting

BWS won't start - what should I check?

Common issues:

  1. Configuration errors:
bws --config config.toml --validate
  1. Port already in use:
lsof -i :8080
  1. File permissions:
ls -la config.toml
ls -la /path/to/static/
  1. Missing dependencies:
ldd /usr/local/bin/bws  # Linux
otool -L /usr/local/bin/bws  # macOS

See Troubleshooting Guide for comprehensive diagnostics.

High memory usage - is this normal?

Memory usage depends on:

Configuration:

  • Cache size (max_memory)
  • Worker threads (worker_threads)
  • Connection pool size

Workload:

  • Number of concurrent connections
  • File sizes being served
  • Request frequency

Normal ranges:

  • Minimal configuration: 10-50MB
  • Production configuration: 100-500MB
  • Heavy caching: 1GB+

Monitor with:

ps aux | grep bws
top -p $(pgrep bws)

Request timeouts - how to fix?

Increase timeouts:

[performance]
request_timeout = 60         # Default: 30 seconds
response_timeout = 60        # Default: 30 seconds
keep_alive_timeout = 120     # Default: 60 seconds

Check system resources:

iostat -x 1    # Disk I/O
free -h        # Memory usage
top            # CPU usage

Network diagnostics:

curl -w "@curl-format.txt" -o /dev/null -s http://localhost:8080/

Where curl-format.txt contains:

time_namelookup:  %{time_namelookup}

time_connect:     %{time_connect}

time_pretransfer: %{time_pretransfer}

time_redirect:    %{time_redirect}

time_starttransfer: %{time_starttransfer}

time_total:       %{time_total}

Development

How can I contribute to BWS?

We welcome contributions! Here's how to get started:

  1. Fork the repository on GitHub
  2. Clone your fork: git clone https://github.com/yourusername/bws.git
  3. Create a feature branch: git checkout -b feature/amazing-feature
  4. Make your changes and add tests
  5. Run tests: cargo test
  6. Submit a pull request

See Contributing Guide for detailed instructions.

How do I build BWS from source?

Prerequisites:

# Install Rust (version 1.89+)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install system dependencies (Ubuntu/Debian)
sudo apt install -y pkg-config libssl-dev build-essential

Build process:

git clone https://github.com/yourusername/bws.git
cd bws
cargo build --release

# Binary will be at target/release/bws

See Building from Source for platform-specific instructions.

Can I extend BWS with custom features?

BWS is designed to be extensible. Common extension points:

Custom MIME types:

#![allow(unused)]
fn main() {
// Add to src/lib.rs
pub fn get_mime_type(path: &str) -> &'static str {
    match path.split('.').last() {
        Some("myext") => "application/x-myformat",
        _ => get_default_mime_type(path),
    }
}
}

Custom headers:

[headers]
"X-Custom-Header" = "Custom Value"
"Cache-Control" = "max-age=3600"

Middleware integration: BWS is built on Pingora, which supports middleware. Consider contributing middleware to the main project.

How do I report bugs?

Before reporting:

  1. Check existing issues on GitHub
  2. Try the latest version
  3. Read the documentation
  4. Gather diagnostic information

Bug report should include:

  • BWS version (bws --version)
  • Operating system and version
  • Configuration file (sanitized)
  • Complete error messages
  • Steps to reproduce
  • Expected vs. actual behavior

Submit issues at: https://github.com/yourusername/bws/issues

License & Support

What license is BWS under?

BWS is released under the MIT License, which allows:

  • Commercial use
  • Modification
  • Distribution
  • Private use

With requirements for:

  • Including the license notice
  • Including the copyright notice

Where can I get support?

Free support:

  • GitHub Issues (bug reports)
  • GitHub Discussions (questions)
  • Documentation (comprehensive guides)
  • Community forums

Commercial support: Contact us for:

  • Priority support
  • Custom development
  • Training and consulting
  • Enterprise licensing

How often is BWS updated?

Regular releases:

  • Patch releases: Monthly (bug fixes)
  • Minor releases: Quarterly (new features)
  • Major releases: Yearly (breaking changes)

Security updates:

  • Critical security fixes: Within 24-48 hours
  • Regular security updates: Weekly

Dependencies:

  • Rust toolchain: Follow Rust stable releases
  • Pingora framework: Updated with upstream releases

Stay updated by:

  • Watching the GitHub repository
  • Following release notes
  • Subscribing to security advisories

Migration

Migrating from Apache/Nginx?

Configuration mapping:

Apache .htaccess โ†’ BWS configuration:

# Apache
DocumentRoot /var/www/html
Listen 80

# BWS
[[sites]]
name = "main"
hostname = "localhost"
port = 8080
static_dir = "/var/www/html"

Common features:

  • Virtual hosts โ†’ Multiple sites
  • SSL configuration โ†’ SSL section
  • Custom headers โ†’ Headers section
  • Access logs โ†’ Logging configuration

Migrating from other Rust web servers?

From Actix-web:

  • Replace route handlers with static file serving
  • Migrate middleware to configuration
  • Update deployment scripts

From Warp:

  • Convert filters to BWS configuration
  • Replace custom handlers with static serving
  • Update error handling

From Rocket:

  • Replace routes with static file configuration
  • Migrate state management to external systems
  • Update launch configuration

Migrating configuration formats?

From JSON:

# Convert JSON to TOML
pip install json2toml
json2toml config.json config.toml

From YAML:

# Convert YAML to TOML
pip install yq
yq -t config.yaml > config.toml

Manual migration: Review and adapt configuration according to BWS schema.

Future Roadmap

What's planned for future versions?

Short-term (next 3 months):

  • Enhanced monitoring and metrics
  • Additional security features
  • Performance optimizations
  • Configuration validation improvements

Medium-term (next 6 months):

  • Plugin system
  • Advanced caching strategies
  • HTTP/3 support
  • Enhanced SSL/TLS configuration

Long-term (next year):

  • GUI configuration interface
  • Distributed deployment support
  • Advanced load balancing
  • Enterprise features

How can I influence the roadmap?

  • Submit feature requests on GitHub
  • Participate in discussions
  • Contribute code
  • Sponsor development
  • Provide feedback and use cases

Don't see your question? Ask on GitHub Discussions or check the documentation.

Changelog

All notable changes to BWS will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

Added

  • ๐Ÿ›ก๏ธ Production-Grade Error Handling: Comprehensive error handling throughout codebase - no more .unwrap() calls
  • ๐Ÿ”„ Automatic SSL Certificate Monitoring: Background certificate renewal service with robust error handling
  • ๐Ÿงน Code Quality Improvements: Zero Clippy warnings achieved for maximum code quality
  • ๐Ÿ”ง Thread-Safe SSL Operations: Fixed critical concurrency issues in certificate management
  • ๐Ÿ“š Enhanced Documentation: Updated documentation reflecting improved robustness and reliability
  • ๏ฟฝ WebSocket Proxy Support: Full WebSocket proxying framework with automatic upgrade detection
  • โš–๏ธ WebSocket Load Balancing: All load balancing algorithms extended to WebSocket connections
  • ๐Ÿ”„ Protocol Transformation: Automatic HTTP to WebSocket URL conversion (httpโ†’ws, httpsโ†’wss)
  • ๐Ÿค Bidirectional Framework: Foundation for real-time message forwarding (streaming pending)
  • ๐Ÿงช WebSocket Testing: Comprehensive test suite and interactive test script
  • ๐Ÿ“– WebSocket Documentation: Complete documentation with examples and configuration guides
  • ๏ฟฝ๐Ÿ”„ Reverse Proxy Functionality: Complete Caddy-style reverse proxy implementation
  • โš–๏ธ Load Balancing: Three algorithms - round-robin, weighted, and least-connections
  • ๐Ÿ”— Connection Tracking: Real-time connection monitoring for least-connections algorithm
  • ๐Ÿท๏ธ Header Management: Advanced proxy header forwarding and customization
  • โฑ๏ธ Request Timeouts: Configurable read/write timeouts for proxy requests
  • ๐Ÿ›ฃ๏ธ Path Transformation: URL rewriting and prefix stripping capabilities
  • ๐Ÿ”ง Per-Site Proxy Config: Individual proxy configuration for each site
  • ๐Ÿงช Load Balancing Tests: Comprehensive test suite for all load balancing methods
  • ๐Ÿ“š Proxy Documentation: Detailed documentation for reverse proxy and load balancing
  • Comprehensive documentation with mdBook
  • Advanced troubleshooting guides
  • Performance monitoring scripts
  • Security hardening guidelines

Changed

  • ๐Ÿš€ Enhanced Reliability: Replaced all dangerous .unwrap() calls with proper error handling
  • ๐Ÿ”’ SSL Manager Improvements: Fixed critical concurrency issues (Future not Send) in certificate operations
  • โšก Async Function Optimization: Improved async/await patterns throughout codebase
  • ๐Ÿ“ Modern String Formatting: Updated 50+ format strings to use modern interpolation
  • ๐Ÿ›ก๏ธ Thread-Safe Operations: All operations use proper atomic operations for concurrency
  • Enhanced Service Architecture: Integrated proxy handler with main web service
  • Thread-Safe Operations: All load balancing uses atomic operations for concurrency
  • Configuration Schema: Extended TOML schema to support proxy configurations
  • Improved error messages and diagnostics
  • Enhanced configuration validation
  • Better logging format and structure

Fixed

  • ๐Ÿšจ Critical SSL Concurrency Issues: Resolved "Future not Send" problems in SSL manager
  • ๐Ÿ›ก๏ธ Race Condition Elimination: Fixed race conditions in certificate validation and load balancing
  • ๐Ÿ’พ Resource Leak Prevention: Proper cleanup of certificate operations and connections
  • โšก Async Function Signatures: Fixed async/await patterns and removed unnecessary async functions
  • ๐Ÿ”ง Iterator and Formatting Issues: Resolved compilation errors from iterator usage
  • ๐Ÿ“ Error Documentation: Added comprehensive documentation for Result-returning functions
  • Proxy Error Handling: Graceful fallback with 502 Bad Gateway responses
  • Connection Cleanup: Proper connection tracking cleanup on request completion
  • Concurrent Safety: Race condition fixes in load balancing counters
  • Minor memory leaks in connection handling
  • Edge cases in path resolution
  • Configuration parsing edge cases

[0.1.5] - 2024-12-19

Added

  • WASM (WebAssembly) MIME type support (application/wasm)
  • Enhanced subdirectory file serving capabilities
  • Comprehensive error handling and logging
  • Security improvements and hardening
  • Performance optimizations
  • Docker containerization with multi-stage builds
  • GitHub Actions CI/CD pipeline with automated testing
  • Automated release workflow with GitHub Releases
  • Container registry publishing (GitHub Container Registry)
  • Supply chain security with attestations
  • Code coverage reporting and quality gates
  • Dependency vulnerability scanning

Changed

  • Improved MIME type detection and handling
  • Enhanced static file serving performance
  • Better error messages and user feedback
  • Upgraded to latest Pingora framework version
  • Optimized binary size and runtime performance

Removed

  • BREAKING: Removed /api/file route for security reasons
  • Legacy file access API endpoints
  • Deprecated configuration options

Fixed

  • Path traversal security vulnerabilities
  • Memory usage optimization in file serving
  • Connection handling edge cases
  • Configuration validation issues
  • Build system improvements

Security

  • Removed insecure file access endpoints
  • Enhanced input validation
  • Improved error handling to prevent information disclosure
  • Added security headers by default
  • Path sanitization improvements

[0.1.4] - 2024-12-15

Added

  • Multi-site configuration support
  • SSL/TLS termination capabilities
  • Custom HTTP headers configuration
  • Configurable logging levels and formats
  • Performance tuning options
  • Connection pooling and management

Changed

  • Refactored configuration system for better flexibility
  • Improved error handling and recovery
  • Enhanced monitoring and observability features
  • Better resource management and cleanup

Fixed

  • Memory leaks in long-running connections
  • Configuration reload handling
  • Signal handling improvements
  • Cross-platform compatibility issues

[0.1.3] - 2024-12-10

Added

  • Comprehensive MIME type support for modern web assets
  • Static file caching mechanisms
  • Request/response logging with customizable formats
  • Health check endpoints for monitoring
  • Graceful shutdown handling
  • Configuration file validation

Changed

  • Improved startup time and resource initialization
  • Better error propagation and handling
  • Enhanced configuration file format
  • More detailed logging and debugging information

Fixed

  • File descriptor leaks
  • Race conditions in multi-threaded operations
  • Memory usage optimization
  • Cross-platform path handling

[0.1.2] - 2024-12-05

Added

  • Virtual host support for multiple domains
  • Custom error page configuration
  • Request rate limiting capabilities
  • Basic authentication support
  • Compression support (gzip, deflate)
  • IPv6 support

Changed

  • Modular architecture for better maintainability
  • Improved configuration parsing and validation
  • Better performance under high load
  • Enhanced security measures

Fixed

  • Buffer overflow in request parsing
  • Deadlock issues in connection handling
  • Memory fragmentation problems
  • Platform-specific compilation issues

[0.1.1] - 2024-11-30

Added

  • Basic HTTP/1.1 server functionality
  • Static file serving with directory indexing
  • Configuration file support (TOML format)
  • Basic logging and error handling
  • Signal handling for graceful shutdown
  • Process daemonization support

Changed

  • Improved code organization and modularity
  • Better error messages and user feedback
  • Enhanced configuration options
  • Performance optimizations

Fixed

  • File permission handling
  • Memory management issues
  • Connection timeout problems
  • Configuration parsing edge cases

Security

  • Input validation improvements
  • Path traversal protection
  • Basic security headers

[0.1.0] - 2024-11-25

Added

  • Initial release of BWS (Basic Web Server)
  • Core HTTP server functionality powered by Pingora
  • Basic static file serving capabilities
  • Simple configuration system
  • Command-line interface
  • Basic error handling and logging
  • Cross-platform support (Linux, macOS, Windows)
  • MIT license

Features

  • High-performance HTTP server based on Cloudflare's Pingora framework
  • Static file serving with automatic MIME type detection
  • Configurable via TOML configuration files
  • Multi-platform support
  • Memory-safe implementation in Rust
  • Lightweight and fast startup
  • Basic security features

Technical Details

  • Built with Rust 1.89+
  • Uses Pingora 0.6.0 framework
  • Supports HTTP/1.1 protocol
  • Asynchronous I/O with Tokio runtime
  • Comprehensive error handling
  • Structured logging support

Release Process

Version Numbering

BWS follows Semantic Versioning:

  • MAJOR version when making incompatible API changes
  • MINOR version when adding functionality in a backwards compatible manner
  • PATCH version when making backwards compatible bug fixes

Release Types

Major Releases (X.0.0):

  • Breaking changes to configuration format
  • Major architectural changes
  • Removal of deprecated features
  • Significant API changes

Minor Releases (X.Y.0):

  • New features and capabilities
  • Performance improvements
  • Non-breaking configuration additions
  • New platform support

Patch Releases (X.Y.Z):

  • Bug fixes and security patches
  • Documentation improvements
  • Performance optimizations
  • Dependency updates

Release Schedule

Regular Releases:

  • Patch releases: Monthly or as needed for critical fixes
  • Minor releases: Quarterly with new features
  • Major releases: Annually or when breaking changes are necessary

Security Releases:

  • Critical security fixes: Within 24-48 hours
  • Regular security updates: As part of monthly patch releases
  • Coordinated vulnerability disclosure: Following responsible disclosure practices

Release Artifacts

Each release includes:

Binary Distributions:

  • Linux (x86_64, ARM64)
  • macOS (Intel, Apple Silicon)
  • Windows (x86_64)

Container Images:

  • Docker images for multiple architectures
  • Published to GitHub Container Registry
  • Tagged with version numbers and latest

Source Code:

  • Tagged releases on GitHub
  • Source code archives (tar.gz, zip)
  • Build instructions and dependencies

Documentation:

  • Release notes and changelog
  • Updated documentation for new features
  • Migration guides for breaking changes

Upgrade Guidelines

Before Upgrading:

  1. Read the changelog and release notes
  2. Check for breaking changes
  3. Backup configuration files
  4. Test in a non-production environment

Minor Version Upgrades:

  • Generally safe with no configuration changes required
  • New features available but not enabled by default
  • Performance improvements included

Major Version Upgrades:

  • May require configuration file updates
  • Review breaking changes carefully
  • Follow migration guides
  • Test thoroughly before production deployment

Patch Version Upgrades:

  • Safe to deploy immediately
  • Include bug fixes and security patches
  • No configuration changes required

Support Policy

Active Support:

  • Latest major version: Full support with new features and fixes
  • Previous major version: Security fixes and critical bug fixes for 12 months
  • Older versions: Community support only

End of Life:

  • Announced 6 months before end of support
  • Final security update provided
  • Migration path documented

Contributing to Releases

Bug Reports:

  • Report issues on GitHub Issues
  • Include version information and reproduction steps
  • Security issues should be reported privately

Feature Requests:

  • Discuss on GitHub Discussions
  • Provide use cases and requirements
  • Consider contributing implementation

Testing:

  • Test release candidates and beta versions
  • Provide feedback on performance and compatibility
  • Report any regressions or issues

Release Notes Format

Each release includes:

Summary:

  • High-level overview of changes
  • Key features and improvements
  • Breaking changes and migration notes

Detailed Changes:

  • Added features and capabilities
  • Changed behavior and improvements
  • Deprecated features and migration path
  • Removed features and alternatives
  • Fixed bugs and issues
  • Security improvements and patches

Technical Details:

  • Dependencies updated
  • Performance improvements
  • Platform-specific changes
  • Build system updates

Upgrade Instructions:

  • Step-by-step upgrade process
  • Configuration changes required
  • Testing recommendations
  • Rollback procedures

Historical Context

Project Milestones

November 2024: BWS project inception

  • Initial concept and planning
  • Technology stack selection (Rust + Pingora)
  • Core architecture design

December 2024: First stable release (0.1.0)

  • Basic HTTP server functionality
  • Static file serving
  • Configuration system
  • Cross-platform support

December 2024: Feature expansion (0.1.1-0.1.4)

  • Multi-site support
  • SSL/TLS capabilities
  • Performance optimizations
  • Security enhancements

December 2024: Production readiness (0.1.5)

  • WASM support
  • Security hardening
  • Comprehensive CI/CD
  • Documentation project

Technology Evolution

Framework Choice:

  • Selected Pingora for proven performance and security
  • Rust for memory safety and performance
  • TOML for human-readable configuration

Feature Development:

  • Started with basic static serving
  • Added multi-site capabilities
  • Implemented security features
  • Enhanced performance and monitoring

Quality Assurance:

  • Implemented comprehensive testing
  • Added automated CI/CD pipelines
  • Security scanning and vulnerability management
  • Documentation and user guides

Community Growth

Open Source:

  • MIT license for maximum compatibility
  • Public development on GitHub
  • Community contributions welcome
  • Transparent development process

Ecosystem:

  • Docker container support
  • Package manager distributions
  • Integration guides and examples
  • Third-party tool compatibility

Future Vision

Short-term Goals:

  • Enhanced monitoring and observability
  • Plugin system for extensibility
  • Advanced caching mechanisms
  • GUI configuration tools

Long-term Vision:

  • Enterprise-grade web server platform
  • Comprehensive hosting solution
  • Cloud-native deployment options
  • Ecosystem of extensions and tools

For the latest information, see GitHub Releases