dograh/scripts/run_web.sh

19 lines
620 B
Bash
Raw Normal View History

feat: add Helm chart for Kubernetes deployment (#365) * feat: add Helm chart for Kubernetes deployment Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Replace bundled Bitnami subcharts with in-chart manifests on official images The Bitnami catalog removed all versioned image tags from docker.io/bitnami in Aug 2025 (old images frozen in bitnamilegacy, maintained catalog now behind a Broadcom subscription), so the bundled postgresql/redis/minio subcharts no longer pull. Replace them with plain in-chart manifests built on official upstream images, keeping the internal/all-in-one path fully self-contained and free of third-party chart packaging that can disappear: - internal-postgres.yaml: pgvector/pgvector:pg17 — upstream Postgres plus the `vector` extension the migrations require. POSTGRES_USER=dograh is the initdb superuser, so CREATE EXTENSION vector succeeds. - internal-redis.yaml: redis:7.4-alpine, password-protected, AOF persistence. - internal-minio.yaml: minio/minio, root creds shared with the app via a single secret (can't drift); the app auto-creates its bucket. Service/secret names are unchanged (<rel>-postgresql, <rel>-redisinternal-master, <rel>-minio) so the app wiring is untouched. Dep passwords are generated once and persisted across upgrades via lookup. Drop the Chart.yaml dependencies, Chart.lock, and the `helm dependency` step; the internal manifests gate on the mode toggles (database.mode=internal, etc.). Also fixes surfaced by smoke-testing on a live EKS cluster: - Dockerfile: ship the per-service run_*.sh entrypoints the chart invokes. - migrate-job: run as a post-install/pre-upgrade hook (the bundled Postgres does not exist during pre-install) with a wait-for-postgres init container. - backend env: declare POSTGRES_PASSWORD/REDIS_PASSWORD before the DATABASE_URL/ REDIS_URL that interpolate them (Kubernetes only expands back-references). - worker liveness probes: pgrep isn't in the slim runtime image; check /proc/1/cmdline instead (each worker execs its process as PID 1). - UI: set HOSTNAME=0.0.0.0 so Next.js standalone doesn't bind to the k8s-injected pod name (which maps to the pod IP only, breaking port-forward/loopback). Verified end-to-end on EKS 1.36: all pods Ready, migrations applied (pgvector extension + 27 tables), UI login page and web API served via port-forward. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-03 12:39:39 +05:30
#!/usr/bin/env bash
set -euo pipefail
BASE_DIR="$(cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" && pwd)"
ENV_FILE="$BASE_DIR/api/.env"
if [[ -f "$ENV_FILE" ]]; then
set -a && . "$ENV_FILE" && set +a
fi
PORT="${WEB_PORT:-8000}"
fix(web): honor X-Forwarded-Proto in uvicorn so request.url is https behind a reverse proxy (#515) * fix(web): honor X-Forwarded-Proto in uvicorn so request.url is https behind a reverse proxy ## Problem When Dograh runs behind a TLS-terminating reverse proxy (Cloudflare → Traefik in Kubernetes, nginx in the docker-compose install), the inside of the cluster/host is plain HTTP. Uvicorn defaults to trusting `scope["scheme"]` from the socket, so `request.url.scheme` reads `http` even though the client dialed `https`. That breaks any code path that hashes or echoes the request URL back to the caller. Concrete symptom seen in production: **Vobiz inbound webhook signatures fail with "signature validation failed for vobiz"** because Vobiz computes HMAC over the URL it dialed (`https://.../inbound/run`) while Dograh recomputes it as `http://...`. Log excerpt from the failing call: ``` WARNING | provider.py | Vobiz webhook signature mismatch. Expected: daOpAZPm..., Got: 1+eW/RxE... WARNING | telephony.py | /inbound/run: signature validation failed for vobiz ``` Twilio, Plivo and any other provider that signs over the callback URL have the same failure mode when Dograh is deployed behind a proxy. ## Fix Start uvicorn with `--proxy-headers --forwarded-allow-ips="*"` in `scripts/run_web.sh`. Uvicorn rewrites `scope["scheme"]` and client address from `X-Forwarded-Proto` / `X-Forwarded-For` when the request originates from a trusted upstream — Traefik and Cloudflare set both correctly, so `request.url.scheme == "https"` inside the app once again and provider signature checks pass. Verified end-to-end on a production k3s install (Traefik + Cloudflare edge → dograh-web pod) — after the change, the very next Vobiz inbound webhook validated successfully and the call connected past the previous 11-second signature-failure hangup. * address review: let operators narrow FORWARDED_ALLOW_IPS Both bot reviewers on #515 flagged `--forwarded-allow-ips="*"` as a defence-in-depth concern: if uvicorn is directly reachable from an untrusted network (bypassing the proxy), any client can spoof `X-Forwarded-Proto` / `X-Forwarded-For`, and uvicorn will rewrite `request.client` / `request.url` from those attacker-controlled headers. Fix: consume `FORWARDED_ALLOW_IPS` from the environment (uvicorn already recognizes this env var; see `deploy/hostinger/docker-compose.yaml:179` for the existing precedent). Default stays `"*"` so the behavior of the original fix is preserved for the standard docker-compose / helm layouts where the app pod is only reachable via the proxy Service. Operators who terminate uvicorn on a host that's also reachable directly can narrow it to the proxy CIDR: FORWARDED_ALLOW_IPS="10.42.0.0/16" ./scripts/run_web.sh * address review: declare FORWARDED_ALLOW_IPS in the helm chart, not the script uvicorn already enables proxy-header handling by default and falls back to the FORWARDED_ALLOW_IPS env var when --forwarded-allow-ips is absent, so the CLI flags were redundant and the script-level "*" default hid a security-relevant trust decision away from operators. Drop the flags, keep run_web.sh deployment-agnostic, and declare the env var where the other deployment config lives — web.forwardedAllowIps in values.yaml (default "*", narrowable to a proxy CIDR) — mirroring how docker-compose already sets it on the api service. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * simplify run_web.sh comment Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: prabhat pankaj <prabhatiitbhu@gmail.com> Co-authored-by: Abhishek Kumar <abhishek@a6k.me> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 10:26:45 +05:30
# uvicorn trusts X-Forwarded-Proto / X-Forwarded-For only from peers listed
# in the FORWARDED_ALLOW_IPS env var (default 127.0.0.1). Behind a reverse
# proxy it must be set (compose: api service env, helm: web.forwardedAllowIps)
# or request.url stays http:// and URL-signed webhook validation fails.
feat: add Helm chart for Kubernetes deployment (#365) * feat: add Helm chart for Kubernetes deployment Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Replace bundled Bitnami subcharts with in-chart manifests on official images The Bitnami catalog removed all versioned image tags from docker.io/bitnami in Aug 2025 (old images frozen in bitnamilegacy, maintained catalog now behind a Broadcom subscription), so the bundled postgresql/redis/minio subcharts no longer pull. Replace them with plain in-chart manifests built on official upstream images, keeping the internal/all-in-one path fully self-contained and free of third-party chart packaging that can disappear: - internal-postgres.yaml: pgvector/pgvector:pg17 — upstream Postgres plus the `vector` extension the migrations require. POSTGRES_USER=dograh is the initdb superuser, so CREATE EXTENSION vector succeeds. - internal-redis.yaml: redis:7.4-alpine, password-protected, AOF persistence. - internal-minio.yaml: minio/minio, root creds shared with the app via a single secret (can't drift); the app auto-creates its bucket. Service/secret names are unchanged (<rel>-postgresql, <rel>-redisinternal-master, <rel>-minio) so the app wiring is untouched. Dep passwords are generated once and persisted across upgrades via lookup. Drop the Chart.yaml dependencies, Chart.lock, and the `helm dependency` step; the internal manifests gate on the mode toggles (database.mode=internal, etc.). Also fixes surfaced by smoke-testing on a live EKS cluster: - Dockerfile: ship the per-service run_*.sh entrypoints the chart invokes. - migrate-job: run as a post-install/pre-upgrade hook (the bundled Postgres does not exist during pre-install) with a wait-for-postgres init container. - backend env: declare POSTGRES_PASSWORD/REDIS_PASSWORD before the DATABASE_URL/ REDIS_URL that interpolate them (Kubernetes only expands back-references). - worker liveness probes: pgrep isn't in the slim runtime image; check /proc/1/cmdline instead (each worker execs its process as PID 1). - UI: set HOSTNAME=0.0.0.0 so Next.js standalone doesn't bind to the k8s-injected pod name (which maps to the pod IP only, breaking port-forward/loopback). Verified end-to-end on EKS 1.36: all pods Ready, migrations applied (pgvector extension + 27 tables), UI login page and web API served via port-forward. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-03 12:39:39 +05:30
cd "$BASE_DIR"
exec uvicorn api.app:app --host 0.0.0.0 --port "$PORT" --workers 1