คู่มือสำหรับนักพัฒนา Laravel และ DevOps

Laravel Load Balancing

ตั้งค่าหลาย Server เพื่อ รับโหลดสูง ใน 2025-2026

คู่มือครบวงจร: Nginx Load Balancer + Redis Session + Database Replication สำหรับ Laravel Application รองรับผู้ใช้หลายหมื่นคนพร้อมกัน

Laravel
Nginx
Redis
Ubuntu

โครงสร้าง Laravel Load Balancing Architecture

Users Clients HTTPS Nginx Load Balancer Round Robin Health Check SSL Termination Sticky Sessions Laravel #1 PHP-FPM Nginx Laravel #2 PHP-FPM Nginx Laravel #3 PHP-FPM Nginx Redis Session Store Cache Queue Driver MySQL Master Write Operations Primary DB MySQL Slave Read Operations Replica DB Replication Legend: HTTPS Traffic App Traffic Session/Cache Database Total: 5-6 Servers 1 Load Balancer | 3 App | 1 Redis | 1 DB Scalable to N servers

ทำไมต้องใช้ Load Balancing กับ Laravel?

ประสิทธิภาพสูงขึ้น

แบ่งเบาภาระการทำงานไปยังหลาย Server ทำให้แต่ละ Server ไม่โหลดเกิน รองรับคนเข้าใช้พร้อมกันได้มากขึ้น 3-10 เท่า

High Availability

ถ้า Server ตัวไหนล่ม ระบบยังทำงานต่อได้ Load Balancer จะส่ง traffic ไปยัง Server ตัวอื่นที่ยังทำงานอยู่อัตโนมัติ

Scale ได้ง่าย

เพิ่ม Server ใหม่ได้ง่ายเมื่อ traffic สูงขึ้น ไม่ต้อง Upgrade Hardware แค่เพิ่ม Server เข้าไปใน Pool

สิ่งที่ต้องเตรียม (Prerequisites)

Hardware Requirements

Load Balancer

1 Server

2 vCPU, 4GB RAM

Laravel App Servers

2-3+ Servers

4 vCPU, 8GB RAM each

Redis Server

1 Server

2 vCPU, 4GB RAM

MySQL Database

1 Master + 1 Slave

4 vCPU, 16GB RAM

Software Requirements

# Operating System Ubuntu 22.04 LTS หรือ Ubuntu 24.04 LTS # Web Server Nginx 1.24+ PHP 8.2+ พร้อม PHP-FPM # Database & Cache MySQL 8.0+ หรือ MariaDB 10.11+ Redis 7.0+ # Laravel Laravel 10.x หรือ 11.x Composer 2.x
1

ตั้งค่า Laravel App Servers (ทุกตัว)

ติดตั้ง Laravel และ Nginx บน App Server ทุกตัวให้เหมือนกัน

ติดตั้ง Nginx และ PHP-FPM

# Update system
sudo apt update && sudo apt upgrade -y

# Install Nginx
sudo apt install nginx -y

# Install PHP 8.2 and extensions
sudo apt install php8.2-fpm php8.2-mysql php8.2-mbstring \
    php8.2-xml php8.2-curl php8.2-zip php8.2-gd \
    php8.2-bcmath php8.2-intl php8.2-redis -y

# Install Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

ตั้งค่า Nginx สำหรับ Laravel

# /etc/nginx/sites-available/laravel
server {
    listen 80;
    server_name _;  # รับจาก Load Balancer
    root /var/www/laravel/public;

    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_hide_header X-Powered-By;
    }

    location ~ /\.ht {
        deny all;
    }

    # Health check endpoint
    location /health {
        access_log off;
        return 200 "OK";
        add_header Content-Type text/plain;
    }
}
# Enable site sudo ln -s /etc/nginx/sites-available/laravel /etc/nginx/sites-enabled/ sudo rm /etc/nginx/sites-enabled/default sudo nginx -t && sudo systemctl restart nginx
2

