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.
