تكنولوجيا March 7, 2026 5 مشاهدة

كيف تبني بنية تحتية كاملة بـ Docker Compose: صفحة هبوط + n8n + FastMCP + Traefik

دليل عملي شامل لبناء بنية تحتية متكاملة على VPS واحد باستخدام Docker Compose، تشمل صفحة هبوط وأتمتة n8n وخادم FastMCP وبروكسي Traefik مع SSL تلقائي.

كيف تبني بنية تحتية كاملة بـ Docker Compose: صفحة هبوط + n8n + FastMCP + Traefik

ما الذي سنبنيه؟

في هذا المقال سنبني بنية تحتية كاملة تعمل على VPS واحد باستخدام Docker Compose. هذه البنية تتضمن 6 خدمات متكاملة تعمل معاً بسلاسة:

Traefik — بروكسي عكسي يدير كل حركة المرور ويوفر شهادات SSL تلقائية من Let's Encrypt.
n8n — منصة أتمتة مفتوحة المصدر لبناء سير عمل بدون كود.
PostgreSQL — قاعدة بيانات n8n.
Redis — طابور المهام لتشغيل n8n في وضع الـ queue.
n8n Worker — عامل منفصل لتنفيذ المهام المُجدولة.
Landing Page — صفحة هبوط بسيطة تُقدَّم عبر Nginx.
FastMCP — خادم MCP بسيط يوفر أدوات حسابية يمكن لـ Claude استخدامها.

المتطلبات الأساسية

قبل البدء تحتاج إلى: خادم VPS يعمل بنظام Ubuntu 22+ مع ذاكرة 4GB على الأقل، واسم نطاق (domain) مُوجَّه إلى IP الخادم، وتثبيت Docker و Docker Compose على الخادم. إذا لم يكن لديك VPS بعد، ننصحك بـ Hostinger — أسعار ممتازة وأداء موثوق - يمكنك الحصول على خصم خاص بمنصتنا من خلال الرابط في البطاقة التالية:

هيكل المشروع

هذا هو الهيكل الذي سنبنيه على الخادم:

bash
project/
├── docker-compose.yml
├── .env
├── landing/
│   └── index.html
└── mcp/
    ├── Dockerfile
    └── server.py

الخطوة 1: ملف المتغيرات البيئية (.env)

أنشئ ملف

.env

في المجلد الرئيسي للمشروع. هذا الملف يحتوي على جميع الإعدادات الحساسة مثل كلمات المرور وأسماء النطاقات. تأكد من تغيير جميع القيم الافتراضية قبل الاستخدام في الإنتاج!

bash
# ============================================
# 🔐 Environment Variables — Docker Compose
# ============================================

# --- Domain & SSL ---
DOMAIN_NAME=example.com
SUBDOMAIN=n8n
[email protected]

# --- PostgreSQL Database ---
DB_NAME=n8n_db
DB_USER=n8n_user
DB_PASSWORD=SuperSecretP@ssw0rd!2026

# --- Redis ---
REDIS_PASSWORD=R3d1s_S3cur3_K3y!xyz

# --- n8n ---
N8N_ENCRYPTION_KEY=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
GENERIC_TIMEZONE=Asia/Amman

ملاحظة مهمة: استبدل

example.com

باسم نطاقك الحقيقي، وغيّر جميع كلمات المرور إلى قيم قوية وفريدة. يمكنك توليد مفتاح التشفير بالأمر:

openssl rand -hex 16

الخطوة 2: خادم FastMCP للعمليات الحسابية

سنبدأ ببناء أبسط جزء — خادم MCP يوفر أدوات حسابية بسيطة. هذا الخادم يعمل ببروتوكول Model Context Protocol (MCP) مما يتيح لنماذج الذكاء الاصطناعي مثل Claude استخدامه كأداة خارجية.

أنشئ الملف

mcp/server.py

:

python
"""
FastMCP Math Server — خادم MCP بسيط للعمليات الحسابية
يعمل مع Claude عبر بروتوكول MCP (Model Context Protocol)
"""

from fastmcp import FastMCP
import math

mcp = FastMCP(
    "Math Tools",
    description="أدوات حسابية بسيطة عبر بروتوكول MCP",
)


@mcp.tool()
def add(a: float, b: float) -> float:
    """جمع رقمين — Add two numbers together."""
    return a + b


