دليل احترافي شامل

إعداد بيئة Laravel + Nginx
على Ubuntu VPS

دليل مفصّل خطوة بخطوة مع شرح كل سطر وإعدادات احترافية جاهزة للإنتاج

Ubuntu 22.04 Nginx PHP 8.3 MySQL 8.0 Laravel 11 Redis Supervisor SSL/HTTPS
📋 فهرس المحتوى
  1. تحديث النظام والحزم الأساسية
  2. تثبيت PHP 8.3 وإضافاته
  3. إعداد PHP-FPM احترافياً
  4. تثبيت وتأمين MySQL 8.0
  5. تثبيت وإعداد Nginx
  6. Virtual Host لمشروع Laravel
  7. تثبيت Composer
  8. رفع وإعداد مشروع Laravel
  9. الصلاحيات الصحيحة
  10. تثبيت SSL مع Certbot
  11. إعداد Firewall
  12. تثبيت Redis
  13. Supervisor لـ Queue Workers
  14. التحقق النهائي
01
تحديث النظام والحزم الأساسية
أول خطوة دائماً قبل أي تثبيت
شرح الأوامر
قبل أي شيء، نحتاج نضمن أن النظام محدّث بالكامل وأن لدينا الأدوات الأساسية. إذا ثبّتنا أي حزمة على نظام قديم ممكن نواجه تعارضات أو مشاكل في التوافق.
apt update && apt upgrade -y — السطر الأول
apt update يجلب قائمة الحزم المحدّثة من الإنترنت دون تثبيت شيء بعد. ثم apt upgrade -y يثبّت التحديثات المتاحة مباشرة دون طلب تأكيد. الـ && تعني "نفّذ الثاني فقط إذا نجح الأول".
apt install -y curl wget git unzip zip software-properties-common — السطر الثاني
curl وwget لتحميل الملفات. git لاستنساخ المشاريع. unzip/zip لفك الضغط. software-properties-common يسمح لنا بإضافة مستودعات خارجية مثل مستودع PHP لاحقاً.
bash
# تحديث قائمة الحزم وترقية النظام
apt update && apt upgrade -y

# تثبيت الأدوات الأساسية
apt install -y curl wget git unzip zip software-properties-common
02
تثبيت PHP 8.3 وجميع الإضافات
المحرك الأساسي لتشغيل Laravel
لماذا نضيف مستودعاً خارجياً؟
Ubuntu الافتراضي يأتي بإصدار PHP قديم. مستودع ondrej/php هو المصدر الرسمي والموثوق لآخر إصدارات PHP على Ubuntu، ويدعمه المجتمع على نطاق واسع.
add-apt-repository ppa:ondrej/php -y — إضافة المستودع
يضيف مستودع Ondrej Surý الذي يحتوي على أحدث إصدارات PHP. بدونه ستحصل على PHP 7.x القديمة. الـ -y للموافقة التلقائية.
php8.3-fpm — أهم مكوّن
FPM تعني FastCGI Process Manager، هو الذي يتواصل مع Nginx لمعالجة ملفات PHP. بدونه، Nginx لا يعرف كيف يشغّل PHP.
قائمة الإضافات المطلوبة — لماذا كل إضافة؟
php8.3-mysql للتواصل مع قاعدة البيانات ← php8.3-mbstring لدعم Unicode والعربية ← php8.3-xml لمعالجة XML ← php8.3-bcmath للعمليات الحسابية الدقيقة (مهم للمدفوعات) ← php8.3-curl لإرسال HTTP requests ← php8.3-zip للضغط وفك الضغط ← php8.3-gd لمعالجة الصور ← php8.3-opcache لتسريع PHP بشكل كبير.
bash
# إضافة مستودع PHP الرسمي
add-apt-repository ppa:ondrej/php -y
apt update

