Skip to content

ferronweb/warpgate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This repository is a result of a vibe-coding experiment, meaning that all the code (even the README contents below) were AI-generated. Please don't use this in production, we recommend using Ferron web server instead.

Also, disregard the MIT license, since this code would be practically public domain, because fully AI-generated works wouldn't be elligble for copyright... The real license would be Unlicense (or some other public domain equivalent) instead...

Anyway, let's proceed to the README proper...


warpgate

A high-performance web server written in Rust with automatic HTTPS, static file serving, and a reverse proxy with load balancing.

Features

  • Automatic HTTPS — Integrates with Let's Encrypt for zero-touch certificate acquisition and renewal. Falls back to a self-signed certificate for development.
  • Static file serving — Serve directories with configurable index files. Path-traversal protected.
  • Reverse proxy — Route requests to backend services with load balancing (round-robin, random) and health checks.
  • Simple configuration — Single TOML file with sensible defaults.
  • Modular design — Each concern (TLS, routing, proxy, config) is an independent module.

Quick start

# warpgate.toml
host = "0.0.0.0"
port = 443
http_port = 80

[tls]
domain = "example.com"
email = "admin@example.com"
staging = false
cache_dir = "./letsencrypt"

[[static]]
path = "/"
root = "/var/www/public"
index = ["index.html"]

[[proxy]]
path = "/api"
upstreams = ["http://127.0.0.1:3000", "http://127.0.0.1:3001"]
balancer = "round-robin"
health_path = "/health"
$ warpgate -c warpgate.toml

Installation

cargo build --release
./target/release/warpgate -c warpgate.toml

Requires Rust 1.75 or later.

Configuration reference

Server settings

Key Default Description
host "0.0.0.0" Address to bind the server to
port 443 HTTPS port
http_port 80 HTTP port (for ACME challenges and redirects)

[tls] — TLS / HTTPS

Three modes are supported. The server picks the mode automatically:

Mode Config required Behaviour
Let's Encrypt (ACME) domain + email Obtains and renews certificates automatically via ACME HTTP-01 challenges
Custom certificates cert_path + key_path Uses the provided PEM files
Self-signed No [tls] section Generates a self-signed certificate (development only)
Key Default Description
domain Domain name for the certificate (required for ACME)
email Email for the Let's Encrypt account (required for ACME)
staging false Use Let's Encrypt staging environment (avoids rate limits during testing)
cache_dir "./letsencrypt" Directory to store ACME account keys and certificates
cert_path Path to a PEM certificate file (for custom certs)
key_path Path to a PEM private key file (for custom certs)

[[static]] — Static file serving

Each table defines a route that serves files from a directory. You can define multiple static routes.

Key Default Description
path URL path prefix (e.g. "/", "/assets")
root Filesystem directory to serve files from
index ["index.html"] Index files to try when a directory is requested

The server prevents path traversal: requested paths are canonicalised and checked against the configured root.

Example — multiple static routes:

[[static]]
path = "/"
root = "/var/www/public"
index = ["index.html", "index.htm"]

[[static]]
path = "/assets"
root = "/var/www/assets"

[[proxy]] — Reverse proxy

Each table defines a route that proxies requests to one or more upstream servers. Supports load balancing and optional health checks.

Key Default Description
path URL path prefix to match (e.g. "/api")
upstreams List of upstream URLs (e.g. ["http://127.0.0.1:3000"])
balancer "round-robin" Load balancing strategy: "round-robin" or "random"
health_path Path to check for health (e.g. "/health"). If set, health checks run in the background
health_interval 30 Seconds between health checks
health_timeout 5 Seconds per health check request

Example — proxy with load balancing and health checks:

[[proxy]]
path = "/api"
upstreams = [
  "http://10.0.0.1:3000",
  "http://10.0.0.2:3000",
  "http://10.0.0.3:3000",
]
balancer = "round-robin"
health_path = "/health"
health_interval = 10
health_timeout = 3

How it works

Client ───► Port 443 (HTTPS) ───► TLS handshake ───► HTTP router
                               │                        │
                               │                  ┌─────┴──────┐
                               │                  │            │
                               │              Static        Proxy
                               │              handler      handler
                               │                  │            │
                               │              Filesystem   Upstreams
                               │
Client ───► Port 80 (HTTP) ───► ACME challenges + redirect to HTTPS
  1. HTTP server (port 80) handles ACME HTTP-01 challenges and redirects everything else to HTTPS.
  2. HTTPS server (port 443) terminates TLS via rustls, then routes requests.
  3. The router checks ACME challenges first, then static routes, then proxy routes.
  4. The proxy handler selects a healthy upstream via the configured load balancer and forwards the request.

Certificate lifecycle

  1. On first start with ACME configured, warpgate orders a certificate from Let's Encrypt, serves the HTTP-01 challenge on port 80, and saves the certificate to cache_dir.
  2. On subsequent starts, it reads the cached certificate.
  3. A background task checks expiry daily and renews when fewer than 30 days remain.

Extending the server

Each module is a single file with a clear interface:

Module File Key types
Config config.rs Config, TlsConfig, StaticConfig, ProxyConfig
TLS tls.rs ChallengeStore, CertificateSource (enum)
Handler handler.rs Router, StaticRoute
Proxy proxy.rs Balancer, ProxyTarget, Backend
Server server.rs run() — the main async entry point

To add a new handler (e.g. WebSocket, CGI, middleware):

  1. Add the routing check in handle_request() in handler.rs.
  2. Implement your handler function.
  3. Add config fields if needed.

License

MIT

About

A vibe-coded web server experiment.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages