Blog

🚀 Laravel Reverb z Dockerem: Przewodnik Produkcyjny

Ten przewodnik pokazuje, jak skonfigurować aplikację Laravel w czasie rzeczywistym z użyciem Laravel Reverb (WebSockety) w środowisku produkcyjnym na Dockerze, na bazie sprawdzonej, produkcyjnej konfiguracji.

📋 Spis treści


1. Wstęp

Laravel Reverb to oficjalny serwer WebSocket dla Laravel. Dzięki Dockerowi możesz uruchomić Reverb jako osobny serwis, przekierować ruch WebSocket przez nginx i korzystać z Laravel Echo na froncie do funkcji czasu rzeczywistego.


2. Struktura projektu i docker-compose

docker-compose.production.yml (fragmenty):

services:
  app:
    image: ...
    container_name: laravel_app
    # ...
    networks:
      - laravel_network
    depends_on:
      - redis

  reverb:
    image: ...
    container_name: laravel_reverb
    command: php artisan reverb:start --host=0.0.0.0 --port=8080 --debug
    volumes:
      - ./.env:/var/www/.env
    ports:
      - "6001:8080" # (opcjonalnie, do bezpośredniego dostępu)
    depends_on:
      - redis
    networks:
      - laravel_network

  nginx:
    image: ...
    container_name: laravel_nginx
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - laravel_storage:/var/www/storage
    networks:
      - laravel_network
    depends_on:
      - app
      - reverb

  redis:
    image: redis:alpine
    container_name: laravel_redis
    # ...
    networks:
      - laravel_network

networks:
  laravel_network:
    driver: bridge

volumes:
  laravel_storage:
  redis_data:

3. Instalacja Reverb i konfiguracja Laravel

  1. Zainstaluj Reverb i zależności Echo:
    composer require laravel/reverb
    php artisan install:broadcasting
    npm install laravel-echo pusher-js
    
  2. Dodaj serwis reverb do docker-compose (patrz wyżej).
  3. Skonfiguruj broadcasting w Laravel: W pliku config/broadcasting.php ustaw:
    'default' => env('BROADCAST_DRIVER', 'reverb'),
    ...
    'connections' => [
        'reverb' => [
            'driver' => 'reverb',
            'key' => env('REVERB_APP_KEY'),
            'secret' => env('REVERB_APP_SECRET'),
            'app_id' => env('REVERB_APP_ID'),
            'host' => env('REVERB_HOST', 'reverb'),
            'port' => env('REVERB_PORT', 8080),
            'scheme' => env('REVERB_SCHEME', 'http'),
        ],
        ...
    ]
    

4. Konfiguracja środowiska (.env)

Backend (.env):

BROADCAST_DRIVER=reverb
REVERB_APP_ID=twoje_app_id
REVERB_APP_KEY=twoj_app_key
REVERB_APP_SECRET=twoj_app_secret
REVERB_HOST=reverb
REVERB_PORT=8080
REVERB_SCHEME=http

# Dla frontendu (Vite):
VITE_REVERB_APP_KEY=twoj_app_key
VITE_REVERB_HOST=twoja_domena_lub_ip
VITE_REVERB_PORT=80
VITE_REVERB_SCHEME=http
  • REVERB_HOST musi odpowiadać nazwie serwisu w docker-compose (tu: reverb).
  • VITE_REVERB_HOST to publiczna domena lub IP, pod którym frontend łączy się z WebSocketem.

5. Konfiguracja proxy nginx

docker/nginx/conf.d/default.conf (fragment):

server {
    listen 80;
    server_name _;
    # ...

    location /app {
        proxy_pass http://reverb:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }
    # ...
}
  • To przekierowuje /app do kontenera reverb na porcie 8080.
  • Echo na froncie łączy się przez /app do Twojej domeny/IP.

6. Wysyłanie eventów

Przykład eventu:

// app/Events/ClickEvent.php
namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class ClickEvent implements ShouldBroadcast
{
    use Dispatchable, SerializesModels;

    public function broadcastOn(): Channel
    {
        return new Channel('clicks');
    }

    public function broadcastAs(): string
    {
        return 'Clicked';
    }
}

Wywołanie eventu w kontrolerze:

// app/Http/Controllers/ClickController.php
public function click(Request $request)
{
    Click::firstOrCreate()->increment('times');
    event(new ClickEvent());
    return redirect()->route('clicks.index');
}

7. Konfiguracja frontendu (Echo)

resources/js/echo.js

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;
window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST ?? window.location.hostname,
    wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
    wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
    forceTLS: import.meta.env.VITE_REVERB_SCHEME === 'https',
    enabledTransports: ['ws'],
    disableStats: true,
    auth: {
        headers: {
            'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')
        }
    }
});

8. Przykład aktualizacji UI w czasie rzeczywistym

Komponent React (Click.tsx):

import { useState, useEffect } from 'react';