@mcp.tool()
def subtract(a: float, b: float) -> float:
    """طرح رقم من آخر — Subtract b from a."""
    return a - b


@mcp.tool()
def multiply(a: float, b: float) -> float:
    """ضرب رقمين — Multiply two numbers."""
    return a * b


@mcp.tool()
def divide(a: float, b: float) -> float:
    """قسمة رقم على آخر — Divide a by b."""
    if b == 0:
        raise ValueError("لا يمكن القسمة على صفر!")
    return a / b


@mcp.tool()
def square_root(n: float) -> float:
    """حساب الجذر التربيعي — Calculate the square root."""
    if n < 0:
        raise ValueError("لا يمكن حساب الجذر التربيعي لعدد سالب!")
    return math.sqrt(n)


@mcp.tool()
def power(base: float, exponent: float) -> float:
    """رفع رقم لأس معين — Raise base to the power of exponent."""
    return math.pow(base, exponent)


if __name__ == "__main__":
    mcp.run(transport="sse", host="0.0.0.0", port=8000)

النقاط الأساسية في هذا الكود: نستخدم مكتبة

fastmcp

لإنشاء خادم MCP بأقل كود ممكن. كل دالة مُزينة بـ

@mcp.tool()

تصبح أداة متاحة لنماذج AI. الخادم يعمل على المنفذ 8000 باستخدام بروتوكول SSE (Server-Sent Events).

الخطوة 3: ملف Dockerfile لخادم MCP

أنشئ الملف

mcp/Dockerfile

:

dockerfile
FROM python:3.12-slim

WORKDIR /app

RUN pip install --no-cache-dir fastmcp

COPY server.py .

EXPOSE 8000

CMD ["python", "server.py"]

ملف Dockerfile بسيط جداً: نبدأ من صورة Python 3.12 المصغرة، نثبت مكتبة

fastmcp

، ننسخ الكود، ونشغل الخادم.

الخطوة 4: صفحة الهبوط (Landing Page)

أنشئ الملف

landing/index.html

. هذه صفحة بسيطة وأنيقة تُعرض على النطاق الرئيسي:

