دليل النشر

نشر FastAPI على VPS: الدليل الكامل للإنتاج

انشر على VPS Cloud ←

دليل عملي

نشر FastAPI على VPS: الدليل الكامل للإنتاج

التطوير10 دقائق للقراءةعدد الخطوات: 7

‏فرض FastAPI نفسه كإطار عمل Python المفضّل لواجهات API السريعة والمُنمَّطة (typed)، بفضل دعمه الأصيل للعمل غير المتزامن ولوثائق OpenAPI. ونشره على VPS الخاص بك يمنحك التحكم في عدد الـworkers وفي WebSocket وزمن الاستجابة، دون سقف تفرضه خدمة مُدارة. يغطي هذا الدليل إجمالية النشر الإنتاجي: الحاوية متعددة المراحل، وقاعدة البيانات مع ترحيل Alembic، وCI/CD الآلي، واستكشاف الأخطاء الشائعة وإصلاحها.

المحتويات· لماذا تستضيف FastAPI ذاتيًا على VPS؟1/9
  1. 01لماذا تستضيف FastAPI ذاتيًا على VPS؟
  2. 02فوائد ملموسة لاستضافة FastAPI ذاتيًا
  3. 03المتطلبات المسبقة للعتاد والبرمجيات والإصدارات
  4. 04نشر FastAPI خطوة بخطوة
  5. 05قاعدة البيانات والترحيل
  6. 06CI/CD والنشر الآلي
  7. 07المراقبة والسجلات
  8. 08استكشاف الأخطاء الشائعة وإصلاحها
  9. 09نشر FastAPI بنقرة واحدة من Marketplace ServOrbit

لماذا تستضيف FastAPI ذاتيًا على VPS؟

يستمد FastAPI كل أدائه من نموذج ASGI غير المتزامن: اتصالات WebSocket دائمة، وبث للاستجابات، واستدعاءات متزامنة لخدمات أخرى. وغالبًا ما تقطع منصات serverless الاتصالات الطويلة وتفوتر كل طلب، مما يضرّ بواجهة API عالية الإنتاجية أو تعمل في الوقت الفعلي. على VPS، تشغّل Uvicorn بإدارة Gunicorn بعدد workers يساوي عدد الأنوية، وتُبقي الاتصالات مفتوحة طالما لزم الأمر، وتضع Nginx في الواجهة لأجل TLS والتخزين المؤقت (buffering). كما تتحكم في مجمّع الاتصالات نحو PostgreSQL وفي ذاكرة Redis المؤقتة، وهما رافعتان أساسيتان عندما يرتفع الحِمل — أمّا المعدّل الذي يُتحمَّل فعليًا فيُقاس على حركتك أنت.

فوائد ملموسة لاستضافة FastAPI ذاتيًا

  • ‏WebSockets وServer-Sent Events دون قطع الاتصال أو timeout مفروض.
  • ضبط دقيق لـworkers الخاصة بـUvicorn/Gunicorn وفق عدد أنوية VPS.
  • لا بدء بارد (cold start): تبقى العملية قائمة بين طلب وآخر.
  • وثائق Swagger وReDoc تُقدَّم داخليًا، متاحة أو محمية حسب رغبتك.
  • تكامل مباشر مع مجمّع PostgreSQL غير متزامن (asyncpg) ومع Redis.
  • تكلفة ثابتة بغض النظر عن عدد استدعاءات API، مثالية لخلفية (backend) إنتاجية.

المتطلبات المسبقة للعتاد والبرمجيات والإصدارات

واجهة FastAPI خفيفة: يكفي 1 vCPU و1 غيغابايت من ذاكرة RAM للبدء، لكن استهدف 2 vCPU و2 غيغابايت بمجرد إضافة قاعدة بيانات وذاكرة تخزين مؤقت على نفس VPS. للحِمل المستمر (أكثر من 100 طلب/ثانية)، اشترط 4 vCPU و4 غيغابايت على الأقل.

الإصدارات الموصى بها في 2025: Python 3.11+ (3.12 للأداء الأقصى)، FastAPI 0.115+ (دعم كامل لـPydantic v2 وتعليقات Python 3.10+)، Uvicorn 0.30+ (إصلاحات استقرار event loop). ثبِّت عبر Docker مع صورة python:3.12-slim، أو من المستودع الرسمي بـpip install fastapi[standard]>=0.115 uvicorn[standard]>=0.30 gunicorn>=22.0.

