www.conf 中具體修改了哪幾行參數與數值

回覆文章
Brave Ye
系統管理員
文章: 5547
註冊時間: 2025-11-08, 13:32
聯繫:

www.conf 中具體修改了哪幾行參數與數值

文章 Brave Ye »

專家架構建議(16GB RAM 如何分配?)既然是不特定大眾使用,為了防止惡意流量瞬間灌爆 MariaDB 資料庫,強烈建議您在 Debian 13 上額外安裝 Redis 作為快取與聊天快取層:
sudo apt update && sudo apt install redis-server -y


第一步:設定 PHP 8.5-FPM 記憶體分配(目標:約 3GB)
PHP-FPM 採用動態或靜態進程管理。
在不特定大眾湧入時,必須限制 max_children 以控制記憶體不超過 3GB。
通常,PHP 8.5 在執行一般網頁/API 邏輯時,單個進程(Process)約佔用 30MB ~ 50MB。
計算公式:3000MB / 40MB ≈ 75。我們保守設定最大進程數為 70。
1 修改 FPM 的 www.conf 設定檔:
bash
sudo nano /etc/php/8.5/fpm/pool.d/www.conf
請謹慎使用程式碼。
2 尋找並修改以下參數(建議使用 dynamic 動態模式,沒人時釋放記憶體,有人時快速擴展):
ini

代碼: 選擇全部

pm = dynamic
pm.max_children = 70       ; 嚴格限制最多 70 個進程,確保總記憶體不超過 3GB
pm.start_servers = 15      ; 啟動時先開 15 個
pm.min_spare_servers = 10  ; 最少保留 10 個空閒進程
pm.max_spare_servers = 25  ; 最多保留 25 個空閒進程
pm.max_requests = 1000     ; 每個進程處理 1000 次請求後重啟,防止免註冊遊客造成的記憶體洩漏
3 修改 PHP 的單一指令碼記憶體上限(防止單個惡意請求吃光記憶體):
bash
sudo nano /etc/php/8.5/fpm/php.ini
修改此行:ini
ini

代碼: 選擇全部

memory_limit = 128M        ; 每支程式最多使用 128MB
4 重啟 PHP-FPM:
bash
sudo systemctl restart php8.5-fpm
第二步:設定 MariaDB 記憶體分配(目標:innodb_buffer_pool_size=4G)
免註冊聊天室會有密集的「歷史訊息寫入」與「遊客暫存資料查詢」。
將 Buffer Pool 設定為 4GB,能讓 MariaDB 把絕大部分的活躍數據與索引直接放在快取記憶體中,讀寫效能會提升數倍。
1修改 MariaDB 設定檔:
bash
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
請謹慎使用程式碼。

2 在 [mysqld] 區段下,加入或修改以下參數:
ini

代碼: 選擇全部

[mysqld]
# 核心快取大小(指定 4GB)
innodb_buffer_pool_size = 4G

# 最佳化寫入效能(免註冊聊天頻繁寫入聊天紀錄)
innodb_log_file_size = 512M
innodb_log_buffer_size = 16M
innodb_flush_log_at_trx_commit = 2  ; 提升聊天室寫入吞吐量的關鍵設定(每秒重整一次磁碟)

# 最大連線數控制,避免免註冊遊客瞬間灌爆資料庫
max_connections = 300
3 重啟 MariaDB 服務:
sudo systemctl restart mariadb

第三步:Apache2 最佳化與 WebSocket 代理(配合免註冊聊天)
使用 Apache2 的 mpm_event 模式(Debian 13 預設搭配 FPM 的模式),能以極低的資源處理大量遊客的連線。
1 確保 Apache 模組已啟用:
sudo a2enmod proxy proxy_http proxy_wstunnel rewrite
2 優化 Apache 的 Event MPM(控制網頁連線記憶體):
sudo nano /etc/apache2/mods-available/mpm_event.conf

代碼: 選擇全部

<IfModule mpm_event_module>
    StartServers             3
    MinSpareThreads         25
    MaxSpareThreads         75
    ThreadLimit             64
    ThreadsPerChild         25
    MaxRequestWorkers      400
    MaxConnectionsPerChild   0
</IfModule>
3 在網站設定檔中實作免註冊聊天的 WebSocket 轉發:
打開您的網站 VirtualHost 設定檔
(例如 /etc/apache2/sites-available/000-default.conf),加入以下設定。
這會將大眾的網頁請求交給 PHP-FPM(3GB),
而將實時聊天的 WebSocket 連線轉發給後台的通訊核心(如 Workerman 或 Node.js,監聽於 8282 埠):

代碼: 選擇全部