html
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>شبّك — منصة الأتمتة الذكية</title>
    <link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@400;700;900&display=swap" rel="stylesheet">
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: 'Tajawal', sans-serif;
            background: #0a0e17;
            color: #e2e8f0;
            min-height: 100vh;
        }
        .hero {
            min-height: 100vh;
            display: flex; flex-direction: column;
            align-items: center; justify-content: center;
            text-align: center; padding: 2rem;
        }
        .logo {
            font-size: 4rem; font-weight: 900;
            background: linear-gradient(135deg, #00A8A8, #FFB703);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            margin-bottom: 1rem;
        }
        .tagline { font-size: 1.4rem; color: #94a3b8; max-width: 500px; line-height: 1.8; }
        .cards {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
            gap: 1.5rem; max-width: 900px; width: 100%;
            margin-top: 3rem;
        }
        .card {
            background: rgba(255,255,255,0.03);
            border: 1px solid rgba(255,255,255,0.06);
            border-radius: 16px; padding: 2rem;
            transition: transform 0.3s, border-color 0.3s;
        }
        .card:hover { transform: translateY(-4px); border-color: #00A8A8; }
        .card h3 { font-size: 1.2rem; color: #00A8A8; margin-bottom: 0.5rem; }
        .card p { color: #64748b; font-size: 0.95rem; line-height: 1.6; }
    </style>
</head>
<body>
    <section class="hero">
        <div class="logo">شبّك</div>
        <p class="tagline">منصة أتمتة ذكية تجمع بين n8n و FastMCP و Traefik.</p>
        <div class="cards">
            <div class="card">
                <h3>⚡ n8n</h3>
                <p>أتمتة سير العمل بدون كود مع دعم لمئات التطبيقات.</p>
            </div>
            <div class="card">
                <h3>🧠 FastMCP</h3>
                <p>خادم MCP بسيط يوفر أدوات حسابية لـ Claude.</p>
            </div>
            <div class="card">
                <h3>🔒 Traefik</h3>
                <p>بروكسي عكسي مع شهادات SSL تلقائية.</p>
            </div>
        </div>
    </section>
</body>
</html>

الخطوة 5: ملف Docker Compose الكامل

هذا هو قلب المشروع — ملف

docker-compose.yml

الذي يربط جميع الخدمات معاً. كل خدمة تعمل في حاوية منفصلة وTraefik يوزع حركة المرور بناءً على اسم النطاق:

yaml
version: "3.9"

services:
  # 🔹 Reverse Proxy with Traefik
  traefik:
    image: "traefik"
    container_name: traefik
    restart: always
    command:
      - "--api=true"
      - "--api.insecure=true"
      - "--log.level=DEBUG"
      - "--accesslog=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.mytlschallenge.acme.httpchallenge=true"
      - "--certificatesresolvers.mytlschallenge.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}"
      - "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - traefik_data:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro

  # 🔹 n8n Main Application
  n8n:
    image: docker.n8n.io/n8nio/n8n:next
    container_name: n8n
    restart: always
    ports:
      - "127.0.0.1:5678:5678"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)"
      - "traefik.http.routers.n8n.tls=true"
      - "traefik.http.routers.n8n.entrypoints=web,websecure"
      - "traefik.http.routers.n8n.tls.certresolver=mytlschallenge"
      - "traefik.http.middlewares.n8n.headers.SSLRedirect=true"
      - "traefik.http.middlewares.n8n.headers.STSSeconds=315360000"
      - "traefik.http.middlewares.n8n.headers.browserXSSFilter=true"
      - "traefik.http.middlewares.n8n.headers.contentTypeNosniff=true"
      - "traefik.http.middlewares.n8n.headers.forceSTSHeader=true"
      - "traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true"
      - "traefik.http.middlewares.n8n.headers.STSPreload=true"
      - "traefik.http.routers.n8n.middlewares=n8n@docker"
    environment:
      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=${DB_NAME}
      - DB_POSTGRESDB_USER=${DB_USER}
      - DB_POSTGRESDB_PASSWORD=${DB_PASSWORD}
      - NODE_ENV=production
      - WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - N8N_PROXY_HOPS=1
      - N8N_RUNNERS_ENABLED=true
      - EXECUTIONS_MODE=queue
      - QUEUE_BULL_REDIS_HOST=redis
      - QUEUE_BULL_REDIS_PORT=6379
      - QUEUE_BULL_REDIS_PASSWORD=${REDIS_PASSWORD}
      - OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
    depends_on:
      - redis
      - postgres
    volumes:
      - n8n_data:/home/node/.n8n
      - /local-files:/files

  # 🔹 Redis (Job Queue)
  redis:
    image: redis:6
    container_name: redis
    restart: always
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data

  # 🔹 PostgreSQL Database
  postgres:
    image: postgres:15
    container_name: n8n-postgres
    restart: always
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - pgdata:/var/lib/postgresql/data

  # 🔹 n8n Worker
  n8n-worker:
    image: n8nio/n8n
    container_name: n8n-worker
    restart: always
    command: worker
    depends_on:
      - redis
      - postgres
    environment:
      - EXECUTIONS_MODE=queue
      - QUEUE_BULL_REDIS_HOST=redis
      - QUEUE_BULL_REDIS_PORT=6379
      - QUEUE_BULL_REDIS_PASSWORD=${REDIS_PASSWORD}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=${DB_NAME}
      - DB_POSTGRESDB_USER=${DB_USER}
      - DB_POSTGRESDB_PASSWORD=${DB_PASSWORD}
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}

  # 🔹 Static Landing Page
  landing:
    image: nginx:alpine
    container_name: landing
    restart: always
    volumes:
      - ./landing:/usr/share/nginx/html:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.landing.rule=Host(`${DOMAIN_NAME}`) || Host(`www.${DOMAIN_NAME}`)"
      - "traefik.http.routers.landing.entrypoints=web,websecure"
      - "traefik.http.routers.landing.tls=true"
      - "traefik.http.routers.landing.tls.certresolver=mytlschallenge"
      - "traefik.http.services.landing.loadbalancer.server.port=80"

  # 🔹 FastMCP Server
  mcp:
    build:
      context: ./mcp
      dockerfile: Dockerfile
    container_name: fastmcp
    restart: always
    expose:
      - "8000"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.mcp.rule=Host(`mcp.${DOMAIN_NAME}`)"
      - "traefik.http.routers.mcp.entrypoints=web,websecure"
      - "traefik.http.routers.mcp.tls=true"
      - "traefik.http.routers.mcp.tls.certresolver=mytlschallenge"
      - "traefik.http.services.mcp.loadbalancer.server.port=8000"
      - "traefik.http.middlewares.mcp-cors.headers.accesscontrolallowmethods=GET,POST,OPTIONS"
      - "traefik.http.middlewares.mcp-cors.headers.accesscontrolalloworiginlist=https://claude.ai,https://api.claude.ai"
      - "traefik.http.middlewares.mcp-cors.headers.accesscontrolallowheaders=*"
      - "traefik.http.middlewares.mcp-cors.headers.accesscontrolmaxage=100"
      - "traefik.http.routers.mcp.middlewares=mcp-cors@docker"
    environment:
      - PYTHONUNBUFFERED=1
      - LOG_LEVEL=INFO

# 🔸 Volumes
volumes:
  traefik_data:
  n8n_data:
  pgdata:
  redis_data:

شرح البنية: كيف تعمل الخدمات معاً؟

دعونا نفهم كيف تتواصل هذه الخدمات:

Traefik يستمع على المنفذين 80 و 443 ويوزع الطلبات حسب اسم النطاق. فعندما يصل طلب إلى

example.com

يذهب لصفحة الهبوط، و

n8n.example.com

يذهب لـ n8n، و

mcp.example.com

يذهب لخادم FastMCP. كل ذلك مع شهادات SSL تلقائية.

n8n يتصل بـ PostgreSQL لتخزين البيانات وبـ Redis لإدارة طابور المهام. العامل (Worker) يقرأ المهام من Redis وينفذها بشكل مستقل، مما يحسن الأداء عند وجود أتمتات ثقيلة.

FastMCP يعمل كخادم مستقل يقدم أدوات عبر بروتوكول SSE. إعدادات CORS تسمح لـ Claude.ai بالاتصال مباشرة.

الخطوة 6: التشغيل والاختبار

بعد إنشاء جميع الملفات، شغّل المشروع بالأوامر التالية:

bash
# بناء صورة FastMCP
docker compose build mcp

# تشغيل جميع الخدمات
docker compose up -d

# التحقق من حالة الخدمات
docker compose ps

# مشاهدة السجلات
docker compose logs -f

بعد التشغيل، تحقق من عمل الخدمات بزيارة:

https://example.com

لصفحة الهبوط،

https://n8n.example.com

لواجهة n8n، و

https://mcp.example.com/sse

لخادم MCP.

ربط FastMCP مع Claude

بعد تشغيل الخادم، يمكنك ربطه مع Claude عبر إعدادات MCP. اذهب إلى إعدادات Claude واختر إضافة خادم MCP جديد، ثم أدخل العنوان:

https://mcp.example.com/sse

بعد الربط، يمكن لـ Claude استخدام الأدوات الحسابية مباشرة. جرّب أن تطلب منه: "احسب لي الجذر التربيعي لـ 144" أو "اجمع 3.14 مع 2.71" وسيستخدم خادم MCP الخاص بك للإجابة!

نصائح للإنتاج

قبل نشر هذه البنية في بيئة إنتاج حقيقية، تأكد من: تغيير جميع كلمات المرور في ملف

.env

إلى قيم قوية وفريدة، وإعداد نسخ احتياطي دوري لقاعدة بيانات PostgreSQL، ومراقبة استخدام الموارد خاصة الذاكرة، وتقييد الوصول إلى Traefik Dashboard في الإنتاج بحذف

--api.insecure=true

.

إذا كنت تبحث عن VPS موثوق بأداء ممتاز لتشغيل هذه البنية:

الخلاصة

في هذا المقال بنينا بنية تحتية كاملة من 7 خدمات تعمل على VPS واحد باستخدام Docker Compose. الجميل في هذا النهج أنه قابل للتوسع — يمكنك إضافة خدمات جديدة بسهولة بمجرد إضافة تعريف جديد في ملف docker-compose.yml مع labels الخاصة بـ Traefik.

خادم FastMCP يفتح لك باباً واسعاً لبناء أدوات مخصصة يمكن لنماذج AI استخدامها. يمكنك توسيعه ليشمل الوصول إلى قواعد بيانات أو APIs خارجية أو أي منطق أعمال تريده.

zip

ملفات مشروع بناء منظومة متكاملة من n8n و صفحة هبوط و خادم mcp

all_n8n_-_files.zip

شارك المقال
شبّك

أعجبك المقال؟ اكتشف المزيد!

تصفح مكتبتنا الشاملة من الأوامر الجاهزة والمقالات المتخصصة في الذكاء الاصطناعي