# تثبيت PHP 8.3 مع جميع الإضافات المطلوبة لـ Laravel
apt install -y php8.3 php8.3-fpm php8.3-cli \
  php8.3-mysql php8.3-pgsql php8.3-sqlite3 \
  php8.3-mbstring php8.3-xml php8.3-bcmath \
  php8.3-curl php8.3-zip php8.3-gd php8.3-intl \
  php8.3-redis php8.3-imagick php8.3-opcache \
  php8.3-tokenizer php8.3-fileinfo

# التحقق من نجاح التثبيت
php -v
php-fpm8.3 -v
03
إعداد PHP-FPM احترافياً
ضبط الذاكرة والأداء والأمان
php.ini — الإعدادات الرئيسية
هذا الملف يتحكم في كيفية عمل PHP بالكامل. الإعدادات الافتراضية مناسبة للتطوير لكن ليست آمنة للإنتاج. سنعدّل كل قيمة بسبب محدد.
memory_limit = 256M
الحد الأقصى للذاكرة لكل طلب PHP. الافتراضي 128M قد لا يكفي لـ Laravel مع Composer والعمليات الثقيلة. 256M مناسب لمعظم المشاريع.
expose_php = Off
يمنع PHP من إرسال نسخته في HTTP headers. هذا أمان مهم — المهاجمون يستخدمون معرفة الإصدار لاستغلال ثغرات معروفة.
display_errors = Off + log_errors = On
في الإنتاج، لا تعرض الأخطاء للمستخدم (قد تكشف معلومات حساسة)، بل سجّلها في ملف اللوق فقط للمطوّر.
opcache.enable = 1
OPcache يخزّن الكود المُترجَم في الذاكرة، فبدلاً من تفسير PHP من جديد مع كل طلب، يُشغّل النسخة المُجمَّعة مسبقاً. هذا يسرّع التطبيق بنسبة 50-80%.
bash — فتح ملف الإعدادات
nano /etc/php/8.3/fpm/php.ini
ابحث عن هذه الإعدادات وعدّلها (استخدم Ctrl+W للبحث في nano):
php.ini
; ===== الأداء والذاكرة =====
memory_limit = 256M             ; حد الذاكرة لكل طلب
max_execution_time = 120        ; أقصى وقت تنفيذ بالثواني
max_input_time = 60            ; وقت قراءة البيانات المدخلة

; ===== رفع الملفات =====
upload_max_filesize = 64M       ; أقصى حجم ملف مرفوع
post_max_size = 64M             ; يجب أن يكون مساوياً أو أكبر من السابق
max_file_uploads = 20          ; أقصى عدد ملفات في طلب واحد

; ===== الأمان =====
expose_php = Off              ; إخفاء إصدار PHP من الـ headers
display_errors = Off           ; لا تعرض الأخطاء للمستخدم
log_errors = On               ; سجّل الأخطاء في الملف
error_log = /var/log/php8.3-error.log

; ===== OPcache - تسريع PHP =====
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 2
opcache.fast_shutdown = 1
www.conf — إعداد PHP-FPM Pool
الـ Pool هو مجموعة العمليات التي تعالج طلبات PHP. dynamic تعني أن عدد العمليات يتكيّف مع الضغط — يبدأ بعدد صغير ويكبر عند الحاجة، وهذا أفضل للـ VPS لأنه يوفر الذاكرة.
listen = /run/php/php8.3-fpm.sock
Nginx و PHP-FPM يتواصلان عبر ملف Socket بدلاً من TCP/IP، هذا أسرع بكثير لأنه يتجنب overhead الشبكة على نفس الجهاز.
pm.max_children = 20
أقصى عدد عمليات PHP تعمل بالتوازي. احسبها هكذا: (ذاكرة VPS - 512MB للنظام) ÷ 30MB لكل عملية. مثلاً 2GB RAM: (2048 - 512) ÷ 30 ≈ 51، لكن 20 كافٍ للبداية.
bash — فتح ملف Pool
nano /etc/php/8.3/fpm/pool.d/www.conf
www.conf
[www]
user = www-data                   ; المستخدم الذي يشغّل PHP-FPM
group = www-data                  ; المجموعة - نفس مستخدم Nginx
listen = /run/php/php8.3-fpm.sock ; مسار ملف Socket
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

