Proxy Hesychia Stripe webhooks off the static site (#42)
Sync runner checkout / sync (push) Successful in 7s
Sync runner checkout / sync (push) Successful in 7s
## Summary - Closes #41. - Stripe live endpoint `we_1TzDNHDV0RPXOyxGCOftavHV` posts to `https://hesychia.ai/api/finance/webhooks/stripe/`. On 2026-10-09 the `chat_web_app` prod vhost returned HTTP 405 fifteen times (`request_time` 0.000, User-Agent Stripe). `pending_webhooks` stayed 1. - `try_files` falls through to `index.html`, and nginx rejects POST on that static file. The Django handler on `chat_backend` never sees the body. - `chat_web_app` now proxies `/api/finance/webhooks/` to the same-env `chat_backend` port (`8003` prod, `8013` beta) via `host.docker.internal`. `Host` is the backend public hostname so `ALLOWED_HOSTS` matches. Other static apps are unchanged. ## Test plan - [ ] `ansible-playbook playbooks/site.yml --syntax-check` (or the web-static portion) renders without error - [ ] Redeploy web-static (`scripts/deploy.sh` path that runs the web-static role) so `nginx.conf` reloads - [ ] `curl -i -X POST http://127.0.0.1:8082/api/finance/webhooks/stripe/` from an app host reaches Django (400 invalid signature or 503 missing secret), not 405 - [ ] Stripe Dashboard: resend a failed event to the Hesychia.ai endpoint and confirm 2xx Reviewed-on: #42
This commit was merged in pull request #42.
This commit is contained in:
1 parent
7f570b40a2
commit
a84350fe60
3 files changed
+40
No files matched your search
@@ -3,6 +3,9 @@ services:
|
||||
web-static:
|
||||
image: {{ web_static_image }}
|
||||
restart: unless-stopped
|
||||
# Webhook locations proxy to chat_backend on the host-published port.
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
|
||||
@@ -30,6 +30,34 @@ server {
|
||||
root {{ (app_catalog[a.name].webroot_pattern | default(web_static_root ~ '/{env}_' ~ a.name)) | replace('{env}', a.env) }};
|
||||
index index.html;
|
||||
|
||||
{%- set api_backend_name = app_catalog[a.name].api_backend | default('') %}
|
||||
{%- if api_backend_name %}
|
||||
{%- set api_proxy_prefix = app_catalog[a.name].api_proxy_prefix | default('/api/') %}
|
||||
{%- set api_match = namespace(port=0, ok=false) %}
|
||||
{%- for item in host_apps | default([]) %}
|
||||
{%- if item.name == api_backend_name and item.env == a.env and (item.enabled | default(true)) %}
|
||||
{%- set api_match.port = item.port %}
|
||||
{%- set api_match.ok = true %}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- if api_match.ok %}
|
||||
{%- set api_host = (app_catalog[api_backend_name].public_hosts | default({}))[a.env] | default('') %}
|
||||
|
||||
# Finance webhooks (Stripe) arrive on the public product host. The SPA
|
||||
# try_files fallback is a static file and returns 405 for POST.
|
||||
location {{ api_proxy_prefix }} {
|
||||
proxy_pass http://host.docker.internal:{{ api_match.port }};
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host {{ api_host if api_host else '$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;
|
||||
proxy_read_timeout 60s;
|
||||
client_max_body_size 2m;
|
||||
}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
|
||||
{% if app_catalog[a.name].error_page_404 | default('') %}
|
||||
error_page 404 {{ app_catalog[a.name].error_page_404 }};
|
||||
|
||||
|
||||
Reference in new issue
Block a user