A high-performance, enterprise-grade URL redirect and response service built in Go.
The Redirector handles URL redirects and custom responses at massive scale with sub-millisecond latency. Unlike general-purpose reverse proxies, it's purpose-built for redirect workloads with features designed for enterprise environments.
Built by a DevOps/Platform Engineer with an emphasis on decentralized configuration ownership. Teams that own redirects can manage their own rules — via GitHub repos, S3 buckets, or any supported source — without depending on a DevOps or Platform Engineering team to make changes on their behalf. The syncer merges multiple team configs with conflict detection and priority-based resolution. For organizations that prefer centralized management, the same architecture works with a single config source.
Domain & URL migrations — Redirect entire domains or URL structures during rebrands, acquisitions, or site reorganizations. Exact, prefix, regex, and glob matching let you handle everything from simple page moves to complex path transformations with capture groups.
SEO preservation — Maintain search engine rankings by issuing proper 301/308 redirects when content moves. Per-rule status codes mean you can return 410 Gone for permanently removed content or 404 for paths you want to disappear from crawlers.
Vanity URLs & short links — Serve /go/slack, /go/wiki, or marketing campaign URLs that redirect to internal or external destinations. Teams manage their own redirect rules via GitHub repos, S3 buckets, or any supported source — no tickets to a platform team required.
Legacy API deprecation — Redirect old API versions to new ones with path rewriting and capture groups (/api/v1/users/123 -> /api/v2/users/123). Return 503 with Retry-After headers during maintenance windows.
Bot & abuse mitigation — Return 404 or 403 for known bot paths (/wp-admin, /.env) and use the host allowlist to reject traffic for unknown domains at O(1) cost before any rule evaluation, providing built-in DDoS protection.
Multi-team configuration at scale — Each team owns their redirect rules in their own repo or config source. The redirector-sync service merges configs from GitHub, GitLab, S3, Azure Blob, GCS, Consul, etcd, and more — with conflict detection, linting, and priority-based resolution.
- Blazing Fast: Built on fasthttp with radix tree routing for < 1ms p99 latency
- Flexible Matching: Exact paths, prefixes, regex with capture groups, and glob wildcards
- Host Allowlist: O(1) early rejection of unknown hosts for DDoS mitigation
- Any HTTP Response: Not just redirects - return 404, 403, 503, or any status with custom bodies
- Header Injection: Add custom headers to any response
- Multi-File Config: Split rules across multiple YAML files for team organization
- Live Monitoring: htop-style TUI for real-time request debugging
- Config Linting: Detect duplicates, conflicts, and performance issues before deployment
- Decoupled Architecture: Separate redirector-sync service for complex config management
- Observable: Stats endpoints, structured logging with rotation
| Binary | Description |
|---|---|
redirector |
Main redirect server |
redirector-sync |
Config sync + lint |
redirector-tui |
Live monitoring dashboard |
# Build all binaries
go build ./...
# Or build individually
go build -o bin/redirector ./cmd/redirector
go build -o bin/redirector-sync ./cmd/redirector-sync
go build -o bin/redirector-tui ./cmd/redirector-tui# Start the redirector
./bin/redirector -config config.yaml
# In another terminal, start the TUI monitor
./bin/redirector-tui -url http://localhost:8081
# Trigger immediate config reload
./bin/redirector sync# Test a redirect
curl -I http://localhost:8080/old-home
# HTTP/1.1 301 Moved Permanently
# Location: https://example.com/
# X-Redirected-By: the-redirector
# X-Rule-ID: homepage-redirectredirector # Start the server
redirector sync # Trigger config reload
redirector version # Show version
redirector help # Show helpBasic structure of a redirector config file:
version: "1.0"
server:
port: 8080 # Redirect traffic port
management_port: 8081 # Stats/health API port
read_timeout: 5s
write_timeout: 5s
defaults:
status_code: 301
preserve_query: true
headers:
X-Powered-By: "the-redirector"
stats:
enabled: true
buffer_size: 1000
sampling_rate: 1.0
rules:
- id: my-rule
match:
type: exact # exact, prefix, regex, or glob
path: /old-path
redirect:
to: https://example.com/new-path
status: 301For a complete reference of every configuration field (server, auth, tracing, rate limiting, logging, and all syncer source types), see docs/CONFIGURATION.md.
The redirector supports four match types — exact, prefix, regex (with capture groups), and glob (with *, **, ? wildcards). Rules can return any HTTP status code, not just redirects.
Short-form rules are also supported for managing large rule sets:
rules:
- /old -> https://new.com
- /blog/* -> https://blog.example.com/ [301, preserve_path]
- ^/product/(\d+)$ -> https://shop.example.com/item/$1 [302]For full details, examples, CSV format, and include files, see docs/RULE_TYPES.md.
When rules specify match.host, the redirector automatically builds an O(1) host allowlist. Requests for unknown hosts are rejected immediately with 421 Misdirected Request — before any rule scanning.
flowchart TD
A[Incoming Request] --> B{Host in allowlist?}
B -- No --> C[421 Misdirected Request<br/>zero rule scanning]
B -- Yes --> D[Match rules<br/>exact / prefix / regex / glob]
D --> E[Response]
The allowlist is derived automatically from match.host fields across all rules. If any rule omits match.host, the allowlist is disabled (that rule is a catch-all).
For full details, see the Host Allowlist section in docs/RULE_TYPES.md.
The management API runs on a separate port (default: 8081) with health checks, stats, config inspection, and Prometheus metrics.
curl http://localhost:8081/health # Liveness probe
curl http://localhost:8081/ready # Readiness probe
curl http://localhost:8081/stats # Summary statistics
curl http://localhost:8081/api/v1/config # Config info
curl -X POST http://localhost:8081/api/v1/reload # Trigger reloadFor all endpoints, Prometheus metrics, and authentication details, see docs/MANAGEMENT_API.md.
Both the redirector and redirector-sync expose a /metrics endpoint in Prometheus text format.
Scrape the redirector:
# prometheus.yml
scrape_configs:
- job_name: redirector
static_configs:
- targets: ['localhost:8081']
- job_name: redirector-sync
static_configs:
- targets: ['localhost:9090'] # webhook server portVerify locally:
# Redirector metrics
curl -s http://localhost:8081/metrics | head -20
# Key metrics to watch:
# redirector_requests_total - request volume by status/rule
# redirector_request_duration_seconds - latency histogram (p50/p99)
# redirector_requests_in_flight - current concurrency
# redirector_config_rules_count - loaded rules
# redirector_rate_limited_total - rate-limited requests by scope
# redirector_host_rejected_total - DDoS-rejected requests
# redirector_build_info - version/commit for deploy tracking
# redirector_uptime_seconds - process uptime
# redirector_config_info - current config version/hash
# process_* / go_* - standard Go runtime metricsSyncer metrics (available when webhook server is enabled):
curl -s http://localhost:9090/metrics | head -20
# Key metrics:
# redirector_sync_sync_total - sync success/failure count
# redirector_sync_last_sync_success - 1 if last sync OK, 0 if failed
# redirector_sync_fetch_duration_seconds - source fetch latency
# redirector_sync_push_total - push success/failure per target
# redirector_sync_lint_errors_total - config validation failuresExample Grafana alert (PromQL):
# Alert if no successful sync in 10 minutes
time() - redirector_sync_last_sync_timestamp_seconds > 600
and redirector_sync_last_sync_success == 0
# Alert on high error rate
rate(redirector_requests_total{status="5xx"}[5m])
/ rate(redirector_requests_total[5m]) > 0.01
# Alert on rate limiting
rate(redirector_rate_limited_total[5m]) > 0
For the full metrics reference, see docs/MANAGEMENT_API.md.
Separate service for pulling configuration from multiple sources (S3, GitHub, GitLab, Azure Blob, GCS, Consul, etcd, HTTP, AWS Parameter Store, AWS Secrets Manager) with failover, multi-team merging, and integrated config linting.
./redirector-sync --config syncer.yaml # Continuous sync
./redirector-sync --config syncer.yaml --one-shot # Fetch once and exit
./redirector-sync --lint --lint-config config.yaml # Validate configFor full setup, source types, conflict resolution, and linting details, see docs/SYNCER.md.
Live monitoring dashboard with htop-style interface.
Generated with VHS. Regenerate: vhs docs/tui-demo.tape
./redirector-tui --url http://localhost:8081Features: real-time request stream, sorting, filtering, latency histogram, and multi-team config conflict view.
For keyboard shortcuts and full details, see docs/TUI.md.
Docker, Kubernetes, and performance tuning guides are available in docs/DEPLOYMENT.md.
| Document | Description |
|---|---|
| Configuration Reference | Every config field for redirector, syncer, and CLI flags |
| Rule Types | Match types, non-redirect responses, host routing, compact formats |
| Management API | Health, stats, config, and Prometheus endpoints |
| Syncer | Multi-source config sync, linting, conflict resolution |
| TUI | Live monitoring dashboard |
| Deployment | Docker, Kubernetes, performance tuning |
| Architecture | Internal design and data flow |
| Features | Feature overview and design decisions |
| GitHub Integration | GitHub App and PAT setup |
| Load Testing | Load testing methodology |
| Performance | Benchmark results |
the-redirector/
├── cmd/
│ ├── redirector/ # Main server
│ ├── redirector-sync/ # Config sync + lint service
│ └── redirector-tui/ # Live monitoring TUI
├── internal/
│ ├── config/ # YAML parsing, validation
│ ├── router/ # Radix tree + regex routing
│ ├── server/ # fasthttp server
│ ├── stats/ # Ring buffer stats
│ ├── lint/ # Linting rules
│ ├── logging/ # Log rotation
│ └── providers/ # Config sources (file, http, github, gitlab, s3, etc.)
├── pkg/redirect/ # Public types
├── config.yaml # Sample configuration
├── syncer.yaml # Sample syncer configuration
└── docs/ # Additional documentation
# Run unit tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run integration tests (requires Docker)
make integration-test
# Build all binaries
go build ./...
# Format code
go fmt ./...
# Vet code
go vet ./...Integration tests run against real services using free emulators:
| Service | Emulator |
|---|---|
| AWS (S3, SSM, Secrets Manager) | LocalStack |
| Azure Blob Storage | Azurite |
| GCP Cloud Storage | fake-gcs-server |
| Consul | Official Docker image |
| etcd | Official Docker image |
make integration-up # Start test infrastructure
make integration-test # Run integration tests
make integration-down # Stop test infrastructureSee IMPLEMENTATION_PLAN.md for detailed status.
Completed:
- Prometheus metrics endpoint
- Hot reload with fsnotify
- Full AWS S3/Parameter Store/Secrets Manager integration
- Azure Blob, GCP Cloud Storage, Consul, etcd integrations
- GitHub integration (PAT + GitHub App JWT auth, release/branch/tag strategies, tag pattern matching)
- GitLab integration (PAT, OAuth2 with auto token refresh, release/branch/tag strategies, tag pattern matching)
- HTTP/HTTPS endpoint provider (bearer/basic auth, ETag caching, custom headers)
- OpenTelemetry tracing
- Load testing infrastructure
- redirector-sync (formerly config-syncer) refactored to use provider Registry (no duplicate source implementations)
- Comprehensive test coverage across all providers (unit + integration)
Upcoming:
- Multi-tenancy support
MIT License - see LICENSE for details.
- fasthttp - High-performance HTTP
- zerolog - Zero-allocation logging
- lumberjack - Log rotation
- bubbletea - TUI framework
- lipgloss - TUI styling