; إدارة العمليات - dynamic أفضل للـ VPS
pm = dynamic                      ; يتكيّف مع الحمل تلقائياً
pm.max_children = 20             ; أقصى عدد عمليات متزامنة
pm.start_servers = 4             ; عدد العمليات عند البدء
pm.min_spare_servers = 2         ; الحد الأدنى للعمليات الخاملة
pm.max_spare_servers = 6         ; الحد الأقصى للعمليات الخاملة
pm.max_requests = 500           ; إعادة تشغيل العملية بعد 500 طلب لمنع تسريب الذاكرة

request_terminate_timeout = 120  ; إنهاء الطلب بعد 120 ثانية
bash — تشغيل PHP-FPM
systemctl restart php8.3-fpm
systemctl enable php8.3-fpm  ; يعمل تلقائياً عند إعادة تشغيل السيرفر
04
تثبيت وتأمين MySQL 8.0
قاعدة البيانات الرئيسية للمشروع
لماذا نأمّن MySQL؟
التثبيت الافتراضي لـ MySQL يأتي ببعض الإعدادات غير الآمنة: مستخدمون مجهولون، قاعدة بيانات test، إمكانية تسجيل الدخول بـ root من الخارج. أداة mysql_secure_installation تحل كل هذا بسؤال واحد تلو الآخر.
CREATE DATABASE ... CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
utf8mb4 هو الترميز الصحيح الذي يدعم العربية والإيموجي. الـ utf8 القديم لا يدعم كل Unicode. unicode_ci يعني المقارنة غير حساسة لحالة الأحرف.
لماذا ننشئ مستخدماً خاصاً وليس نستخدم root؟
أمان أساسي: إذا اخترق أحد تطبيقك وحصل على بيانات الاتصال بقاعدة البيانات، لن يستطيع الوصول إلا لقاعدة بيانات مشروعك فقط، وليس كل قواعد البيانات على السيرفر.
bash
# تثبيت MySQL
apt install -y mysql-server mysql-client
systemctl start mysql
systemctl enable mysql

# تشغيل أداة التأمين التفاعلية
mysql_secure_installation
ℹ️
في أداة التأمين: اختر VALIDATE PASSWORD → Level 2 (Strong) ← Remove anonymous users: Y ← Disallow root login remotely: Y ← Remove test database: Y ← Reload privileges: Y
SQL — إنشاء قاعدة البيانات والمستخدم
-- الدخول لـ MySQL
-- في terminal اكتب أولاً: mysql -u root -p

-- إنشاء قاعدة البيانات مع الترميز الصحيح للعربية
CREATE DATABASE laravel_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- إنشاء مستخدم مخصص للمشروع (لا تستخدم root أبداً)
CREATE USER 'laravel_user'@'localhost' IDENTIFIED BY 'StrongPassword@2024';

-- منح الصلاحيات لقاعدة البيانات فقط
GRANT ALL PRIVILEGES ON laravel_db.* TO 'laravel_user'@'localhost';

-- تحديث جدول الصلاحيات فوراً
FLUSH PRIVILEGES;
EXIT;
05
تثبيت وإعداد Nginx
الـ Web Server الرئيسي
nginx.conf — الإعدادات الرئيسية
هذا الملف يتحكم في سلوك Nginx بالكامل. كل إعداد له تأثير مباشر على الأداء والأمان. سنشرح أهم الإعدادات.
worker_processes auto
يجعل Nginx يكتشف عدد CPU cores تلقائياً وينشئ عملية لكل core. هذا يستغل كامل قدرة المعالج.
worker_rlimit_nofile 65535
أقصى عدد ملفات مفتوحة في نفس الوقت. كل اتصال يفتح ملفاً، لذا هذا الرقم يحدد أقصى عدد اتصالات متزامنة.
server_tokens off
يخفي رقم إصدار Nginx من HTTP headers ورسائل الخطأ. أمان مهم لإخفاء معلومات عن المهاجمين.
gzip on — وإعداداته
يضغط الاستجابات قبل إرسالها للمتصفح. CSS وJS والـ JSON تصغر 60-80% بالضغط، مما يسرّع التحميل بشكل كبير. gzip_comp_level 6 هو توازن جيد بين الضغط واستهلاك المعالج.
limit_req_zone — Rate Limiting
يقيّد عدد الطلبات من نفس الـ IP. rate=30r/s تعني 30 طلب في الثانية. هذا يحمي من هجمات DDoS وbrute force. الـ 10m هو حجم الذاكرة المخصصة لتتبع الـ IPs (10MB تتسع لـ 160,000 IP).
bash
# تثبيت Nginx
apt install -y nginx
systemctl start nginx
systemctl enable nginx

