Ingress Controller
Kubernetes Ingress Controller
The nvelox-ingress-controller watches standard Kubernetes Ingress resources and translates them into nvelox configuration. It runs as a sidecar alongside nvelox, writing config and triggering hot reloads.
Architecture
The controller follows a simple pipeline:
- Watch — controller-runtime watches Ingress, Secret, Service, and EndpointSlice resources
- Translate — a pure function converts Ingress rules into nvelox YAML config
- Write — atomic YAML write with SHA256 hash gate to avoid unnecessary reloads
- Reload — SIGHUP sent to the nvelox sidecar process
IngressClass
The controller watches for Ingress resources with spec.ingressClassName: nvelox. Only Ingresses matching this class are translated.
Kubernetes API
|
| (watch Ingress/Secret/Service)
v
Controller (sidecar pod)
|
| translate to nvelox YAML
v
Atomic write + SHA256 gate
|
| SIGHUP
v
Nvelox process (same pod)
|
| proxy traffic
v
Backend Services
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
nvelox.io/redirect-https: "true"
spec:
ingressClassName: nvelox
tls:
- secretName: my-app-tls
hosts:
- app.example.com
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 8080
Annotations
All nvelox-specific behavior is configured via annotations on the Ingress resource. Annotations are prefixed with nvelox.io/.
nvelox.io/redirect-https
Set to "true" to redirect HTTP requests to HTTPS. Returns a 301 with the same host and path but https:// scheme.
nvelox.io/rate-limit-per-second
Per-IP requests per second. Example: "100".
nvelox.io/rate-limit-per-minute
Per-IP requests per minute. Example: "6000".
nvelox.io/sticky-cookie
Enable session affinity with a cookie. Value is the cookie name. Example: "nvelox-sticky".
nvelox.io/allow-cidrs
Comma-separated CIDR ranges to allow. All other IPs are denied. Example: "10.0.0.0/8,192.168.0.0/16".
nvelox.io/deny-cidrs
Comma-separated CIDR ranges to deny. Example: "203.0.113.0/24".
nvelox.io/strip-prefix
Strip a path prefix before forwarding to the backend. Example: "/api" removes /api from the request path.
nvelox.io/request-headers
Inject headers into requests before forwarding. Format: "Header-Name: value". Multiple headers separated by comma. Example: "X-Forwarded-Proto: https".
nvelox.io/response-headers
Inject headers into responses before sending to the client. Same format as request-headers. Example: "X-Server: nvelox".
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: full-example
annotations:
nvelox.io/redirect-https: "true"
nvelox.io/rate-limit-per-second: "100"
nvelox.io/rate-limit-per-minute: "6000"
nvelox.io/sticky-cookie: "nvelox-sticky"
nvelox.io/allow-cidrs: "10.0.0.0/8,172.16.0.0/12"
nvelox.io/deny-cidrs: "10.0.100.0/24"
nvelox.io/strip-prefix: "/api"
nvelox.io/request-headers: "X-Forwarded-Proto: https"
nvelox.io/response-headers: "X-Server: nvelox"
spec:
ingressClassName: nvelox
tls:
- secretName: example-tls
hosts:
- example.com
rules:
- host: example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 8080
Helm Chart
Install the ingress controller via Helm. The chart deploys the controller and nvelox as a sidecar in a single pod, plus the required RBAC resources and IngressClass.
helm repo add nvelox https://nvelox.github.io/charts
helm repo update
helm install nvelox-ic nvelox/nvelox-ingress-controller \
--namespace nvelox-system \
--create-namespace \
--set image.repository=ghcr.io/nvelox/nvelox-ingress-controller \
--set image.tag=0.1.0
# values.yaml
replicaCount: 1
image:
repository: ghcr.io/nvelox/nvelox-ingress-controller
tag: 0.1.0
pullPolicy: IfNotPresent
nvelox:
image:
repository: ghcr.io/nvelox/nvelox
tag: latest
ingressClass:
name: nvelox
default: false
resources:
requests:
cpu: 100m
memory: 128Mi
RBAC Permissions
The controller needs cluster-scoped read access to watch Ingress, Secret, Service, and EndpointSlice resources. The Helm chart creates these automatically:
ingresses— get, list, watchsecrets— get, list, watchservices— get, list, watchendpointslices— get, list, watchingressclasses— get, list, watch
Troubleshooting
Ingress not picked up
Verify spec.ingressClassName is set to nvelox and the IngressClass resource exists.
503 Bad Gateway
Check that the backend Service has valid endpoints: kubectl get endpoints <service>. Also verify nvelox.io/request-headers: "X-Forwarded-Proto: https" is set if the backend enforces HTTPS.
TLS certificate errors
The TLS secret referenced in spec.tls[].secretName must exist and be of type kubernetes.io/tls with valid tls.crt and tls.key data.
Config not updating
The controller uses a SHA256 hash gate — if the generated config hasn't changed, no reload is triggered. Check controller logs for translation errors.
# Check IngressClass
kubectl get ingressclass nvelox
# Check ingress status
kubectl describe ingress my-app
# Controller logs
kubectl logs -n nvelox-system -l app=nvelox-ingress-controller
# Nvelox sidecar logs
kubectl logs -n nvelox-system -l app=nvelox-ingress-controller -c nvelox
# Verify endpoints
kubectl get endpoints my-app -o wide