من جهة البنية التحتية: Docker Engine 24+، Docker Compose v2 (plugin متكامل، docker compose)، Nginx 1.24+ كبروكسي عكسي، ونطاق مُوجَّه نحو VPS للحصول على شهادة TLS. نظام Ubuntu 22.04/24.04 LTS هو الأساس الموصى به؛ Debian 12 يعمل أيضًا.

نشر FastAPI خطوة بخطوة

  1. تهيئة VPS والتطبيق

    اتصل عبر SSH، وثبِّت Docker، واستنسخ مستودعك، وأنشئ ملف .env من النموذج .env.example المُرفق بمشروعك. يجب أن يحتوي هذا الملف على الحد الأدنى:

    DATABASE_URL=postgresql+asyncpg://user:password@db:5432/appdb
    REDIS_URL=redis://redis:6379/0
    SECRET_KEY=changeme-in-production
    CORS_ORIGINS=["https://yourdomain.com"]
    ENVIRONMENT=production

    تأكّد من أن نقطة الدخول تكشف فعلًا app = FastAPI() وأن التطبيق يُحمِّل إعداداته من متغيرات البيئة (لا تُكتب أبدًا في الكود مباشرة).

  2. التعبئة في حاوية باستخدام Dockerfile متعدد المراحل

    يفصل النهج متعدد المراحل مرحلة البناء (تصريف الاعتماديات، توليد wheels) عن صورة وقت التشغيل، مما يُقلّص الحجم النهائي بنسبة 60 إلى 80% ويُزيل أدوات التصريف من سطح الهجوم:

    # ── Stage 1 : build ──────────────────────────────────────
    FROM python:3.12-slim AS builder
    WORKDIR /app
    COPY requirements.txt .
    RUN pip install --upgrade pip && \
        pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt
    
    # ── Stage 2 : runtime ────────────────────────────────────
    FROM python:3.12-slim
    WORKDIR /app
    COPY --from=builder /wheels /wheels
    RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels
    COPY . .
    EXPOSE 8000
    CMD ["gunicorn", "main:app", "-k", "uvicorn.workers.UvicornWorker",
         "--bind", "0.0.0.0:8000", "--workers", "4",
         "--timeout", "120", "--keep-alive", "5"]

    أضف نقطة نهاية /health في تطبيقك لفحوصات السلامة:

    @app.get("/health")
    async def health():
        return {"status": "ok"}
  3. ضبط workers في Gunicorn بالشكل الأمثل

    صيغة (2 × الأنوية) + 1 هي نقطة الانطلاق لـworkers الـCPU-bound. بما أن FastAPI هو ASGI/غير متزامن، يتعامل كل worker مع طلبات متعددة تزامنيًا عبر event loop — للأحمال الـI/O-bound النموذجية (استدعاءات قاعدة البيانات، طلبات HTTP الخارجية)، النطاق الأنوية + 1 إلى 2 × الأنوية أنسب.

    مرِّر القيمة عبر متغير بيئة لتعديلها دون إعادة بناء الصورة:

    WEB_CONCURRENCY=4  # في .env أو docker-compose.yml
    CMD ["gunicorn", "main:app", "-k", "uvicorn.workers.UvicornWorker",
         "--bind", "0.0.0.0:8000",
         "--workers", "${WEB_CONCURRENCY:-4}"]

    تحت الحِمل العالي، راقب استخدام CPU لكل worker (docker stats) وعدد الطلبات المنتظرة في سجلات Gunicorn (--access-logfile -) قبل زيادة عدد الـworkers.

  4. تنسيق الخدمات مع Docker Compose

    في docker-compose.yml، عرِّف خدمة api وخدمة db بـPostgreSQL وخدمة redis. استخدم depends_on مع condition: service_healthy كي تنتظر الـAPI جاهزية قاعدة البيانات قبل أن تبدأ:

    services:
      api:
        build: .
        env_file: .env
        ports: ["8000:8000"]
        depends_on:
          db:
            condition: service_healthy
          redis:
            condition: service_started
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
          interval: 30s
          retries: 3
    
      db:
        image: postgres:16-alpine
        environment:
          POSTGRES_USER: user
          POSTGRES_PASSWORD: password
          POSTGRES_DB: appdb
        volumes: ["pgdata:/var/lib/postgresql/data"]
        healthcheck:
          test: ["CMD", "pg_isready", "-U", "user"]
          interval: 10s
          retries: 5
    
      redis:
        image: redis:7-alpine
    
    volumes:
      pgdata:
  5. وضع Nginx كبروكسي عكسي

    اضبط كتلة خادم بـproxy_pass http://api:8000، ولأجل WebSockets أضف الترويسات الضرورية. عطِّل التخزين المؤقت (buffering) للبث عند الحاجة:

    server {
        listen 443 ssl;
        server_name api.yourdomain.com;
    
        location / {
            proxy_pass http://api:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_buffering off;
        }
    }
  6. التأمين بشهادة TLS

    احصل على شهادة Let's Encrypt عبر Certbot أو حاوية companion، وافرض HTTPS وأعِد توجيه HTTP. وتذكّر تقييد الوصول إلى /docs و/openapi.json في الإنتاج إذا لم تكن الـAPI عامة.

  7. التشغيل والاختبار

    ابدأ باستخدام docker compose up -d، وتحقّق من السلامة عبر نقطة النهاية /health التي أضفتها، واختبر الوثائق التفاعلية. راقب سجلات Uvicorn لضبط عدد الـworkers تحت الحِمل الفعلي.