# فتح ملف الإعداد الرئيسي
nano /etc/nginx/nginx.conf
nginx.conf
user www-data;                    # المستخدم الذي يشغّل Nginx
worker_processes auto;            # عملية لكل CPU core تلقائياً
worker_rlimit_nofile 65535;       # أقصى ملفات مفتوحة = أقصى اتصالات
pid /run/nginx.pid;

events {
    worker_connections 1024;       # اتصالات لكل عملية
    multi_accept on;              # قبول عدة اتصالات في وقت واحد
    use epoll;                     # أفضل آلية للـ Linux
}

http {
    # الأساسيات
    sendfile on;                   # إرسال الملفات مباشرة من kernel
    tcp_nopush on;                 # تجميع البيانات قبل الإرسال
    tcp_nodelay on;                # إرسال فوري للبيانات الصغيرة
    keepalive_timeout 65;          # إبقاء الاتصال مفتوحاً 65 ثانية
    server_tokens off;             # إخفاء إصدار Nginx - أمان

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # ===== الضغط - يقلل حجم الاستجابة 60-80% =====
    gzip on;
    gzip_vary on;                   # يخبر الـ CDN أن الاستجابة مضغوطة
    gzip_proxied any;
    gzip_comp_level 6;              # مستوى الضغط 1-9 (6 = توازن مثالي)
    gzip_min_length 1024;           # لا تضغط الملفات الصغيرة جداً
    gzip_types
        text/plain text/css text/xml text/javascript
        application/json application/javascript
        application/xml+rss image/svg+xml;

    # ===== Logs =====
    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log warn;

    # ===== حجم الطلبات =====
    client_max_body_size 64M;       # أقصى حجم للـ request body
    client_body_buffer_size 128k;

    # ===== Rate Limiting - حماية من DDoS والـ brute force =====
    limit_req_zone $binary_remote_addr zone=general:10m rate=30r/s;
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}
06
Virtual Host لمشروع Laravel
إعداد Nginx الخاص بموقعك
لماذا root يشير لـ /public فقط؟
Laravel يضع كل الكود الحساس خارج مجلد public. إذا عيّنت root على مجلد المشروع كله، يمكن للزوار الوصول لملف .env والكود المصدري مباشرة. المجلد public هو الشيء الوحيد المسموح للعالم الخارجي رؤيته.
try_files $uri $uri/ /index.php?$query_string
هذا هو قلب إعداد Laravel مع Nginx. يبحث أولاً عن ملف حقيقي بهذا الاسم، ثم مجلد، ثم يرسل الطلب لـ index.php ليعالجه Laravel. هذا ما يجعل الـ routes تعمل.
fastcgi_pass unix:/run/php/php8.3-fpm.sock
يوجّه ملفات PHP لـ PHP-FPM عبر الـ Socket الذي أعددناه سابقاً. هذا هو الجسر بين Nginx وPHP.
expires 1y + Cache-Control public, immutable
الملفات الثابتة (CSS/JS/Images) لا تتغير كثيراً. نطلب من المتصفح تخزينها لسنة كاملة. عند تغييرها، Laravel يضيف version hash في اسم الملف تلقائياً فيجبر المتصفح على تحميل النسخة الجديدة.
location ~ /\. { deny all; }
يمنع الوصول لأي ملف يبدأ بنقطة مثل .env و.git و.htaccess. هذا أمان حرج — ملف .env يحتوي كلمات مرور قاعدة البيانات.
bash — إنشاء ملف الموقع
nano /etc/nginx/sites-available/laravel
nginx — Virtual Host
server {
    listen 80;
    listen [::]:80;                       # يدعم IPv6 أيضاً
    server_name yourdomain.com www.yourdomain.com;

    # مجلد public فقط هو المكشوف - أمان مهم
    root /var/www/laravel/public;
    index index.php index.html;

    # ملفات log مستقلة لكل موقع
    access_log /var/log/nginx/laravel_access.log;
    error_log  /var/log/nginx/laravel_error.log;

    # قلب إعداد Laravel - يوجّه كل الطلبات لـ index.php
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # معالجة ملفات PHP عبر PHP-FPM
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;

        # Timeouts للطلبات الثقيلة
        fastcgi_connect_timeout 60s;
        fastcgi_send_timeout 120s;
        fastcgi_read_timeout 120s;
        fastcgi_buffer_size 64k;
        fastcgi_buffers 8 64k;
    }

    # الملفات الثابتة - Cache سنة كاملة لتسريع التحميل
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg|webp)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;                    # لا نسجّل طلبات الصور لتوفير مساحة
    }

    # حظر الوصول لملفات .env و .git وغيرها - أمان حرج
    location ~ /\. {
        deny all;
        access_log off;
    }

    # حظر الوصول للملفات الحساسة مباشرة
    location ~ /(\.env|composer\.(json|lock)|package\.json|artisan) {
        deny all;
    }

    # Rate Limiting - 50 طلب burst لكل IP
    limit_req zone=general burst=50 nodelay;
    limit_conn addr 20;                    # أقصى 20 اتصال متزامن لكل IP

    # Security Headers - يحمي من هجمات XSS وClickjacking
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
bash — تفعيل الموقع
# ربط الملف في sites-enabled
ln -s /etc/nginx/sites-available/laravel /etc/nginx/sites-enabled/

