Frontline
Multi-tenant frontline and routing service
Location: go/apps/frontline/
CLI Command: unkey run frontline
What It Does
Frontline is the multi-tenant HTTP frontline service that serves as the entry point for all customer traffic. It handles TLS termination, hostname-based routing, and proxying requests to environment-scoped sentinels.
Frontline handles four main responsibilities:
- TLS Termination: Terminates TLS for custom domains using ACME (Let's Encrypt) or local certificates
- Hostname Routing: Looks up frontline routes by hostname to find the target deployment and environment
- Sentinel Selection: Routes requests to the appropriate environment-scoped sentinel
- Smart Proxying: Forwards to local sentinels or cross-region NLBs with hop count protection
Architecture
Multi-Tenant Design
Frontline is a multi-tenant service running as a Kubernetes Deployment behind a Network Load Balancer. A single Frontline instance handles traffic for all customer deployments, performing hostname lookups and routing decisions to forward requests to the appropriate environment sentinel.
Request Flow
Database Schema
Frontline uses the following tables for routing decisions:
TLS Strategy
ACME (Let's Encrypt)
Frontline uses ACME (Automated Certificate Management Environment) to obtain and renew TLS certificates from Let's Encrypt:
- Challenge Handler: The
/acmeroute responds to HTTP-01 challenges - Certificate Storage: Certificates are stored in MySQL
certificatestable - Automatic Renewal: Certificates are renewed before expiration
- SNI Support: Multiple hostnames supported via Server Name Indication
Local Development
For local development, Frontline can generate self-signed certificates:
TLS Termination Flow
- Client connects with SNI hostname (e.g.,
api.customer.com) - Frontline looks up certificate in database by hostname
- TLS handshake completes with customer's certificate
- Request is decrypted and forwarded to environment sentinel as plain HTTP
Sentinel Routing
Frontline routes requests to environment-scoped sentinels based on the environment_id from the frontline route lookup.
Sentinel Discovery
Routing Strategy
Frontline routes based on:
environment_idfrom the frontline route lookup- Sentinel service discovery via Kubernetes DNS
- Current region (for local vs cross-region routing)
If no local sentinel is found, Frontline forwards to the region's NLB, triggering cross-region forwarding.
Request Headers
Frontline passes metadata to the Sentinel via HTTP headers:
X-Deployment-ID: The target deployment IDX-Environment-ID: The environment ID (for validation)X-Unkey-Hop-Count: Hop count for cross-region loop prevention
Cross-Region Forwarding
When no local sentinel is available, Frontline forwards requests to the region's Network Load Balancer.
Hop Count Protection
To prevent infinite loops, Frontline tracks hops via HTTP header:
Forwarding Strategy
Why NLB Instead of Direct Sentinel?
Forwarding to the region's NLB (instead of directly to a remote sentinel) provides:
- Load balancing: NLB distributes across available Frontline instances in the target region
- Health checking: NLB only routes to healthy Frontline replicas
- Simplicity: No need for cross-region sentinel discovery
- Consistency: Same frontline lookup and routing logic applies in the target region
Error Handling
Frontline provides user-friendly error pages for common scenarios:
Error Middleware
Status Code Mapping
- 404 Not Found: No frontline route configured for hostname
- 503 Service Unavailable: Environment sentinel not available
- 508 Loop Detected: Maximum hop count exceeded (prevents infinite loops)
Observability
Frontline uses structured logging for:
- Hostname lookups and routing decisions
- Sentinel discovery and selection
- Proxy operations (success/failure)
- Cross-region forwarding
- TLS certificate operations
- Error conditions with context
Future Improvements
Planned Features
- Sentinel Health Checks: Active health probing for environment sentinels
- Sticky Sessions: Support sticky routing based on client session
Scalability
Frontline is designed to scale horizontally:
- Stateless: No persistent state, all routing from database
- Database-driven: Routing decisions from MySQL lookups (indexed on hostname)
- Minimal processing: Pure proxy layer, no business logic execution