<VirtualHost *:80>
    ServerName yourdomain.com
    DocumentRoot /var/www/html

    # 1. 正常的網頁、API 邏輯、管理後台轉發給 PHP 8.5-FPM
    <FilesMatch \.php$>
        SetHandler "proxy:unix:/run/php/php8.5-fpm.sock|fcgi://localhost"
    </FilesMatch>

    # 2. 聊天室 WebSocket 專用轉發(重要:大眾聊天不卡 FPM 的關鍵)
    # 當前端 JS 連線 ws://://yourdomain.com 時,Apache 會自動分流
    ProxyPass /ws ws://127.0.0.1:8282/
    ProxyPassReverse /ws ws://127.0.0.1:8282/
</VirtualHost>
4 重啟 Apache2:
sudo systemctl restart apache2


1為了讓您完美測試 Apache + PHP 8.5-FPM + Let's Encrypt SSL 的架構,
以下為您提供一套「乾淨、不需資料庫、免註冊」的 Workerman 聊天室範例原始碼。
這套架構的核心逻辑在於:
1 網頁前端(HTML/JS) 透過 Apache2 + SSL 載入,完全不耗 FPM 進程。
2 網頁中的 WebSocket 連線 連向 wss://您的網域/ws。
3 Apache2 收到 wss 連線後,自動卸載 SSL 憑證,並將乾淨的 ws 流量轉發給後台用 PHP-CLI 執行的 Workerman(監聽在內網 127.0.0.1:8282)。
請按照以下步驟在您的 Debian 13 伺服器上部署:
1 安裝 Composer 與 Workerman 套件在伺服器上建立專案目錄(例如 /var/www/chat),並使用 Composer 安裝最新版的 Workerman(已完全相容 PHP 8.5):

代碼: 選擇全部

mkdir -p /var/www/chat
cd /var/www/chat
sudo apt update && sudo apt install composer -y
composer require workerman/workerman
2 後端通訊程式碼:server.php
在 /var/www/chat/ 下建立一個 server.php 檔案。這支程式將在後台常駐,負責將訊息廣播給所有人,並會自動為免註冊用戶指派一個臨時的「匿名路人」暱稱。
nano /var/www/chat/server.php

代碼: 選擇全部

<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;

require_once __DIR__ . '/vendor/autoload.php';

// 監聽內網 8282 埠(由 Apache 作為反向代理將外部 wss 導進來)
$ws_worker = new Worker("websocket://127.0.0.1:8282");

// 啟動 4 個進程(配備 16GB RAM,開 4~8 個進程非常輕鬆)
$ws_worker->count = 4;

// 當有新遊客連線時
$ws_worker->onConnect = function(TcpConnection $connection) {
    // 免註冊:隨機分配一個臨時暱稱存在連線物件中
    $connection->username = "匿名路人_" . rand(1000, 9999);
};

// 當有人發送訊息時
$ws_worker->onMessage = function(TcpConnection $connection, $data) use ($ws_worker) {
    $messageData = json_decode($data, true);
    
    if (isset($messageData['content']) && trim($messageData['content']) !== '') {
        $payload = json_encode([
            'username' => $connection->username,
            'content'  => htmlspecialchars($messageData['content']), // 防 XSS 攻擊
            'time'     => date('H:i:s')
        ]);

        // 廣播給目前所有在線上的遊客
        foreach ($ws_worker->connections as $client_connection) {
            $client_connection->send($payload);
        }
    }
};

// 執行所有 Worker
Worker::runAll();
3 前端網頁程式碼:index.php在同一個目錄(或您 Apache 指向的 DocumentRoot)建立 index.php。前端完全使用原生 JavaScript,無任何肥大框架。
nano /var/www/chat/index.php

代碼: 選擇全部

