@tdio/static-serve
v0.0.4
Published
A simple, lightweight static file server written in Go, designed with features for modern web application serving
Downloads
96
Readme
static-serve
A simple, lightweight static file server written in Go, designed with features for modern web application serving.
Features
- Static File Serving: Serves files from a specified root directory.
- Dotfile Hiding: Automatically hides files and directories starting with a dot (
.) for security. - SPA Mode: Supports Single Page Application (SPA) routing by redirecting 404s to
index.html(enabled via--spa). - Virtual Mounts: Mount files or directories to specific paths using
--mount. - Reverse Proxy (Fallback): Proxy specific paths to upstream URLs using
--proxy. Local files take priority; proxy only triggers when a file is not found locally. - HTTPS Mode: Serve over TLS with
--tls-certand--tls-key. - CORS Controls: Opt-in CORS middleware with origin, credentials, and max-age tuning.
- Health Check: Built-in health check endpoint at
/healthz. - Request Tracing: Adds
X-Request-Idheaders to requests for tracing. - Response Caching Hints: Default
Cache-Controlplus weak ETag generation and 304 handling. - Custom Logging: Configurable request logging format.
- Graceful Shutdown: Handles OS interrupts for graceful server shutdown.
Architecture
The server processes requests through a middleware pipeline, with the proxy acting as a fallback when local files are not found:
flowchart TB
subgraph client [Client]
REQ[HTTP Request]
end
subgraph middleware [Middleware Pipeline]
TRACE[Tracing]
LOG[Logging]
CORS[CORS]
CACHE[Caching]
end
subgraph handler [Request Handler]
ROUTER[Router]
FS[File Server]
FALLBACK{File Found?}
PROXY[Proxy to Upstream]
end
subgraph response [Response]
LOCAL[Local File]
UPSTREAM[Upstream Response]
ERR404[404 Not Found]
end
REQ --> TRACE --> LOG --> CORS --> CACHE --> ROUTER
ROUTER --> FS
FS --> FALLBACK
FALLBACK -->|Yes| LOCAL
FALLBACK -->|No & Proxy Match| PROXY --> UPSTREAM
FALLBACK -->|No & No Proxy| ERR404Request Flow
- Tracing: Assigns a unique
X-Request-Idto each request - Logging: Logs request details in configurable format
- CORS: Handles preflight requests and sets CORS headers
- Caching: Adds
Cache-Controlheaders and handlesETag/304responses - Router: Routes to mounted paths, health checks, or default file server
- File Server: Attempts to serve the file from local filesystem
- Fallback Proxy: If file not found (404) and a proxy rule matches, forwards to upstream
Installation
You can install static-serve globally using npm:
npm install -g @tdio/static-serveOr run it directly using npx:
npx @tdio/static-serve [OPTIONS] [ROOT_DIR]Usage
static-serve [OPTIONS] [ROOT_DIR]If ROOT_DIR is not specified, it defaults to the current directory (./).
Options
| Flag | Description | Default |
|------|-------------|---------|
| --address | The TCP address to listen on. | :3000 |
| --mount | Mount specific directory to a virtual path (can be repeated). Format: <physical_path>:<virtual_path> or src=<physical_path>,dst=<virtual_path> | "" |
| --proxy | Proxy specific upstream to a virtual path (can be repeated). | "" |
| --spa | Enable SPA mode (redirects missing files to /index.html). | false |
| --logger-format | Custom server logger format (Go template syntax). | {{.Method}} {{.URL.Path}} {{.Status}} {{.RemoteAddr}} {{.UserAgent}} |
| --tls-cert | Path to TLS certificate file. Enables HTTPS (requires --tls-key). | "" |
| --tls-key | Path to TLS private key file. Enables HTTPS (requires --tls-cert). | "" |
| --cors | Enable CORS middleware for all routes. | false |
| --cors-allow-origins | Comma-separated allowed origins (* allowed). | * |
| --cors-allow-credentials | Whether to include Access-Control-Allow-Credentials. | false |
| --cors-max-age | Preflight cache max-age (Go duration). | 24h0m0s |
| -v | Print version and exit. | false |
Mount Configuration
static-serve allows you to mount files or directories to virtual paths. This is useful for serving assets from multiple locations or exposing individual files at specific URLs.
- Simple Format:
--mount <physical_path>:<virtual_path> - Advanced Format (Key-Value):
--mount src=<physical_path>,dst=<virtual_path>
Parameters:
src(orsource): The physical directory or file on your machine.dst(orpath): The virtual path on the server where the source will be accessible.
Examples:
# Mount a directory (these two forms are functionally identical)
static-serve --mount /mnt/test/static:/static
static-serve --mount src=/mnt/test/static,dst=/static
# Mount a single file
static-serve --mount ./config.json:/api/config
static-serve --mount src=./config.json,dst=/api/configProxy Configuration
static-serve supports proxying requests to upstream servers using a fallback pattern:
Local File Found? ──Yes──► Serve Local File
│
No
│
▼
Proxy Rule Matches? ──Yes──► Forward to Upstream
│
No
│
▼
Return 404This is useful for:
- Development: Serve local static assets while proxying API calls to a backend server
- Caching/CDN pattern: Serve cached files locally, fetch from origin on cache miss
- Hybrid deployments: Override specific upstream resources with local versions
Simple Format
<url_path>:<upstream_url>
Example: /api:http://localhost:8080
Note: This format automatically enables change_origin and strip_prefix.
Advanced Format (Key-Value)
path=<url_path>,url=<upstream_url>[,change_origin=bool][,strip_prefix=bool][,methods=GET|POST|...]
Parameters:
path: The virtual path on the current server to match.url: The upstream URL to forward requests to.change_origin: Whether to rewrite theHostheader to match the upstream URL. Default:true.strip_prefix: Whether to strip the matched path prefix before forwarding the request. Default:true.method(s): pipe-separated list of HTTP methods to proxy. If specified, only these methods will be proxied. Others will pass through to local file serving or return 405. Default: all methods.
Examples
Serve current directory on port 8080:
static-serve --address :8080Serve specific directory with SPA mode enabled:
static-serve --spa ./distMount files or directories:
# Mount directories
static-serve --mount "/var/www/static:/static" --mount "/mnt/media/images:/images" ./public
# Mount a single file
static-serve --mount "./config.json:/api/config"
# Using advanced KV format
static-serve --mount "src=/var/www/static,dst=/static"
static-serve --mount "src=./config.json,dst=/api/config"Proxy API requests (fallback behavior):
Basic Proxy: Forward
/apitohttp://localhost:8080when files don't exist locally.static-serve --proxy "/api:http://localhost:8080"- If
./api/users.jsonexists locally → serves the local file - If
./api/users.jsondoesn't exist → forwards tohttp://localhost:8080/users
- If
Advanced Config: Forward
/apibut keep the/apiprefix in the upstream request.static-serve --proxy "path=/api,url=http://localhost:8080,strip_prefix=false"Requests to
http://localhost:3000/api/userswill be forwarded tohttp://localhost:8080/api/users(if no local file exists).Method Filtering: Only proxy POST and PUT requests to the upstream server.
static-serve --proxy "path=/api,url=http://localhost:8080,methods=POST|PUT"GET /api/users→ serves local./api/usersor 404POST /api/users→ proxies tohttp://localhost:8080/users(if no local file exists)
Local Override Pattern: Override specific upstream assets with local versions.
# Create local override mkdir -p ./assets echo "local override" > ./assets/config.json # Start server with proxy fallback static-serve --proxy "/assets:http://cdn.example.com/assets" ./GET /assets/config.json→ serves local./assets/config.jsonGET /assets/other.js→ proxies tohttp://cdn.example.com/assets/other.js
Serve over HTTPS:
static-serve --tls-cert ./cert.pem --tls-key ./key.pem ./publicEnable CORS for specific origins:
static-serve --cors --cors-allow-origins "https://app.example.com,https://admin.example.com" --cors-allow-credentialsHealth Check
The server exposes a health check endpoint at /healthz.
curl http://localhost:3000/healthz
# Returns 204 No Content if healthy