پیش‌نمایش خصوصی: سایت آنلاین اما غیرعمومی تا زمان انتشار

- گیت ورود Traefik (Basic Auth) روی همه مسیرها: سایت، API، تصاویر و چت — بدون رمز فقط ۴۰۱
- لایه دوم noindex: هدر X-Robots-Tag روی همه پاسخ‌ها + robots.txt مسدودکننده + نقشه سایت خالی
- اسکریپت scripts/preview-mode.sh on|off|status — ساخت خودکار نام کاربری/رمز و هماهنگ‌کردن .env
- دو دامنه (DOMAIN + DOMAIN_ALIAS) با گواهی TLS و ریدایرکت ۳۰۱ دامنه دوم به اصلی در زمان انتشار
- اسکیمای FAQPage در پوسته سئوی سمت سرور (فارسی و انگلیسی) برای خزنده‌های بدون جاوااسکریپت
- مستندسازی جریان پیش‌نمایش و چک‌لیست انتشار در README و .env.example
This commit is contained in:
MMD
2026-09-26 22:47:04 +03:30
parent 1d29e50852
commit d25db9367c
8 changed files with 485 additions and 9 deletions
+33 -5
View File
@@ -6,6 +6,16 @@
#
# همه درخواست‌های HTTP به HTTPS هدایت می‌شوند و مسیریابی‌ها فقط روی دامنه DOMAIN پاسخ می‌دهند.
# برای داشبوردها: analytics.DOMAIN (آنالیتیکس) و grafana.DOMAIN (مانیتورینگ، با فایل monitoring).
#
# ---- پیش‌نمایش خصوصی و انتشار (scripts/preview-mode.sh) ----
# در حالت پیش‌نمایش (PREVIEW_MODE=on) کل سایت پشت Basic Auth است و noindex می‌گیرد:
# تیم با یک نام کاربری/رمز مشترک وارد می‌شود، محتوا را ویرایش می‌کند و هیچ‌کس دیگری —
# از جمله گوگل — به سایت دسترسی ندارد. برای انتشار عمومی:
# bash scripts/preview-mode.sh off → deploy مجدد → ثبت sitemap در Search Console.
#
# DOMAIN دامنه اصلی است و DOMAIN_ALIAS دامنه دوم (هر دو مسیر و گواهی می‌گیرند).
# در زمان انتشار، برای جلوگیری از محتوای تکراری، دامنه دوم را به اصلی ریدایرکت کنید:
# ALIAS_REDIRECT=on (در .env) — ریدایرکت ۳۰۱ دائمی به دامنه اصلی.
services:
traefik:
@@ -43,7 +53,7 @@ services:
- traefik.http.routers.media.entrypoints=websecure
- traefik.http.routers.media.tls.certresolver=le
- traefik.http.routers.media.priority=100
- traefik.http.routers.media.middlewares=media-rewrite,sec-headers
- traefik.http.routers.media.middlewares=${PREVIEW_MIDDLEWARES:+$PREVIEW_MIDDLEWARES,}media-rewrite,sec-headers
- traefik.http.middlewares.media-rewrite.replacepathregex.regex=^/media/(.*)
- traefik.http.middlewares.media-rewrite.replacepathregex.replacement=/aramesh-media/$$1
- traefik.http.services.media.loadbalancer.server.port=9000
@@ -53,16 +63,18 @@ services:
# سایت هم‌مبدأ است — CORS لازم نیست
CORS_ORIGINS: '[]'
SITE_URL: https://${DOMAIN:?DOMAIN را در .env تنظیم کنید}
# پیش‌نمایش خصوصی — هدر noindex + robots مسدودکننده (لایه دوم؛ لایه اول گیت Traefik)
PREVIEW_MODE: ${PREVIEW_MODE:-off}
labels:
- traefik.enable=true
- traefik.http.routers.api.rule=Host(`${DOMAIN}`) && PathPrefix(`/api`)
- traefik.http.routers.api.entrypoints=websecure
- traefik.http.routers.api.tls.certresolver=le
- traefik.http.routers.api.middlewares=api-flood,sec-headers
- traefik.http.routers.api.middlewares=${PREVIEW_MIDDLEWARES:+$PREVIEW_MIDDLEWARES,}api-flood,sec-headers
- traefik.http.routers.seo.rule=Host(`${DOMAIN}`) && (PathPrefix(`/blog/`) || Path(`/blog`) || PathPrefix(`/projects/`) || Path(`/projects`) || Path(`/en`) || PathPrefix(`/en/`) || PathPrefix(`/robots.txt`) || PathPrefix(`/sitemap.xml`))
- traefik.http.routers.seo.entrypoints=websecure
- traefik.http.routers.seo.tls.certresolver=le
- traefik.http.routers.seo.middlewares=sec-headers
- traefik.http.routers.seo.middlewares=${PREVIEW_MIDDLEWARES:+$PREVIEW_MIDDLEWARES,}sec-headers
frontend:
labels:
@@ -70,12 +82,28 @@ services:
- traefik.http.routers.web.rule=Host(`${DOMAIN}`) && PathPrefix(`/`)
- traefik.http.routers.web.entrypoints=websecure
- traefik.http.routers.web.tls.certresolver=le
- traefik.http.routers.web.middlewares=sec-headers
- traefik.http.routers.web.middlewares=${PREVIEW_MIDDLEWARES:+$PREVIEW_MIDDLEWARES,}sec-headers
# تعریف یک‌بارهٔ میان‌افزار هدرهای امنیتی — روی همهٔ روترهای websecure استفاده می‌شود
- traefik.http.middlewares.sec-headers.headers.stsSeconds=31536000
- traefik.http.middlewares.sec-headers.headers.stsIncludeSubdomains=true
- traefik.http.middlewares.sec-headers.headers.stsPreload=true
- traefik.http.middlewares.sec-headers.headers.contentTypeNosniff=true
# ---- گیت پیش‌نمایش خصوصی ----
# ورود با نام کاربری/رمز مشترک (htpasswd) — تا وقتی PREVIEW_MIDDLEWARES تنظیم است فعال می‌شود
- traefik.http.middlewares.preview-auth.basicauth.users=${PREVIEW_AUTH_USERS:-disabled:nope}
- traefik.http.middlewares.preview-auth.basicauth.realm=Aramesh private preview
# لایه دوم جلوگیری از ایندکس — حتی اگر گیت حذف شد، گوگل چیزی ذخیره نکند
- traefik.http.middlewares.preview-noindex.headers.customresponseheaders.X-Robots-Tag=noindex, nofollow, noarchive
# ---- ریدایرکت دامنه دوم به اصلی (زمان انتشار: ALIAS_REDIRECT=on) ----
- traefik.http.middlewares.to-primary.redirectregex.regex=^https?://[^/]+(.*)
- traefik.http.middlewares.to-primary.redirectregex.replacement=https://${DOMAIN}$$1
- traefik.http.middlewares.to-primary.redirectregex.permanent=true
- traefik.http.routers.alias-redirect.rule=Host(`${DOMAIN_ALIAS:-invalid.invalid}`)
- traefik.http.routers.alias-redirect.entrypoints=websecure
- traefik.http.routers.alias-redirect.tls.certresolver=le
- traefik.http.routers.alias-redirect.priority=1000
- traefik.http.routers.alias-redirect.middlewares=${ALIAS_REDIRECT_MIDDLEWARES:-sec-headers}
- traefik.http.routers.alias-redirect.service=web
chatbot:
labels:
@@ -84,7 +112,7 @@ services:
- traefik.http.routers.chat.entrypoints=websecure
- traefik.http.routers.chat.tls.certresolver=le
- traefik.http.routers.chat.priority=100
- traefik.http.routers.chat.middlewares=api-flood,sec-headers
- traefik.http.routers.chat.middlewares=${PREVIEW_MIDDLEWARES:+$PREVIEW_MIDDLEWARES,}api-flood,sec-headers
umami:
labels: