Reverse Proxy & Traffic Management Skill
This skill enables management of incoming internet traffic and reverse proxy configuration on the home network, specifically focused on the Raspberry Pi gateway running Caddy, OAuth2-proxy, and fail2ban security.
Overview
The reverse-proxy skill provides capabilities to manage the public-facing gateway server (raspberrypi.local) that handles:
- •HTTPS termination with Let's Encrypt
- •OAuth2 authentication for protected services
- •Security monitoring with fail2ban
- •Reverse proxying to internal services
This server is the source of truth for all incoming traffic configuration. Reference repository: /home/seth/Software/dev/squelch
Gateway Server
raspberrypi (Gateway/Proxy Server)
- •Host: raspberrypi.local (192.168.0.76)
- •SSH:
ssh pi(port 2222) - •Public Domain: lab.sethlakowske.com
- •Role: Internet gateway, reverse proxy, OAuth gateway, security enforcement
- •Key Services:
- •Caddy (port 443 HTTPS, port 80 HTTP)
- •oauth2-proxy-google (port 4180)
- •oauth2-proxy-good-neighbor (port 4182)
- •oauth2-proxy-service-monitor (port 4183)
- •fail2ban (security)
- •service-monitor (port 8000)
Configuration Repository
- •Location:
/home/seth/Software/dev/squelch - •Structure:
- •
oauth-caddy-package/- OAuth2 authentication package - •
squelch-package/- fail2ban security package - •
config-backup/- Production configuration backups - •
CLAUDE.md- Complete architecture documentation
- •
Architecture
Internet (lab.sethlakowske.com)
|
v
[Caddy :443] ────── Let's Encrypt HTTPS
|
├─> /oauth2/* ──> [oauth2-proxy :4180] Google Auth
├─> /good-neighbor/* ──> [oauth2-proxy :4182] ──> Backend :3000
├─> /service-monitor/* ──> [oauth2-proxy :4183] ──> Backend :8000
└─> /* ──> Backend :8080 (public)
|
v
[fail2ban] monitors /var/log/caddy/access.log
|
v
[iptables] blocks malicious IPs
Common Operations
1. Check Gateway Status
# Check all critical services ssh pi "systemctl status caddy oauth2-proxy-google oauth2-proxy-good-neighbor oauth2-proxy-service-monitor fail2ban" # Quick status check ssh pi "systemctl is-active caddy oauth2-proxy-google fail2ban" # Check if services are listening on expected ports ssh pi "sudo ss -tlnp | grep -E '(443|4180|4182|4183|8000)'"
2. Manage Caddy
# Check Caddy status ssh pi "systemctl status caddy" # View Caddy configuration ssh pi "cat /etc/caddy/Caddyfile" # Validate Caddy configuration ssh pi "sudo caddy validate --config /etc/caddy/Caddyfile" # Reload Caddy (graceful, no downtime) ssh pi "sudo systemctl reload caddy" # Restart Caddy (brief downtime) ssh pi "sudo systemctl restart caddy" # View Caddy logs ssh pi "journalctl -u caddy -n 100 --no-pager" ssh pi "journalctl -u caddy -f" # Follow logs # View access logs (JSON format) ssh pi "tail -f /var/log/caddy/access.log" ssh pi "tail -100 /var/log/caddy/access.log | jq ."
3. Manage OAuth2-Proxy Services
# Check all OAuth proxy services ssh pi "systemctl status oauth2-proxy-google" ssh pi "systemctl status oauth2-proxy-good-neighbor" ssh pi "systemctl status oauth2-proxy-service-monitor" # Restart specific OAuth proxy ssh pi "sudo systemctl restart oauth2-proxy-google" # View OAuth proxy logs ssh pi "journalctl -u oauth2-proxy-google -n 50 --no-pager" ssh pi "journalctl -u oauth2-proxy-good-neighbor -f" # Check OAuth proxy configuration ssh pi "cat /etc/oauth2-proxy/google.cfg" ssh pi "cat /etc/oauth2-proxy/good-neighbor.cfg" # Test OAuth proxy health ssh pi "curl -s http://localhost:4180/ping"
4. Manage fail2ban Security
# Check fail2ban status ssh pi "sudo systemctl status fail2ban" # View all active jails ssh pi "sudo fail2ban-client status" # View specific jail status ssh pi "sudo fail2ban-client status sshd" ssh pi "sudo fail2ban-client status squelch-caddy-auth" ssh pi "sudo fail2ban-client status squelch-caddy-badbots" ssh pi "sudo fail2ban-client status squelch-caddy-scan" # List banned IPs ssh pi "sudo squelch-ban list" ssh pi "sudo squelch-ban list squelch-caddy-auth" # Ban an IP manually ssh pi "sudo squelch-ban ban 1.2.3.4 squelch-caddy-auth" # Unban an IP ssh pi "sudo squelch-ban unban 1.2.3.4" # Check if IP is banned ssh pi "sudo squelch-ban check 1.2.3.4" # View fail2ban logs ssh pi "sudo journalctl -u fail2ban -n 100 --no-pager" ssh pi "sudo journalctl -u fail2ban | grep Ban"
5. Security Status Dashboard
# View comprehensive security status ssh pi "sudo squelch-status" # Real-time security monitoring ssh pi "sudo squelch-monitor" # Check recent authentication failures ssh pi "sudo journalctl -u fail2ban --since '1 hour ago' | grep -E '(Ban|Found)'" # View recent access patterns ssh pi "tail -100 /var/log/caddy/access.log | jq -r '.request.remote_ip' | sort | uniq -c | sort -nr"
6. Add New Protected Route
To add a new service behind OAuth authentication:
- •
Verify backend service is running:
bash# Test backend health curl -s http://ubuntu-box.local:3001/health
- •
Create OAuth2-proxy configuration:
bash# SSH to gateway ssh pi # Create new OAuth config (based on template) sudo cp /etc/oauth2-proxy/good-neighbor.cfg.template /etc/oauth2-proxy/new-service.cfg # Edit configuration sudo nano /etc/oauth2-proxy/new-service.cfg # Update: # - http_address = "127.0.0.1:4184" (new port) # - upstreams = ["http://ubuntu-box.local:3001/"] # - cookie_name = "_oauth2_proxy_new_service" # - redirect_url = "https://lab.sethlakowske.com/new-service/oauth2/callback"
- •
Create systemd service:
bashsudo cat > /etc/systemd/system/oauth2-proxy-new-service.service << 'EOF'
[Unit] Description=OAuth2 Proxy for New Service After=network.target
[Service] Type=simple User=www-data Group=www-data ExecStart=/usr/bin/oauth2-proxy --config=/etc/oauth2-proxy/new-service.cfg Restart=always RestartSec=5
[Install] WantedBy=multi-user.target EOF
Enable and start service
sudo systemctl daemon-reload sudo systemctl enable oauth2-proxy-new-service sudo systemctl start oauth2-proxy-new-service sudo systemctl status oauth2-proxy-new-service
4. **Update Caddyfile**:
```bash
sudo nano /etc/caddy/Caddyfile
# Add route (before the catch-all /* route):
# route /new-service* {
# reverse_proxy localhost:4184
# }
- •
Apply Caddy changes:
bash# Validate configuration sudo caddy validate --config /etc/caddy/Caddyfile # Reload Caddy (graceful) sudo systemctl reload caddy
- •
Verify setup:
bash# Test OAuth proxy curl -s http://localhost:4184/ping # Test public endpoint (should redirect to OAuth) curl -I https://lab.sethlakowske.com/new-service/
- •
Backup configuration:
bash# From local machine scp pi:/etc/caddy/Caddyfile ~/Software/dev/squelch/config-backup/caddy/ scp pi:/etc/oauth2-proxy/new-service.cfg ~/Software/dev/squelch/config-backup/oauth2-proxy/
7. Add Public (Non-Authenticated) Route
For services that don't require OAuth:
- •
Update Caddyfile:
bashssh pi "sudo nano /etc/caddy/Caddyfile" # Add route (order matters - more specific first): # route /public-api/* { # reverse_proxy ubuntu-box.local:3002 # } - •
Reload Caddy:
bashssh pi "sudo caddy validate --config /etc/caddy/Caddyfile && sudo systemctl reload caddy"
- •
Test:
bashcurl -s https://lab.sethlakowske.com/public-api/health | jq .
8. Update Backend Port Mapping
To change where a route proxies to:
- •
For OAuth-protected routes, update OAuth2-proxy config:
bashssh pi "sudo nano /etc/oauth2-proxy/good-neighbor.cfg" # Change: upstreams = ["http://ubuntu-box.local:NEW_PORT/"] ssh pi "sudo systemctl restart oauth2-proxy-good-neighbor"
- •
For public routes, update Caddyfile:
bashssh pi "sudo nano /etc/caddy/Caddyfile" # Change reverse_proxy line ssh pi "sudo systemctl reload caddy"
9. View Current Route Configuration
# View Caddyfile routes ssh pi "cat /etc/caddy/Caddyfile | grep -A 2 'route'" # View all OAuth proxy upstreams ssh pi "grep 'upstreams' /etc/oauth2-proxy/*.cfg" # Show all listening services ssh pi "sudo ss -tlnp | grep -E '(caddy|oauth2-proxy)'"
10. Analyze Traffic Patterns
# Top IPs accessing the server
ssh pi "tail -1000 /var/log/caddy/access.log | jq -r '.request.remote_ip' | sort | uniq -c | sort -nr | head -10"
# Most requested URIs
ssh pi "tail -1000 /var/log/caddy/access.log | jq -r '.request.uri' | sort | uniq -c | sort -nr | head -10"
# Failed authentication attempts (401/403)
ssh pi "tail -1000 /var/log/caddy/access.log | jq 'select(.status == 401 or .status == 403)'"
# Response time analysis
ssh pi "tail -1000 /var/log/caddy/access.log | jq -r '.duration' | awk '{sum+=\$1; count++} END {print \"Average:\", sum/count, \"seconds\"}'"
# Status code distribution
ssh pi "tail -1000 /var/log/caddy/access.log | jq -r '.status' | sort | uniq -c | sort -nr"
Configuration Files Reference
Critical Configuration Files
| File | Purpose | Service |
|---|---|---|
/etc/caddy/Caddyfile | Main reverse proxy configuration | caddy |
/etc/oauth2-proxy/google.cfg | Google OAuth for general use | oauth2-proxy-google |
/etc/oauth2-proxy/good-neighbor.cfg | OAuth for good-neighbor service | oauth2-proxy-good-neighbor |
/etc/oauth2-proxy/service-monitor.cfg | OAuth for service-monitor | oauth2-proxy-service-monitor |
/etc/fail2ban/jail.d/squelch.conf | fail2ban jail configuration | fail2ban |
/etc/fail2ban/filter.d/squelch-*.conf | fail2ban filters | fail2ban |
/var/log/caddy/access.log | HTTP access logs (JSON) | caddy |
Configuration Backup Location
All production configs should be backed up to:
~/Software/dev/squelch/config-backup/
├── caddy/
│ ├── Caddyfile
│ └── Caddyfile.template
└── oauth2-proxy/
├── google.cfg
├── good-neighbor.cfg
├── service-monitor.cfg
└── *.cfg.template
Backup Workflow
# Backup current production configs ssh pi "cat /etc/caddy/Caddyfile" > ~/Software/dev/squelch/config-backup/caddy/Caddyfile ssh pi "cat /etc/oauth2-proxy/google.cfg" > ~/Software/dev/squelch/config-backup/oauth2-proxy/google.cfg # Or use scp scp pi:/etc/caddy/Caddyfile ~/Software/dev/squelch/config-backup/caddy/ scp pi:/etc/oauth2-proxy/*.cfg ~/Software/dev/squelch/config-backup/oauth2-proxy/ # Commit to git cd ~/Software/dev/squelch git add config-backup/ git commit -m "Backup production proxy configs" git push
Routing Patterns
Current Routes (lab.sethlakowske.com)
Based on the production Caddyfile:
| Route | Auth | Backend | Port | Description |
|---|---|---|---|---|
/oauth2/* | No | oauth2-proxy | 4180 | OAuth callback handler |
/good-neighbor* | Yes (Google) | good-neighbor | 3000 | Protected service |
/service-monitor* | Yes (Google) | service-monitor | 8000 | Protected monitoring |
/* | No | default backend | 8080 | Public routes |
Caddy Route Ordering
IMPORTANT: Caddy processes routes in order. More specific routes must come BEFORE catch-all routes:
lab.sethlakowske.com {
log {
output file /var/log/caddy/access.log
}
# OAuth callback (most specific)
route /oauth2/* {
reverse_proxy localhost:4180
}
# Protected service routes
route /good-neighbor* {
reverse_proxy localhost:4182
}
route /service-monitor* {
reverse_proxy localhost:4183
}
# Catch-all public routes (LAST)
route /* {
reverse_proxy localhost:8080
}
}
Security Monitoring
fail2ban Jails
| Jail Name | Purpose | Trigger | Max Retry | Ban Time |
|---|---|---|---|---|
sshd | SSH brute force | Failed SSH login | 2 | 24h |
squelch-caddy-auth | Auth failures | 401/403 responses | 5 | 1h+ |
squelch-caddy-badbots | Bad bots/scanners | Attack paths | 2 | 1h+ |
squelch-caddy-scan | Directory scanning | Multiple 404s | 3 | 1h+ |
Ban Escalation
fail2ban uses progressive ban times:
- •1st offense: 1 hour
- •2nd offense: 2 hours
- •3rd offense: 4 hours
- •Continues doubling up to max 168h (7 days)
Monitoring Commands
# Real-time ban events
ssh pi "sudo journalctl -u fail2ban -f | grep Ban"
# Recently banned IPs
ssh pi "sudo journalctl -u fail2ban --since '1 hour ago' | grep 'Ban '"
# Ban statistics
ssh pi "sudo fail2ban-client status | grep 'Currently banned:'"
# Analyze attack patterns
ssh pi "tail -1000 /var/log/caddy/access.log | jq 'select(.status >= 400) | {ip: .request.remote_ip, status: .status, uri: .request.uri}'"
Troubleshooting
Problem: Service Not Accessible from Internet
- •
Check Caddy is running and listening:
bashssh pi "systemctl status caddy" ssh pi "sudo ss -tlnp | grep :443"
- •
Check route configuration:
bashssh pi "cat /etc/caddy/Caddyfile | grep -A 3 'route /your-service'"
- •
Test from gateway server:
bashssh pi "curl -I http://localhost:4180/ping" # OAuth proxy ssh pi "curl -I https://localhost/your-service/" # Through Caddy
- •
Check DNS:
bashdig lab.sethlakowske.com
- •
Check firewall:
bashssh pi "sudo iptables -L -n | grep -E '(443|80)'"
Problem: OAuth Loop/Redirect Issues
- •
Check OAuth proxy is running:
bashssh pi "systemctl status oauth2-proxy-google"
- •
Verify OAuth config:
bashssh pi "grep redirect_url /etc/oauth2-proxy/google.cfg" # Should match: https://lab.sethlakowske.com/oauth2/callback
- •
Check cookie settings:
bashssh pi "grep -E '(cookie_secure|cookie_domain)' /etc/oauth2-proxy/google.cfg"
- •
View OAuth logs:
bashssh pi "journalctl -u oauth2-proxy-google -n 50 --no-pager"
Problem: fail2ban Banning Legitimate IPs
- •
Check which jail banned the IP:
bashssh pi "sudo squelch-ban check 192.168.1.100"
- •
Review why IP was banned:
bashssh pi "sudo journalctl -u fail2ban | grep '192.168.1.100'"
- •
Unban the IP:
bashssh pi "sudo squelch-ban unban 192.168.1.100"
- •
Add to ignore list (if trusted):
bashssh pi "sudo nano /etc/fail2ban/jail.d/squelch.conf" # Add to ignoreip: 192.168.1.100 ssh pi "sudo systemctl restart fail2ban"
Problem: Backend Service Not Receiving Traffic
- •
Check backend is running:
bashcurl -s http://ubuntu-box.local:3000/health
- •
Verify OAuth proxy upstream:
bashssh pi "grep upstreams /etc/oauth2-proxy/good-neighbor.cfg"
- •
Test OAuth proxy directly:
bashssh pi "curl -I http://localhost:4182/"
- •
Check Caddy route:
bashssh pi "cat /etc/caddy/Caddyfile | grep -A 2 'good-neighbor'"
Problem: SSL Certificate Issues
- •
Check certificate status:
bashssh pi "journalctl -u caddy | grep -i certificate"
- •
Verify DNS is correct:
bashdig lab.sethlakowske.com # Should point to public IP
- •
Check port 80 is accessible (needed for Let's Encrypt):
bashssh pi "sudo ss -tlnp | grep :80"
- •
Force certificate renewal:
bashssh pi "sudo systemctl restart caddy"
Reference Documentation
Complete architecture documentation available at:
~/Software/dev/squelch/CLAUDE.md
This includes:
- •Detailed component interactions
- •Security architecture (defense-in-depth)
- •Attack scenario walkthroughs
- •Configuration patterns
- •Best practices
- •Maintenance procedures
Integration with Other Skills
network-admin Skill
- •Use network-admin for general server management commands
- •reverse-proxy focuses specifically on traffic/proxy configuration
- •Coordinate for service deployments requiring both skills
service-monitor Skill
- •service-monitor itself is protected by OAuth via this gateway
- •Access at: https://lab.sethlakowske.com/service-monitor/
- •Use service-monitor skill for monitoring operations
- •Use reverse-proxy skill for routing configuration
Usage Guidelines
When to Use reverse-proxy
Use this skill for:
- •Configuring new public-facing routes
- •Managing OAuth authentication for services
- •Analyzing traffic patterns and security events
- •Troubleshooting access issues from internet
- •Managing fail2ban security
- •Updating SSL/TLS configuration
- •Monitoring gateway health
When to Delegate to Remote Claude
For complex gateway changes:
ssh pi -t "cd ~/Software/dev/squelch && lfg" # Claude on gateway has direct access to all configs and logs
Best Practices
- •
Always backup configs before changes:
bashscp pi:/etc/caddy/Caddyfile ~/Software/dev/squelch/config-backup/caddy/
- •
Validate Caddy config before reload:
bashssh pi "sudo caddy validate --config /etc/caddy/Caddyfile"
- •
Use reload instead of restart (when possible):
bashssh pi "sudo systemctl reload caddy" # Graceful, no downtime
- •
Monitor logs after changes:
bashssh pi "journalctl -u caddy -f"
- •
Document route changes in git commits
- •
Test from multiple locations:
- •From gateway:
ssh pi "curl http://localhost:PORT" - •From LAN:
curl http://raspberrypi.local:PORT - •From internet:
curl https://lab.sethlakowske.com/route
- •From gateway:
Common Workflows
Workflow 1: Deploy New Protected Service
- •Service is running on ubuntu-box:3001
- •Create OAuth proxy config on gateway
- •Create systemd service for OAuth proxy
- •Update Caddyfile with new route
- •Reload Caddy
- •Test from internet
- •Backup configs to git
Workflow 2: Investigate Security Event
- •Check fail2ban status:
ssh pi "sudo squelch-status" - •Review banned IPs:
ssh pi "sudo squelch-ban list" - •Analyze access logs:
ssh pi "tail -1000 /var/log/caddy/access.log | jq 'select(.status >= 400)'" - •Review fail2ban logs:
ssh pi "sudo journalctl -u fail2ban --since '1 hour ago'" - •Determine if legitimate or attack
- •Take action (unban or leave banned)
Workflow 3: Update Backend Port
- •Verify new backend works:
curl http://ubuntu-box.local:NEW_PORT/health - •Update OAuth proxy config: edit
/etc/oauth2-proxy/SERVICE.cfg - •Restart OAuth proxy:
sudo systemctl restart oauth2-proxy-SERVICE - •Test:
curl https://lab.sethlakowske.com/service/ - •Backup config
Workflow 4: Add Temporary Public Route
- •Edit Caddyfile:
ssh pi "sudo nano /etc/caddy/Caddyfile" - •Add route BEFORE catch-all
- •Validate:
ssh pi "sudo caddy validate --config /etc/caddy/Caddyfile" - •Reload:
ssh pi "sudo systemctl reload caddy" - •Test:
curl https://lab.sethlakowske.com/new-route/
Examples
Example 1: Check Gateway Health
# One-liner health check ssh pi "systemctl is-active caddy oauth2-proxy-google fail2ban && echo 'Gateway healthy'" # Detailed status ssh pi "sudo squelch-status"
Example 2: Analyze Failed Auth Attempts
# Recent 401/403 responses
ssh pi "tail -500 /var/log/caddy/access.log | jq 'select(.status == 401 or .status == 403) | {time: .ts, ip: .request.remote_ip, uri: .request.uri, status: .status}'"
# IPs with most auth failures
ssh pi "tail -1000 /var/log/caddy/access.log | jq -r 'select(.status == 401) | .request.remote_ip' | sort | uniq -c | sort -nr"
Example 3: Emergency IP Ban
# Ban IP immediately in all relevant jails ssh pi "sudo squelch-ban ban 1.2.3.4 squelch-caddy-auth" ssh pi "sudo squelch-ban ban 1.2.3.4 squelch-caddy-badbots" ssh pi "sudo squelch-ban ban 1.2.3.4 squelch-caddy-scan" # Verify ban ssh pi "sudo squelch-ban check 1.2.3.4"
Example 4: View Current Configuration
# Show all routes and their backends ssh pi "cat /etc/caddy/Caddyfile | grep -E '(route|reverse_proxy)'" # Show all OAuth proxy ports and upstreams ssh pi "grep -E '(http_address|upstreams)' /etc/oauth2-proxy/*.cfg" # Show all active services ssh pi "systemctl list-units --type=service --state=running | grep -E '(caddy|oauth2-proxy|fail2ban)'"