網站又被太多連線連到連不上網站, 雖然網站掛在 cloudflare 後面, 還是被太多連線造成網站掛掉.
伺服器現況分析
從你提供的日誌來看,你的伺服器正在遭受大規模的自動化掃描攻擊。這些攻擊者利用工具不斷嘗試存取你多個 WordPress 網站的敏感目錄,例如 wp-includes 或 wp-admin。雖然 Apache 正確地攔截了這些請求並顯示 client denied,但短時間內湧入的龐大連線數已經讓你的系統吃不消。在重啟之前,load average 高達 56,這表示你的 CPU 負載已經爆表,且 1GB 的記憶體完全耗盡,迫使系統頻繁使用硬碟的 Swap 空間,這正是伺服器變得極度緩慢的主因。
重啟後的觀察
重啟 Apache 後,記憶體雖然釋放出了一些空間,load average 也降到了 22,但這個數值對 1GB 的小主機來說依然非常危險。日誌中出現的大量 TIME_WAIT 代表剛才有非常多連線被切斷。目前掃描行為明顯還在持續,如果不做進一步的防護,系統很快會再次因為記憶體不足而陷入卡頓。此外,你在這台小主機上跑了至少五個不同的 WordPress 網站,這會讓資源分配變得非常吃緊。
具體應對建議
既然你的伺服器在 Cloudflare 後面,最有效的辦法是到 Cloudflare 的後台開啟 Under Attack 模式,或者建立 WAF 防護規則。你可以設定一條規則:只要請求的路徑包含 wp-includes 或以 .php 結尾且位於敏感目錄,就直接在 Cloudflare 端阻擋或要求驗證。這樣惡意流量就不會直接撞擊你的 Apache。另外,建議你檢查各個網站的 .htaccess 檔案,確保已經關閉目錄瀏覽功能。如果預算允許,這台主機的記憶體建議增加到 2GB 以上,才能比較穩定地運行這麼多網站。
Cloudflare WAF 防護規則建議
既然你的日誌顯示攻擊者都在掃描 wp-includes 與 wp-admin 底下的特定 PHP 檔案,你可以直接在 Cloudflare 的 Security -> WAF 建立一條規則。這能讓惡意請求在到達你的 Ubuntu 伺服器前就被攔截,大幅降低 CPU 負載與記憶體消耗。
建議的 WAF 規則邏輯
你可以選擇 Block (直接阻擋) 或 Managed Challenge (要求過圖形驗證)。規則條件建議如下:
- Field: URI Path
- Operator: contains
- Value: /wp-includes/
- AND
- Field: URI Path
- Operator: ends with
- Value: .php
這條規則會抓出所有嘗試直接執行 wp-includes 資料夾內程式碼的行為,這在正常的 WordPress 運作中幾乎是不需要的。
伺服器端優化建議
除了外層防護,你的主機目前資源非常緊繃,建議調整 Apache 的設定來避免記憶體被耗盡:
- 降低 MaxRequestWorkers: 你的記憶體僅 1GB,如果這個數值設得太高,當攻擊來襲時,Apache 會開啟過多處理程序導致進入 Swap。
- 調整 KeepAliveTimeout: 將這個數值改為 2 或 3 秒,讓閒置連線快點斷開,釋放資源給下一個請求。
- 安裝 Fail2Ban: 雖然在 Cloudflare 後面,但如果你有安裝 mod_remoteip,Fail2Ban 依然可以根據日誌自動將頻繁掃描的 IP 加入系統防火牆阻擋。
Apache 記憶體優化設定
針對 1GB 記憶體的伺服器,我們必須嚴格限制 Apache 的行程數量,避免它把記憶體吃光導致系統進入 Swap 甚至當機。請根據你使用的 MPM 模式(通常是 event 或 worker)修改設定。
請編輯 /etc/apache2/mods-available/mpm_event.conf 或 /etc/apache2/mods-available/mpm_worker.conf:
Apache
<IfModule mpm_event_module>
StartServers 2
MinSpareThreads 10
MaxSpareThreads 25
ThreadsPerChild 25
# 這是關鍵,限制最大同時連線數,1GB 建議設在 100-150 之間
MaxRequestWorkers 100
MaxConnectionsPerChild 1000
</IfModule>
連線控制優化
接著請編輯 /etc/apache2/apache2.conf,調整連線回收的速度:
- KeepAlive On: 保持開啟,但要縮短時間。
- MaxKeepAliveRequests 100: 限制每個連線的請求數。
- KeepAliveTimeout 2: 原本預設通常是 5 秒,縮短到 2 秒可以讓無用的連線趕快斷開。
針對 wp-includes 的本地端防護
雖然 Cloudflare 擋了第一層,但在伺服器本機端也可以加上這段設定,直接在 Apache 層級拒絕非法存取。請將此段加入你的 VirtualHost 設定中:
Apache
<Directory "/var/www/*/wp-includes">
<Files "*.php">
Require all denied
</Files>
</Directory>
這樣即便攻擊者繞過 Cloudflare 直接連到你伺服器的 IP,Apache 也會直接回絕請求,不會去執行 PHP 程式,能省下大量 CPU 運算。
設定完成後,請記得執行 sudo apachectl configtest 確認沒語法錯誤,再重啟服務:
sudo systemctl restart apache2
在 Ubuntu 系統中,這類設定通常有兩個地方可以放,取決於你想針對單一網站還是全伺服器生效。
1. 針對特定網站(建議做法)
如果你想針對特定的 WordPress 網站進行防護,請到 /etc/apache2/sites-available/ 目錄下找對應的設定檔。例如你的網站名稱可能是 vpn.conf 或 000-default.conf。
你可以使用這個指令列出所有啟用的設定檔路徑:
ls /etc/apache2/sites-enabled/
然後使用編輯器開啟該檔案:
sudo nano /etc/apache2/sites-available/你的檔案名稱.conf
將防護程式碼放在 <VirtualHost *:80> 或 <VirtualHost *:443> 的區塊內即可。
2. 針對伺服器所有網站
因為你這台主機跑了 vpn, jasonfonts, stackoverflow, krita 等多個網站,如果你想一次全部保護,可以修改全域安全性設定檔:
sudo nano /etc/apache2/conf-available/security.conf
將這段程式碼貼在檔案的最末端:
Apache
<Directory "/var/www/*/wp-includes">
<Files "*.php">
Require all denied
</Files>
</Directory>
<Directory "/var/www/*/wp-content/uploads">
<Files "*.php">
Require all denied
</Files>
</Directory>
補充:我也順便幫你加上了 uploads 資料夾的 PHP 阻擋,因為那是駭客最常上傳惡意後門程式的地方。
3. 套用並重啟
如果你是修改 security.conf,請確保該設定檔已啟用:
sudo a2enconf security
最後檢查語法並重啟 Apache:
sudo apachectl configtest
sudo systemctl restart apache2
你可以將新的規則邏輯直接加入現有的表達式中。為了讓規則更嚴謹,我們使用括號將 wp-includes 的路徑與 .php 副檔名組合起來。
修改後的 Cloudflare WAF 規則表達式如下:
SQL
(http.request.uri.path contains "/cgi-bin/")
or (http.referer contains "binance.com")
or (http.request.uri.path eq "/xmlrpc.php")
or (http.request.uri.path contains "/wp-includes/" and http.request.uri.path targets_lib_path_suffix ".php")
或是更直覺的寫法:
SQL
(http.request.uri.path contains "/cgi-bin/")
or (http.referer contains "binance.com")
or (http.request.uri.path eq "/xmlrpc.php")
or (http.request.uri.path contains "/wp-includes/" and http.request.uri.path matches ".*\.php$")
設定說明
- 為什麼要加 AND: 如果只阻擋
/wp-includes/,會連帶擋掉正常的 CSS 或 JS 檔案,導致網站排版壞掉。加上.php的條件後,就只會針對該目錄下的程式執行檔進行阻擋,這是最安全的作法。 - 建議動作 (Action): 既然你目前的 Log 顯示這全是惡意掃描,建議將此規則的 Action 設為 Block(阻擋)或 Managed Challenge(驗證碼)。
後續檢查
設定完成後,你可以觀察 Cloudflare 的 Security -> Events,看是否有攔截到來自 /wp-includes/ 的請求。如果攔截成功,你 Ubuntu 伺服器上的 Apache error.log 應該就不會再出現這些 IP 的掃描紀錄,系統負載也會隨之下降。
既然無法使用 Matches 運算子,我們可以改用比較基礎的 contains 或 ends with 來組合。這在 Cloudflare 免費版或一般方案都能運作。
修改後的 WAF 規則建議
你可以將表達式改成以下內容,這樣就不需要 Matches:
SQL
(http.request.uri.path contains "/cgi-bin/")
or (http.referer contains "binance.com")
or (http.request.uri.path eq "/xmlrpc.php")
or (http.request.uri.path contains "/wp-includes/" and http.request.uri.path contains ".php")
為什麼這樣寫有效
- contains “.php”: 雖然沒有正則表達式那麼精準,但絕大多數針對
wp-includes的攻擊都是直接存取.php檔案。在正常情況下,WordPress 核心不會讓使用者從瀏覽器直接讀取該目錄下的 PHP 檔案,所以這條規則非常安全。 - 組合條件: 透過
and將目錄與副檔名綁在一起,可以確保不會誤擋到wp-includes裡的圖片或樣式表(CSS/JS)。
操作步驟
- 登入 Cloudflare,進入 Security > WAF。
- 點擊現有規則旁邊的 Edit。
- 點擊右下角的 Edit expression 切換到純文字模式。
- 將上面的代碼貼上並點擊 Deploy。
設定完成後,建議你先觀察半小時,看伺服器的 load average 是否有從 22 慢慢降下來。如果還有其他特定路徑在報錯,我們可以再繼續擴充這條規則。
好的,我們把 wp-content/uploads 的防護也併入。在 WordPress 中,uploads 資料夾是用來存放圖片和媒體檔的,絕對不應該出現任何可執行的 .php 檔案。如果有人嘗試在裡面執行 PHP,那幾乎可以確定是駭客上傳了後門程式。
更新後的 Cloudflare WAF 表達式
請將規則更新為以下內容:
SQL
(http.request.uri.path contains "/cgi-bin/")
or (http.referer contains "binance.com")
or (http.request.uri.path eq "/xmlrpc.php")
or (http.request.uri.path contains "/wp-includes/" and http.request.uri.path contains ".php")
or (http.request.uri.path contains "/wp-content/uploads/" and http.request.uri.path contains ".php")
規則說明與後續建議
- 阻擋 uploads 內的 PHP: 這是非常強效的防護。駭客最常見的手法是利用外掛漏洞上傳一個名為
shell.php或info.php的檔案到圖片區。現在這條規則會在對方執行這些後門時,直接在 Cloudflare 端切斷連線。 - 確認負載: 更新規則後,你可以再次觀察伺服器的
top指令或load average。如果規則奏效,連線數(Connection Counts)裡的ESTABLISHED數量應該會顯著減少,因為惡意請求在進入你的 Apache 之前就被擋掉了。 - 檢查其他目錄: 你的日誌中還提到了
wp-admin/css/colors/ectoplasm/這種奇怪的掃描,這通常是針對特定外掛漏洞。目前的規則已經涵蓋了最危險的兩個區域(includes 和 uploads)。
要查看 Cloudflare 攔截了哪些 IP,請按照以下步驟操作,這能幫你確認防護規則是否發揮作用:
1. 進入 Cloudflare 事件日誌
登入 Cloudflare 後,在左側選單點擊 Security(安全性) > Events(事件)。
2. 查看活動摘要
在該頁面你會看到一個圖表和下方的清單。你可以從清單中看到:
- Action taken: 如果顯示 Block,表示該請求已被成功攔截。
- Rule ID: 確認是否為剛才設定的那條 WAF 規則。
- IP address: 攻擊者的來源 IP。
- Path: 對方嘗試存取的路徑(例如
/wp-includes/xxx.php)。
3. 使用篩選功能(選用)
如果事件太多,你可以點擊 Add filter,選擇 Service 等於 WAF,或是直接搜尋特定路徑,這樣就能精確看到針對 WordPress 敏感目錄的攻擊頻率。
觀察伺服器壓力是否釋放
在 Cloudflare 設定好之後,建議你在 Ubuntu 終端機執行 uptime 或 top。
- 如果 load average 從原本的 20-50 降到 2 以下,說明 Cloudflare 已經幫你的 CPU 擋掉了大半的工作。
- 如果負載依然很高,請再執行一次
netstat -n | awk '/^tcp/ {print $6}' | sort | uniq -c | sort -n,看看ESTABLISHED的數量有沒有減少。
如果負載還是降不下來,可能還有其他非 PHP 的資源存取(例如大量的圖片請求)在消耗頻寬,到時候我們再針對那些行為調整規則。