Skip to content

Repository files navigation

Static http server

Build Status Opensource ByJG GitHub source GitHub license GitHub release

A really minimal HTTP/HTTPS Server image for static files written in Go.

Why?

  • Create a simple HTML website
  • Serve static files with HTTP and HTTPS (self-signed certificate by default)
  • SPA (Single Page Application) support for frontend frameworks like React, Angular, Vue
  • In-memory LRU file cache with configurable limits
  • Health check endpoint for Kubernetes probes
  • Really small footprint

How to use the "Parking page"?

The image includes a self-contained parking page (single HTML file, no external dependencies) that can be customized by setting the environment variables:

  • HTML_TITLE - Page title (default: "Coming soon")
  • TITLE - Main heading (default: "soon")
  • MESSAGE - Body message
  • BG_IMAGE - Background image URL
  • FACEBOOK - Facebook page URL
  • TWITTER - Twitter page URL
  • YOUTUBE - YouTube page URL

e.g.

docker run -p 8080:8080 -e TITLE=soon -e "MESSAGE=Keep In Touch" byjg/static-httpserver

Configuration

The server can be configured via CLI flags or environment variables. CLI flags take precedence over environment variables.

CLI Flag Env Variable Default Description
--root-dir ROOT_DIR (required) Root directory for static files
--port PORT (disabled) HTTP listening port. Not set = HTTP disabled
--tls-port TLS_PORT 8443 HTTPS listening port
--tls-cert-dir TLS_CERT_DIR /certs Directory to look for cert.pem and key.pem
--spa SPA_MODE false Enable SPA routing
--show-headers SHOW_HEADERS false Display request headers on the parking page
--cache-max-size CACHE_MAX_SIZE 50000000 Max total cache size in bytes (0 to disable)
--cache-max-file CACHE_MAX_FILE_SIZE 5000000 Max individual file size to cache in bytes
--proxy PROXY_ROUTES (none) Proxy route as /prefix=http://target (repeatable flag, comma-separated env)
--proxy-timeout PROXY_TIMEOUT 30 Proxy upstream response timeout in seconds
--proxy-ca PROXY_CA_FILE (none) CA certificate file (PEM) for verifying backend TLS — takes precedence over --proxy-insecure
--proxy-insecure PROXY_INSECURE false Skip TLS verification for proxy backends — use only on trusted networks
--version Print version and exit

The Docker image sets --root-dir /static and --port 8080 by default.

CLI Usage

# Serve current directory on HTTPS only (port 8443)
static-httpserver --root-dir .

# Serve with both HTTP and HTTPS
static-httpserver --root-dir /var/www/html --port 8080

# SPA mode
static-httpserver --root-dir ./dist --port 3000 --spa

Install via deb/rpm

# Debian/Ubuntu
apt install static-httpserver

# RHEL/CentOS
yum install static-httpserver

HTTPS / TLS

HTTPS is always enabled (default port 8443). By default, a self-signed certificate is generated in memory at startup.

To use your own certificates, provide a directory with cert.pem and key.pem:

# CLI
static-httpserver --root-dir ./html --tls-cert-dir /path/to/certs

# Docker
docker run -p 8080:8080 -p 8443:8443 \
    -v /path/to/certs:/certs:ro \
    byjg/static-httpserver

HTTP is optional — only started when --port or PORT is set.

SPA Mode

When enabled, any request that doesn't match an existing file and has no file extension is served the index.html page. This supports client-side routing in frameworks like React, Angular, and Vue.

Requests for missing static assets (e.g., /missing.css) still return 404.

docker run -p 8080:8080 -e SPA_MODE=true byjg/static-httpserver

Reverse Proxy

The server can forward requests matching a path prefix to a backend service. This is useful for:

  • Avoiding CORS issues by serving the frontend and API from the same origin
  • Hiding backend services from direct client access
  • Replacing nginx/caddy as a reverse proxy sidecar in Kubernetes
# CLI — multiple routes
static-httpserver --root-dir ./dist --spa \
    --proxy /api=http://backend:3000 \
    --proxy /auth=http://auth-service:4000

# Docker — comma-separated env
docker run -p 8080:8080 \
    -e SPA_MODE=true \
    -e PROXY_ROUTES="/api=http://backend:3000,/auth=http://auth:4000" \
    byjg/static-httpserver

The proxy strips the prefix before forwarding: a request to /api/users is forwarded as /users to the target.

