Use Cases¶
Navigator addresses common challenges in multi-tenant and distributed applications. This page describes some typical use cases with configuration examples.
Background¶
Navigator was designed to address challenges that arise in modern multi-tenant Rails applications, particularly those using SQLite for database-per-tenant architectures. While SQLite was the motivation for many features, Navigator is database-agnostic and works with any Rails backend.
Key Resources:
- Multi-Tenant Rails: Everybody Gets a Database - Mike Dalessio
- SQLite Replication with Beamer - Stephen Margheim
- Kamal Geo Proxy - Kevin McConnell
Navigator is inspired by Basecamp's Thruster and implemented as a reverse proxy in Go.
Quick Start¶
To use Navigator in your Dockerfile:
COPY --from=samruby/navigator:latest /navigator /usr/local/bin/navigator
CMD ["navigator", "config/navigator.yml"]
Use Case 1: Multi-Tenant and Monorepos¶
Challenge: Serve multiple tenants with isolated databases from a single codebase, potentially with different application components (API, admin, web).
Solution: Navigator launches separate instances of the same Rails application for each tenant, varying environment variables such as DATABASE_URL
.
Capabilities¶
- Multi-tenant setup: Multiple tenants sharing the same codebase with isolated databases using template variables
- Monorepo structure: API server, admin panel, and web server from different directories
- Managed processes: Background services like Sidekiq shared across tenants
- Different tenant types: Production, staging/demo, and development environments
Configuration Example¶
server:
listen: 3000
static:
public_dir: public
applications:
env:
DATABASE_URL: "sqlite3:db/${tenant_id}.sqlite3"
RAILS_ENV: "production"
tenants:
- name: acme
path: /acme
working_dir: /app
var:
tenant_id: acme_production
- name: widgets-co
path: /widgets
working_dir: /app
var:
tenant_id: widgets_production
How it works¶
- Each tenant has its own process and database
- Processes start on-demand and idle out when not in use
- Single Docker image serves all tenants
- Template variables customize environment per tenant
See multi-tenant-monorepo-example.yml for a complete example.
Use Case 2: Machine Auto-Suspend (Fly.io)¶
Challenge: Reduce costs and enable global distribution by automatically suspending or stopping machines when idle.
Solution: Navigator tracks active requests and triggers machine suspension or shutdown after a configurable idle timeout.
How it works¶
Fly.io supports autostop and suspend for idle machines. Navigator tracks active requests and triggers suspension/shutdown after a configurable timeout, enabling distribution across many machines that only run when needed.
Lifecycle Hooks¶
Navigator's lifecycle hooks enable powerful automation for machine state changes:
Pre-suspension hooks (idle
event) could:
- Upload databases and files to S3 or cloud storage
- Send metrics to monitoring services
- Notify other services about pending suspension
- Checkpoint long-running computations
Post-resume hooks (resume
event) could:
- Sync state from shared storage
- Reconnect to external services
- Notify monitoring systems of machine availability
- Restore application state
Configuration Example¶
server:
idle:
action: suspend # or "stop"
timeout: 20m
hooks:
server:
idle:
- command: /usr/local/bin/backup-to-s3.sh
timeout: 30s
resume:
- command: /usr/local/bin/restore-from-s3.sh
timeout: 30s
applications:
tenants:
- name: myapp
path: /
working_dir: /app
See suspend-stop-example.yml for a complete example.
Use Case 3: WebSocket Support¶
Challenge: Run WebSocket servers alongside Rails applications, especially with Rails 8's Solid Cable which requires Action Cable and Rails on the same machine.
Solution: Navigator acts as both reverse proxy and process manager, routing WebSocket requests to standalone servers.
Background¶
WebSockets enable two-way communication between server and browser, with connections typically open for minutes or hours. Rails recommends running a separate Standalone Cable Server for performance, scalability, and stability.
Rails 7 and earlier: Three services (Rails, Redis, Action Cable) Rails 8 with Solid Cable: Action Cable and Rails must run on the same machine
How it works¶
Navigator combines reverse proxy routing and process management in a single tool, eliminating the need for separate tools like Nginx/Traefik and Foreman/Overmind.
Configuration Example¶
server:
listen: 3000
static:
public_dir: public
# Reverse proxy WebSocket requests to standalone Action Cable server
reverse_proxies:
- name: action-cable
path: "^/cable"
target: "http://localhost:28080"
websocket: true
applications:
# Disable WebSocket tracking for main app (proxies WebSockets elsewhere)
track_websockets: true # Global default
tenants:
- name: main-app
path: /
working_dir: /app
track_websockets: false # Override: this app proxies WebSockets to standalone server
WebSocket Connection Tracking¶
Navigator can track WebSocket connections to prevent apps from shutting down during idle timeouts. This is useful when apps handle WebSockets directly, but unnecessary when proxying to standalone servers.
When to disable tracking: - Apps that proxy WebSockets to separate services (like example above) - Apps that don't handle WebSocket connections at all - When minimizing memory overhead is critical
See websockets-example.yml and WebSocket Support documentation for complete examples.
Use Case 4: Sticky Sessions¶
Challenge: Maintain session affinity so requests from the same client route to the same machine, crucial for WebSocket connections or locally stored data.
Solution: Navigator provides built-in sticky session support using HTTP cookies.
Features¶
- Cookie-based routing: Stores machine ID in HTTP-only cookie
- Cross-region support: Works across all Fly.io regions
- Automatic failover: Serves maintenance page if target machine unavailable
- Large request handling: Falls back to reverse proxy for requests >1MB
- Path-specific sessions: Optional configuration for specific URL paths
- Configurable duration: Session lifetime using Go duration format
Configuration Example¶
routes:
fly:
sticky_sessions:
enabled: true
cookie_name: "_navigator_machine"
cookie_max_age: "2h"
cookie_secure: true
cookie_httponly: true
paths:
- "/app/*"
- "/dashboard/*"
applications:
tenants:
- name: myapp
path: /
working_dir: /app
How it works¶
- Same user always routes to same machine
- Maintains long-lived WebSocket connections
- Enables machine-specific cached data
- No external session store required
See sticky-sessions-example.yml and Sticky Sessions feature page for more details.
Use Case 5: Dynamic Routing with Fly-Replay¶
Challenge: Route requests to specific regions, apps, or machines while handling failures gracefully.
Solution: Navigator implements Fly.io's Dynamic Routing with smart fallback behavior.
Fly-Replay Modes¶
Prefer mode: Requests that can't route to intended destination go to available server Force mode: Failed routing returns error
Navigator's Approach¶
Navigator takes a middle ground: when requests can't be routed to the intended destination, it shows a user-friendly maintenance page that can be searched in logs. This is better than silent failures and provides visibility for debugging.
Configuration Example¶
server:
listen: 3000
routes:
fly:
replay:
- path: "^/api/"
app: api-backend
status: 307
- path: "^/admin/"
region: ord # Chicago
status: 307
applications:
tenants:
- name: web-app
path: /
working_dir: /app
Features¶
- Multi-target routing: Route to regions, apps, or specific machines
- Smart fallback: Automatic reverse proxy for requests >1MB
- Maintenance pages: User-friendly error pages
- Pattern matching: Flexible URL pattern configuration
- Method filtering: Apply rules to specific HTTP methods
See routing-example.yml for a complete example.
Future Use Case Ideas¶
While Navigator currently focuses on the use cases above, there are several interesting directions worth exploring based on production usage patterns and community feedback.
A/B Testing and Feature Flags¶
Route different users to different application instances based on cookies, headers, or URL parameters. This would enable:
- Testing new features with a subset of users
- Gradual feature rollouts
- Canary deployments at the proxy level
- User cohort experimentation
Potential Configuration:
routing:
ab_tests:
- name: new-ui-test
header: X-Feature-Flag
value: new-ui
target: /v2
percentage: 10 # 10% of users
Rate Limiting and Protection¶
Per-tenant or per-IP rate limiting to prevent abuse:
- Automatic blocking of suspicious traffic patterns
- Per-tenant request quotas
- Integration with fail2ban or similar tools
- DDoS protection at the application level
Potential Configuration:
rate_limiting:
global:
requests_per_minute: 1000
per_tenant:
requests_per_minute: 100
per_ip:
requests_per_minute: 60
Health Checks and Circuit Breakers¶
Automatic health monitoring with resilience patterns:
- Health checks for tenant apps before proxying (already implemented)
- Circuit breaker patterns to prevent cascading failures
- Graceful degradation when services are unavailable
- Automatic retry with exponential backoff for Fly-Replay fallback (already implemented)
Potential Configuration:
health_checks:
interval: 30s
timeout: 5s
unhealthy_threshold: 3
circuit_breaker:
failure_threshold: 5
timeout: 60s
Enhanced Observability¶
Integration with observability platforms:
- Datadog, New Relic, Honeycomb integration
- OpenTelemetry distributed tracing
- Prometheus metrics endpoint (planned)
- Comprehensive monitoring across all tenants
Potential Configuration:
observability:
opentelemetry:
enabled: true
endpoint: http://collector:4318
prometheus:
enabled: true
path: /metrics
Request Transformation¶
Advanced request/response manipulation:
- Header injection and removal
- Request/response body transformation
- Content negotiation
- Protocol upgrades (HTTP/1.1 → HTTP/2)
Geographic Routing Intelligence¶
Smarter geographic routing based on:
- Client IP geolocation
- Latency measurements
- Regional capacity
- Time-of-day patterns
These ideas represent potential evolution paths as usage patterns and requirements emerge from production deployments. Community feedback and real-world needs will guide prioritization.
Choosing Your Use Case¶
Your Scenario | Recommended Use Case | Key Features |
---|---|---|
Multiple customers with separate DBs | Multi-Tenant (#1) | Process isolation, template variables |
Global deployment on Fly.io | Auto-Suspend (#2) | Cost optimization, lifecycle hooks |
Rails 8 with Solid Cable | WebSockets (#3) | Process management, routing |
Stateful sessions across regions | Sticky Sessions (#4) | Cookie-based affinity |
Multi-region deployment | Dynamic Routing (#5) | Fly-Replay, maintenance pages |
See Also¶
- Examples - Complete configuration examples
- Features - Detailed feature documentation
- Configuration Reference - Complete YAML reference
- Architecture - Technical implementation details
- Deployment - Production deployment guides