A lightweight, high-performance HTTP redirect service with JSON-based configuration. Perfect for managing domain redirects in containerized environments like Coolify, or behind reverse proxies like Traefik.
- JSON Configuration - Simple, declarative redirect rules without environment variable complexity
- Multiple Sources per Rule - Redirect multiple domains to a single target
- Flexible Redirect Types - Support for
permanent(301),temporary(302), or any 3xx status code - Path & Query Preservation - Optionally preserve URL paths and query parameters
- Wildcard Support - Match subdomains with
*.domain.compatterns - Auto www Handling - Rules for
domain.comautomatically matchwww.domain.com - Proxy-Aware - Correctly handles
X-Forwarded-Hostheaders from reverse proxies - Trusted Proxy Mode - Configurable trust for proxy headers (
TRUST_PROXY) - Rate Limiting - Built-in protection against request flooding
- Secure by Default - Target URL validation prevents open redirect vulnerabilities
- Lightweight - ~30MB Docker image based on Alpine Linux
- Health Endpoint - Built-in
/healthendpoint for container orchestration
# Clone the repository
git clone https://github.com/bauer-group/CS-SimpleHTTPRedirector.git
cd CS-SimpleHTTPRedirector
# Create your configuration
cp config/redirects.example.json config/redirects.json
# Edit config/redirects.json with your redirect rules
# Start the service
docker compose up -d# Copy environment template
cp .env.example .env
# Edit .env with your settings
# Start with Traefik labels
docker compose -f docker-compose.traefik.yml up -d# Build and run with port mapping
docker compose -f docker-compose.development.yml up --build
# Test a redirect
curl -I -H "Host: example.com" http://localhost:8080/The configuration file is a JSON array of redirect rules:
[
{
"source": ["old-domain.com", "www.old-domain.com"],
"target": "https://new-domain.com",
"type": "permanent",
"preserve_path": true,
"preserve_query": true
},
{
"source": ["campaign.example.com"],
"target": "https://shop.example.com/promo",
"type": "temporary",
"preserve_path": false,
"preserve_query": true
},
{
"source": ["*.legacy.com"],
"target": "https://modern.com",
"type": "308",
"preserve_path": true,
"preserve_query": false
}
]| Property | Type | Required | Default | Description |
|---|---|---|---|---|
source |
string[] |
Yes | - | Array of source hostnames to match |
target |
string |
Yes | - | Target URL to redirect to |
type |
string |
No | permanent |
Redirect type (see below) |
preserve_path |
boolean |
No | false |
Append original path to target |
preserve_query |
boolean |
No | false |
Append query parameters to target |
| Type | HTTP Status | Use Case |
|---|---|---|
permanent |
301 | Permanent domain moves (SEO-friendly) |
temporary |
302 | Temporary redirects, A/B testing |
303 |
303 | Redirect after POST (See Other) |
307 |
307 | Temporary redirect preserving method |
308 |
308 | Permanent redirect preserving method |
Sources are matched in the following order:
- Exact match -
docs.example.commatchesdocs.example.com - Wildcard match -
*.example.commatchesanything.example.com - www handling -
example.comalso matcheswww.example.com(and vice versa)
Example with preserve_path: true:
source.com/products/item-123 → target.com/products/item-123
Example with preserve_query: true:
source.com?ref=campaign&id=42 → target.com?ref=campaign&id=42
Example with target path and preservation:
{
"source": ["old-docs.com"],
"target": "https://new-site.com/documentation/",
"preserve_path": true
}old-docs.com/api/v2 → new-site.com/documentation/api/v2
| File | Purpose | Network |
|---|---|---|
docker-compose.yml |
Coolify deployment | Coolify-managed |
docker-compose.traefik.yml |
Standalone with Traefik | External proxy network |
docker-compose.development.yml |
Local development | Host port 8080 |
Copy .env.example to .env and configure as needed:
# Server settings (all compose files)
TRUST_PROXY=true # Trust X-Forwarded-* headers (default: true)
# For docker-compose.traefik.yml
STACK_NAME=redirector # Container name prefix
PROXY_NETWORK=proxy # External Traefik network
CONFIG_PATH=./config # Config directory path
REDIRECT_HOST_RULE=Host(`...`) # Traefik routing rule
# For docker-compose.development.yml
HOST_PORT=8080 # Local port mapping| Variable | Default | Description |
|---|---|---|
TRUST_PROXY |
true |
Trust X-Forwarded-* headers from reverse proxy. Set to false if exposed directly to the internet. |
The service exposes a health endpoint at /health:
curl http://localhost:8080/health
# {"status":"healthy"}All redirects are logged with source, target, and status code:
2025/01/15 10:30:45 Loaded 3 redirect rules
2025/01/15 10:30:45 [old-domain.com www.old-domain.com] -> https://new-domain.com (301, path=true, query=true)
2025/01/15 10:30:45 Starting HTTP Redirector on port 8080
2025/01/15 10:31:02 Redirecting old-domain.com/page -> https://new-domain.com/page (301)
- Add repository as a Docker Compose project
- Select
docker-compose.yml - Configure domains in Coolify's GUI (add all source domains)
- Mount config volume or use Coolify's file manager to edit
config/redirects.json - Deploy
# Build the Docker image
docker build -t simple-http-redirector:latest ./src
# Build with specific Go version
docker build --build-arg GO_VERSION=1.25 -t simple-http-redirector:latest ./src┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Client │────▶│ Traefik/Proxy │────▶│ Redirector │
│ │ │ │ │ │
│ │◀────│ X-Forwarded-* │◀────│ 301/302/3xx │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ redirects.json │
└─────────────────┘
MIT License - see LICENSE for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
- Issues: GitHub Issues
- Documentation: GitHub Wiki