# حذف الموقع الافتراضي
rm /etc/nginx/sites-enabled/default

# اختبار صحة الإعدادات قبل التطبيق
nginx -t

# تطبيق الإعدادات بدون إيقاف السيرفر
systemctl reload nginx
07
تثبيت Composer
مدير حزم PHP
ما هو Composer؟
Composer هو مدير الحزم الرسمي لـ PHP، مثل npm لـ Node.js. Laravel وكل إضافاته تُثبَّت عبره. نحمّله من الموقع الرسمي ونضعه في مسار عام ليكون متاحاً من أي مكان.
mv composer.phar /usr/local/bin/composer
نحرّك الملف لـ /usr/local/bin حتى يمكن استدعاؤه بكتابة composer فقط من أي مجلد بدلاً من php composer.phar الطويلة.
bash
# تحميل Composer من الموقع الرسمي
curl -sS https://getcomposer.org/installer | php

# نقله لمسار عام ليكون متاحاً من أي مكان
mv composer.phar /usr/local/bin/composer

# إعطاؤه صلاحية التنفيذ
chmod +x /usr/local/bin/composer

# التحقق من التثبيت
composer --version
08
رفع وإعداد مشروع Laravel
نشر المشروع وإعداد بيئة الإنتاج
أوامر تحسين الأداء للإنتاج
Laravel في وضع التطوير يقرأ الإعدادات والـ routes من الملفات مع كل طلب. في الإنتاج نقوم بـ "cache" لهذه الملفات ليحملها Laravel مرة واحدة فقط، مما يسرّع التطبيق بشكل ملحوظ.
php artisan key:generate
ينشئ مفتاح تشفير عشوائي يُستخدم لتشفير الـ sessions والـ cookies. بدونه Laravel يرفض العمل في الإنتاج. يُكتب في APP_KEY في ملف .env.
php artisan config:cache + route:cache + view:cache
config:cache يجمع كل ملفات الإعداد في ملف واحد محسوب مسبقاً. route:cache يجمع كل الـ routes في ملف PHP واحد بدلاً من قراءتها كل طلب. view:cache يُجمِّع قوالب Blade مسبقاً. كل هذا يقلل وقت الاستجابة.
php artisan storage:link
ينشئ رابط رمزي من public/storage إلى storage/app/public حتى يمكن عرض الملفات المرفوعة (الصور وغيرها) في المتصفح مباشرة.
bash
# إنشاء المجلد
mkdir -p /var/www/laravel

