Laravel-Websockets 中使用 SSL

家豬配種專家發表於2020-07-20

因為手頭一個 ws 的專案必須 PWA 化,所以對應的 Websockets 也要使用 SSL,由於 Laravel-Websockets 文件中關於如何支援 SSL 寫得不是很詳細,把 issue 裡面相關的問題都看了一遍最後才解決了,記錄一下:yum:

  1. 生成證照(*.example.com)

    我使用的是 Let’s Encrypt 的免費萬用字元證照,生成步驟如下

    # 先確保你的機器上裝了 git
    cd /opt
    git clone https://github.com/certbot/certbot.git
    cd certbot
    ./certbot-auto certonly --manual  --preferred-challenges=dns --email my@email.com --server https://acme-v02.api.letsencrypt.org/directory --agree-tos  -d *.example.com -d example.com

    然後按照提示為你的域名新增一個 TXT 的解析,用以驗證你對域名的所有權,稍等片刻,讓 DNS 快取更新後驗證成功即可生成 SSL 證照。

  2. 修改配置檔案

    config/broadcasting.php

    <?php
    $ssl_pusher_config = [
     'driver' => 'pusher',
     'key' => env('PUSHER_APP_KEY'),
     'secret' => env('PUSHER_APP_SECRET'),
     'app_id' => env('PUSHER_APP_ID'),
     'options' => [
         'cluster' => env('PUSHER_APP_CLUSTER'),
         'encrypted' => true,
         'host' => '127.0.0.1',
         'port' => 6001,
         'scheme' => 'https',
         'curl_options' => [
             CURLOPT_SSL_VERIFYHOST => 0,
             CURLOPT_SSL_VERIFYPEER => 0,
         ]
     ]
    ];
    $not_ssl_pusher_config = [
     'driver' => 'pusher',
     'key' => env('PUSHER_APP_KEY'),
     'secret' => env('PUSHER_APP_SECRET'),
     'app_id' => env('PUSHER_APP_ID'),
     'options' => [
         'cluster' => env('PUSHER_APP_CLUSTER'),
         'encrypted' => true,
         'host' => '127.0.0.1',
         'port' => 6001,
         'scheme' => 'http'
     ]
    ];
    return [
     ...
     'connections' => [
         // 本地開發環境中不使用 SSL
         'pusher' => env('APP_ENV') === 'local' ? $not_ssl_pusher_config : $ssl_pusher_config,
         ...
     ],
    ];

    config/websockets.php

     ...
     'ssl' => [
         'local_cert' => env('SSL_CERT', null),
         'local_pk' => env('SSL_PK', null),
         'passphrase' => env('JWT_SECRET', null), // 這個是可選項,作用類似於 JWT_SECRET, 用於加密
         'verify_peer' => false,
     ],
     ...
  3. .env 相關配置

    BROADCAST_DRIVER=pusher
    ...
    PUSHER_APP_ID=appid
    PUSHER_APP_KEY=websocketkey
    PUSHER_APP_SECRET=secret
    ...
    SSL_CERT=/etc/letsencrypt/live/example.com/fullchain.pem
    SSL_PK=/etc/letsencrypt/live/example.com/privkey.pem
  4. 前端呼叫

    import Echo from 'laravel-echo';
    let echor = new Echo({
     broadcaster: 'pusher',
     key: process.env.MIX_PUSHER_APP_KEY,
     wsHost: window.location.hostname,
     wsPort: 6001,
     wssPort: 6001,
     disableStats: true,
     enabledTransports: ['ws', 'wss'],
     // 我用的是 jwt 進行驗證的,如果你用的 session,請忽略此
     auth: {
         headers: {
             Authorization: `${store.state.auth.token.token_type}  ${store.state.auth.token.access_token}`
         }
     }
    });
    export default echor;
  5. 部署

    開放 6001 埠

    sudo ufw allow 6001

    讓 websockets 持續執行,首先安裝 supervisor

    apt install supervisor

    建立一個新的 supervisor 程式

    # 建立一個 websockets.conf
    touch /etc/supervisor/conf.d/websockets.conf
    # 填寫如下
    [program:websockets]
    command=/usr/bin/php /your-project-location/artisan websockets:serve
    numprocs=1
    autostart=true
    autorestart=true
    user=sudo-www
    # 載入 websockets.conf
    supervisorctl update
    supervisorctl start websockets
    # 驗證狀態
    supervisorctl status

    完成~

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章