<!DOCTYPE html>
<html lang="zh-TW">
<head>
    <meta charset="UTF-8">
    <title>PHP 8.5 + Workerman 免註冊極速聊天室</title>
    <style>
        body { font-family: sans-serif; background: #f0f2f5; margin: 0; padding: 20px; }
        #chat-box { width: 100%; max-width: 600px; margin: 0 auto; background: #fff; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); display: flex; flex-direction: column; height: 80vh; }
        #messages { flex: 1; padding: 20px; overflow-y: auto; border-bottom: 1px solid #eee; }
        .msg { margin-bottom: 15px; line-height: 1.4; }
        .msg .meta { font-size: 12px; color: #888; margin-bottom: 3px; }
        .msg .content { background: #e4e6eb; padding: 8px 12px; border-radius: 15px; display: inline-block; max-width: 80%; word-break: break-all; }
        #input-area { padding: 15px; display: flex; gap: 10px; }
        #msg-input { flex: 1; padding: 10px; border: 1px solid #ccc; border-radius: 20px; outline: none; }
        #send-btn { padding: 10px 20px; background: #0084ff; color: #fff; border: none; border-radius: 20px; cursor: pointer; }
    </style>
</head>
<body>

<div id="chat-box">
    <div id="messages"></div>
    <div id="input-area">
        <input type="text" id="msg-input" placeholder="輸入訊息... (免註冊直接聊)" autocomplete="off">
        <button id="send-btn">發送</button>
    </div>
</div>

<script>
    // 【重要】請將此處 yourdomain.com 換成您的 Let's Encrypt 網域
    // 因為網站是 HTTPS,WebSocket 必須走安全協定 wss:// 且不能帶埠號(由 Apache 443 反代)
    const wsUri = "wss://zine-tw.com/plus/ws";
const ws = new WebSocket(wsUri);

    const messagesDiv = document.getElementById('messages');
    const msgInput = document.getElementById('msg-input');
    const sendBtn = document.getElementById('send-btn');

    ws.onmessage = function(e) {
        const data = json.parse(e.data);
        const msgHtml = `
            <div class="msg">
                <div class="meta"><strong>${data.username}</strong> <span style="font-size:10px;">[${data.time}]</span></div>
                <div class="content">${data.content}</div>
            </div>
        `;
        messagesDiv.innerHTML += msgHtml;
        messagesDiv.scrollTop = messagesDiv.scrollHeight; // 自動捲動到底部
    };

    function sendMsg() {
        const text = msgInput.value.trim();
        if (text !== '') {
            ws.send(JSON.stringify({ content: text }));
            msgInput.value = '';
        }
    }

    sendBtn.onclick = sendMsg;
    msgInput.onkeypress = function(e) { if(e.key === 'Enter') sendMsg(); };
</script>
</body>
</html>
4. 關鍵:Let's Encrypt 環境下的 Apache2 VirtualHost 最終設定檔
當您使用 certbot 申請了 Let's Encrypt SSL 後,您的 Apache2 應該會有一個帶有 _ssl 的設定檔
(例如 /etc/apache2/sites-available/000-default-le-ssl.conf)。
請編輯該 SSL 設定檔,將 WebSocket 的反向代理(WSTunnel) 設定塞進 <VirtualHost *:443> 區塊內。
請確保內容包含以下結構(注意 /ws 代理必須放在最上面):

代碼: 選擇全部

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName yourdomain.com
    DocumentRoot /var/www/chat

    # 1. 啟用 SSL(Certbot 自動生成的這部分保持原樣)
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/://yourdomain.com
    SSLCertificateKeyFile /etc/letsencrypt/live/://yourdomain.com

    # 2. 核心:將前端 WSS 請求代理轉發給後台 Workerman 的 8282 埠
    # 這裡會自動解開 Let's Encrypt 加密,以乾淨的 ws 傳給 PHP
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule ^/ws(.*)           ws://127.0.0.1:8282/$1 [P,L]

    ProxyPass /ws ws://127.0.0.1:8282/
    ProxyPassReverse /ws ws://127.0.0.1:8282/

    # 3. 一般網頁與 FPM 設定
    <FilesMatch \.php$>
        SetHandler "proxy:unix:/run/php/php8.5-fpm.sock|fcgi://localhost"
    </FilesMatch>

    <Directory /var/www/chat>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
</IfModule>
sudo systemctl restart apache2
5. 啟動與測試!
現在萬事俱備,請在終端機啟動 Workerman 後端通訊引擎:
php /var/www/chat/server.php start
1. 移動並安裝檔案
請將所有檔案建立或移動到 /var/www/html/plus 目錄下:

代碼: 選擇全部

# 建立目錄並進入
mkdir -p /var/www/html/plus
cd /var/www/html/plus

# 重新安裝 workerman 確保路徑正確
sudo apt update && sudo apt install composer -y
composer require workerman/workerman
接著建立後端 server.php(這支檔案的內容「完全不需要修改」,依舊保持原樣即可):
nano /var/www/html/plus/server.php
(將上一回提供的 server.php 原始碼一字不漏貼進去,它一樣在背景監聽 127.0.0.1:8282)
nano /var/www/html/plus/index.php
貼入上一回提供的 index.php 原始碼,
但請將 JavaScript 裡面的 wsUri 加上 /plus 子目錄。
這樣當 Apache 收到請求時,才能精準辨識這是來自子目錄聊天室的 WebSocket 連線:
const wsUri = "wss://://yourdomain.com";
const ws = new WebSocket(wsUri);
回覆文章

誰在線上

正在瀏覽這個版面的使用者:沒有註冊會員 和 0 位訪客