The KEEL HTTP(S) Server Kit (Golang)

A small-footprint, security-first HTTP(S) core for Kubernetes and long-lived ops. Not nginx. Not HAProxy. This is the
smallest, most secure subset of features fully app-integrated—built to be durable for 10+ years and a goal of
"30,000 GitHub star" boring.
Documentation
| Document |
Contents |
| docs/config-reference.md |
Complete YAML schema, ENV vars, secrets file pattern, validation rules, hot reload |
| docs/security.md |
OWASP middleware, authn (JWT + mTLS), external authz (OPA / custom HTTP), memory backpressure, concurrency limits, TLS policy, upstream security |
| docs/observability.md |
Health probes, distributed tracing, Prometheus metrics, StatsD, structured logging, access log schema, admin endpoints, SLO signals |
| docs/operations.md |
Graceful shutdown, signals, Kubernetes pre-stop, circuit breaker, sidecar health probing, hot reload |
| docs/deployment.md |
Helm chart (full values reference), Docker Compose test harness, library mode walkthrough |
| docs/FIPS.md |
FIPS compliance: BoringCrypto, build instructions, runtime verification, constraints |
| docs/release-policy.md |
Release tagging policy, semver versioning rules, schema-driven version computation |
| docs/governance.md |
Engineering governance standards submodule — what it is, why, and how to update it |
| docs/ai-tooling.md |
AI coding assistant integration — Claude Code, Cursor, GitHub Copilot adapter symlinks |
| docs/impact.md |
Use-case guide — who Keel is for, feature × community impact matrix, AI workload patterns, supply chain provenance posture |
| docs/no-comparison.md |
Competitive landscape — why Envoy/service meshes, Caddy/NGINX, and single-trick sidecars are the wrong fit for brownfield compliance, and why the real competitor is the status quo |
| docs/ROADMAP.md |
Planned future capabilities |
| SECURITY.md |
CVE policy, private reporting, triage timeline, coordinated disclosure |
| TRADEMARK.md |
Trademark policy and permitted use |
FIPS users: See docs/FIPS.md for the complete guide to building, running, and verifying FIPS 140 compliance.
0. Call to Action
- Minimal size, maximal performance + functionality: scratch-style images in the ~5–8 MB range while
still being a good Kubernetes/observability citizen.
- Keel-haul legacy services into compliance: run Keel as a sidecar envelope around legacy HTTP/HTTPS apps to force
modern security posture without rewriting the app.
- AuthZ for every legacy service via OPA or any HTTP policy engine: delegate authorization decisions to an external
policy engine — no application code changes required.
- Memory backpressure prevents OOM and signals the load balancer: Keel monitors heap usage and flips
/readyz before
the process is OOM-killed, forcing the LB to drain traffic gracefully.
- Maximum flexibility without feature sprawl: defaults are built-in and on; you opt out at build time to reach a
smaller/stricter subset.
- Build on top, not alongside: use Keel as a Go library to build your own service with production-grade TLS, authn,
observability, and lifecycle already wired in.
1. Why Golang
We picked golang because it hits the best "ops-to-footprint" ratio for a deployable HTTP(S) core:
- Single self-contained binary (scratch-style images, easy rollbacks).
- HTTPS in the standard library (
net/http + crypto/tls).
- Mature ecosystem for routing, middleware, and observability.
- Fast builds + easy cross-compile for Linux/macOS/Windows.
1.1 Size + HTTPS Comparison (Illustrative)
| Option |
Typical minimal prod container size |
HTTPS/TLS story |
Notes |
| golang |
~5-8 MB |
Built-in crypto/tls; easy to make TLS1.3-only |
Best "small + capable + boring" combo |
| Rust |
~5–15 MB |
Strong crates (rustls, hyper/axum) |
Great, but more build complexity |
| Zig |
~10–30+ MB |
You bring TCP/TLS/HTTP(S) plumbing |
Not "that small" once you add HTTP(S) |
| Python |
~40–120+ MB |
Runtime-heavy; TLS via OpenSSL |
Great DX; not aligned with "tiny core" |
| Ruby |
~40–120+ MB |
Runtime-heavy; TLS via OpenSSL |
Same size story as Python |
| Node.js |
~60–150+ MB |
Runtime-heavy; TLS via OpenSSL |
Often the largest option |
2. Stated Objective: 10+ Year Durability
This project optimizes for:
- Longevity: stable APIs, conservative dependencies, strong upgrade story.
- Small prod footprint: core image target ~5–8 MB (scratch-style + CA certs where needed).
- Security posture by default: TLS 1.3-only, safe defaults, documented hardening, proactive vulnerability handling.
- Operational excellence: predictable behavior in Kubernetes, systemd, Windows services, and "boring" infra.
3. Default-On Feature Set with Build-Time Opt-Out
All major features are built-in by default. There is no command-line feature matrix.
- Runtime config is via YAML file, ENV vars, and secrets file (see docs/config-reference.md).
- Feature inclusion is controlled only at build time via negative tags (defaults are on, you opt out).
3.1 CI Discipline: Scripts-First
All CI must use provided POSIX bash scripts to the maximum extent possible. CI config files must not contain long
chains of inline run: lines.
Rule: CI invokes comprehensive scripts from ./scripts/ (e.g., ./scripts/ci/build.sh, ./scripts/test/ci.sh, ./scripts/release.sh).
3.2 Build-Time Opt-Out Flags
Build tags are negative ("remove X"), so defaults stay on:
| Tag |
Removes |
no_otel |
OTLP/OpenTelemetry tracing |
no_prom |
Prometheus /metrics |
no_statsd |
StatsD output |
no_remotelog |
Remote log sink support |
no_owasp |
OWASP hardening middleware layer |
no_authn |
Authn middleware layer |
no_authz |
External authorization middleware layer |
no_sidecar |
Sidecar reverse-proxy envelope mode |
no_h2 |
HTTP/2 support |
no_h3 |
HTTP/3 support |
no_acme |
ACME/Let's Encrypt certificate management |
Example:
go build -tags 'no_h3,no_statsd' ./cmd/keel
Size rule: If a feature is opted out, its dependencies are not linked — no container bloat.
3.3 Deployment Modes
3.3.1 Library Mode (In-Process)
Your Go app links Keel and registers handlers. Lowest latency; simplest runtime for Go services.
srv := keel.New(
keel.WithConfig(cfg),
keel.WithRoute(ports.HTTP, "/api/v1/", myapi.Handler()),
keel.WithRoute(ports.HTTP, "/api/v1/health", myapi.HealthHandler()),
)
srv.Run(ctx)
Keel exports its middleware pipeline so application code can compose it independently:
import "github.com/keelcore/keel/pkg/core/mw"
// Apply individual middleware to your own handler.
h := mw.OWASP(cfg, mw.RequestID(myHandler))
Context keys for request metadata injected by Keel:
import "github.com/keelcore/keel/pkg/core/ctxkeys"
requestID := r.Context().Value(ctxkeys.RequestID).(string)
traceID := r.Context().Value(ctxkeys.TraceID).(string)
See docs/deployment.md — Library Mode for the
complete walkthrough.
3.3.2 Sidecar Mode (Envelope / Reverse-Proxy)
Keel runs as a sidecar and proxies to an upstream service. Two upstream topologies are explicitly supported:
Intra-pod (localhost upstream): Keel and the app share a pod. The app listens on localhost:<port> over plain HTTP;
Keel owns all external-facing ports and applies TLS, authn, OWASP hardening, observability, and backpressure. The pod
network namespace is the trust boundary — no TLS is needed on the loopback leg.
Out-of-pod (remote upstream): Keel proxies to a service running outside the pod — a legacy VM, a third-party API
endpoint, or a service in another namespace not covered by a service mesh. In this topology Keel establishes a TLS or
mTLS connection to the upstream, presenting a client certificate if the upstream requires mutual authentication (see
docs/security.md — Upstream TLS and mTLS).
Keel-hauling: both topologies allow forcing old HTTP/HTTPS services into modern security compliance
without rewriting them.
3.3.3 ACME Edge Mode (Standalone TLS Terminator)
When ACME is enabled, Keel manages its own certificate via Let's Encrypt (or any ACME-compatible CA) with automatic renewal.
Critical constraint: The ACME http-01 challenge requires a route at:
GET http://<domain>/.well-known/acme-challenge/<token>
This route must be served over plain HTTP on port 80, even if Keel redirects all other HTTP traffic to
HTTPS. Keel handles this automatically:
- Plain HTTP listener on port 80 is kept alive.
/.well-known/acme-challenge/ path is registered before any redirect or authn middleware.
- All other HTTP paths are 301-redirected to HTTPS.
- Certificate renewal is automatic; Keel reloads the cert without restart or dropped connections.
ACME must not be combined with the no_acme build tag. ACME requires cert_file/key_file to be left empty (Keel
manages them).
4. Authentication and OWASP Hardening (Overview)
Both layers are default-on and independently opt-outable at build time.
OWASP middleware (no_owasp to opt out) injects canonical security headers on every response
(X-Content-Type-Options, X-Frame-Options, Content-Security-Policy, Strict-Transport-Security, etc.) and enforces
request size and timeout limits. See docs/security.md — OWASP Middleware
for the full header list with explanations of each one.
Authn layer (no_authn to opt out) validates incoming JWT bearer tokens (HS256, RS256, ES256) and optionally maps
mTLS client certificate identities to principals. trusted_signers is the list of keys Keel trusts; trusted_ids is
the allowlist of principal identifiers. In sidecar mode, Keel re-signs outbound requests as its own identity (my_id).
See docs/security.md — Authentication Layer for the full trust model.
5. Extension Model
5.1 Route Registration
srv := keel.New(
keel.WithConfig(cfg),
keel.WithRegistrar(myapi.NewRegistrar()),
keel.WithRegistrar(admin.NewRegistrar()),
keel.WithRoute(ports.HTTP, "/ping", pingHandler),
)
srv.Run(ctx)
5.2 Built-In Default Route
If no user route claims port 80 + /, Keel serves a built-in default response. This guarantees deterministic "it
boots" behavior.
5.3 Middleware Export
import "github.com/keelcore/keel/pkg/core/mw"
h := mw.RequestID(
mw.AccessLog(logger,
mw.OWASP(cfg,
yourHandler)))
5.4 Readiness Dependency Registration
srv := keel.New(
keel.WithReadinessCheck("db", func(ctx context.Context) error {
return db.PingContext(ctx)
}),
keel.WithReadinessCheck("cache", func(ctx context.Context) error {
return cache.Ping(ctx)
}),
)
5.5 Admin Reload Endpoint
POST /admin/reload triggers the same hot reload as SIGHUP. Returns 200 on success or 422 if the new config is invalid
(old config stays active).
6. Library Mode Walkthrough
6.1 Wrap the Keel Config
import keelconfig "github.com/keelcore/keel/pkg/config"
type AppConfig struct {
App AppSettings `yaml:"app"`
Keel keelconfig.Config `yaml:"keel"`
}
// Pre-populate with Keel's defaults before unmarshaling your YAML.
// Without this, keys absent from your YAML would get zero values
// rather than Keel's intended defaults.
cfg := AppConfig{Keel: keelconfig.Defaults()}
// ... unmarshal your YAML on top of cfg ...
After loading:
keel, err := keelconfig.From(&cfg.Keel)
cfg.Keel = keel
6.2 Create the Server
import (
keelcore "github.com/keelcore/keel/pkg/core"
"github.com/keelcore/keel/pkg/core/logging"
"github.com/keelcore/keel/pkg/core/ports"
)
log := logging.New(logging.Config{JSON: true})
srv := keelcore.NewServer(log, cfg.Keel)
srv.AddRoute(ports.HTTPS, "GET /hello", http.HandlerFunc(hello))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
srv.Run(ctx)
6.3 Your keel.yaml Nests Under the keel: Key
app:
name: myapp
keel:
listeners:
https: { enabled: true, port: 8443 }
health: { enabled: true, port: 9091 }
ready: { enabled: true, port: 9092 }
tls:
cert_file: /etc/myapp/tls.crt
key_file: /etc/myapp/tls.key
authn:
enabled: true
my_id: myapp
logging:
json: true
level: info
See docs/deployment.md for the complete library mode walkthrough, Helm chart reference, and Docker
Compose test harness.
Security Governance
- Vulnerability reporting and CVE policy: SECURITY.md
- SBOM and provenance attached to each GitHub Release — see
Supply Chain Verification for consumer verification instructions.
- FIPS compliance guide: docs/FIPS.md
- Emergency CI bypass procedure: docs/break-glass.md — authorisation requirements, minimal-fix
discipline, and the 48-hour post-incident checklist for pushing directly to
main when a critical production issue
cannot wait for normal CI gates.
Engineering Governance
Keel follows the keelcore/standards engineering governance framework, pinned as
a git submodule at .standards/. The standards cover coding discipline, CI supply-chain rules, bash script portability,
observability requirements, security posture, and runtime/deployment requirements.
The submodule is consumed by AI coding tools (Claude Code, Cursor, GitHub Copilot) and human contributors alike — the
same rules apply to both. To update the pinned standards version:
git submodule update --remote .standards
git add .standards && git commit -m "chore: update standards"
See docs/governance.md for the full explanation: what the submodule contains, why the submodule
pattern was chosen over copy-paste, how to initialize it after a fresh clone, and how to propose changes upstream.
Keel is an open-source project and welcomes contributions of all kinds — from documentation fixes to new middleware
layers. The table below covers the contribution workflow, the people who maintain the project, and the community norms
everyone is asked to follow. If you already have a fix in mind, docs/LAZY.md is the fastest path to a
merged PR.
| Document |
Contents |
| docs/CONTRIBUTING.md |
Full contribution guide — dev setup, coding standards, Conventional Commits format, testing checklist, and PR process |
| docs/LAZY.md |
Quick-path contribution guide — fork → branch → PR in five minutes for contributors who already have a fix ready |
| docs/MAINTAINERS.md |
Current maintainers, the path to maintainership, and ongoing maintainer responsibilities |
| docs/CODE_OF_CONDUCT.md |
CNCF Code of Conduct — the community norms all participants agree to |
11. What This Is Not
- Not a generic L7 proxy buffet.
- Not a "kitchen sink" mesh replacement.
- Not nginx/haproxy.
- Not a full-blown WAF.
Keel provides a minimal, security-first subset of features that are fully app-integrated. For perimeter
DDoS defense, use a dedicated solution in front of Keel.