سئوی سمت سرور (backend/app/seo_pages.py) - متا/canonical/hreflang/JSON-LD برای همهٔ صفحات عمومی (شش صفحهٔ استاتیک فارسی که قبلاً پوستهٔ خالی بودند) - canonical سمت سرور (قبلاً فقط با JS ست میشد)، ۴۰۴ واقعی برای مسیرهای ناموجود - اسکیما: Organization با لوگوی ImageObject، FAQPage، LocalBusiness، BreadcrumbList، CreativeWork پروژه با همهٔ تصاویر بهصورت ImageObject (نام/توضیح + موقعیت پروژه) - hreflang فقط وقتی ترجمهٔ انگلیسی واقعاً وجود دارد؛ sitemap با URLهای درصدگذاریشده - llms.txt و robots.txt تازهساز از دیتابیس؛ سیاست صریح خزندههای AI + Allow: /api/site - _site_content_html: محتوای واقعی سایت بهصورت HTML خوانا در <noscript> — خزندههای بدون جاوااسکریپت (GPTBot/OAI-SearchBot/ClaudeBot/PerplexityBot) از ۲۴۰ نویسه به ۸٬۵۰۰+ نویسه محتوای معنایی میرسند - Cache-Control: no-store روی HTML و llms.txt (جلوگیری از کش کهنهٔ CDN)، max-age روی sitemap فرانتاند - api.tsx: خواندن دادهٔ تزریقشدهٔ سرور (window.__SITE__) بهعنوان حالت اولیه — رندر بدون XHR - App.tsx: اسکلت بارگذاری بهجای DOM خالی (رفع Soft 404 گوگل) - index.html: فاوآیکون واقعی برند (قبلاً به vite.svg ناموجود اشاره میکرد) + preload فونت زیرساخت - Dockerfile: آینهٔ PyPI (Tsinghua/Aliyun) — PyPI برای IP ایران بلاک است - Caddyfile: هر مسیر پسونددار بدون فایل واقعی ۴۰۴ میگیرد (قبلاً HTML اسپا برمیگرداند) - docker-compose.prod.yml: مسیرهای seo برای صفحات استاتیک + llms.txt + کلیدهای IndexNow داده - seed_data*.py: حذف دفاتر و معرفیهای دمو (که در هر استقرار برمیگشتند)؛ تنها دفتر واقعی: اصفهان، ملاصدرا شمالی داراییها - فاوآیکون/آیکونهای برند از لوگوی رسمی + کلیدهای IndexNow
36 lines
1.8 KiB
Docker
36 lines
1.8 KiB
Docker
# بکاند FastAPI — تصویر باریک و بدون root
|
|
FROM python:3.13-slim
|
|
|
|
WORKDIR /app
|
|
|
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
PYTHONUNBUFFERED=1
|
|
|
|
COPY requirements.txt .
|
|
# PyPI برای IP ایران بلاک است (connection timeout) — آینهٔ Tsinghua پیشفرض است و
|
|
# Aliyun بهعنوان منبع دوم؛ با --build-arg قابل بازنویسی است (مثلاً روی CI خارج ایران)
|
|
ARG PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
|
ARG PIP_EXTRA_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
|
|
RUN pip install --no-cache-dir -i "$PIP_INDEX_URL" --extra-index-url "$PIP_EXTRA_INDEX_URL" -r requirements.txt
|
|
|
|
# FFmpeg — نرمالسازی رسانه به WebP برای ورودیهایی که Pillow نمیخواند
|
|
# (ویدیو → WebP متحرک، فرمتهای تصویری خاص). مسیر Pillow به آن وابسته نیست.
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends ffmpeg \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
COPY app ./app
|
|
COPY alembic.ini ./
|
|
COPY migrations ./migrations
|
|
|
|
# کاربر بدون دسترسی root — برنامه چیزی روی دیسک محلی نمینویسد
|
|
RUN useradd --system --create-home appuser \
|
|
&& chown -R appuser:appuser /app
|
|
USER appuser
|
|
|
|
EXPOSE 8000
|
|
# ساخت جداول پایه، مهاجرتهای Alembic و seed (بدون حذف دادههای موجود) و سپس
|
|
# اجرای سرور با exec — تا SIGTERM (docker stop) مستقیم به uvicorn برسد و خاموشی
|
|
# تمیز انجام شود؛ --proxy-headers برای دیدن IP واقعی کلاینت پشت Traefik
|
|
CMD ["sh", "-c", "python -m app.db_init && alembic upgrade head && python -m app.seed && exec uvicorn app.main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips='*'"]
|