The --proxy-timeout flag (default 30s) controls how long the server waits for a response from the upstream.

Proxy backend TLS

When the backend uses HTTPS with a self-signed or private CA certificate, use --proxy-ca to provide the CA cert for verification:

static-httpserver --root-dir ./dist \
    --proxy /api=https://internal-service:8443 \
    --proxy-ca /path/to/ca.crt

For trusted internal networks (e.g. WireGuard mesh) where managing a CA cert is impractical, --proxy-insecure skips verification entirely:

static-httpserver --root-dir ./dist \
    --proxy /api=https://internal-service:8443 \
    --proxy-insecure

Note: If both --proxy-ca and --proxy-insecure are set, --proxy-ca takes precedence and a warning is logged. Never use --proxy-insecure for backends reachable from untrusted networks.

TLS termination with hardened OIDC exposure

A common pattern is to use static-httpserver as a TLS-terminating reverse proxy that exposes only specific OIDC/OAuth endpoints publicly, while keeping the rest of the API internal:

static-httpserver \
    --root-dir /var/www/empty \
    --tls-port 443 \
    --tls-cert-dir /etc/letsencrypt/live/nimbus.example.com \
    --proxy /.well-known/openid-configuration=https://10.106.103.1:8443/.well-known/openid-configuration \
    --proxy /keys=https://10.106.103.1:8443/keys \
    --proxy /authorize=https://10.106.103.1:8443/authorize \
    --proxy /oauth/token=https://10.106.103.1:8443/oauth/token \
    --proxy /login=https://10.106.103.1:8443/login \
    --proxy /callback=https://10.106.103.1:8443/callback \
    --proxy /userinfo=https://10.106.103.1:8443/userinfo \
    --proxy-ca /var/lib/nimbus/ca.crt

In this setup:

  • The browser connects over HTTPS with a trusted public cert (Let's Encrypt)
  • Only OIDC endpoints are forwarded — the rest of the API returns 404
  • The backend connection is verified using the internal CA cert
  • The internal API remains unreachable from the public internet

Health Check

The server exposes a /health endpoint that returns {"status":"ok"} with HTTP 200. This is used by the Helm chart for Kubernetes liveness and readiness probes.

Using with Helm 3

3.2. Using HELM 3

Minimal configuration

helm repo add byjg https://opensource.byjg.com/helm
helm repo update
helm upgrade --install mysite byjg/static-httpserver \
    --namespace default \
    --set "ingress.hosts={www.example.org,example.org}" \
    --set parameters.title=Welcome

Parameters:

ingress:
  hosts: []               # Required
parameters:
  htmlTitle: ""
  title: "soon"
  message: ""
  backgroundImage: ""
  facebook: ""
  twitter: ""
  youtube: ""
  spaMode: ""
  showHeaders: ""
  rootDir: ""
  port: ""
  tlsPort: ""
  tlsCertDir: ""
  cacheMaxSize: ""
  cacheMaxFileSize: ""
This HELM package is setup to work with [EasyHAProxy](https://github.com/byjg/docker-easy-haproxy)

Enabling as Addon on MicroK8s

The Parking addon deploys a static webserver to ‘park’ a domain. This involves all necessary ingress, service and Pods. This addon adds the proper labels which can be discovered by EasyHAProxy.

To enable this addon:

microk8s enable parking <domainlist>

… where domainlist is the comma separated list of domains to be parked.

To disable the addon:

microk8s disable parking

Follow this discussion: https://discuss.kubernetes.io/t/addon-parking/23186

Use your own static pages

Mount your own HTML directory to replace the default parking page:

docker run -p 8080:8080 -v /path/to/local/html:/static byjg/static-httpserver

Create your own image

FROM byjg/static-httpserver

COPY /path/to/html /static

Using with React / Vue / Angular (SPA)

Use a multi-stage Dockerfile to build your frontend app and serve it with SPA routing:

FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM byjg/static-httpserver
ENV SPA_MODE=true
COPY --from=builder /app/build /static

Note: adjust the build output folder depending on your framework:

  • React (CRA): build
  • Vite: dist
  • Next.js (static export): out
  • Angular: dist/<project-name>/browser

Then build and run:

docker build -t myapp .
docker run -p 8080:8080 myapp

Open source ByJG

About

Really minimal HTTP Server for static files written in GO

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages