Content Management that can withstand the plundering hoards

Static Webserver

The public-facing static HTTP server serves files only. It has no knowledge of the CMS, Kubernetes, Custom Resources, databases or authentication providers. Each website gets its own Deployment; ingress routing decides which Deployment receives each request.

Runtime interface

The server requires minimal configuration:

/webserver --root=/www/current --listen=:8080

Configuration is provided through flags or VIKING_* environment variables (flags take precedence). The server does not require a Kubernetes API connection. Timeout/header settings protect against slow or idle clients holding a goroutine and a file descriptor indefinitely:

Flag Env var Default Purpose
--read-timeout VIKING_READ_TIMEOUT 30s Maximum time to read a full request body
--write-timeout VIKING_WRITE_TIMEOUT 30s Maximum time to write a response
--idle-timeout VIKING_IDLE_TIMEOUT 120s Maximum idle keep-alive lifetime
--read-header-timeout VIKING_READ_HEADER_TIMEOUT 5s Header read timeout
--admin-shutdown-timeout VIKING_ADMIN_SHUTDOWN_TIMEOUT 5s Admin listener drain budget (public and admin drain concurrently)
--shutdown-timeout VIKING_SHUTDOWN_TIMEOUT 10s Public listener drain budget
--max-header-bytes VIKING_MAX_HEADER_BYTES 65536 (64 KiB) Maximum request header size; oversized headers get 431/400

Both listeners apply these timeouts, so a slow or idle client cannot hold a goroutine and an FD indefinitely.

HTTP features

Implemented: HTTP/1.1, GET and HEAD, correct status codes, MIME handling, configurable index files, 404 and 405 responses, ETag, Last-Modified, conditional and Range requests, Cache-Control headers, safe URL/path handling, graceful shutdown, and health/readiness endpoints. Security headers: every response (public and admin) carries X-Content-Type-Options: nosniff and Referrer-Policy: no-referrer.

Optional (intended design): precompressed gzip/Brotli assets, custom error pages, SPA fallback, configurable directory redirects.

Not supported: CGI, PHP, server-side scripting, dynamic template execution, database queries, arbitrary URL rewriting, general-purpose reverse proxying.

Health and metrics

Implemented endpoints on a separate internal admin listener (:8081): /healthz, /readyz, /metrics. Readiness reflects availability of the active published content and must return an unavailable response when no valid publication exists. See Contracts.

Metrics use controlled label cardinality: the method label is folded to a fixed set (GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS, OTHER) so arbitrary client method tokens cannot grow the label set; no URLs or Host headers are used as labels.

Security

The webserver must run as non-root in a scratch container with a read-only root filesystem, all capabilities dropped, privilege escalation disabled, a restrictive seccomp profile, ServiceAccount token automounting disabled (it makes no Kubernetes API calls), no access to the private CMS PVC or Secrets, no application need for outbound network access, and protection against directory and symlink traversal. See Security.

Performance

Initial implementation relies on kernel page caching rather than a custom application-level cache. Benchmarks must compare Go net/http, Go fasthttp and an Apache HTTPD baseline across cached/uncached, local/RWX, direct/ingress and single/multi-replica workloads. No unsupported performance claims should be made. These are evaluation goals, not benchmark results supplied by this document. Source-level benchmarks are in frontend/internal/server/benchmark_test.go.

The complete runtime interface and actual HTTP statuses/caching/Range semantics are documented in configuration and frontend HTTP reference.