# Router Plugins > Traffic router plugins for progressive delivery (Nginx, AWS ALB, and custom implementations). **Status:** Planned (not yet implemented) **Source:** [Architecture Advisory Section 11.4](../../../product/advisories/09-Jan-2026%20-%20Stella%20Ops%20Orchestrator%20Architecture.md) **Related Modules:** [Progressive Delivery Module](../modules/progressive-delivery.md), [Plugin System](../modules/plugin-system.md) **Sprint:** [110_004 Router Plugins](../../../../implplan/SPRINT_20260110_110_004_PROGDL_nginx_router.md) ## Overview Router plugins enable traffic shifting for progressive delivery. The orchestrator ships with an Nginx router plugin for v1, with HAProxy, Traefik, and AWS ALB available as additional plugins. --- ## Router Plugin Interface All router plugins implement the `TrafficRouterPlugin` interface: ```typescript interface TrafficRouterPlugin { // Configuration configureRoute(config: RouteConfig): Promise; // Traffic operations shiftTraffic(from: string, to: string, percentage: number): Promise; getTrafficDistribution(): Promise; // Health validateConfig(): Promise; reload(): Promise; } interface RouteConfig { upstream: string; serverName: string; variations: Variation[]; splitType: "weight" | "header" | "cookie"; headerName?: string; headerValueB?: string; stickySession?: boolean; stickyDuration?: number; } interface Variation { name: string; targets: string[]; weight: number; } interface TrafficDistribution { variations: { name: string; percentage: number; targets: string[]; }[]; } ``` --- ## Nginx Router Plugin (v1 Built-in) The Nginx plugin generates and manages Nginx configuration for traffic splitting. ### Implementation ```typescript class NginxRouterPlugin implements TrafficRouterPlugin { async configureRoute(config: RouteConfig): Promise { const upstreamConfig = this.generateUpstreamConfig(config); const serverConfig = this.generateServerConfig(config); // Write configuration files await this.writeConfig( `/etc/nginx/conf.d/upstream-${config.upstream}.conf`, upstreamConfig ); await this.writeConfig( `/etc/nginx/conf.d/server-${config.upstream}.conf`, serverConfig ); // Validate configuration const validation = await this.validateConfig(); if (!validation.valid) { throw new Error(`Nginx config validation failed: ${validation.error}`); } // Reload nginx await this.reload(); } } ``` ### Upstream Configuration ```typescript private generateUpstreamConfig(config: RouteConfig): string { const lines: string[] = []; for (const variation of config.variations) { lines.push(`upstream ${config.upstream}_${variation.name} {`); for (const target of variation.targets) { lines.push(` server ${target};`); } lines.push(`}`); lines.push(``); } // Combined upstream with weights (for percentage-based routing) if (config.splitType === "weight") { lines.push(`upstream ${config.upstream} {`); for (const variation of config.variations) { const weight = variation.weight; for (const target of variation.targets) { lines.push(` server ${target} weight=${weight};`); } } lines.push(`}`); } return lines.join("\n"); } ``` ### Server Configuration ```typescript private generateServerConfig(config: RouteConfig): string { if (config.splitType === "header" || config.splitType === "cookie") { // Split block based on header/cookie return ` map $http_${config.headerName || "x-variation"} $${config.upstream}_backend { default ${config.upstream}_A; "${config.headerValueB || "B"}" ${config.upstream}_B; } server { listen 80; server_name ${config.serverName}; location / { proxy_pass http://$${config.upstream}_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } `; } else { // Weight-based (default) return ` server { listen 80; server_name ${config.serverName}; location / { proxy_pass http://${config.upstream}; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } `; } } ``` ### Traffic Shifting ```typescript async shiftTraffic(from: string, to: string, percentage: number): Promise { const config = await this.getCurrentConfig(); // Update weights for (const variation of config.variations) { if (variation.name === to) { variation.weight = percentage; } else { variation.weight = 100 - percentage; } } await this.configureRoute(config); } async getTrafficDistribution(): Promise { // Parse current nginx config to get weights const config = await this.parseCurrentConfig(); return { variations: config.variations.map(v => ({ name: v.name, percentage: v.weight, targets: v.targets, })), }; } ``` --- ## AWS ALB Router Plugin The AWS ALB plugin manages weighted target groups for traffic splitting. ### Implementation ```typescript class AWSALBRouterPlugin implements TrafficRouterPlugin { private alb: AWS.ELBv2; async configureRoute(config: RouteConfig): Promise { const listenerArn = config.listenerArn; // Create/update target groups for each variation const targetGroupArns: Record = {}; for (const variation of config.variations) { const tgArn = await this.ensureTargetGroup( `${config.upstream}-${variation.name}`, variation.targets ); targetGroupArns[variation.name] = tgArn; } // Update listener rule with weighted target groups await this.alb.modifyRule({ RuleArn: config.ruleArn, Actions: [{ Type: "forward", ForwardConfig: { TargetGroups: config.variations.map(v => ({ TargetGroupArn: targetGroupArns[v.name], Weight: v.weight, })), TargetGroupStickinessConfig: { Enabled: config.stickySession || false, DurationSeconds: config.stickyDuration || 3600, }, }, }], }).promise(); } async shiftTraffic(from: string, to: string, percentage: number): Promise { const rule = await this.getRule(); const forwardConfig = rule.Actions[0].ForwardConfig; // Update weights for (const tg of forwardConfig.TargetGroups) { if (tg.TargetGroupArn.includes(`-${to}`)) { tg.Weight = percentage; } else { tg.Weight = 100 - percentage; } } await this.alb.modifyRule({ RuleArn: rule.RuleArn, Actions: rule.Actions, }).promise(); } async getTrafficDistribution(): Promise { const rule = await this.getRule(); const forwardConfig = rule.Actions[0].ForwardConfig; const variations = []; for (const tg of forwardConfig.TargetGroups) { const targets = await this.getTargetGroupTargets(tg.TargetGroupArn); const name = tg.TargetGroupArn.split("-").pop(); variations.push({ name, percentage: tg.Weight, targets: targets.map(t => t.Id), }); } return { variations }; } } ``` --- ## Router Plugin Catalog | Plugin | Status | Description | |--------|--------|-------------| | Nginx | v1 Built-in | Configuration-based weight/header routing | | HAProxy | Plugin | Runtime API for traffic management | | Traefik | Plugin | Dynamic configuration via API | | AWS ALB | Plugin | Weighted target groups | | Envoy | Planned | xDS API integration | --- ## Creating Custom Router Plugins To create a custom router plugin: 1. **Implement Interface:** Create a class implementing `TrafficRouterPlugin` 2. **Register Plugin:** Add to plugin registry with capabilities 3. **Configuration Schema:** Define JSON Schema for plugin config 4. **Health Checks:** Implement connection testing 5. **Rollback Support:** Handle traffic reversion on failures ### Example Plugin Manifest ```yaml plugin: name: my-router version: 1.0.0 type: router capabilities: - traffic-routing - weight-based - header-based config: type: object properties: endpoint: type: string description: Router API endpoint auth: type: object properties: type: enum: [basic, token] credentialRef: type: string ``` --- ## See Also - [Progressive Delivery Module](../modules/progressive-delivery.md) - [Plugin System](../modules/plugin-system.md) - [Canary Controller](canary.md) - [A/B Release Models](ab-releases.md)