YARP (Yet Another Reverse Proxy) Production Guide: .NET 8 Patterns 2025
YARP (Yet Another Reverse Proxy) is Microsoft's high-performance reverse proxy built on .NET, designed for modern microservices architectures. Unlike traditional reverse proxies, YARP is code-first, integrates seamlessly with .NET applications, and provides exceptional performance for routing, load balancing, and request transformation.
This comprehensive guide covers YARP production deployment patterns, performance optimization, configuration strategies, authentication integration, and enterprise-scale deployment practices. You'll learn how to configure YARP for high-throughput scenarios, implement advanced routing patterns, integrate with authentication systems, and monitor production deployments.
Understanding YARP
What is YARP?
YARP is a reverse proxy library for .NET that:
- Routes requests to backend services
- Load balances traffic across multiple instances
- Transforms requests/responses on the fly
- Handles authentication at the proxy layer
- Provides observability through metrics and logging
YARP vs Other Solutions
YARP Advantages:
- Native .NET integration
- Code-first configuration
- High performance (built on ASP.NET Core)
- Extensible middleware pipeline
- Microsoft-supported
When to Use YARP:
- .NET-based microservices
- Need for code-based configuration
- High-performance requirements
- Integration with .NET authentication
Getting Started with YARP
Installation
Install YARP NuGet package:
dotnet add package Yarp.ReverseProxy
Basic Configuration
Configure YARP in Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add YARP
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
// Use YARP
app.MapReverseProxy();
app.Run();
Configuration File
Define routes and clusters in appsettings.json:
{
"ReverseProxy": {
"Routes": {
"api-route": {
"ClusterId": "api-cluster",
"Match": {
"Path": "/api/{**catch-all}"
}
}
},
"Clusters": {
"api-cluster": {
"Destinations": {
"destination1": {
"Address": "https://api1.example.com/"
},
"destination2": {
"Address": "https://api2.example.com/"
}
}
}
}
}
}
Code-Based Configuration
Programmatic Route Configuration
Configure routes in code for flexibility:
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
.LoadFromMemory(GetRoutes(), GetClusters());
static RouteConfig[] GetRoutes()
{
return new[]
{
new RouteConfig
{
RouteId = "api-route",
ClusterId = "api-cluster",
Match = new RouteMatch
{
Path = "/api/{**catch-all}"
},
Transforms = new[]
{
new Dictionary<string, string>
{
["PathPattern"] = "/{**catch-all}"
}
}
}
};
}
static ClusterConfig[] GetClusters()
{
return new[]
{
new ClusterConfig
{
ClusterId = "api-cluster",
LoadBalancingPolicy = "RoundRobin",
Destinations = new Dictionary<string, DestinationConfig>
{
["destination1"] = new DestinationConfig
{
Address = "https://api1.example.com/"
},
["destination2"] = new DestinationConfig
{
Address = "https://api2.example.com/"
}
},
HealthCheck = new HealthCheckConfig
{
Enabled = true,
Interval = TimeSpan.FromSeconds(30),
Timeout = TimeSpan.FromSeconds(5),
Path = "/health"
}
}
};
}
Load Balancing Strategies
Round Robin
Distribute requests evenly:
new ClusterConfig
{
ClusterId = "api-cluster",
LoadBalancingPolicy = "RoundRobin",
Destinations = /* ... */
}
Least Requests
Route to destination with fewest active requests:
new ClusterConfig
{
ClusterId = "api-cluster",
LoadBalancingPolicy = "LeastRequests",
Destinations = /* ... */
}
Power of Two Choices
Select two random destinations, choose one with fewer requests:
new ClusterConfig
{
ClusterId = "api-cluster",
LoadBalancingPolicy = "PowerOfTwoChoices",
Destinations = /* ... */
}
Custom Load Balancing
Implement custom load balancing policy:
public class CustomLoadBalancingPolicy : ILoadBalancingPolicy
{
public string Name => "Custom";
public DestinationState PickDestination(
HttpContext context,
ClusterState cluster,
IReadOnlyList<DestinationState> availableDestinations)
{
// Custom selection logic
return availableDestinations
.OrderBy(d => d.ConcurrentRequestCount)
.First();
}
}
// Register custom policy
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
.AddLoadBalancingPolicy<CustomLoadBalancingPolicy>("Custom");
Request/Response Transformation
Path Transformation
Transform request paths:
new RouteConfig
{
RouteId = "api-route",
ClusterId = "api-cluster",
Match = new RouteMatch
{
Path = "/api/v1/{**catch-all}"
},
Transforms = new[]
{
new Dictionary<string, string>
{
["PathPattern"] = "/v1/{**catch-all}"
}
}
}
Header Transformation
Add, remove, or modify headers:
public class CustomTransform : RequestTransform
{
public override ValueTask ApplyAsync(RequestTransformContext context)
{
// Add custom header
context.HttpContext.Request.Headers.Add("X-Proxy-Request-Id",
Guid.NewGuid().ToString());
// Remove header
context.HttpContext.Request.Headers.Remove("X-Original-Header");
return default;
}
}
// Register transform
builder.Services.AddReverseProxy()
.AddTransforms(builderContext =>
{
builderContext.AddRequestTransform(async transformContext =>
{
transformContext.HttpContext.Request.Headers.Add(
"X-Proxy-Request-Id", Guid.NewGuid().ToString());
});
});
Response Transformation
Transform response content:
public class ResponseTransformMiddleware
{
private readonly RequestDelegate _next;
public ResponseTransformMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var originalBodyStream = context.Response.Body;
using var responseBody = new MemoryStream();
context.Response.Body = responseBody;
await _next(context);
// Transform response
responseBody.Seek(0, SeekOrigin.Begin);
var responseText = await new StreamReader(responseBody).ReadToEndAsync();
// Apply transformation
var transformedResponse = TransformResponse(responseText);
// Write transformed response
await context.Response.WriteAsync(transformedResponse);
}
}
Authentication Integration
JWT Authentication
Validate JWT tokens at the proxy:
builder.Services.AddAuthentication()
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://auth.example.com";
options.Audience = "api.example.com";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true
};
});
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapReverseProxy();
Forward Authentication
Forward authentication to backend:
public class ForwardAuthTransform : RequestTransform
{
public override ValueTask ApplyAsync(RequestTransformContext context)
{
var user = context.HttpContext.User;
if (user.Identity.IsAuthenticated)
{
// Forward user claims
var claims = user.Claims.Select(c => $"{c.Type}={c.Value}");
context.HttpContext.Request.Headers.Add("X-User-Claims",
string.Join(",", claims));
}
return default;
}
}
Health Checks
Destination Health Checks
Monitor destination health:
new ClusterConfig
{
ClusterId = "api-cluster",
HealthCheck = new HealthCheckConfig
{
Enabled = true,
Interval = TimeSpan.FromSeconds(30),
Timeout = TimeSpan.FromSeconds(5),
Path = "/health",
Policy = "Passive"
},
Destinations = /* ... */
}
Custom Health Check
Implement custom health check logic:
public class CustomHealthCheckPolicy : IHealthCheckPolicy
{
public string Name => "Custom";
public Task<DestinationHealthState> CheckHealthAsync(
HttpContext context,
ClusterState cluster,
DestinationState destination,
CancellationToken cancellationToken)
{
// Custom health check logic
var isHealthy = CheckDestinationHealth(destination);
return Task.FromResult(new DestinationHealthState
{
Destination = destination,
Health = isHealthy ? DestinationHealth.Healthy : DestinationHealth.Unhealthy
});
}
}
Performance Optimization
Connection Pooling
Optimize HTTP connection pooling:
builder.Services.AddHttpClient("YARP")
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
MaxConnectionsPerServer = 100,
PooledConnectionLifetime = TimeSpan.FromMinutes(2)
});
Caching
Implement response caching:
builder.Services.AddMemoryCache();
app.UseResponseCaching();
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
var cacheKey = context.Request.Path + context.Request.QueryString;
if (context.Request.Method == "GET" &&
await _cache.TryGetValueAsync(cacheKey, out var cachedResponse))
{
context.Response.StatusCode = 200;
await context.Response.WriteAsync(cachedResponse);
return;
}
await next();
if (context.Response.StatusCode == 200)
{
var responseBody = await ReadResponseBody(context.Response);
await _cache.SetAsync(cacheKey, responseBody, TimeSpan.FromMinutes(5));
}
});
});
Compression
Enable response compression:
builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
});
app.UseResponseCompression();
Observability
Metrics
Track YARP metrics:
builder.Services.AddSingleton<IMetricsCollector, MetricsCollector>();
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
await next();
stopwatch.Stop();
var metrics = context.RequestServices.GetRequiredService<IMetricsCollector>();
metrics.RecordRequest(
context.Request.Path,
context.Response.StatusCode,
stopwatch.ElapsedMilliseconds);
});
});
Logging
Configure structured logging:
builder.Logging.AddConsole()
.AddJsonConsole(options =>
{
options.IncludeScopes = true;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss ";
});
// Log proxy requests
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
var logger = context.RequestServices
.GetRequiredService<ILogger<Program>>();
logger.LogInformation(
"Proxying request: {Method} {Path} to {Destination}",
context.Request.Method,
context.Request.Path,
context.GetRouteValue("destination"));
await next();
});
});
Advanced Patterns
Circuit Breaker
Implement circuit breaker pattern:
public class CircuitBreakerMiddleware
{
private readonly ConcurrentDictionary<string, CircuitBreakerState> _circuits;
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var destination = GetDestination(context);
var circuit = _circuits.GetOrAdd(destination, _ => new CircuitBreakerState());
if (circuit.IsOpen)
{
context.Response.StatusCode = 503;
await context.Response.WriteAsync("Service unavailable");
return;
}
try
{
await next();
circuit.RecordSuccess();
}
catch (Exception ex)
{
circuit.RecordFailure();
throw;
}
}
}
Rate Limiting
Implement rate limiting:
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("api", opt =>
{
opt.Window = TimeSpan.FromMinutes(1);
opt.PermitLimit = 100;
});
});
app.UseRateLimiter();
app.MapReverseProxy()
.RequireRateLimiting("api");
Production Deployment
Configuration Management
Use environment-specific configuration:
builder.Configuration
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables()
.AddAzureKeyVault(/* ... */);
High Availability
Deploy multiple YARP instances:
# docker-compose.yml
services:
yarp-proxy:
image: yarp-proxy:latest
replicas: 3
ports:
- "80:80"
- "443:443"
environment:
- ASPNETCORE_ENVIRONMENT=Production
Monitoring
Set up comprehensive monitoring:
builder.Services.AddApplicationInsightsTelemetry();
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
var telemetry = context.RequestServices
.GetRequiredService<TelemetryClient>();
var operation = telemetry.StartOperation<RequestTelemetry>(
context.Request.Path);
try
{
await next();
operation.Telemetry.Success = context.Response.StatusCode < 400;
}
finally
{
telemetry.StopOperation(operation);
}
});
});
Best Practices
1. Use Health Checks
Always enable health checks for destinations:
HealthCheck = new HealthCheckConfig
{
Enabled = true,
Interval = TimeSpan.FromSeconds(30)
}
2. Implement Retry Logic
Add retry for transient failures:
builder.Services.AddHttpClient("YARP")
.AddPolicyHandler(GetRetryPolicy());
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.WaitAndRetryAsync(3, retryAttempt =>
TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
3. Monitor Performance
Track key metrics:
- Request latency
- Error rates
- Destination health
- Throughput
4. Secure Configuration
Store sensitive configuration securely:
- Use Azure Key Vault
- Use environment variables
- Never commit secrets
Advanced YARP Patterns
Dynamic Route Configuration
Configure routes dynamically at runtime:
public class DynamicRouteManager
{
private readonly IProxyConfigProvider _configProvider;
public async Task AddRouteAsync(RouteConfig route)
{
var config = await _configProvider.GetConfigAsync();
config.Routes.Add(route);
await _configProvider.UpdateConfigAsync(config);
}
public async Task RemoveRouteAsync(string routeId)
{
var config = await _configProvider.GetConfigAsync();
config.Routes.RemoveAll(r => r.RouteId == routeId);
await _configProvider.UpdateConfigAsync(config);
}
}
Custom Load Balancing
Implement custom load balancing algorithms:
public class WeightedRoundRobinPolicy : ILoadBalancingPolicy
{
public string Name => "WeightedRoundRobin";
public DestinationState PickDestination(
HttpContext context,
ClusterState cluster,
IReadOnlyList<DestinationState> availableDestinations)
{
var totalWeight = availableDestinations.Sum(d => d.Weight);
var random = new Random().NextDouble() * totalWeight;
var current = 0.0;
foreach (var destination in availableDestinations)
{
current += destination.Weight;
if (random <= current)
{
return destination;
}
}
return availableDestinations.Last();
}
}
Real-World Deployment Scenarios
Scenario 1: Multi-Region Deployment
Deploy YARP across multiple regions:
public class MultiRegionYarpConfig
{
public ClusterConfig CreateMultiRegionCluster()
{
return new ClusterConfig
{
ClusterId = "global-api-cluster",
LoadBalancingPolicy = "WeightedRoundRobin",
Destinations = new Dictionary<string, DestinationConfig>
{
["us-east"] = new DestinationConfig
{
Address = "https://api-us-east.example.com",
Weight = 3
},
["eu-west"] = new DestinationConfig
{
Address = "https://api-eu-west.example.com",
Weight = 2
},
["asia-pacific"] = new DestinationConfig
{
Address = "https://api-asia.example.com",
Weight = 1
}
}
};
}
}
Scenario 2: Blue-Green Deployment
Support blue-green deployments:
public class BlueGreenDeploymentManager
{
public async Task SwitchToGreenAsync()
{
var config = await GetCurrentConfigAsync();
// Update all routes to point to green
foreach (var route in config.Routes)
{
route.ClusterId = "green-cluster";
}
await UpdateConfigAsync(config);
// Monitor green cluster health
await MonitorGreenClusterHealthAsync();
}
}
Performance Tuning
Connection Pool Optimization
Optimize connection pooling:
builder.Services.AddHttpClient("YARP", client =>
{
client.Timeout = TimeSpan.FromSeconds(30);
})
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
MaxConnectionsPerServer = 200,
PooledConnectionLifetime = TimeSpan.FromMinutes(2),
PooledConnectionIdleTimeout = TimeSpan.FromSeconds(30),
UseCookies = false,
AllowAutoRedirect = false
});
Response Caching
Implement intelligent caching:
public class IntelligentCacheMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var cacheKey = GenerateCacheKey(context.Request);
if (await _cache.TryGetValueAsync(cacheKey, out var cachedResponse))
{
context.Response.StatusCode = 200;
await context.Response.WriteAsync(cachedResponse);
return;
}
await next(context);
if (context.Response.StatusCode == 200 && IsCacheable(context.Request))
{
var responseBody = await ReadResponseBodyAsync(context.Response);
await _cache.SetAsync(cacheKey, responseBody, GetCacheDuration(context.Request));
}
}
private bool IsCacheable(HttpRequest request)
{
return request.Method == "GET" &&
!request.Headers.ContainsKey("Cache-Control");
}
}
Extended FAQ
Q: How do I handle WebSocket connections with YARP?
A: YARP supports WebSocket proxying:
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.UseWebSockets();
});
Q: Can I use YARP with gRPC?
A: Yes, YARP supports gRPC:
builder.Services.AddGrpc();
app.MapGrpcService<MyGrpcService>();
app.MapReverseProxy();
Q: How do I implement custom routing logic?
A: Use custom middleware:
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
// Custom routing logic
var route = DetermineRoute(context);
context.Request.Path = route;
await next();
});
});
Conclusion
YARP provides a powerful, high-performance reverse proxy solution for .NET applications. By following the patterns and practices outlined in this guide, you can build production-ready reverse proxy deployments that handle high traffic, provide excellent observability, and integrate seamlessly with your .NET ecosystem.
Key Takeaways:
- Use code-based configuration for flexibility
- Implement health checks for all destinations
- Enable observability with metrics and logging
- Optimize performance with connection pooling and caching
- Secure authentication at the proxy layer
- Monitor production deployments comprehensively
- Dynamic configuration for runtime changes
- Custom load balancing for advanced scenarios
- Multi-region support for global deployments
- Performance tuning for optimal throughput
Next Steps:
- Set up YARP in your application
- Configure routes and clusters
- Implement health checks
- Add authentication
- Set up monitoring
- Optimize performance
- Plan for scale
Production Deployment Checklist
Pre-Deployment
- Configure health checks for all destinations
- Set up monitoring and alerting
- Configure authentication and authorization
- Set up rate limiting
- Test failover scenarios
- Document configuration
- Review security settings
- Load test the proxy
Post-Deployment
- Monitor proxy metrics
- Review error logs
- Check destination health
- Verify authentication works
- Monitor performance
- Review security events
- Optimize based on metrics
Additional Resources
YARP Documentation
- Official YARP documentation
- YARP GitHub repository
- YARP samples
- YARP community discussions
Related Topics
- API Gateway patterns
- Reverse proxy best practices
- Load balancing strategies
- Service mesh integration
YARP Configuration Examples
Basic Configuration
Simple reverse proxy setup:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.MapReverseProxy();
app.Run();
Advanced Configuration
Code-based configuration:
builder.Services.AddReverseProxy()
.LoadFromMemory(new[]
{
new RouteConfig
{
RouteId = "api-route",
ClusterId = "api-cluster",
Match = new RouteMatch
{
Path = "/api/{**catch-all}"
}
}
}, new[]
{
new ClusterConfig
{
ClusterId = "api-cluster",
Destinations = new Dictionary<string, DestinationConfig>
{
["destination1"] = new DestinationConfig
{
Address = "https://api1.example.com"
},
["destination2"] = new DestinationConfig
{
Address = "https://api2.example.com"
}
}
}
});
Monitoring and Diagnostics
Health Check Integration
Integrate with health checks:
builder.Services.AddHealthChecks()
.AddCheck<YarpHealthCheck>("yarp");
app.MapHealthChecks("/health");
Metrics Collection
Collect YARP metrics:
builder.Services.AddSingleton<IMetricsConsumer<YarpMetrics>>(
new PrometheusMetricsConsumer());
app.UseMetricServer();
YARP Advanced Features
Request/Response Transformation
Transform requests and responses:
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
// Transform request
context.Request.Headers.Add("X-Forwarded-For",
context.Connection.RemoteIpAddress.ToString());
await next();
// Transform response
if (context.Response.StatusCode == 200)
{
context.Response.Headers.Add("X-Processed-By", "YARP");
}
});
});
Custom Routing Logic
Implement custom routing:
public class CustomRouteMatcher
{
public RouteConfig MatchRoute(HttpContext context)
{
var path = context.Request.Path.Value;
if (path.StartsWith("/api/v1/"))
{
return new RouteConfig
{
RouteId = "api-v1",
ClusterId = "api-v1-cluster"
};
}
if (path.StartsWith("/api/v2/"))
{
return new RouteConfig
{
RouteId = "api-v2",
ClusterId = "api-v2-cluster"
};
}
return null;
}
}
YARP Performance Tuning
Connection Management
Optimize connection handling:
builder.Services.AddHttpClient("YARP", client =>
{
client.Timeout = TimeSpan.FromSeconds(30);
})
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(2),
PooledConnectionIdleTimeout = TimeSpan.FromSeconds(30),
MaxConnectionsPerServer = 100,
EnableMultipleHttp2Connections = true
});
Response Caching
Implement response caching:
app.UseResponseCaching();
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
if (context.Request.Method == "GET")
{
var cacheKey = GenerateCacheKey(context.Request);
if (await TryGetCachedResponseAsync(cacheKey, context.Response))
{
return; // Return cached response
}
}
await next();
if (context.Response.StatusCode == 200 && IsCacheable(context.Request))
{
await CacheResponseAsync(context.Request, context.Response);
}
});
});
YARP Load Balancing
Load Balancing Strategies
Implement different load balancing strategies:
public class LoadBalancingConfig
{
public static ClusterConfig CreateRoundRobinCluster()
{
return new ClusterConfig
{
ClusterId = "api-cluster",
LoadBalancingPolicy = "RoundRobin",
Destinations = new Dictionary<string, DestinationConfig>
{
["destination1"] = new DestinationConfig { Address = "https://api1.example.com" },
["destination2"] = new DestinationConfig { Address = "https://api2.example.com" },
["destination3"] = new DestinationConfig { Address = "https://api3.example.com" }
}
};
}
public static ClusterConfig CreateLeastRequestsCluster()
{
return new ClusterConfig
{
ClusterId = "api-cluster",
LoadBalancingPolicy = "LeastRequests",
Destinations = new Dictionary<string, DestinationConfig>
{
["destination1"] = new DestinationConfig { Address = "https://api1.example.com" },
["destination2"] = new DestinationConfig { Address = "https://api2.example.com" }
}
};
}
}
Health Check Integration
Integrate health checks with load balancing:
builder.Services.AddReverseProxy()
.LoadFromConfig(config.GetSection("ReverseProxy"))
.AddProxyLoadBalancer<HealthCheckLoadBalancer>();
public class HealthCheckLoadBalancer : ILoadBalancer
{
public DestinationState PickDestination(
HttpContext context,
ClusterState cluster,
IReadOnlyList<DestinationState> availableDestinations)
{
var healthy = availableDestinations
.Where(d => d.Health == DestinationHealth.Healthy)
.ToList();
if (healthy.Count == 0)
{
return availableDestinations.First(); // Fallback
}
// Round-robin among healthy destinations
return healthy[_currentIndex++ % healthy.Count];
}
}
YARP Security
Request Validation
Validate incoming requests:
public class RequestValidator
{
public async Task<bool> ValidateRequestAsync(HttpContext context)
{
// Validate content length
if (context.Request.ContentLength > MaxContentLength)
{
return false;
}
// Validate headers
if (!ValidateHeaders(context.Request.Headers))
{
return false;
}
// Validate rate limits
if (!await CheckRateLimitAsync(context))
{
return false;
}
return true;
}
}
Response Security Headers
Add security headers to responses:
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
await next();
// Add security headers
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("X-Frame-Options", "DENY");
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
context.Response.Headers.Add("Strict-Transport-Security",
"max-age=31536000; includeSubDomains");
});
});
YARP Advanced Configuration
Dynamic Configuration
Update configuration dynamically:
public class DynamicYarpConfig
{
private readonly IConfigurationManager _configManager;
public async Task UpdateRouteAsync(RouteConfig route)
{
await _configManager.UpdateRouteAsync(route);
}
public async Task UpdateClusterAsync(ClusterConfig cluster)
{
await _configManager.UpdateClusterAsync(cluster);
}
}
Configuration Validation
Validate YARP configuration:
public class YarpConfigValidator
{
public ValidationResult ValidateConfig(YarpConfig config)
{
var errors = new List<string>();
// Validate routes
foreach (var route in config.Routes)
{
if (string.IsNullOrEmpty(route.RouteId))
{
errors.Add($"Route missing RouteId");
}
if (string.IsNullOrEmpty(route.ClusterId))
{
errors.Add($"Route {route.RouteId} missing ClusterId");
}
}
// Validate clusters
foreach (var cluster in config.Clusters)
{
if (cluster.Destinations == null || !cluster.Destinations.Any())
{
errors.Add($"Cluster {cluster.ClusterId} has no destinations");
}
}
return new ValidationResult
{
IsValid = errors.Count == 0,
Errors = errors
};
}
}
YARP Troubleshooting
Common Issues
Troubleshoot common YARP issues:
public class YarpTroubleshooter
{
public async Task<DiagnosticsResult> DiagnoseAsync()
{
var diagnostics = new DiagnosticsResult();
// Check configuration
diagnostics.ConfigurationValid = await ValidateConfigurationAsync();
// Check destinations
diagnostics.DestinationsHealthy = await CheckDestinationsAsync();
// Check routing
diagnostics.RoutingWorking = await TestRoutingAsync();
return diagnostics;
}
}
YARP Production Deployment
Deployment Checklist
Complete deployment checklist:
public class YarpDeploymentChecklist
{
public async Task<DeploymentStatus> CheckDeploymentReadinessAsync()
{
var status = new DeploymentStatus();
// Check configuration
status.ConfigurationValid = await ValidateConfigurationAsync();
// Check destinations
status.DestinationsHealthy = await CheckAllDestinationsAsync();
// Check health checks
status.HealthChecksWorking = await TestHealthChecksAsync();
// Check monitoring
status.MonitoringConfigured = await CheckMonitoringAsync();
// Check security
status.SecurityConfigured = await CheckSecurityAsync();
return status;
}
}
Performance Tuning
Tune YARP performance:
public class YarpPerformanceTuner
{
public void OptimizePerformance()
{
// Optimize connection pooling
builder.Services.AddHttpClient("YARP", client =>
{
client.Timeout = TimeSpan.FromSeconds(30);
})
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.FromMinutes(2),
PooledConnectionIdleTimeout = TimeSpan.FromSeconds(30),
MaxConnectionsPerServer = 100,
EnableMultipleHttp2Connections = true
});
// Enable response compression
builder.Services.AddResponseCompression();
// Enable response caching
builder.Services.AddResponseCaching();
}
}
YARP Advanced Configuration
Dynamic Configuration Updates
Update configuration dynamically:
public class DynamicConfigurationUpdater
{
public async Task UpdateConfigurationAsync(YarpConfig config)
{
// Validate configuration
var validation = await ValidateConfigurationAsync(config);
if (!validation.IsValid)
{
throw new InvalidOperationException("Invalid configuration");
}
// Update configuration
await UpdateConfigAsync(config);
// Notify YARP
await NotifyYarpAsync(config);
}
}
YARP Health Monitoring
Monitor YARP health:
public class YarpHealthMonitor
{
public async Task<HealthStatus> GetYarpHealthAsync()
{
var health = new HealthStatus
{
Status = HealthStatus.Healthy
};
// Check destinations
var destinationsHealth = await CheckDestinationsHealthAsync();
if (!destinationsHealth.IsHealthy)
{
health.Status = HealthStatus.Degraded;
health.Issues.Add("Some destinations unhealthy");
}
// Check configuration
var configHealth = await CheckConfigurationHealthAsync();
if (!configHealth.IsValid)
{
health.Status = HealthStatus.Unhealthy;
health.Issues.Add("Configuration issues");
}
return health;
}
}
For more API gateway guidance, explore our API Gateway Comparison: Ocelot vs YARP vs Kong or Ocelot API Gateway guide.