1. The problem I’m having:
I have a Node.js application using LemonSqueezy webhooks that works perfectly in local environment and other hosting providers like fly.io. However, when deployed on my VPS using Caddy as reverse proxy with Cloudflare, the webhooks fail with a signature verification error. The error persists even when Cloudflare is paused, suggesting an issue with how the request body is being handled through Caddy. Error: ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH
occurs during webhook signature verification.
I don’t exactly know if this is a Caddy problem or not but weirdly enough even after extensive logging in my code none of them show up in my docker logs, and that is why i am here asking for your help.
I will be honest and say that this is my first time hosting a full web app on a VPS with Caddy and Cloudflare especially a one with payment integration so if i have made any mistake please be kind and help me through it, also ignore any minor issues in my post as this is my first time posting in the community here.
2. Error messages and/or full log output:
text
Webhook error: RangeError: Input buffers must have the same byte length
at _paymentsWebhookfn (/app/src/payment/lemonSqueezy/webhook.ts:27:17)
at <anonymous> (/app/build/server/src/routes/apis/index.ts:39:14)
at <anonymous> (/app/out/sdk/server/utils.ts:26:11)
at Layer.handle [as handle_request] (/app/build/server/node_modules/express/lib/router/layer.js:95:5)
at next (/app/build/server/node_modules/express/lib/router/route.js:149:13)
at /app/build/server/node_modules/body-parser/lib/read.js:137:5
3. Caddy version:
bash
Caddy v2.7.6
4. How I installed and ran Caddy:
a. System environment:
- Ubuntu 22.04 LTS
- Docker for containerization
- Caddy as reverse proxy
- Cloudflare for DNS and SSL
b. Command:
bash
docker run -d \
--name myapp \
--env-file .env.production \
-p 127.0.0.1:3001:3001 \
--network app-vps-network \
myapp
c. Service/unit/compose file:
N/A - Using Docker directly
d. My complete Caddy config:
{
auto_https off
}
myapp.com, www.myapp.com {
encode gzip
root * /home/username/webdevelopment/myapp/client
try_files {path} /index.html
file_server
tls /home/username/webdevelopment/myapp/cloudflare-origin-cert.pem /home/username/webdevelopment/myapp/cloudflare-origin-key.pem
log {
output file /var/log/caddy/myapp_access.log
format json
}
}
api.myapp.com {
@webhook {
path /payments-webhook
path /operations/*
}
handle @webhook {
header Content-Type application/json
header -Content-Encoding
reverse_proxy localhost:3001 {
header_up Host {http.request.host}
header_up Content-Type application/json
header_up X-Signature {http.request.header.X-Signature}
}
}
handle {
reverse_proxy localhost:3001
}
tls /home/username/webdevelopment/myapp/cloudflare-origin-cert.pem /home/username/webdevelopment/myapp/cloudflare-origin-key.pem
log {
output file /var/log/caddy/api_access.log
format json
level DEBUG
}
}
bot.myapp.com {
reverse_proxy localhost:3000
tls /home/username/webdevelopment/myapp/cloudflare-origin-cert.pem /home/username/webdevelopment/myapp/cloudflare-origin-key.pem
log {
output file /var/log/caddy/bot_access.log
format json
}
}
5. Links to relevant resources:
- LemonSqueezy Webhook Documentation: API Docs: The Webhook Object • Lemon Squeezy