# خيار 1: استنساخ مشروع موجود من Git
git clone https://github.com/yourusername/your-project.git /var/www/laravel

# خيار 2: إنشاء مشروع Laravel جديد
composer create-project laravel/laravel /var/www/laravel

# الانتقال للمجلد
cd /var/www/laravel

# إذا كان مشروع موجود من Git، ثبّت الحزم
composer install --no-dev --optimize-autoloader

# نسخ ملف البيئة
cp .env.example .env
nano .env
.env — إعدادات البيئة
APP_NAME="اسم مشروعك"
APP_ENV=production             # وضع الإنتاج - مهم
APP_KEY=                         # سيُملأ تلقائياً بأمر key:generate
APP_DEBUG=false               # أطفئ Debug في الإنتاج - أمان
APP_URL=https://yourdomain.com

LOG_CHANNEL=stack
LOG_LEVEL=error               # سجّل الأخطاء فقط لتوفير المساحة

# ===== قاعدة البيانات =====
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_db
DB_USERNAME=laravel_user
DB_PASSWORD=StrongPassword@2024

# ===== Cache والـ Session =====
CACHE_DRIVER=file             # غيّره لـ redis إذا ثبّتت Redis
SESSION_DRIVER=file          # غيّره لـ redis إذا ثبّتت Redis
QUEUE_CONNECTION=sync        # غيّره لـ database أو redis للـ queues
bash — إكمال إعداد Laravel
# توليد مفتاح التشفير - ضروري
php artisan key:generate

# تشغيل الـ migrations لإنشاء جداول قاعدة البيانات
php artisan migrate --force

# ===== تحسين الأداء للإنتاج =====
php artisan config:cache      # تجميع ملفات الإعداد في ملف واحد
php artisan route:cache       # تجميع الـ routes في ملف واحد
php artisan view:cache        # تجميع قوالب Blade مسبقاً
php artisan event:cache       # تجميع الـ events والـ listeners

# إنشاء رابط Storage لعرض الملفات المرفوعة
php artisan storage:link
09
الصلاحيات الصحيحة
توازن بين الأمان وإمكانية الكتابة
لماذا هذه الصلاحيات بالذات؟
الصلاحيات الخاطئة إما تمنع التطبيق من العمل (too restrictive) أو تفتح ثغرات أمنية (too permissive). المبدأ: www-data يملك الملفات ويقرأها، ولا يكتب إلا في storage وbootstrap/cache.
chown -R www-data:www-data
Nginx وPHP-FPM يعملان كمستخدم www-data. إذا كان مالك الملفات شخصاً آخر، ستحصل على أخطاء "Permission denied". هذا يجعل PHP قادراً على قراءة كل الملفات.
644 للملفات / 755 للمجلدات
644 تعني: المالك يقرأ ويكتب، الجميع يقرأ فقط. 755 للمجلدات تضيف صلاحية الدخول للمجلد (x). هذا الحد الأدنى الآمن.
chmod 775 للـ storage وbootstrap/cache
فقط هذين المجلدين يحتاجان للكتابة: Laravel يحتاج يكتب ملفات الـ cache والـ logs والـ sessions. 775 تعني المالك والمجموعة يكتبان، الآخرون يقرؤون فقط.
bash
# جعل www-data مالك كل الملفات
chown -R www-data:www-data /var/www/laravel

# الصلاحيات الأساسية الآمنة
find /var/www/laravel -type f -exec chmod 644 {} \;
find /var/www/laravel -type d -exec chmod 755 {} \;

