This guide demonstrates how to deploy a working Spooky HTTP/3 proxy in under 10 minutes. You will set up a basic proxy configuration, generate self-signed certificates, and verify HTTP/3 connectivity to a backend service.
Prerequisites
- Rust 1.85 or later installed (edition 2024)
- Basic familiarity with command-line tools
- An HTTP/2 backend service running locally (or use the example backend provided)
- UDP port 9889 available for QUIC traffic
Step 1: Build Spooky
Clone the repository and build the release binary:
git clone https://github.com/nishujangra/spooky.git
cd spooky
cargo build --release
The compiled binary will be located at target/release/spooky. Build time is typically 2-5 minutes depending on your system.
Step 2: Generate Self-Signed Certificates
QUIC requires TLS 1.3, so you need certificate and key files. For testing purposes, generate a self-signed certificate:
mkdir -p certs
openssl req -x509 -newkey rsa:4096 -nodes \
-keyout certs/key.pem \
-out certs/cert.pem \
-days 365 \
-subj "/CN=localhost"
This creates:
- certs/cert.pem: The TLS certificate
- certs/key.pem: The private key
Note: For production deployments, use certificates from a trusted Certificate Authority (CA). See TLS Configuration for production certificate setup.
Step 3: Start a Test Backend Server
You need an HTTP/2 backend for Spooky to forward traffic to. If you don't have one running, use the provided HTTP/2 test backend:
# Using Spooky's built-in HTTP/2 test backend
cargo run --bin h2_backend -- --port 8080
This starts an HTTP/2-only server on 127.0.0.1:8080. Spooky requires HTTP/2 backends - HTTP/1.1 backends are not supported.
Step 4: Create Configuration File
Create a minimal configuration file named config.yaml:
version: 1
listen:
protocol: http3
port: 9889
address: "0.0.0.0"
tls:
cert: "certs/cert.pem"
key: "certs/key.pem"
upstream:
default:
load_balancing:
type: "random"
route:
path_prefix: "/"
backends:
- id: "local-backend"
address: "127.0.0.1:8080"
weight: 100
health_check:
path: "/"
interval: 5000
timeout_ms: 2000
success_threshold: 2
failure_threshold: 3
log:
level: info
This configuration:
- Listens for HTTP/3 connections on UDP port 9889
- Uses the generated self-signed certificates
- Forwards all requests to 127.0.0.1:8080 using random load balancing
- Performs health checks every 5 seconds on the backend
Step 5: Start Spooky
Launch the proxy with the configuration file:
./target/release/spooky --config config.yaml
Expected output:
[INFO] Loading configuration from config.yaml
[INFO] Starting Spooky HTTP/3 proxy
[INFO] Listening on 0.0.0.0:9889 (HTTP/3)
[INFO] Backend local-backend (127.0.0.1:8080) marked healthy
[INFO] Proxy started successfully
The proxy is now accepting HTTP/3 connections on port 9889 and forwarding them to the backend on port 8080.
Step 6: Test Connectivity
Verify that HTTP/3 requests are being proxied correctly. You will need an HTTP/3-capable client such as curl with HTTP/3 support.
Using curl with HTTP/3
If you have curl compiled with HTTP/3 support:
curl --http3-only -k https://localhost:9889/
The -k flag bypasses certificate validation for self-signed certificates. You should see the response from your backend server.
Using curl with Alt-Svc Discovery
For a more realistic test that mimics browser behavior:
curl -k \
--resolve localhost:9889:127.0.0.1 \
https://localhost:9889/
Verify HTTP/3 connectivity by forcing HTTP/3-only requests:
curl -k --http3-only https://localhost:9889/
If successful, you should receive a response from your backend. HTTP/3 connectivity is confirmed when the request succeeds (Spooky doesn't advertise Alt-Svc headers).
Using a Custom HTTP/3 Client
If you don't have HTTP/3 support in curl, you can use other clients:
Using h3i (HTTP/3 interactive client):
cargo install h3i
h3i https://localhost:9889/ --insecure
Using qh3 (QUIC HTTP/3 client):
git clone https://github.com/cloudflare/quiche.git
cd quiche/tools/apps
cargo build --release
./target/release/quiche-client https://localhost:9889/ --no-verify
Step 7: Verify Backend Forwarding
Check that requests are being forwarded to the backend. In the terminal running Spooky, you should see log entries indicating request handling:
[INFO] QUIC connection established from 127.0.0.1:55420
[INFO] HTTP/3 stream 0: GET /
[INFO] Forwarding to backend local-backend (127.0.0.1:8080)
[INFO] Response 200 OK forwarded to client
In the backend server terminal, verify that HTTP requests are being received.
Step 8: Test Path-Based Routing (Optional)
To demonstrate routing capabilities, modify the configuration to add multiple upstream pools:
upstream:
api_backend:
load_balancing:
type: "round-robin"
route:
path_prefix: "/api"
backends:
- id: "api-server"
address: "127.0.0.1:8001"
weight: 100
default_backend:
load_balancing:
type: "random"
route:
path_prefix: "/"
backends:
- id: "default-server"
address: "127.0.0.1:8080"
weight: 100
Restart Spooky with the updated configuration. Requests to /api/* will route to port 8001, while all other requests route to port 8080.
Test the routing:
# Routes to default backend (port 8080)
curl --http3-only -k https://localhost:9889/
# Routes to API backend (port 8001)
curl --http3-only -k https://localhost:9889/api/users
Common Issues and Solutions
Port Already in Use
If port 9889 is already bound:
Error: Address already in use (os error 98)
Solution: Either stop the conflicting process or change the port in config.yaml.
Backend Connection Refused
If Spooky cannot connect to the backend:
[ERROR] Failed to connect to backend local-backend: Connection refused
Solution: Ensure the backend service is running on the configured address and port.
Certificate Errors
If the certificate is not found:
[ERROR] Failed to load TLS certificate: No such file or directory
Solution: Verify that the certificate paths in config.yaml are correct and the files exist.
Health Check Failures
If backends are marked unhealthy:
[WARN] Backend local-backend health check failed: timeout
Solution: Ensure the health check path exists on the backend and responds within the timeout period (default 2 seconds).
Next Steps
You now have a working HTTP/3 to HTTP/2 proxy. To further configure and optimize Spooky:
- Configuration Reference - Complete configuration options including advanced load balancing and routing
- TLS Setup - Configure production TLS certificates with Let's Encrypt or other CAs
- Load Balancing Guide - Understand different load balancing algorithms and when to use them
- Production Deployment - Best practices for production deployment including systemd integration and monitoring
- Troubleshooting - Solutions to common operational issues
For HTTP/3 and QUIC protocol details:
- HTTP/3 Overview - HTTP/3 protocol implementation and differences from HTTP/2
- QUIC Overview - QUIC transport protocol details and how Spooky uses it