2025年12月27日 星期六

Laravel 12 WebSocket (Reverb) 容器化全攻略:Nginx 反向代理實戰

Laravel 12 WebSocket (Reverb) 容器化全攻略:Nginx 反向代理實戰

1. 專案架構概覽

在 Docker 環境中,我們將流量分為兩路:

Nginx 站在最前端作為唯一入口,負責處理 TLS 終止(若有)與 WebSocket 的協議升級(Protocol Upgrade)。

目錄結構建議

Plaintext
laravel-project/
├── docker-compose.yml
├── Dockerfile
├── .env
├── nginx/
│   └── default.conf           # Nginx 反向代理設定
├── resources/js/echo.js       # 前端 Echo 配置
└── app/Events/MessageSent.php # 廣播事件範例

2. Nginx 配置:協議升級 (nginx/default.conf)

WebSocket 連線必須正確處理 UpgradeConnection 標頭。

Nginx
server {
    listen 80;
    server_name localhost;
    root /var/www/html/public;
    index index.php;

    # WebSocket 請求 (Reverb 預設路徑 /app)
    location /app {
        proxy_http_version 1.1;
        proxy_set_header Host $http_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 Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";

        proxy_read_timeout 86400s; # 防止長連線被切斷
        proxy_pass http://reverb:8080;
    }

    # Laravel 一般 HTTP 請求
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

3. Docker 編排:docker-compose.yml

定義四個服務,確保 Reverb 與 App 共用同一份程式碼與 Redis 驅動。

YAML
services:
  app:
    build: .
    container_name: laravel-app
    volumes:
      - .:/var/www/html
    depends_on:
      - redis

  reverb:
    build: .
    container_name: laravel-reverb
    command: php artisan reverb:start --host=0.0.0.0 --port=8080
    volumes:
      - .:/var/www/html
    depends_on:
      - app

  nginx:
    image: nginx:alpine
    container_name: laravel-nginx
    ports:
      - "80:80"
    volumes:
      - .:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
      - reverb

  redis:
    image: redis:alpine

4. 前端配置:Laravel Echo (resources/js/echo.js)

Laravel 12 的 Echo 透過 Vite 環境變數讀取設定,並透過 Nginx 轉發。

import Echo from 'laravel-echo';
import Pusher from 'pusher-js'; // Reverb 仍使用 Pusher 協定

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

5. 環境變數設定 (.env)

區分容器間通訊(後端)與瀏覽器連線(前端)。

程式碼片段
BROADCAST_CONNECTION=reverb
QUEUE_CONNECTION=redis

# 後端 (PHP 容器連向 Reverb 容器)
REVERB_HOST=reverb
REVERB_PORT=8080

# 前端 (瀏覽器連向 Nginx)
VITE_REVERB_APP_KEY=my-reverb-key
VITE_REVERB_HOST=localhost
VITE_REVERB_PORT=80
VITE_REVERB_SCHEME=http

6. Dockerfile 核心優化

確保安裝 pcntl 擴充,這是 Reverb 處理併發連線所必須的。

Dockerfile
FROM php:8.3-fpm

RUN apt-get update && apt-get install -y \
    libpng-dev zip unzip git curl

# 安裝必要 PHP 擴充
RUN docker-php-ext-install pdo_mysql pcntl bcmath

WORKDIR /var/www/html

# 修正權限
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache

7. 部署與驗證步驟

  1. 安裝依賴: composer install && npm install && npm run build

  2. 啟動容器: docker compose up -d

  3. 檢查連線: * 開啟瀏覽器 F12 → NetworkWS 標籤。


8. 常見排錯檢查清單

  • 連線被拒: 檢查 nginx/default.conf 中的 proxy_pass 是否正確指向服務名 reverb

  • 廣播沒反應: 確保有容器在執行 php artisan queue:work,因為廣播通常是非同步的。

  • 權限問題: 確保 Docker 中的 storage 目錄對 www-data 使用者是可寫入的。

這套架構讓你在移除所有手動操作的同時,獲得了極高的可擴充性與穩定性,非常適合現代 Laravel 開發。

沒有留言:

張貼留言

[技術深度] 打造 Laravel 12 高併發即時客服系統:從 Octane Swoole 到 Reverb 擴展架構

[技術深度] 打造 Laravel 12 高併發即時客服系統:從 Octane Swoole 到 Reverb 擴展架構 🏎️ 1. 內存常駐化:Laravel Octane + Swoole 的性能飛躍 傳統 PHP-FPM 每個 Request 都要經歷一次框架加載( B...