# هذين المجلدين فقط يحتاجان صلاحية كتابة
chmod -R 775 /var/www/laravel/storage
chmod -R 775 /var/www/laravel/bootstrap/cache
10
تثبيت SSL مجاني مع Certbot
HTTPS إلزامي لأي موقع حديث
لماذا SSL ضروري؟
بدون SSL، كل البيانات بين المستخدم وموقعك (كلمات المرور، البيانات الشخصية) تُرسَل كنص عادي قابل للاعتراض. المتصفحات الحديثة تُظهر "Not Secure" للمواقع بدون HTTPS. Certbot يوفر شهادات SSL مجانية من Let's Encrypt مع تجديد تلقائي.
certbot --nginx
Certbot يتعرف على إعدادات Nginx تلقائياً، يحصل على الشهادة، ويُعدّل ملف Nginx لإضافة HTTPS وإعادة التوجيه من HTTP لـ HTTPS. كل هذا تلقائياً!
certbot renew --dry-run
شهادات Let's Encrypt صالحة 90 يوماً فقط. هذا الأمر يختبر عملية التجديد التلقائي دون تجديد فعلي. Certbot يضيف تلقائياً مهمة cron لتجديد الشهادة قبل انتهائها.
bash
# تثبيت Certbot مع plugin الـ Nginx
apt install -y certbot python3-certbot-nginx

# الحصول على الشهادة وإعداد HTTPS تلقائياً
# استبدل yourdomain.com بدومينك الفعلي
certbot --nginx -d yourdomain.com -d www.yourdomain.com

# اختبار التجديد التلقائي
certbot renew --dry-run

# التحقق من أن timer التجديد يعمل
systemctl status certbot.timer
بعد تثبيت Certbot، سيُعدّل ملف Nginx تلقائياً ويضيف redirect من HTTP لـ HTTPS وإعدادات SSL الكاملة.
11
إعداد Firewall
الخط الدفاعي الأول للسيرفر
مبدأ أقل الصلاحيات
الـ Firewall يعمل بمبدأ "أغلق كل شيء، وافتح ما تحتاجه فقط". نحتاج فقط SSH للإدارة، وHTTP/HTTPS للموقع. أي port آخر مغلق = سطح هجوم أصغر.
ufw allow 'Nginx Full'
Nginx Full هو اسم مختصر يفتح كلا الـ port 80 (HTTP) والـ port 443 (HTTPS) دفعة واحدة. يمكنك التحقق من هذه الـ profiles بأمر ufw app list.
⚠️
تحذير: تأكد من إضافة OpenSSH قبل تفعيل ufw، وإلا ستُغلق على نفسك باب الدخول للسيرفر!
bash
# السماح بـ SSH أولاً - لا تنسَ هذا!
ufw allow OpenSSH

# السماح بـ HTTP (80) و HTTPS (443) معاً
ufw allow 'Nginx Full'

# تفعيل الـ Firewall
ufw enable

# التحقق من القواعد المفعّلة
ufw status
12
تثبيت Redis
Cache سريع للـ Sessions والبيانات المتكررة
لماذا Redis موصى به؟
بدون Redis، Laravel يخزّن الـ sessions والـ cache في ملفات. مع Redis، كل شيء في الذاكرة RAM مباشرة، مما يجعل القراءة والكتابة أسرع بـ 10-100 مرة. مهم جداً عند التعامل مع حركة مرور عالية.
supervised systemd
يجعل Redis يعمل تحت إشراف systemd. هذا يعني systemd يعيد تشغيل Redis تلقائياً إذا توقف، ويديره كخدمة نظام رسمية.
bash
# تثبيت Redis
apt install -y redis-server

# فتح ملف الإعدادات
nano /etc/redis/redis.conf

# ابحث عن: supervised no
# وغيّرها إلى:
supervised systemd   # يجعل systemd يدير Redis

# إعادة التشغيل بعد التعديل
systemctl restart redis-server
systemctl enable redis-server