بالنسبة إلى المهام الطويلة (إرسال رسائل البريد الإلكتروني، معالجة الصور، الاستدعاءات الخارجية البطيئة)، لا تحجب حلقة الأحداث (event loop): انقلها إلى worker يعمل في الخلفية باستخدام BackgroundTasks للحالات البسيطة، أو إلى Celery/ARQ مع Redis للمعالجات الثقيلة. واجهة API تستجيب بسرعة وتفوّض العمل غير المتزامن تبقى سريعة الاستجابة حتى تحت التزامن العالي.

قاعدة البيانات والترحيل

لتطبيقات FastAPI في الإنتاج، يوفر asyncpg مدمجًا مع SQLAlchemy 2.x (الوضع غير المتزامن) أفضل توازن بين الأداء وقابلية الصيانة. اضبط مجمّع الاتصالات وفق الحِمل المتوقع:

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker

engine = create_async_engine(
    DATABASE_URL,
    pool_size=10,        # اتصالات دائمة
    max_overflow=20,     # اتصالات إضافية عند الذروة
    pool_timeout=30,     # ثوانٍ قبل الخطأ
    pool_recycle=1800,   # إعادة تدوير بعد 30 دقيقة لتجنب timeouts PostgreSQL
    echo=False,
)

AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)

أدخِل الجلسة في مساراتك عبر تبعية FastAPI:

async def get_db():
    async with AsyncSessionLocal() as session:
        yield session

لترحيل المخطط (schema)، Alembic هو الأداة المعيارية. هيِّئه في مشروعك (alembic init migrations) ثم اضبط alembic.ini للإشارة إلى DATABASE_URL. الأوامر الأساسية:

# توليد ترحيل من نماذج SQLAlchemy
alembic revision --autogenerate -m "add_users_table"

# تطبيق الترحيلات المعلّقة
alembic upgrade head

# التحقق من الحالة الحالية
alembic current

في الإنتاج، شغِّل alembic upgrade head قبل تشغيل الـAPI — أضفها كأمر تهيئة في docker-compose.yml أو في سكريبت بدء منفصل. لا تُشغِّل الترحيلات أبدًا من نسخ متعددة في آنٍ واحد.

CI/CD والنشر الآلي

تكفي خطوط أنابيب GitHub Actions بسيطة لمعظم مشاريع FastAPI: بناء الصورة، ودفعها إلى سجل، ونشرها على VPS عبر SSH مع zero-downtime.

# .github/workflows/deploy.yml
name: Deploy FastAPI
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build & push Docker image
        run: |
          docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
          echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
          docker push ghcr.io/${{ github.repository }}:${{ github.sha }}

      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.VPS_HOST }}
          username: deploy
          key: ${{ secrets.VPS_SSH_KEY }}
          script: |
            cd /opt/myapp
            export IMAGE_TAG=${{ github.sha }}
            docker compose pull api
            docker compose up -d --no-deps api
            docker compose exec api alembic upgrade head

خيار --no-deps على docker compose up يُعيد تشغيل حاوية api فحسب دون المساس بـdb أو redis، مما يضمن zero-downtime للخدمات المساندة. للنشرات الأكثر متانة مع rollback فوري، تَوِّج صورك بـSHA الـcommit واحتفظ بآخر 3 نسخ محليًا.

المراقبة والسجلات