ตั้งค่า Redis Server (Session & Cache)

Redis ใช้เก็บ Session และ Cache ร่วมกันระหว่าง App Servers ทุกตัว

ติดตั้ง Redis

# Install Redis
sudo apt install redis-server -y

# Configure Redis
sudo nano /etc/redis/redis.conf

ตั้งค่า Redis Configuration

# /etc/redis/redis.conf

# Bind to all interfaces (หรือ IP ของ network)
bind 0.0.0.0

# ตั้งค่า password (สำคัญมาก!)
requirepass YOUR_STRONG_PASSWORD_HERE

# Max memory
maxmemory 2gb
maxmemory-policy allkeys-lru

# Persistence (optional)
save 900 1
save 300 10
# Restart Redis sudo systemctl restart redis-server sudo systemctl enable redis-server # Test connection redis-cli -a YOUR_STRONG_PASSWORD_HERE ping

คำเตือน

ต้องตั้งค่า Firewall ให้เข้าถึง Redis ได้เฉพาะจาก App Servers เท่านั้น! Redis ที่ไม่มี password และเปิด public เป็นช่องโหว่ร้ายแรง

3

ตั้งค่า Laravel ให้ใช้ Redis Session

ตั้งค่า Laravel บน App Server ทุกตัวให้ใช้ Redis สำหรับ Session และ Cache

ติดตั้ง Laravel Redis Package

cd /var/www/laravel
composer require predis/predis

ตั้งค่า .env สำหรับ Redis

# .env

# Session Driver - ใช้ Redis
SESSION_DRIVER=redis
SESSION_CONNECTION=session

# Cache Driver - ใช้ Redis
CACHE_DRIVER=redis
CACHE_CONNECTION=cache

# Queue Driver - ใช้ Redis (optional)
QUEUE_CONNECTION=redis

# Redis Configuration
REDIS_CLIENT=predis
REDIS_HOST=192.168.1.100  # IP ของ Redis Server
REDIS_PASSWORD=YOUR_STRONG_PASSWORD_HERE
REDIS_PORT=6379

# แยก Database สำหรับ Session และ Cache
REDIS_CACHE_DB=1
REDIS_SESSION_DB=2

ตั้งค่า config/database.php

// config/database.php
'redis' => [
    'client' => env('REDIS_CLIENT', 'predis'),

    'default' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD'),
        'port' => env('REDIS_PORT', 6379),
        'database' => 0,
    ],

    'cache' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD'),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_CACHE_DB', 1),
    ],

    'session' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD'),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_SESSION_DB', 2),
    ],
],

เคล็ดลับ

การแยก Database ของ Redis สำหรับ Session และ Cache ช่วยให้จัดการง่ายขึ้น และป้องกันการชนกันของข้อมูล

4

ตั้งค่า Nginx Load Balancer

ตั้งค่า Nginx เป็น Load Balancer สำหรับกระจาย traffic ไปยัง App Servers

ติดตั้ง Nginx บน Load Balancer Server

# Install Nginx
sudo apt update
sudo apt install nginx -y

ตั้งค่า Load Balancer Configuration

# /etc/nginx/conf.d/load-balancer.conf

# Upstream block - กำหนด App Servers
upstream laravel_backend {
    # Load Balancing Methods:
    # - ค่า default คือ Round Robin (หมุนเวียน)
    # - ip_hash; สำหรับ Sticky Sessions
    # - least_conn; สำหรับ Least Connections

    # ip_hash;  # เปิดใช้ถ้าต้องการ Sticky Sessions

    # App Server 1
    server 192.168.1.101:80 weight=3 max_fails=3 fail_timeout=30s;

    # App Server 2
    server 192.168.1.102:80 weight=3 max_fails=3 fail_timeout=30s;

    # App Server 3
    server 192.168.1.103:80 weight=3 max_fails=3 fail_timeout=30s;

    # Backup Server (optional) - ใช้เมื่อ server อื่นล่ม
    # server 192.168.1.104:80 backup;

    # Keepalive connections
    keepalive 32;
}

