Caddy Proxy Setup
Configure Caddy reverse proxy to serve AddonPulse tracking with automatic HTTPS
Caddy is a powerful web server with automatic HTTPS that makes reverse proxying simple and secure. This guide shows how to configure Caddy to proxy AddonPulse tracking through your own domain.
Overview
Caddy's reverse_proxy directive makes it incredibly easy to proxy requests. Combined with automatic HTTPS via Let's Encrypt, Caddy provides a secure, low-configuration solution for proxying analytics.
What you'll achieve:
- Automatic HTTPS with Let's Encrypt
- Simple reverse proxy configuration
- Header forwarding for accurate tracking
- Support all AddonPulse features
Prerequisites
- Caddy installed (version 2.0 or later)
- Domain pointing to your server
- Your AddonPulse instance URL
https://app.addonpulse.com - Your AddonPulse site ID (found in your dashboard)
Caddy automatically obtains and renews SSL certificates from Let's Encrypt. No manual SSL configuration needed!
Implementation
Configure Caddyfile
Add or update your Caddyfile with the analytics proxy configuration:
# /etc/caddy/Caddyfile
yourdomain.com {
# Your main site configuration
# ...
# AddonPulse Analytics Proxy
# Main tracking script
handle /analytics/script.js {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
rewrite * /api/script.js
}
# Event tracking endpoint
handle /analytics/track {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up Content-Type {header.Content-Type}
}
rewrite * /api/track
}
# User identification endpoint
handle /analytics/identify {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up Content-Type {header.Content-Type}
}
rewrite * /api/identify
}
# Site configuration
handle /analytics/site/tracking-config/* {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
rewrite * /api/site/tracking-config{path}
}
}# /etc/caddy/Caddyfile
yourdomain.com {
# Main tracking script
handle /analytics/script.js {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
rewrite * /api/script.js
}
# Event tracking
handle /analytics/track {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
rewrite * /api/track
}
}Caddy 2.4+ supports a cleaner syntax with handle_path:
# /etc/caddy/Caddyfile
yourdomain.com {
handle_path /analytics/* {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
rewrite * /api{uri}
}
}This proxies all /analytics/* requests to https://app.addonpulse.com/api/*.
Validate Caddyfile
Test your configuration for syntax errors:
caddy validate --config /etc/caddy/CaddyfileYou should see:
Valid configurationReload Caddy
Apply the changes by reloading Caddy:
sudo caddy reload --config /etc/caddy/CaddyfileOr if using systemd:
sudo systemctl reload caddyCaddy will automatically obtain an SSL certificate from Let's Encrypt on first request if one doesn't exist.
Update Your Tracking Script
Update your HTML to load the script from your proxied domain:
<!DOCTYPE html>
<html>
<head>
<!-- ... other head elements -->
<script src="/analytics/script.js" async data-site-id="YOUR_SITE_ID"></script>
</head>
<body>
<!-- Your content -->
</body>
</html>Replace YOUR_SITE_ID with your actual site ID from the AddonPulse dashboard.
Verify the Setup
Test your configuration:
-
Check Caddy is running:
sudo systemctl status caddy -
Test script loading:
curl -I https://yourdomain.com/analytics/script.jsYou should see
HTTP/2 200withcontent-type: application/javascript. -
Open your website in a browser with Developer Tools and verify:
- Script loads from
/analytics/script.js - Tracking requests go to
/analytics/track - Data appears in AddonPulse dashboard
- Script loads from
How It Works
Caddy's reverse_proxy directive forwards requests to AddonPulse's servers:
- Browser requests
https://yourdomain.com/analytics/script.js - Caddy matches the handle block
- Rewrites the path to
/api/script.js - Forwards to
https://app.addonpulse.com/api/script.jswith proper headers - Returns response to browser
The AddonPulse script auto-detects it's being served from your domain and sends all tracking to your domain's endpoints.
Advanced Configuration
Caching with Cache-Control
Add caching headers for better performance:
yourdomain.com {
# Scripts - cache for 1 hour
handle /analytics/script.js {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
rewrite * /api/script.js
header Cache-Control "public, max-age=3600"
}
# Config - cache for 5 minutes
handle /analytics/site/tracking-config/* {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
rewrite * /api/site/tracking-config{path}
header Cache-Control "public, max-age=300"
}
# Tracking - no cache
handle /analytics/track {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
rewrite * /api/track
header Cache-Control "no-store"
}
}Subdomain Proxy
Use a dedicated subdomain for analytics:
# /etc/caddy/Caddyfile
analytics.yourdomain.com {
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
rewrite * /api{uri}
}Then use:
<script src="https://analytics.yourdomain.com/script.js" data-site-id="123"></script>Environment-Based Configuration
Use Caddy's environment variable support:
# /etc/caddy/Caddyfile
{$DOMAIN:yourdomain.com} {
handle_path /analytics/* {
reverse_proxy {$ADDONPULSE_HOST:https://app.addonpulse.com} {
header_up Host {upstream_hostport}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
rewrite * /api{uri}
}
}Then set environment variables:
export DOMAIN=yourdomain.com
export ADDONPULSE_HOST=https://app.addonpulse.com
caddy runRate Limiting
Protect your proxy with rate limiting using the rate_limit plugin:
yourdomain.com {
handle /analytics/track {
rate_limit {
zone analytics {
key {remote_host}
events 100
window 1m
}
}
reverse_proxy https://app.addonpulse.com {
header_up Host app.addonpulse.com
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
rewrite * /api/track
}
}The rate_limit directive requires the caddy-ratelimit plugin. Install with: xcaddy build --with github.com/mholt/caddy-ratelimit
Troubleshooting
Certificate errors
Problem: Caddy fails to obtain SSL certificate.
Solution:
- Verify domain points to your server (DNS)
- Check ports 80 and 443 are open
- Ensure no other process is using port 443
- Check Caddy logs:
journalctl -u caddy -f
Incorrect geolocation
Problem: All visitors show same location.
Solution: Ensure you're forwarding client IP:
reverse_proxy https://app.addonpulse.com {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}502 Bad Gateway
Problem: Caddy returns 502 when accessing analytics endpoints.
Solution:
- Verify AddonPulse backend is accessible:
curl -I https://app.addonpulse.com/api/script.js - Check Caddy logs for errors:
journalctl -u caddy -n 50
Path rewriting not working
Problem: Requests go to wrong AddonPulse endpoints.
Solution:
Use the rewrite directive correctly:
handle /analytics/script.js {
rewrite * /api/script.js # Rewrite before reverse_proxy
reverse_proxy https://app.addonpulse.com {
# ... headers
}
}Related Resources
- Tracking Script Documentation - Script configuration options
- Generic Proxy Guide - Framework-agnostic concepts
- Caddy Documentation - Official Caddy docs
- Caddy reverse_proxy - Reverse proxy directive docs