Hosting Guide
CritterWatch supports several hosting topologies. Choose based on your team's needs and infrastructure constraints.
Standalone Server (Recommended)
The most common production topology. CritterWatch runs as its own dedicated web application, separate from the services it monitors.
Advantages:
- Clear separation of concerns
- Isolated failure domain — if CritterWatch crashes, monitored services are unaffected
- Independently scalable and deployable
- Simpler security boundary
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.AddCritterWatch(
builder.Configuration.GetConnectionString("critterwatch")!,
opts =>
{
opts.UseRabbitMq(new Uri(builder.Configuration.GetConnectionString("rabbitmq")!))
.AutoProvision();
opts.ListenToRabbitQueue("critterwatch").Sequential();
});
var app = builder.Build();
app.UseCritterWatch();
app.Run();The embedded Vue SPA is served from the server's root path. Navigate to https://your-critterwatch-host/ to open the console.
Embedded in an Existing Application
CritterWatch can be embedded as middleware in an existing ASP.NET Core application. Useful when you want the monitoring console co-located with another admin tool.
// CritterWatch can be embedded directly in an existing ASP.NET Core application
var builder = WebApplication.CreateBuilder(args);
// Add your application's existing services
builder.Services.AddControllers();
// Add CritterWatch on top
builder.AddCritterWatch(
builder.Configuration.GetConnectionString("critterwatch")!,
opts =>
{
opts.UseRabbitMq(new Uri("amqp://localhost")).AutoProvision();
opts.ListenToRabbitQueue("critterwatch").Sequential();
});
var app = builder.Build();
app.MapControllers();
// Mount CritterWatch with a custom SignalR hub path
app.UseCritterWatch(signalRRoute: "/critterwatch/api/messages");
app.Run();Route Conflicts
When embedding CritterWatch in an existing application, ensure there are no route conflicts with your application's existing endpoints. CritterWatch registers routes under /api/critterwatch/* by default.
.NET Aspire Orchestration
For development and staging environments, .NET Aspire provides the best developer experience. It automatically manages service connections, environment variables, and the Vue dev server.
// In your AppHost Program.cs
var builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddPostgres("postgres");
var rabbit = builder.AddRabbitMQ("rabbit");
// Your monitored services
var tripService = builder.AddProject<Projects.TripService>("trip-service")
.WithReference(postgres)
.WithReference(rabbit);
// CritterWatch server
var critterwatch = builder.AddProject<Projects.CritterWatchBff>("critterwatch")
.WithReference(postgres)
.WithReference(rabbit)
.WaitFor(tripService);
builder.Build().Run();The
Projects.*types are generated by Aspire's source generator from the project references in your AppHost. Seesrc/BffHost/Program.csin this repo for a worked example with the full sample-services lineup.
During Aspire-hosted development, the Vue frontend runs as a separate Vite dev server (port 5173) that proxies to the CritterWatch backend. The embedded SPA middleware is not used in this mode.
Building the NuGet Package with Embedded Frontend
When publishing the CritterWatch NuGet package (or distributing as a private package), build with the EmbedFrontend property to bundle the Vue SPA:
dotnet pack src/CritterWatch.Services -p:EmbedFrontend=trueOr for a regular build:
dotnet build src/CritterWatch.Services -p:EmbedFrontend=trueWithout -p:EmbedFrontend=true, the frontend is not embedded — it must be served by a separate dev server (the Aspire configuration handles this automatically).
Production Considerations
HTTPS
Always serve CritterWatch over HTTPS in production. CritterWatch gives operators significant control over your services — plaintext communication is a security risk.
// Enforce HTTPS redirection
app.UseHttpsRedirection();
app.UseHsts();
app.UseCritterWatch();Authentication
CritterWatch does not ship with built-in authentication. Add ASP.NET Core authentication middleware before UseCritterWatch():
app.UseAuthentication();
app.UseAuthorization();
// Protect the SignalR hub
app.MapHub<CommunicationHub>("/api/messages")
.RequireAuthorization();
app.UseCritterWatch();Network Isolation
In production, CritterWatch should not be publicly accessible. Place it behind a VPN, internal load balancer, or IP allowlist. The transport (RabbitMQ) connecting CritterWatch to your services should also be on an internal network.
Scaling
CritterWatch runs single-node by default — no extra configuration needed for small deployments. For horizontal scaling, the console supports a clustered topology (2+ BFF nodes behind a load balancer): per-service partitioning prevents two nodes from processing the same service's updates concurrently, leader-pinned ticks ensure alert evaluators and metrics scrapers fire exactly once across the cluster, and a Redis SignalR backplane fans push messages to every connected browser regardless of which node owns the WebSocket. See Clustering for the full topology, the opt-in configuration, and the trade-offs.
For single-node deployments — the default — use a process manager (systemd, Kubernetes) to restart CritterWatch automatically on failure.
Health Checks
Register ASP.NET Core health checks to monitor CritterWatch itself:
builder.Services.AddHealthChecks()
.AddNpgSql(connectionString, name: "critterwatch-db");
app.MapHealthChecks("/health");