nano-web
Static file server built with Rust. Serves files from memory with pre-compressed variants.
Performance
- Axum/Hyper HTTP stack
- Files pre-compressed at startup (brotli/gzip/zstd)
- Lock-free concurrent HashMap routing
- Zero-copy serving with Bytes
Benchmark (M3 Max 36GB):
I know web-server benchmarks are mostly useless, however, this server does very little, and this is it's literal use case (serve file quick!).
Based on trying other high-performance servers locally, I reckon nano-web would place in the top ten in the TechEmpower plaintext webserver benchmarks if ran on their hardware (haven't got around to submitting it yet). It beats out may-minihttp, for instance.
Features
- In-memory file serving with compression
- SPA mode with index.html fallback
- Dev mode with file watching
- Health endpoint at
/_health - Runtime environment variable injection
- JSON/console logging
- Docker image size of ~5MB
📦 Installation
Install with Mise (via ubi)
Install with Cargo
Download Binary
Pre-built binaries available on GitHub Releases.
🐳 Docker
Multi-arch images available:
FROM ghcr.io/radiosilence/nano-web:latest
COPY ./dist /public/
Production example:
FROM node:lts-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM ghcr.io/radiosilence/nano-web:latest
COPY --from=builder /app/dist/ /public/
EXPOSE 3000
🔧 Usage
# Serve files from ./public/ on port 3000
# Custom directory and port
# SPA mode with dev reloading
# See all options
⚙️ Configuration
| Variable | CLI Flag | Default | Description |
|---|---|---|---|
PORT |
--port, -p |
3000 |
Port to listen on |
--spa |
--spa |
false |
Enable SPA mode (serve index.html for 404s) |
--dev |
--dev, -d |
false |
Enable dev mode (hot-reload files) |
CONFIG_PREFIX |
--config-prefix |
VITE_ |
Environment variable injection prefix |
LOG_LEVEL |
--log-level |
info |
Logging: debug, info, warn, error |
LOG_FORMAT |
--log-format |
console |
Format: json or console |
LOG_REQUESTS |
--log-requests |
false |
Enable request logging |
Environment Variables
# Docker example
⚡ Runtime Environment Injection
Inject configuration at runtime without rebuilding, so you can re-use the same image for different things quickly and easily (or distribute it).
<!-- Your index.html -->
// env.ts
import * as z from "zod";
const EnvSchema = z.object({
API_URL: z.url(),
});
// Parse and validate environment variables
const result = EnvSchema.safeParse(window.ENV);
if (!result.success) {
throw new Error(
`Environment validation failed:\n${z.prettifyError(result.error)}`,
);
}
export const { API_URL } = result.data;
# Same build, different configs
Template Engine
Uses MiniJinja template syntax for environment variable injection. Variables available:
{{env.VARIABLE_NAME}}- Direct variable access{{Json}}- Raw JSON string of all prefixed variables{{EscapedJson}}- JSON-escaped for inline JavaScript
Templating is run at startup and cached.
🏥 Health Checks
Built-in health endpoint at /_health:
📊 Logging
Console format (default):
2025-08-12T18:15:00.990620Z INFO nano_web::routes: Processing 18 files in parallel
at src/routes.rs:70
2025-08-12T18:15:01.207449Z INFO nano_web::routes: Routes populated: 20 routes
at src/routes.rs:102
2025-08-12T18:15:01.207466Z INFO nano_web::server: Routes loaded: 20
at src/server.rs:46
2025-08-12T18:15:01.207564Z INFO nano_web::server: Starting server on 0.0.0.0:3001
at src/server.rs:53
JSON format for log aggregation:
🛠️ Building from Source
# Clone and build
# Run tests
# Run benchmarks
Development
# Development server with hot-reload
# Watch for changes
🌰 Advanced: Unikernels
Deploy as unikernels with Nanos:
Architecture
- HTTP: Axum + Hyper
- Routing: Lock-free DashMap with FxHash
- Compression: Parallel pre-compression at startup
- Memory: Zero-copy serving with Bytes
- Security: Path validation, security headers
- Runtime: Tokio async
Compared to previous Go version: 70% faster (130k vs 76k req/sec), lower latency, no GC overhead.
📄 License
Licensed under the MIT License - see LICENSE for details.
🙏 Acknowledgments
- Axum - Ergonomic async web framework
- Hyper - Fast HTTP implementation
- Tokio - Asynchronous runtime
- DashMap - Lock-free concurrent HashMap
- Brotli - Compression library