Since Pulse is not publicly accessible, added comprehensive guide for exposing only the webhook endpoint to Autotask via reverse proxy. Covers 4 approaches: 1. Nginx + Let's Encrypt (recommended for production) 2. Cloudflare Tunnel (easiest, no firewall changes) 3. Caddy (automatic HTTPS) 4. Traefik (for Docker users) Each includes: - Complete configuration examples - Setup steps - Security recommendations (rate limiting, IP whitelisting) - Testing procedures - Troubleshooting guides Security features: - Only /api/webhooks/autotask exposed - SSL/TLS encryption required - Rate limiting (100 req/min, burst 20) - Optional IP whitelisting for Autotask - All other paths return 404 File: docs/WEBHOOK_REVERSE_PROXY.md
11 KiB
Webhook Reverse Proxy Configuration
Overview
Since your Pulse application is not publicly accessible, you need to expose only the webhook endpoint to Autotask. This guide covers secure reverse proxy configurations.
Option 1: Nginx Reverse Proxy (Recommended)
Architecture
Internet → Nginx (Public) → Pulse App (Internal)
Port 443 Port 3100
Only /api/webhooks/autotask is exposed
Nginx Configuration
Create /etc/nginx/sites-available/pulse-webhooks:
# Rate limiting zone - prevents abuse
limit_req_zone $binary_remote_addr zone=webhook_limit:10m rate=100r/m;
# Upstream to Pulse application
upstream pulse_app {
server localhost:3100; # Adjust to your Pulse app port
}
server {
listen 80;
server_name webhooks.yourdomain.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name webhooks.yourdomain.com;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/webhooks.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/webhooks.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Security headers
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Logging
access_log /var/log/nginx/pulse-webhooks-access.log;
error_log /var/log/nginx/pulse-webhooks-error.log;
# Health check endpoint
location = /api/webhooks/autotask {
# Rate limiting - 100 requests per minute, burst of 20
limit_req zone=webhook_limit burst=20 nodelay;
# Only allow POST and GET
limit_except GET POST {
deny all;
}
# Optional: IP whitelist for Autotask
# Get Autotask IP ranges from their documentation
# allow 1.2.3.4/24; # Autotask IP range
# deny all;
# Proxy to Pulse app
proxy_pass http://pulse_app;
proxy_http_version 1.1;
# Headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
# Buffer settings
proxy_buffering off;
proxy_request_buffering off;
}
# Block all other paths
location / {
return 404;
}
}
Setup Steps
1. Install Nginx
sudo apt update
sudo apt install nginx
2. Install Certbot (for SSL)
sudo apt install certbot python3-certbot-nginx
3. Create Configuration
sudo nano /etc/nginx/sites-available/pulse-webhooks
Paste the configuration above, adjusting:
server_nameto your domainupstream pulse_appto your Pulse app address
4. Enable Site
sudo ln -s /etc/nginx/sites-available/pulse-webhooks /etc/nginx/sites-enabled/
sudo nginx -t # Test configuration
5. Get SSL Certificate
sudo certbot --nginx -d webhooks.yourdomain.com
6. Start Nginx
sudo systemctl enable nginx
sudo systemctl restart nginx
7. Test
curl https://webhooks.yourdomain.com/api/webhooks/autotask
# Should return: {"status":"active"...}
Option 2: Cloudflare Tunnel (Zero Trust)
Architecture
Internet → Cloudflare → Cloudflared (Tunnel) → Pulse App
No open ports needed!
Setup Steps
1. Install Cloudflared
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
2. Login to Cloudflare
cloudflared tunnel login
3. Create Tunnel
cloudflared tunnel create pulse-webhooks
# Note the tunnel ID shown
4. Create Configuration
Create ~/.cloudflared/config.yml:
tunnel: <TUNNEL_ID>
credentials-file: /root/.cloudflared/<TUNNEL_ID>.json
ingress:
# Webhook endpoint only
- hostname: webhooks.yourdomain.com
path: /api/webhooks/autotask
service: http://localhost:3100
# Health check
- hostname: webhooks.yourdomain.com
path: /api/webhooks/*
service: http://localhost:3100
# Catch-all (deny everything else)
- service: http_status:404
5. Route DNS
cloudflared tunnel route dns pulse-webhooks webhooks.yourdomain.com
6. Run Tunnel
# Test first
cloudflared tunnel run pulse-webhooks
# If working, install as service
sudo cloudflared service install
sudo systemctl start cloudflared
sudo systemctl enable cloudflared
7. Test
curl https://webhooks.yourdomain.com/api/webhooks/autotask
Cloudflare Tunnel Benefits
- ✅ No firewall changes needed
- ✅ No open ports
- ✅ Free tier available
- ✅ Built-in DDoS protection
- ✅ Automatic SSL/TLS
- ✅ Easy to set up
Option 3: Caddy (Automatic HTTPS)
Caddy Configuration
Create /etc/caddy/Caddyfile:
webhooks.yourdomain.com {
# Automatic HTTPS via Let's Encrypt
# Rate limiting
rate_limit {
zone webhook {
key {remote_host}
events 100
window 1m
}
}
# Only allow webhook endpoint
handle /api/webhooks/autotask {
reverse_proxy localhost:3100
}
# Block everything else
handle {
respond 404
}
# Logging
log {
output file /var/log/caddy/pulse-webhooks.log
}
}
Setup:
# Install Caddy
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
# Configure
sudo nano /etc/caddy/Caddyfile
# Paste configuration above
# Start
sudo systemctl restart caddy
sudo systemctl enable caddy
Option 4: Docker with Traefik
If you're using Docker Compose, add Traefik as a reverse proxy:
docker-compose.yml
services:
# Your existing Pulse app
app:
image: pulse-app
networks:
- internal
# No ports exposed!
# Traefik reverse proxy
traefik:
image: traefik:v2.10
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json
networks:
- internal
labels:
- "traefik.enable=true"
networks:
internal:
driver: bridge
traefik.yml
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: admin@yourdomain.com
storage: /acme.json
httpChallenge:
entryPoint: web
providers:
docker:
exposedByDefault: false
# Rate limiting
http:
middlewares:
webhook-ratelimit:
rateLimit:
average: 100
burst: 20
Update Pulse App Labels
app:
labels:
- "traefik.enable=true"
- "traefik.http.routers.webhooks.rule=Host(`webhooks.yourdomain.com`) && PathPrefix(`/api/webhooks/autotask`)"
- "traefik.http.routers.webhooks.entrypoints=websecure"
- "traefik.http.routers.webhooks.tls.certresolver=letsencrypt"
- "traefik.http.routers.webhooks.middlewares=webhook-ratelimit"
- "traefik.http.services.webhooks.loadbalancer.server.port=3100"
Security Recommendations
1. IP Whitelisting (If Possible)
Get Autotask's IP ranges and whitelist them:
Nginx:
# Inside location block
allow 1.2.3.4/24; # Autotask IP range
deny all;
Cloudflare: Use Cloudflare Access rules to restrict by IP
2. Rate Limiting
All configurations above include rate limiting:
- 100 requests per minute
- Burst of 20 requests
- Prevents abuse/DDoS
3. Monitoring
Monitor webhook endpoint:
# Nginx access log
tail -f /var/log/nginx/pulse-webhooks-access.log
# Check for suspicious activity
grep -v "200\|201" /var/log/nginx/pulse-webhooks-access.log | tail -20
4. Firewall Rules
# UFW example - only allow 80/443
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Testing Your Setup
1. Health Check
curl https://webhooks.yourdomain.com/api/webhooks/autotask
# Expected: {"status":"active"...}
2. Test Webhook POST
curl -X POST https://webhooks.yourdomain.com/api/webhooks/autotask \
-H "Content-Type: application/json" \
-d '{
"eventId": "test_123",
"eventType": "create",
"entityType": "Tickets",
"entityId": 99999,
"eventTimestamp": "2026-01-24T10:00:00Z"
}'
3. Verify Blocked Paths
curl https://webhooks.yourdomain.com/
# Expected: 404 Not Found
curl https://webhooks.yourdomain.com/admin
# Expected: 404 Not Found
4. Test Rate Limiting
# Send 150 requests quickly
for i in {1..150}; do
curl -s https://webhooks.yourdomain.com/api/webhooks/autotask > /dev/null
done
# Should see 429 Too Many Requests after ~100 requests
Autotask Configuration
Once your endpoint is exposed:
- Go to Autotask → Admin → Webhooks
- Create webhook with URL:
https://webhooks.yourdomain.com/api/webhooks/autotask - Test webhook from Autotask UI
- Monitor logs to verify receipt
Troubleshooting
Webhook Not Received
Check 1: DNS Resolution
nslookup webhooks.yourdomain.com
Check 2: SSL Certificate
curl -v https://webhooks.yourdomain.com/api/webhooks/autotask
# Look for SSL handshake errors
Check 3: Proxy Logs
# Nginx
tail -f /var/log/nginx/pulse-webhooks-error.log
# Cloudflare Tunnel
sudo journalctl -u cloudflared -f
Check 4: Firewall
sudo ufw status
# Ensure 80/443 are allowed
502 Bad Gateway
Pulse app is not reachable:
# Check Pulse app is running
docker ps | grep pulse-app
# Check port
netstat -tlnp | grep 3100
# Test direct connection
curl http://localhost:3100/api/webhooks/autotask
Recommended Approach
For Production: Nginx + Let's Encrypt
- Most control
- Best performance
- Industry standard
For Quick Setup: Cloudflare Tunnel
- Fastest to set up
- No firewall changes
- Good for testing
For Docker Users: Traefik
- Integrates with Docker
- Automatic SSL
- Container-native
Summary
You need to expose only /api/webhooks/autotask to the internet for Autotask to reach it. Use a reverse proxy to:
- ✅ Expose only the webhook endpoint
- ✅ Add SSL/TLS encryption
- ✅ Implement rate limiting
- ✅ Optional IP whitelisting
- ✅ Keep rest of application private
Choose the approach that fits your infrastructure best!