export default function Click({ click }) {
    const [times, setTimes] = useState(click?.times || 0);

    useEffect(() => {
        const channel = window.Echo.channel('clicks');
        channel.listen('.Clicked', () => {
            setTimes(prev => prev + 1); // Lub pobierz nową wartość z backendu
        });
        return () => {
            window.Echo.leave('clicks');
        };
    }, []);

    // ...obsługa kliknięcia/resetu...
}
  • Dzięki temu UI aktualizuje się w czasie rzeczywistym u wszystkich użytkowników bez przeładowania strony.

9. Checklist produkcyjny i rozwiązywanie problemów

  • REVERB_HOST w .env ustawiony na nazwę serwisu Docker (reverb)
  • VITE_REVERB_HOST to Twoja publiczna domena/IP
  • Nginx proxyfikuje /app do kontenera reverb
  • Wszystkie kontenery są w tej samej sieci Docker
  • Po zmianie .env uruchom php artisan config:clear i php artisan cache:clear
  • Port WebSocket nie jest wystawiony publicznie (chyba że to konieczne)
  • W produkcji używaj HTTPS dla bezpieczeństwa (patrz sekcja niżej)
  • Sprawdzaj logi: docker logs laravel_reverb, docker logs laravel_nginx, storage/logs/laravel.log
  • Używaj ShouldBroadcastNow dla natychmiastowej dostawy eventów

Typowe problemy:

  • cURL error 7: Failed to connect to 0.0.0.0 – ustaw REVERB_HOST na nazwę serwisu Docker, nie 0.0.0.0.
  • WebSocket łączy się, ale nie ma eventów: sprawdź dispatch eventu, konfigurację broadcastingu i logi.
  • WebSocket rozłącza się po 60s: zwiększ proxy_read_timeout w nginx.

10. Bezpieczeństwo produkcyjne: HTTPS i WSS

W środowisku produkcyjnym zawsze używaj HTTPS dla aplikacji i WSS (WebSocket Secure) dla połączeń WebSocket. Dzięki temu cała komunikacja między użytkownikiem a serwerem jest szyfrowana i bezpieczna.

Jak włączyć HTTPS/WSS:

  1. Uzyskaj certyfikaty SSL (np. Let's Encrypt) i umieść je w kontenerze nginx (np. docker/nginx/ssl/).
  2. Zaktualizuj konfigurację nginx, aby nasłuchiwał na porcie 443 i używał SSL:
server {
    listen 443 ssl;
    server_name twojadomena.pl;
    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    # ...
    location /app {
        proxy_pass http://reverb:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Scheme $scheme;
        proxy_set_header SERVER_PORT $server_port;
        proxy_set_header REMOTE_ADDR $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }
    # ...
}
  1. Zmapuj certyfikaty SSL w docker-compose:
nginx:
  # ...
  volumes:
    - ./docker/nginx/ssl:/etc/nginx/ssl:ro
  1. Zaktualizuj .env dla frontendu:
VITE_REVERB_SCHEME=https
VITE_REVERB_PORT=443
  1. Zaktualizuj konfigurację Echo:
window.Echo = new Echo({
    // ...
    forceTLS: true, // lub: import.meta.env.VITE_REVERB_SCHEME === 'https',
    wsPort: 80,
    wssPort: 443,
    // ...
});
  1. W nginx ustaw przekierowanie z HTTP na HTTPS dla pełnego bezpieczeństwa.

Checklist:

  • Certyfikaty SSL są poprawne i zmapowane do nginx
  • Nginx nasłuchuje na 443 i proxyfikuje /app jak wcześniej
  • VITE_REVERB_SCHEME=https i forceTLS: true w konfiguracji Echo
  • Frontend łączy się przez wss://twojadomena.pl/app/...

Uwaga:

Przeglądarki blokują połączenia ws:// (nieszyfrowane WebSockety) z aplikacji ładowanej przez https://. W produkcji zawsze używaj wss://!


11. Podsumowanie

Z tą konfiguracją masz gotową, produkcyjną aplikację Laravel z WebSocketami (Reverb) na Dockerze. Możesz broadcastować eventy i aktualizować frontend w czasie rzeczywistym dla wszystkich użytkowników.


Więcej porad Laravel & DevOps: Dominik Jasiński na LinkedIn

Wsparcie istniejącego systemu

Potrzebujesz pomocy z działającą aplikacją?

Pomagam firmom rozwijać działające systemy, porządkować wdrożenia i dodawać nowe funkcje bez dokładania chaosu do projektu.

Komentarze (0)
Zaloguj się, aby dodać komentarz

Musisz być zalogowany, aby dodać komentarz.

Zaloguj się

Potrzebujesz kogoś, kto weźmie odpowiedzialność za kolejny krok?

Porozmawiajmy o Twoim projekcie i określmy zakres, który ma sens dla Twoich celów.