Free Tunnel Services for LPI
To test webhooks from external services, you'll need to expose your local LPI instance to the internet. Here are several free options that work great with LPI.
Cloudflare Tunnel (cloudflared)
Installation
# macOS
brew install cloudflared
# Linux
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
# Windows
# Download from https://github.com/cloudflare/cloudflared/releases
Usage with LPI
# Start LPI first
lpi --proxy 8091 --target {you_app_local_port:8080}
# In another terminal, start the tunnel
cloudflared tunnel --url http://localhost:8091
You'll get a URL like https://random-name.trycloudflare.com
- use this as your webhook endpoint.
Using Custom Domains (DNS on Cloudflare)
If your DNS is managed on Cloudflare, you can use your own domain with subdomains for persistent tunnels:
# First time setup - authenticate with Cloudflare
cloudflared tunnel login
# Create a named tunnel
cloudflared tunnel create lpi-dev
# Route it to a subdomain
cloudflared tunnel route dns lpi-dev t1.example.com
# Run the tunnel
cloudflared tunnel run --url http://localhost:8091 lpi-dev
Now you can use https://t1.example.com
as your webhook endpoint! Create multiple tunnels for different environments:
t1.example.com
for developmentt2.example.com
for stagingwebhook.example.com
for production testing
Pros
- No account required for quick testing (random URLs)
- Fast and reliable
- HTTPS by default
- No time limits
- Custom domains available if DNS is on Cloudflare
Cons
- Random URL changes each time (unless using custom domain)
- Custom domains require Cloudflare DNS management
ngrok
How It Works
ngrok creates secure tunnels to localhost and provides a web interface for inspecting HTTP traffic. It's the most popular tunneling service with both free and paid tiers.
Installation
# macOS
brew install ngrok/ngrok/ngrok
# Linux/Windows - Download from https://ngrok.com/download
# Or use npm
npm install -g @ngrok/ngrok
Setup
# Sign up for free account at https://ngrok.com
# Get your authtoken from the dashboard
ngrok config add-authtoken YOUR_AUTHTOKEN
Usage with LPI
# Start LPI
lpi --proxy 8091 --target {you_app_local_port:8080}
# Start ngrok tunnel
ngrok http 8091
You'll get a URL like https://abc123.ngrok.io
- use this as your webhook endpoint.
Advanced Features
# Custom subdomain (paid plans)
ngrok http 8091 --subdomain=myapp
# Basic auth protection
ngrok http 8091 --basic-auth="username:password"
# Custom domain (paid plans)
ngrok http 8091 --hostname=webhook.yourdomain.com
Pros
- Most popular and well-documented
- Built-in request inspection (3-day history)
- Authentication and security features
- Reliable infrastructure
- Custom domains and subdomains available
- Mobile apps for monitoring
Cons
- Requires account signup
- Free tier has connection limits
- Inspection history limited to 3 days
- Can be expensive for heavy usage
- Some corporate firewalls block ngrok domains
Note: Both ngrok and LPI provide request inspection. ngrok's inspection is limited to 3 days, while LPI stores requests locally for longer-term analysis and provides additional webhook testing features.
SSH Tunneling
If you have access to a VPS or remote server with SSH:
Setup
# Start LPI
lpi --proxy 8091 --target {you_app_local_port:8080}
# Create SSH tunnel (maps remote port to local port)
ssh -R 8090:localhost:8091 [email protected]
Web Server Configuration
For subdomain setup, configure your web server to proxy the tunneled port:
Nginx configuration (/etc/nginx/sites-available/tunnel
):
server {
listen 80;
server_name mytunnel.example.com;
location / {
proxy_pass http://localhost:8090;
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;
}
}
Apache configuration (/etc/apache2/sites-available/tunnel.conf
):
<VirtualHost *:80>
ServerName mytunnel.example.com
ProxyPass / http://localhost:8090/
ProxyPassReverse / http://localhost:8090/
ProxyPreserveHost On
</VirtualHost>
DNS Setup
Create an A record pointing your subdomain to your VPS:
Type: A
Name: mytunnel
Value: [your-vps-ip-address]
TTL: 300 (or your preferred value)
Pros
- Completely under your control
- Use your own domain or subdomain
- No third-party dependencies
Cons
- Requires VPS with SSH access
- Need to configure web server and DNS
- Manual setup for each subdomain
LocalTunnel
Installation
npm install -g localtunnel
Usage with LPI
# Start LPI
lpi --proxy 8091 --target {you_app_local_port:8080}
# Start LocalTunnel
lt --port 8091
You'll get a URL like https://random.loca.lt
Pros
- Easy to install via npm
- Can request custom subdomains
- Open source
Cons
- Requires Node.js
- Shows warning page to visitors
- Can be slow
Bore
How It Works
Bore creates a TCP tunnel between your local machine and a remote server, bypassing NAT firewalls. When you run bore local 8091 --to bore.pub
, it:
- Connects to the bore.pub server - Establishes a control connection to coordinate the tunnel
- Gets assigned a random port - The server assigns you a public port (e.g.,
bore.pub:12345
) - Forwards traffic - Any requests to
bore.pub:12345
get forwarded to your locallocalhost:8091
- Maintains the connection - Keeps the tunnel alive as long as the bore client is running
The public URL will look like: http://bore.pub:12345
(where 12345 is randomly assigned)
Installation
# macOS
brew install bore-cli
# Linux/Windows
cargo install bore-cli
Usage with LPI
# Start LPI
lpi --proxy 8091 --target {you_app_local_port:8080}
# Start Bore tunnel
bore local 8091 --to bore.pub
Self-Hosting (Optional)
If you prefer to run your own bore server:
# On your VPS
bore server
# On your local machine (replace your-server.com with your VPS)
bore local 8091 --to your-server.com
Pros
- Fast and lightweight
- Written in Rust
- Minimal dependencies
- Can self-host for better reliability
Cons
- Less well-known
- Requires Rust/cargo for installation
- Public bore.pub service occasionally experiences downtime
Stripe CLI
How It Works
The Stripe CLI creates a secure tunnel between Stripe's servers and your local development environment, allowing you to receive real webhook events locally. This is essential for testing payment flows and webhook handling during development.
Installation
# macOS
brew install stripe/stripe-cli/stripe
# Linux/Windows - Download from GitHub releases
# https://github.com/stripe/stripe-cli/releases
Setup
# Login to your Stripe account
stripe login
# This will open a browser to authenticate with Stripe
Usage with LPI
# Start LPI
lpi --proxy 8091 --target {you_app_local_port:8080}
# Forward Stripe webhooks to your local endpoint
stripe listen --forward-to localhost:8091/webhook/stripe
# Or specify events you want to listen for
stripe listen --events payment_intent.succeeded,payment_intent.payment_failed --forward-to localhost:8091/webhook/stripe
Testing Webhooks
# Trigger test events to verify your webhook handling
stripe trigger payment_intent.succeeded
stripe trigger customer.created
stripe trigger invoice.payment_failed
Webhook Endpoint Signing
The Stripe CLI automatically handles webhook signature verification. Your webhook endpoint will receive a Stripe-Signature
header that you should verify in your application:
// Example webhook verification
const signature = req.headers['stripe-signature'];
const event = stripe.webhooks.constructEvent(req.body, signature, process.env.STRIPE_WEBHOOK_SECRET);
Pros
- Official Stripe tool
- Handles authentication automatically
- Real webhook events from Stripe
- Built-in event triggering for testing
- Automatic signature verification
- Free to use
Cons
- Stripe-specific (only works for Stripe webhooks)
- Requires Stripe account and authentication
- Limited to webhook forwarding (not general tunneling)
Getting Your Webhook Secret
When you run stripe listen
, it will display your webhook signing secret:
> Ready! Your webhook signing secret is whsec_1234567890abcdef...
Add this to your environment variables for webhook verification.
Comparison Table
Service | Setup Time | Reliability | Custom Domains | Account Required | Best For |
---|---|---|---|---|---|
Cloudflared | 2 min | Excellent | Yes (with CF DNS) | No | Quick testing, reliable tunnels |
ngrok | 3 min | Excellent | Yes (paid plans) | Yes | Popular choice, built-in inspection |
SSH Tunnel | 5 min | Excellent | Yes (with VPS) | VPS access | Production-like testing, full control |
LocalTunnel | 3 min | Fair | Limited | No | Node.js projects, quick setup |
Bore | 2 min | Good* | No (random ports) | No | Lightweight, Rust projects |
Stripe CLI | 3 min | Excellent | N/A | Stripe account | Stripe webhook testing only |
*Note: Bore's public bore.pub service occasionally experiences downtime. Self-hosting improves reliability.
Best Practices
- For Quick Testing: Use cloudflared - it's the most reliable and fastest to set up
- For Popular Choice: Use ngrok - widely documented with built-in inspection (though limited to 3 days)
- For Permanent URLs: Use SSH tunnel with your own VPS for full control
- For Stripe Webhooks: Use Stripe CLI for authentic webhook events and automatic signature verification
- For Lightweight Setup: Use Bore if you prefer minimal dependencies and Rust-based tools
- For Node.js Projects: LocalTunnel integrates well with npm-based workflows
- For CI/CD: Consider the paid tier of any service for stability and guaranteed uptime
Security Considerations
- These tunnels expose your local LPI to the internet
- Anyone with the URL can send requests to your LPI instance
- Always close tunnels when not actively testing
- Consider using webhook signature verification for production webhooks
- For SSH tunnels: Ensure your VPS is properly secured with key-based authentication and firewall rules
- For development: Never expose sensitive data, database credentials, or API keys through these tunnels
- Rate limiting: Consider implementing rate limiting in your local application to prevent abuse
- IP allowlisting: If possible, restrict tunnel access to known webhook provider IP ranges
Troubleshooting
Tunnel URL Not Working
- Ensure LPI is running on the expected port (default: 8091)
- Check firewall settings on your local machine
- Try accessing http://localhost:8091 directly first
- Verify the tunnel service is actually running and connected
Slow Response Times
- This is normal for free tunnel services
- Try a different service or upgrade to paid tier
- Consider using a VPS closer to your webhook source
- Check your local internet connection stability
Connection Drops
- Free services may have connection limits or timeouts
- Restart the tunnel service
- For critical testing, use multiple tunnel services as backup
- Consider upgrading to paid tiers for better stability
Service-Specific Issues
ngrok
- Re-authenticate if getting auth errors:
ngrok config add-authtoken YOUR_TOKEN
- Free tier has connection limits - upgrade if hitting limits
- Some corporate networks block ngrok - try cloudflared as alternative
Bore
- If bore.pub is unreachable, try self-hosting a bore server on your VPS
- Connection refused errors may indicate bore.pub is temporarily down
- Try different ports if you're getting port allocation errors
Cloudflared
- Clear browser cache if seeing stale content
- If random URLs keep changing, set up a named tunnel with custom domain
- Check Cloudflare status page if connections are failing
LocalTunnel
- Try a different subdomain if getting rate limited
- The warning page is normal - click through to access your app
- Install the latest version if experiencing connection issues
Stripe CLI
- Re-authenticate with
stripe login
if webhooks stop working - Check your Stripe account permissions if authentication fails
- Verify your webhook endpoint URL format is correct
SSH Tunnels
- Ensure SSH key authentication is working properly
- Check if your VPS firewall allows the tunnel port
- Verify web server configuration is correctly proxying to localhost
Port Conflicts
- If port 8091 is busy, start LPI on a different port:
./lpi --port 8092
- Update your tunnel command to match the new port
- Check what's using the port:
lsof -i :8091
(macOS/Linux) ornetstat -ano | findstr :8091
(Windows)
Next Steps
- Start with cloudflared for immediate testing
- Set up your webhook provider to send to your tunnel URL
- Monitor requests in the LPI web interface at http://localhost:3001
- Test with a simple webhook first (like a GitHub webhook) before moving to payment providers
- Keep your tunnel logs open in a separate terminal to monitor incoming requests
- Document your webhook URLs and tunnel setup for team members