# HTTP Server - Redirect to HTTPS
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

    # Redirect all HTTP to HTTPS
    return 301 https://$server_name$request_uri;
}

# HTTPS Server
server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    # SSL Configuration
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    # Security Headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Proxy Settings
    location / {
        proxy_pass http://laravel_backend;
        proxy_http_version 1.1;

        # Headers สำหรับ Laravel
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;

        # Connection headers
        proxy_set_header Connection "";

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        # Buffer settings
        proxy_buffer_size 4k;
        proxy_buffers 8 16k;
    }

    # Health Check Endpoint
    location /health {
        access_log off;
        proxy_pass http://laravel_backend/health;
        proxy_connect_timeout 5s;
        proxy_read_timeout 5s;
    }

    # Status Page (internal only)
    location /nginx_status {
        stub_status on;
        allow 127.0.0.1;
        allow 192.168.1.0/24;
        deny all;
    }
}
# Test และ Restart Nginx sudo nginx -t sudo systemctl restart nginx sudo systemctl enable nginx
5

ตั้งค่า Trusted Proxies ใน Laravel

Laravel ต้องรู้ว่า request มาจาก Load Balancer เพื่อให้ได้ IP และ HTTPS ที่ถูกต้อง

ติดตั้ง TrustedProxy Package

cd /var/www/laravel
composer require fideloper/proxy

ตั้งค่า TrustProxies Middleware

// app/Http/Middleware/TrustProxies.php

namespace App\Http\Middleware;

use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;

class TrustProxies extends Middleware
{
    /**
     * trusted Proxy IPs
     * ใส่ IP ของ Load Balancer
     */
    protected $proxies = [
        '192.168.1.100',  // Load Balancer IP
        // หรือใช้ '*' เพื่อ trust ทุก proxy (ไม่แนะนำสำหรับ production)
        // '*',
        // หรือใช้ CIDR
        // '192.168.1.0/24',
    ];

    /**
     * Headers ที่จะ trust
     */
    protected $headers =
        Request::HEADER_X_FORWARDED_FOR |
        Request::HEADER_X_FORWARDED_HOST |
        Request::HEADER_X_FORWARDED_PORT |
        Request::HEADER_X_FORWARDED_PROTO |
        Request::HEADER_X_FORWARDED_AWS_ELB;
}

ตั้งค่า .env สำหรับ HTTPS

# .env

# Force HTTPS (สำหรับ production ที่ใช้ Load Balancer)
APP_URL=https://yourdomain.com

# Trust all proxies (ถ้าใช้ cloud provider)
TRUSTED_PROXIES=**

ข้อมูลเพิ่มเติม

ถ้าใช้ AWS ALB, Google Cloud Load Balancer, หรือ Cloudflare ให้ใช้ protected $proxies = '*'; เพราะ IP ของ Load Balancer เปลี่ยนแปลงได้

6

ตั้งค่า Database Read/Write Split

แยกการอ่าน (Read) ไป Slave และการเขียน (Write) ไป Master เพื่อเพิ่มประสิทธิภาพ

ตั้งค่า Laravel Database Connection

// config/database.php

'mysql' => [
    'driver' => 'mysql',
    'url' => env('DATABASE_URL'),
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'laravel'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'prefix_indexes' => true,
    'strict' => true,
    'engine' => null,
    'options' => extension_loaded('pdo_mysql') ? array_filter([
        PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    ]) : [],

    // Read/Write Split Configuration
    'read' => [
        'host' => [
            env('DB_SLAVE_HOST', '192.168.1.201'),  // MySQL Slave
            // สามารถเพิ่มหลาย slave ได้
            // env('DB_SLAVE_HOST_2', '192.168.1.202'),
        ],
    ],
    'write' => [
        'host' => env('DB_MASTER_HOST', '192.168.1.200'),  // MySQL Master
    ],
    'sticky' => true,  // ใช้ master สำหรับ read หลังจาก write ใน request เดียวกัน
],

