From 049cc41afcca2143bfb0ed93f70755c0b3a53ccc Mon Sep 17 00:00:00 2001 From: javad Date: Fri, 11 Sep 2026 14:01:52 +0330 Subject: [PATCH] static and media url fix 4 --- Dockerfile.nginx | 8 ++++++++ docker-compose.yml | 7 +++++-- docs/DEPLOYMENT_COOLIFY.md | 3 +++ tests/test_deployment.py | 9 +++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 Dockerfile.nginx diff --git a/Dockerfile.nginx b/Dockerfile.nginx new file mode 100644 index 0000000..22dc849 --- /dev/null +++ b/Dockerfile.nginx @@ -0,0 +1,8 @@ +ARG NGINX_IMAGE=nginx:1.27-alpine +FROM ${NGINX_IMAGE} + +# The official Nginx entrypoint renders templates into /etc/nginx/conf.d. +# Baking the template into the image avoids stale or missing host bind mounts +# in Git-based Coolify deployments while preserving env substitution for +# MEDIA_SIGNING_SECRET. +COPY docker/nginx.conf /etc/nginx/templates/default.conf.template diff --git a/docker-compose.yml b/docker-compose.yml index 913e554..bc3dd00 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -82,7 +82,11 @@ services: stop_grace_period: 20s nginx: - image: ${NGINX_IMAGE:-nginx:1.27-alpine} + build: + context: . + dockerfile: Dockerfile.nginx + args: + NGINX_IMAGE: ${NGINX_IMAGE:-nginx:1.27-alpine} restart: unless-stopped networks: - coolify @@ -111,7 +115,6 @@ services: web: condition: service_healthy volumes: - - ./docker/nginx.conf:/etc/nginx/templates/default.conf.template:ro - static_data:/app/staticfiles:ro - media_data:/app/media:ro environment: diff --git a/docs/DEPLOYMENT_COOLIFY.md b/docs/DEPLOYMENT_COOLIFY.md index b8ed98d..ec7662b 100644 --- a/docs/DEPLOYMENT_COOLIFY.md +++ b/docs/DEPLOYMENT_COOLIFY.md @@ -36,6 +36,8 @@ customer_ticket_seed Traefik خود Coolify ruleهای Host/PathPrefix، TLS و reverse proxy را تولید می‌کند. به‌دلیل باگ رقابت route مسیرمحور با route عمومی در برخی نسخه‌های Coolify، Compose روی routerهای تولیدشده‌ی nginx صراحتاً `priority=10000`، یک service روی پورت 80 و شبکه‌ی resource-specific را تنظیم می‌کند. ترتیب سه Domain بالا را تغییر ندهید، چون شماره routerهای `0` تا `2` از همین ترتیب ساخته می‌شود. Nginx جلوی Django قرار نمی‌گیرد و فقط فایل‌های static و media را سرو می‌کند. +کانفیگ `docker/nginx.conf` هنگام build توسط `Dockerfile.nginx` داخل image قرار می‌گیرد. بنابراین در Git-based deployment هیچ bind mountای از فایل کانفیگ روی میزبان Coolify وجود ندارد و هر redeploy دقیقاً کانفیگ همان commit را اجرا می‌کند. entrypoint رسمی image مقدار `MEDIA_SIGNING_SECRET` را در template جایگزین و فایل نهایی را در `/etc/nginx/conf.d/default.conf` ایجاد می‌کند. + فایل‌های آپلودی تیکت عمومی نیستند: Django ابتدا مجوز را بررسی می‌کند و سپس کاربر را با یک URL امضاشده پنج‌دقیقه‌ای به `/protected-media/` روی Nginx می‌فرستد. branding عمومی زیر `/media/branding/` مستقیماً از Nginx سرو می‌شود. ## 3. متغیرهای ضروری @@ -140,6 +142,7 @@ SECURE_HSTS_PRELOAD=false - `GET /healthz/` هم web server و هم اتصال دیتابیس را بررسی می‌کند. - `docker compose ps` باید `web` و `nginx` را healthy و worker را Running نشان دهد. - `docker compose logs --tail=200 web notification-worker nginx` خطاهای startup و provider را نمایش می‌دهد. +- داخل کانتینر Nginx، `nginx -T` باید `location = /healthz/` را نشان دهد و `wget -S -O - http://127.0.0.1/healthz/` باید پاسخ `200` برگرداند. پاسخ `404` در این تست یعنی image یا commit جدید deploy نشده است. - وضعیت outbox را می‌توان در Django admin یا shell از مدل `NotificationJob` بررسی کرد؛ FAILED و `last_error` دلیل خطا را نگه می‌دارند. - برای پردازش کنترل‌شده یک job مشخص: `python manage.py process_notifications --once --job-id `. diff --git a/tests/test_deployment.py b/tests/test_deployment.py index 2001c70..c039e0a 100644 --- a/tests/test_deployment.py +++ b/tests/test_deployment.py @@ -36,12 +36,21 @@ def test_bale_missing_token_is_not_silently_successful(settings): def test_nginx_serves_assets_without_proxying_django(): root = Path(__file__).resolve().parents[1] nginx = (root / "docker" / "nginx.conf").read_text(encoding="utf-8") + nginx_dockerfile = (root / "Dockerfile.nginx").read_text(encoding="utf-8") compose = (root / "docker-compose.yml").read_text(encoding="utf-8") assert "location /static/" in nginx assert "location ^~ /media/branding/" in nginx assert "location /protected-media/" in nginx + assert "location = /healthz/" in nginx + assert "return 200" in nginx assert "secure_link_md5" in nginx assert "proxy_pass" not in nginx + assert "dockerfile: Dockerfile.nginx" in compose + assert "./docker/nginx.conf:" not in compose + assert ( + "COPY docker/nginx.conf /etc/nginx/templates/default.conf.template" + in nginx_dockerfile + ) assert "media_data:/app/media:ro" in compose assert "notification-worker:" in compose assert " db:" not in compose