يمكنك الوصول إلى سجلات Uvicorn مباشرةً عبر Docker:

# سجلات في الوقت الفعلي
docker compose logs -f api

# آخر 100 سطر
docker compose logs --tail=100 api

للسجلات المهيكلة بصيغة JSON (قابلة للفهرسة بمجمِّع مثل Loki أو Elasticsearch)، استبدل مُسجِّل Python القياسي بـloguru أو structlog:

from loguru import logger
import sys

logger.remove()
logger.add(sys.stdout, format="{time} {level} {message}", serialize=True)

@app.middleware("http")
async def log_requests(request, call_next):
    logger.info("request", method=request.method, url=str(request.url))
    response = await call_next(request)
    logger.info("response", status=response.status_code)
    return response

لكشف مقاييس Prometheus، أضف نقطة نهاية /metrics بـprometheus-fastapi-instrumentator:

from prometheus_fastapi_instrumentator import Instrumentator

Instrumentator().instrument(app).expose(app, endpoint="/metrics")

ثم قيِّد /metrics على شبكتك الداخلية من Nginx (allow 127.0.0.1; deny all;) لتفادي كشف المقاييس علنًا.

استكشاف الأخطاء الشائعة وإصلاحها

‏Worker timed out (pid XXXXX) — أنهى Gunicorn worker لم يستجب ضمن مهلة --timeout. الأسباب الشائعة: مسار متزامن (def بدلًا من async def) يحجب event loop، أو عملية حجب (قراءة ملف، استدعاء شبكة) تُنفَّذ دون asyncio.run_in_executor. زيادة --timeout يُخفي المشكلة؛ الإصلاح الصحيح هو جعل المسار غير متزامن أو تفويض العمل الحاجب.

‏Address already in use (port 8000) — عملية Gunicorn سابقة لا تزال نشطة. في Docker: docker compose down ثم docker compose up -d يُجبر على إعادة إنشاء الحاوية ويُحرّر المنفذ. تحقق بـdocker ps -a أنه لا تعمل حاوية zombie.

‏502 Bad Gateway بعد نشر — أعاد Nginx توجيه الطلب إلى الـAPI أثناء إعادة تشغيلها. انتظر 10 إلى 15 ثانية حتى يؤكد فحص سلامة Docker أن الحاوية الجديدة healthy قبل اعتبار النشر مكتملًا. أضف proxy_read_timeout 60; في Nginx لاستيعاب عمليات البدء البطيئة.

‏CORS في الإنتاج: No 'Access-Control-Allow-Origin' header — يخدم FastAPI الأصول (origins) المُعلَن عنها في CORSMiddleware. تحقق أن CORS_ORIGINS في ملف .env يحتوي على رابط الواجهة الأمامية بالضبط (البروتوكول + النطاق + المنفذ إن لم يكن قياسيًا، دون شرطة مائلة في النهاية). قيمة ["*"] تعمل في التطوير لكن لا يجب إرسالها إلى الإنتاج أبدًا.

‏رفض اتصال قاعدة البيانات عند البدء — بدأت الـAPI قبل أن تصبح PostgreSQL جاهزة. depends_on مع condition: service_healthy في Docker Compose يحلّ هذا. في Kubernetes أو في نشرات بدون Compose، نفِّذ حلقة retry مع تراجع أسي (exponential backoff) في كود بدء التطبيق.

نشر FastAPI بنقرة واحدة من Marketplace ServOrbit

تقدّم Marketplace ServOrbit قالب FastAPI Stack جاهزًا: Python 3.12 وUvicorn وGunicorn وNginx وPostgreSQL 16 تُثبَّت تلقائيًا على VPS عند الطلب. لا جلسة SSH للإعداد الأساسي — تصل مباشرة إلى خطوة استنساخ مستودعك وتشغيل Uvicorn. صفحة marketplace تحتوي المواصفات والحالات ودليل الاستخدام الأول.

انشر FastAPI Stack في دقائق

قالب ServOrbit FastAPI Stack يثبّت Python 3.12 وUvicorn وGunicorn وNginx وPostgreSQL 16 على VPS. شغّل واجهتك API فورًا.

بحاجة إلى مساعدة؟

تصفّح مركز المساعدة والأسئلة الشائعة، أو تواصل مع فريقنا — معاودة اتصال أو WhatsApp أو بريد إلكتروني. الدعم بـالعربية والفرنسية والإنجليزية.

راسلنا على WhatsAppيُفتح في علامة تبويب جديدة