ตั้งค่า .env

# .env

# Master Database (Write)
DB_MASTER_HOST=192.168.1.200
DB_HOST=192.168.1.200

# Slave Database (Read)
DB_SLAVE_HOST=192.168.1.201

# Database Credentials
DB_DATABASE=laravel_production
DB_USERNAME=laravel_user
DB_PASSWORD=your_secure_password

Sticky Connection

การตั้งค่า 'sticky' => true จะทำให้ Laravel ใช้ Master สำหรับ Read operations ใน request เดียวกันหลังจาก Write ป้องกันปัญหา Replication Lag

วิธี Load Balancing ต่างๆ (Load Balancing Methods)

Round Robin (Default)

หมุนเวียน request ไปยัง server แต่ละตัวตามลำดับ วิธีนี้เป็น default ของ Nginx

upstream backend {
    server 192.168.1.101;
    server 192.168.1.102;
    server 192.168.1.103;
}

IP Hash (Sticky Sessions)

client IP เดียวกันจะไปยัง server เดียวกันเสมอ เหมาะสำหรับ session-based apps

upstream backend {
    ip_hash;
    server 192.168.1.101;
    server 192.168.1.102;
}

Least Connections

ส่ง request ไปยัง server ที่มี connection น้อยที่สุด เหมาะสำหรับ long-lived connections

upstream backend {
    least_conn;
    server 192.168.1.101;
    server 192.168.1.102;
}

Weighted Round Robin

กำหนดน้ำหนักให้ server ที่แรงกว่ารับ traffic มากกว่า

upstream backend {
    server 192.168.1.101 weight=5;  # แรงกว่า
    server 192.168.1.102 weight=3;
    server 192.168.1.103 weight=2;  # อ่อนกว่า
}

Health Checks และ Monitoring

Laravel Health Check Route

// routes/web.php

Route::get('/health', function () {
    return response()->json([
        'status' => 'ok',
        'timestamp' => now()->toISOString(),
        'server' => gethostname(),
        'php_version' => PHP_VERSION,
    ], 200);
})->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);

// Health check แบบละเอียด
Route::get('/health/detailed', function () {
    $checks = [
        'database' => checkDatabaseConnection(),
        'redis' => checkRedisConnection(),
        'storage' => checkStorageAccess(),
    ];

    $allHealthy = collect($checks)->every(fn($check) => $check === true);

    return response()->json([
        'status' => $allHealthy ? 'healthy' : 'unhealthy',
        'checks' => $checks,
        'server' => gethostname(),
        'timestamp' => now()->toISOString(),
    ], $allHealthy ? 200 : 503);
})->withoutMiddleware([\App\Http\Middleware\VerifyCsrfToken::class]);

Helper Functions

// app/helpers.php

function checkDatabaseConnection(): bool
{
    try {
        DB::connection()->getPdo();
        return true;
    } catch (\Exception $e) {
        return false;
    }
}

function checkRedisConnection(): bool
{
    try {
        Redis::connection()->ping();
        return true;
    } catch (\Exception $e) {
        return false;
    }
}

function checkStorageAccess(): bool
{
    try {
        Storage::disk('local')->put('health-check.txt', 'ok');
        Storage::disk('local')->delete('health-check.txt');
        return true;
    } catch (\Exception $e) {
        return false;
    }
}

Nginx Passive Health Check

upstream laravel_backend {
    # Passive health checks
    server 192.168.1.101:80 max_fails=3 fail_timeout=30s;
    server 192.168.1.102:80 max_fails=3 fail_timeout=30s;
    server 192.168.1.103:80 max_fails=3 fail_timeout=30s;
}

# max_fails=3: ถ้า fail 3 ครั้ง จะ mark เป็น unhealthy
# fail_timeout=30s: รอ 30 วินาทีก่อนลองใหม่

