Local network tool that transparently redirects all X/Twitter traffic to xcancel.com, allowing you to browse Twitter content without directly accessing X's servers.
Caddy is a simpler alternative to nginx with automatic HTTPS handling and a much more readable configuration format.
Caddy is better if you want:
nginx is better if you:
For this project (simple redirect): Either works great! Caddy is simpler.
twitter.com, www.twitter.com, x.com, www.x.com, t.co, www.t.co {
tls /etc/caddy/ssl/twitter_bundle.pem /etc/caddy/ssl/twitter_key.pem
redir https://xcancel.com{uri} permanent
}
server {
ssl_protocols TLSv1.2 TLSv1.3;
listen 443 ssl;
listen 80;
http2 on;
listen 443 quic reuseport;
server_name twitter.com www.twitter.com x.com www.x.com t.co www.t.co _;
ssl_certificate /etc/nginx/ssl/twitter_bundle.pem;
ssl_certificate_key /etc/nginx/ssl/twitter_key.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
add_header Alt-Svc 'h3=":443"; ma=86400' always;
add_header X-Protocol $server_protocol always;
location / {
return 301 https://xcancel.com$request_uri;
}
}
Both do the exact same thing. Caddy is just more concise.
# Instead of docker-compose.yaml, use docker-compose.caddy.yaml
docker compose -f docker-compose.caddy.yaml up -d
Caddy uses:
caddy/Caddyfile - Main configuration (already configured)caddy/ssl/ - SSL certificates (same as nginx)Same process as nginx! Generate certificates using either:
Then copy to caddy/ssl/:
# mkcert example
mkcert twitter.com x.com "*.twitter.com" "*.x.com" t.co "*.t.co"
cp twitter.com+5.pem caddy/ssl/twitter_bundle.pem
cp twitter.com+5-key.pem caddy/ssl/twitter_key.pem
chmod 644 caddy/ssl/twitter_bundle.pem
chmod 600 caddy/ssl/twitter_key.pem
# Start Caddy
docker compose -f docker-compose.caddy.yaml up -d
# Check logs
docker compose -f docker-compose.caddy.yaml logs -f caddy
# Check status
docker compose -f docker-compose.caddy.yaml ps
Same as nginx! Configure your DNS to point domains to Caddy’s IP:
Use the same test script:
./scripts/test-redirect.sh
The script works with both nginx and Caddy - it tests DNS and redirects, not the server implementation.
Same as nginx - choose bridge or macvlan:
Bridge (default, simpler):
# Uses ports 80 and 443 on host
docker compose -f docker-compose.caddy.yaml up -d
Macvlan (for dedicated IP):
docker-compose.caddy.yamlmacvlan_lan networknetworks section in caddy serviceports section.env with your network settingsdocker compose -f docker-compose.caddy.yaml logs -f caddy
docker compose -f docker-compose.caddy.yaml restart caddy
Caddy automatically reloads when Caddyfile changes! No restart needed if you mount the file as a volume (which we do).
Or manually:
docker compose -f docker-compose.caddy.yaml exec caddy caddy reload --config /etc/caddy/Caddyfile
docker compose -f docker-compose.caddy.yaml down
Already using nginx and want to switch?
# Stop nginx
docker compose down
# Start Caddy
docker compose -f docker-compose.caddy.yaml up -d
# Copy SSL certificates if in different location
cp nginx/ssl/twitter_bundle.pem caddy/ssl/
cp nginx/ssl/twitter_key.pem caddy/ssl/
DNS stays the same - just point to the new container’s IP (or same IP if using same host).
# Stop Caddy
docker compose -f docker-compose.caddy.yaml down
# Start nginx
docker compose up -d
# Copy SSL certificates if needed
cp caddy/ssl/twitter_bundle.pem nginx/ssl/
cp caddy/ssl/twitter_key.pem nginx/ssl/
Edit caddy/Caddyfile:
twitter.com, www.twitter.com, x.com, www.x.com, t.co, www.t.co {
# Remove the tls line
redir https://xcancel.com{uri} permanent
}
twitter.com, www.twitter.com, x.com, www.x.com, t.co, www.t.co {
tls /etc/caddy/ssl/twitter_bundle.pem /etc/caddy/ssl/twitter_key.pem
redir https://your-alternative-frontend.com{uri} permanent
}
twitter.com, www.twitter.com, x.com, www.x.com, t.co, www.t.co, additional.domain {
tls /etc/caddy/ssl/twitter_bundle.pem /etc/caddy/ssl/twitter_key.pem
redir https://xcancel.com{uri} permanent
}
twitter.com, www.twitter.com, x.com, www.x.com, t.co, www.t.co {
tls /etc/caddy/ssl/twitter_bundle.pem /etc/caddy/ssl/twitter_key.pem
log {
output file /var/log/caddy/access.log
}
redir https://xcancel.com{uri} permanent
}
Then mount a log directory:
volumes:
- ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
- ./caddy/ssl:/etc/caddy/ssl:ro
- ./caddy/logs:/var/log/caddy # Add this
# Check logs
docker compose -f docker-compose.caddy.yaml logs caddy
# Common issues:
# - Port 80 or 443 already in use
# - Invalid Caddyfile syntax
# - SSL certificate files missing or wrong permissions
# Verify certificates exist
ls -l caddy/ssl/
# Check permissions
# - .pem files: 644 (readable)
# - .key files: 600 (read by owner only)
# Test certificate
openssl x509 -in caddy/ssl/twitter_bundle.pem -text -noout
# Validate Caddyfile syntax
docker compose -f docker-compose.caddy.yaml exec caddy caddy validate --config /etc/caddy/Caddyfile
# Reload configuration
docker compose -f docker-compose.caddy.yaml exec caddy caddy reload --config /etc/caddy/Caddyfile
If you have nginx still running:
# Stop nginx first
docker compose down
# Then start Caddy
docker compose -f docker-compose.caddy.yaml up -d
Or use different ports in .env:
HTTP_PORT=8080
HTTPS_PORT=8443
For this simple redirect use case:
Difference is negligible for home/small network use. Both handle way more traffic than you’ll ever see.
Caddy has many features we’re not using here:
For our simple redirect, we’re just scratching the surface of what Caddy can do.
For this project:
Both work perfectly for this redirect. The choice is personal preference.