Skip to content

Hosting Guide

CritterWatch supports several hosting topologies. Choose based on your team's needs and infrastructure constraints.

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
csharp
// 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.

csharp
// 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.

csharp
// 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. See src/BffHost/Program.cs in 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:

bash
dotnet pack src/CritterWatch.Services -p:EmbedFrontend=true

Or for a regular build:

bash
dotnet build src/CritterWatch.Services -p:EmbedFrontend=true

Without -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.

csharp
// 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():

csharp
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:

csharp
builder.Services.AddHealthChecks()
    .AddNpgSql(connectionString, name: "critterwatch-db");

app.MapHealthChecks("/health");

Released under the MIT License.