SSL/TLS Configuration (Let's Encrypt)

ติดตั้ง Certbot

# Install Certbot
sudo apt install certbot python3-certbot-nginx -y

# Obtain SSL Certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# Test Auto-renewal
sudo certbot renew --dry-run

SSL Configuration ที่แนะนำ

# /etc/nginx/conf.d/ssl-params.conf

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;

# HSTS (optional - ใช้เมื่อแน่ใจว่าใช้ HTTPS เท่านั้น)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

การแก้ปัญหาที่พบบ่อย (Troubleshooting)

Session หายเมื่อ Refresh หน้า

สาเหตุ: Session ถูกเก็บแยกกันในแต่ละ server

# แก้ไข: ตรวจสอบว่าใช้ Redis Session ถูกต้อง
# ใน .env
SESSION_DRIVER=redis
REDIS_HOST=192.168.1.100  # IP ของ Redis Server ที่ใช้ร่วมกัน

IP ของ User แสดงเป็น IP ของ Load Balancer

สาเหตุ: Laravel ไม่ trust proxy headers

// แก้ไข: app/Http/Middleware/TrustProxies.php
protected $proxies = '*';  // หรือใส่ IP ของ Load Balancer

protected $headers = Request::HEADER_X_FORWARDED_ALL;

ข้อมูลไม่อัปเดทหลังจาก Save

สาเหตุ: Replication Lag ระหว่าง Master และ Slave

// แก้ไข: เปิดใช้ sticky connection
// config/database.php
'mysql' => [
    // ...
    'sticky' => true,  // ใช้ master สำหรับ read หลัง write
],

CSRF Token Mismatch

สาเหตุ: Session ไม่ตรงกันเนื่องจาก load balancing

# แก้ไข: .env
SESSION_SECURE_COOKIE=true
SESSION_SAME_SITE=none  # สำหรับ cross-domain
SESSION_DOMAIN=yourdomain.com

เคล็ดลับเพิ่มประสิทธิภาพ (Performance Tips)

ใช้ Redis Cache

Cache query results, view fragments, และ config ใน Redis ลดการ query database ลงได้ 50-80%

ใช้ Queue System

ส่ง email, process uploads, และ heavy tasks ไปทำใน background ด้วย Redis Queue + Laravel Horizon

Enable OPcache

เปิด OPcache ใน PHP-FPM เพื่อ cache compiled PHP code เพิ่มความเร็วได้ 2-3 เท่า

PHP-FPM Tuning

ปรับ pm.max_children, pm.start_servers ให้เหมาะสมกับ RAM ของ server

PHP-FPM Optimization

# /etc/php/8.2/fpm/pool.d/www.conf

# สำหรับ Server 8GB RAM
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500

# สำหรับ Server 16GB RAM
pm = dynamic
pm.max_children = 100
pm.start_servers = 20
pm.min_spare_servers = 10
pm.max_spare_servers = 40
pm.max_requests = 1000

สรุปขั้นตอนทั้งหมด

1

ตั้งค่า Laravel App Servers

ติดตั้ง Nginx + PHP-FPM + Laravel ทุกตัว

2

ตั้งค่า Redis Server

สำหรับ Session และ Cache ร่วมกัน

3

ตั้งค่า Laravel Redis

แก้ไข .env และ config/database.php

4

ตั้งค่า Nginx Load Balancer

Config upstream และ proxy settings

5

ตั้งค่า Trusted Proxies

ให้ Laravel รู้จัก Load Balancer

6

ตั้งค่า Database Replication

แยก Read/Write operations

ผลลัพธ์ที่คาดหวัง

  • ✓ รองรับ concurrent users เพิ่มขึ้น 3-10 เท่า
  • ✓ High Availability - ระบบไม่ downtime ถ้า server ล่ม 1-2 ตัว
  • ✓ Response time ลดลง 50-70%
  • ✓ Scale ได้ง่ายโดยเพิ่ม App Server เข้าไปใน pool