# اختبار Redis - يجب أن يرد: PONG
redis-cli ping
بعد تثبيت Redis، عدّل هذه القيم في ملف .env:
.env — تحديث للـ Redis
CACHE_DRIVER=redis              # Cache في الذاكرة بدلاً من الملفات
SESSION_DRIVER=redis           # Sessions في الذاكرة - أسرع
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
13
Supervisor لـ Queue Workers
لمعالجة المهام في الخلفية
ما هو الـ Queue Worker؟
بعض المهام تأخذ وقتاً (إرسال الإيميلات، معالجة الصور، التقارير). بدلاً من إبطاء الاستجابة للمستخدم، نضع هذه المهام في "قائمة انتظار" ويعالجها worker في الخلفية. Supervisor يضمن أن هذا الـ worker يعمل دائماً ويُعيد تشغيله إذا توقف.
numprocs = 2
نشغّل عمليتين متوازيتين للـ queue. إذا كان لديك مهام كثيرة يمكن رفعه، لكن كل عملية تأخذ ذاكرة.
--max-time=3600
نعيد تشغيل الـ worker كل ساعة (3600 ثانية). هذا يمنع تسريب الذاكرة التدريجي في العمليات طويلة الأمد. Supervisor يُعيد تشغيله فوراً بعد توقفه.
bash
# تثبيت Supervisor
apt install -y supervisor

# إنشاء ملف إعداد الـ worker
nano /etc/supervisor/conf.d/laravel-worker.conf
laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d  ; اسم العملية مع رقمها
command=php /var/www/laravel/artisan queue:work --sleep=3 --tries=3 --max-time=3600
; --sleep=3: انتظر 3 ثواني إذا ما في مهام
; --tries=3: حاول 3 مرات قبل تمييز المهمة كفاشلة
; --max-time=3600: أعد التشغيل كل ساعة

autostart=true                  ; يبدأ تلقائياً مع Supervisor
autorestart=true               ; يُعيد التشغيل إذا توقف
stopasgroup=true
killasgroup=true
user=www-data                   ; يشتغل بنفس مستخدم Laravel
numprocs=2                      ; عمليتان متوازيتان
redirect_stderr=true
stdout_logfile=/var/www/laravel/storage/logs/worker.log
stopwaitsecs=3600
bash — تشغيل Supervisor
# قراءة الإعدادات الجديدة
supervisorctl reread

# تطبيق التغييرات
supervisorctl update

# تشغيل الـ workers
supervisorctl start laravel-worker:*

# التحقق من حالتهم
supervisorctl status
14
التحقق النهائي من كل شيء
تأكد أن كل الخدمات تعمل بشكل صحيح
bash — فحص حالة الخدمات
# فحص حالة جميع الخدمات - يجب أن تكون active (running)
systemctl status nginx
systemctl status php8.3-fpm
systemctl status mysql
systemctl status redis-server
systemctl status supervisor

# أو كلها دفعة واحدة
systemctl status nginx php8.3-fpm mysql redis-server supervisor

# اختبار صحة إعدادات Nginx
nginx -t

# اختبار صحة إعدادات PHP-FPM
php-fpm8.3 -t

# متابعة أخطاء Nginx الآن
tail -f /var/log/nginx/laravel_error.log

# متابعة أخطاء Laravel الآن
tail -f /var/www/laravel/storage/logs/laravel.log
💡
إذا عدّلت ملف .env أو أي ملف إعداد لاحقاً، شغّل دائماً: php artisan config:cache لتطبيق التغييرات في وضع الإنتاج.
🏗️ البنية النهائية للسيرفر
🌐
Nginx
يستقبل الطلبات ويوزّعها
PHP-FPM 8.3
يعالج كود Laravel
🗄️
MySQL 8.0
قاعدة البيانات الرئيسية
🔴
Redis
Cache وSessions سريعة
⚙️
Supervisor
Queue Workers دائمة التشغيل
🔒
SSL + UFW
HTTPS وحماية Firewall