Skip to content

About

Really minimal HTTP Server for static files written in GO

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

1 watching

Forks

Repository files navigation

Static http server

Build Status Opensource ByJG Install MCP Server GitHub source GitHub license GitHub release

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

Features

  • Create a simple HTML website
  • Serve static files with HTTP and HTTPS (self-signed certificate generated and reused automatically)
  • SPA (Single Page Application) support for frontend frameworks like React, Angular, Vue
  • Reverse proxy by path prefix, including TLS termination for a backend that only speaks HTTP
  • In-memory LRU file cache with configurable limits
  • Health check endpoint for Kubernetes probes
  • Really small footprint

Quick start

# The built-in parking page, on http://localhost:8080 and https://localhost:8443
docker run -p 8080:8080 -p 8443:8443 byjg/static-httpserver

# Your own static pages
docker run -p 8080:8080 -v /path/to/local/html:/static byjg/static-httpserver

# Without Docker: serve the current directory over HTTPS (port 8443)
static-httpserver --root-dir .

Install

Docker

docker pull byjg/static-httpserver

deb/rpm

Add the ByJG package repository, then:

# Debian/Ubuntu
apt install static-httpserver

# RHEL/CentOS
yum install static-httpserver

Homebrew

On macOS (or Linux) with Homebrew:

brew install byjg/tap/static-httpserver

Homebrew builds it from source, installing Go only for the build.

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 -p 8443:8443 -e TITLE=soon -e "MESSAGE=Keep In Touch" byjg/static-httpserver

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

Or create your own image:

FROM byjg/static-httpserver

COPY /path/to/html /static

SPA Mode (React / Vue / Angular)

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

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

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
--bind BIND_ADDRESS 0.0.0.0 IP address to listen on
--only-https ONLY_HTTPS false Never start the HTTP listener, even when a port is set
--port PORT (disabled) HTTP listening port. Not set = HTTP disabled
--tls-port TLS_PORT 8443 HTTPS listening port
--tls-cert-dir TLS_CERT_DIR (see below) Directory to look for cert.pem and key.pem, and where the self-signed certificate is saved
--tls-cert-file TLS_CERT_FILE (none) TLS certificate file — takes precedence over --tls-cert-dir
--tls-key-file TLS_KEY_FILE (none) TLS private key file — must be used together with --tls-cert-file
--tls-selfsigned-hosts TLS_SELFSIGNED_HOSTS (none) Extra hostnames/IPs the self-signed certificate must be valid for (comma-separated)
--spa SPA_MODE false Enable SPA routing
--show-headers SHOW_HEADERS false Display request headers on the parking page
--health-path HEALTH_PATH /_health Path of the health endpoint
--headers-path HEADERS_PATH /_headers Path of the request headers endpoint (needs --show-headers)
--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, / proxies everything (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

--tls-cert-dir defaults to /certs when running as root and to ~/.static-httpserver/certs otherwise, so an unprivileged process always has somewhere to keep its certificate.

The Docker image sets --root-dir /static, --port 8080 and --tls-cert-dir /certs by default.

CLI Usage

# Serve current directory over HTTPS (port 8443)
static-httpserver --root-dir .
curl -k https://localhost:8443/

# Add plain HTTP on port 8080
static-httpserver --root-dir /var/www/html --port 8080
curl http://localhost:8080/

# HTTPS only, ignoring any port set through PORT
static-httpserver --root-dir /var/www/html --only-https

# Listen on one address only
static-httpserver --root-dir . --bind 127.0.0.1

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

HTTPS / TLS

HTTPS is always enabled (default port 8443). With no certificate provided, the server generates a self-signed one, saves it in --tls-cert-dir and reuses it on the next start. HTTP is optional — it only starts when --port or PORT is set, and --only-https turns it off even then.

# Docker: publish the HTTPS port and keep the certificate in a volume
docker run -p 8443:8443 \
    -v $(pwd)/html:/static:ro \
    -v $(pwd)/certs:/certs \
    byjg/static-httpserver

To use your own certificate, put cert.pem and key.pem in --tls-cert-dir, or point at the files with --tls-cert-file and --tls-key-file.

See HTTPS / TLS for what the self-signed certificate covers, when it is regenerated, how to make clients trust it and the details of using your own certificates.

Reverse Proxy

The server can forward requests matching a path prefix to a backend service, stripping the prefix before forwarding. When several routes match, the most specific prefix wins.

# Static frontend plus an API on the same origin
static-httpserver --root-dir ./dist --spa \
    --proxy /api=http://backend:3000 \
    --proxy /auth=http://auth-service:4000

# HTTPS in front of a backend that only speaks HTTP
static-httpserver \
    --root-dir /var/www/empty \
    --only-https --tls-port 443 \
    --proxy /=http://127.0.0.1:3000

See Reverse Proxy for the forwarded headers, the catch-all / route, a npm run serve-https script for local development, backend TLS verification and a hardened OIDC example.

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.

The underscore keeps it out of the way of an application's own /health, which matters when the whole site is proxied to a backend. --health-path (env HEALTH_PATH) moves it; the Helm chart exposes it as parameters.healthPath and points the probes at whatever it is set to.

Upgrading: the endpoint used to be /health. Kubernetes probes defined outside this chart, uptime monitors and load balancer checks have to be pointed at /_health, or the old path restored with --health-path /health.

Using with 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: ""
  healthPath: ""        # defaults to /_health
  rootDir: ""
  port: ""
  tlsPort: ""
  tlsCertDir: ""
  cacheMaxSize: ""
  cacheMaxFileSize: ""

Tip: this HELM package is setup to work with EasyHAProxy

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


Open source ByJG

About

Really minimal HTTP Server for static files written in GO

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages