跳转到帖子
在手机APP中查看

一个更好的浏览方法。了解更多

PHP论坛人

主屏幕上的全屏APP,带有推送通知、徽章等。

在iOS和iPadOS上安装此APP
  1. 在Safari中轻敲分享图标
  2. 滚动菜单并轻敲添加到主屏幕
  3. 轻敲右上角的添加按钮。
在安卓上安装此APP
  1. 轻敲浏览器右上角的三个点菜单 (⋮) 。
  2. 轻敲添加到主屏幕安装APP
  3. 轻敲安装进行确认。

SSH登入提示 Part 1 + (監控 記憶體、硬碟使用率) + (監控 Nginx、PHP、MariaDB) + 監控面板

精选回复

SSH登入提示 Part 1 + (監控 記憶體、硬碟使用率) + (監控 Nginx、PHP、MariaDB) + 監控面板



----------
前言
----------

什麼是MOTD?

MOTD (Message of the Day) 是使用者透過SSH登入Linux系統時,系統自動顯示的歡迎訊息。MOTD常用於以下用途:

顯示即時系統資訊:伺服器名稱、負載、記憶體與磁碟使用量

服務狀態監控:Nginx、PHP-FPM、MariaDB 等關鍵服務的運作狀態

安全警告:提醒登入者遵守使用規範,嚇阻未授權存取

維護通知:公告排程維護時間或緊急異常狀況

實用提示:常用指令、重要路徑、緊急聯絡資訊



--------------------
MOTD的運作機制
--------------------

Linux 系統中的MOTD分為兩種類型:


靜態MOTD
/etc/motd
純文字檔,內容固定不變



動態MOTD
/etc/update-motd.d/
由腳本動態產生,每次登入時即時執行




注意:在Debian 13中,若同時存在靜態與動態MOTD,兩者的內容都會顯示

若只想顯示動態內容,建議將 /etc/motd 的內容清空







---------------------
腳本用途與背景
---------------------

什麼是 update-motd.d?

Linux系統在使用者透過SSH登入時,會自動執行 /etc/update-motd.d/ 目錄下所有可執行的腳本,並將輸出顯示為「每日訊息」 (Message of the Day,MOTD)

這套機制讓管理員在登入的瞬間就能掌握伺服器現況,無需手動執行 top、df、ss 等指令



--------------------
腳本命名規則
--------------------

目錄內的腳本以數字開頭,系統會依序執行:

/etc/update-motd.d/
  00-header          ← 最先執行(通常是歡迎訊息)
  10-system-info     ← 本教學的腳本位置
  90-updates         ← 較晚執行

數字越小優先執行。10-system-info 是常見慣例,代表「基礎系統資訊」



------------------------
為什麼需要自訂腳本?
------------------------

Debian預設的MOTD只顯示最基本的資訊,對於運行論壇的生產伺服器而言遠遠不夠。自訂腳本可以讓你在登入瞬間看到:

CPU負載、記憶體、磁碟使用狀況

Nginx / PHP-FPM / MariaDB / Redis 服務狀態

即時網路連線數與 QPS

Fail2ban封鎖狀況與最新攻擊IP

論壇線上人數



-----------------------
安裝必要套件
-----------------------


基礎工具 (通常已內建)
apt install -y procps iproute2 coreutils



Fail2ban (防暴力破解)
apt install -y fail2ban


sysstat (提供 iostat,用於磁碟 IO 統計)
apt install -y sysstat


MaxMind GeoLite2 資料庫 免費版
apt install -y geoipupdate mmdb-bin



Redis 客戶端工具
apt install -y redis-tools




安裝 sysstat 後,需啟用資料收集
sed -i 's/ENABLED="false"/ENABLED="true"/' /etc/default/sysstat





------------------
啟用服務
------------------

systemctl enable --now sysstat



systemctl enable --now fail2ban



systemctl enable --now geoipupdate


systemctl enable --now geoipupdate.service



systemctl enable --now geoipupdate.timer








-------------------------
重啟服務
-------------------------

systemctl restart sysstat



systemctl restart fail2ban



systemctl restart geoipupdate



systemctl restart geoipupdate.timer



systemctl restart geoipupdate.service



---------------------------
檢查服務狀態
---------------------------

systemctl status fail2ban


systemctl status geoipupdate.service



systemctl status geoipupdate.timer




檢查 sysstat 服務狀態
systemctl status sysstat


正常會看到類似:
Loaded: loaded (/usr/lib/systemd/system/sysstat.service; enabled; preset: enabled)
Active: active (exited)




再確認資料是否真的有收集
sar -u 1 3


或者
ls /var/log/sysstat/


應該會看到 (數字是日期)
sa13
sar13










---------------------
靜態MOTD
---------------------

靜態MOTD適合用來顯示固定的警告訊息、伺服器識別資訊或使用規範聲明


修改
vi /etc/motd


修改原有內容,建議將內容清空




儲存檔案並離開vi編輯器
按 Esc,輸入 :wq,按 Enter







測試結果,先SSH登出
exit



再次SSH登入,應可看到已刪除靜態MOTD的情況







---------------------------------------------
動態MOTD (適用於即時系統資訊)
---------------------------------------------

動態MOTD透過 Shell 腳本在每次登入時即時產生系統狀態資訊,非常適合用來監控VPS,讓管理員一登入就掌握伺服器狀況






------------------------------------------
建立自訂腳本,進入動態MOTD目錄
------------------------------------------

cd /etc/update-motd.d/


ls -la


目錄中的腳本會依 檔名的數字前綴 由小到大依序執行。建議命名規則:


| 前綴     | 用途建議
|--------|----------
| 00–09  | 橫幅標題、安全警告
| 10–49  | 系統資訊 (負載、記憶體、磁碟)
| 50–79  | 服務狀態
| 80–99  | 更新通知、其他提示

建立系統資訊腳本
vi /etc/update-motd.d/10-system-info



貼上以下內容 (請注意:第1行不能為空白)



#!/bin/bash
# /etc/update-motd.d/10-system-info
# Debian 13 論壇伺服器 SSH 登入資訊看板

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# 顏色定義
RED="\033[1;31m"
GREEN="\033[1;32m"
YELLOW="\033[1;33m"
CYAN="\033[1;36m"
WHITE="\033[1;37m"
RESET="\033[0m"

# 安全數值比較函數
safe_num_compare() {
local val=$1
local threshold=$2
local operator=$3
val=$(echo "$val" | grep -o '[0-9]*' | head -1)
[ -z "$val" ] || ! [[ "$val" =~ ^[0-9]+$ ]] && val=0
case "$operator" in
"gt") [ "$val" -gt "$threshold" ] 2>/dev/null && return 0 ;;
"lt") [ "$val" -lt "$threshold" ] 2>/dev/null && return 0 ;;
"ge") [ "$val" -ge "$threshold" ] 2>/dev/null && return 0 ;;
"le") [ "$val" -le "$threshold" ] 2>/dev/null && return 0 ;;
*) return 1 ;;
esac
return 1
}

# 主機資訊
HOST=$(hostname -s)
IP=$(hostname -I | awk '{print $1}')
OS=$(grep PRETTY_NAME /etc/os-release | cut -d '"' -f2)
KERNEL=$(uname -r)
UPTIME=$(uptime -p | sed 's/up //')

# CPU
CPU=$(nproc)
LOAD=$(cut -d' ' -f1-3 /proc/loadavg)
IOWAIT=$(vmstat 1 2 2>/dev/null | tail -1 | awk '{print $16}')
[ -z "$IOWAIT" ] && IOWAIT=0

# 記憶體
MEM_TOTAL=$(free -m | awk '/Mem:/ {print $2}')
MEM_USED=$(free -m | awk '/Mem:/ {print $3}')
MEM_PERCENT=0
[ "$MEM_TOTAL" -gt 0 ] && MEM_PERCENT=$((MEM_USED * 100 / MEM_TOTAL))
SWAP_TOTAL=$(free -m | awk '/Swap:/ {print $2}')
SWAP_USED=$(free -m | awk '/Swap:/ {print $3}')

# 磁碟
DISK=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
DISK_DISPLAY=$(df -h / | awk 'NR==2 {print $3"/"$2" ("$5")"}')

# 網路
TCP=$(ss -ant | wc -l | tr -d '[:space:]' | grep -o '[0-9]*' | head -1)
[ -z "$TCP" ] && TCP=0
SYN=$(ss -ant state syn-recv 2>/dev/null | wc -l | tr -d '[:space:]' | grep -o '[0-9]*' | head -1)
[ -z "$SYN" ] && SYN=0
HTTP_CONN=$(ss -ant '( sport = :80 or sport = :443 )' 2>/dev/null | wc -l | tr -d '[:space:]' | grep -o '[0-9]*' | head -1)
[ -z "$HTTP_CONN" ] && HTTP_CONN=0

# Web 服務進程
NGINX_WORKERS=$(pgrep -c nginx 2>/dev/null || echo 0)
PHP_PROC=$(pgrep -c php-fpm 2>/dev/null || echo 0)

# MariaDB
_MYSQL_STATUS=$(mysqladmin status 2>/dev/null)
MYSQL_THREADS=$(echo "$_MYSQL_STATUS" | awk '{print $4}')
MYSQL_QPS=$(echo "$_MYSQL_STATUS" | awk '{print $9}')
[ -z "$MYSQL_THREADS" ] && MYSQL_THREADS="N/A"
[ -z "$MYSQL_QPS" ] && MYSQL_QPS="N/A"
MYSQL_SLOW=$(mysql -e "SHOW GLOBAL STATUS LIKE 'Slow_queries';" 2>/dev/null | awk 'NR==2 {print $2}')
[ -z "$MYSQL_SLOW" ] && MYSQL_SLOW="N/A"

# Redis
REDIS_STATUS=$(systemctl is-active redis-server 2>/dev/null || systemctl is-active redis 2>/dev/null)
[ -z "$REDIS_STATUS" ] && REDIS_STATUS="未安裝"
_REDIS_STATS=$(redis-cli info stats 2>/dev/null)
REDIS_HITS=$(echo "$_REDIS_STATS" | grep keyspace_hits | cut -d: -f2 | tr -d '[:space:]')
REDIS_MISS=$(echo "$_REDIS_STATS" | grep keyspace_misses | cut -d: -f2 | tr -d '[:space:]')
HITRATE="N/A"
if [[ "$REDIS_HITS" =~ ^[0-9]+$ && "$REDIS_MISS" =~ ^[0-9]+$ ]]; then
_TOTAL=$((REDIS_HITS + REDIS_MISS))
[ "$_TOTAL" -gt 0 ] && HITRATE=$((REDIS_HITS * 100 / _TOTAL))"%"
fi

# Nginx QPS
_LOG="/var/log/nginx/access.log"
if [ -f "$_LOG" ]; then
R1=$(wc -l < "$_LOG" | tr -d '[:space:]' | grep -o '[0-9]*' | head -1)
sleep 1
R2=$(wc -l < "$_LOG" | tr -d '[:space:]' | grep -o '[0-9]*' | head -1)
QPS=$((R2 - R1))
else
QPS=0
fi
RPM=$((QPS * 60))

# Fail2ban
FAIL2BAN=$(fail2ban-client status 2>/dev/null | grep "Total banned" | awk '{print $NF}')
[ -z "$FAIL2BAN" ] && FAIL2BAN=0
RECENT_BANS=$(tail -n 20 /var/log/fail2ban.log 2>/dev/null | grep " Ban " | awk '{print $1,$2,$NF}' | tail -5)

# GeoIP 設定
MMDB="/usr/share/GeoIP/GeoLite2-Country.mmdb"

# 攻擊來源 IP (TOP5)
TOPIP=$(tail -n 5000 "$_LOG" 2>/dev/null | awk '{print $1}' | sort | uniq -c | sort -rn | head -5)

# 攻擊來源國家 (只查最後 200 個 IP,避免 SSH 登入過慢)
if [ -f "$MMDB" ]; then
ATTACK_COUNTRY=$(tail -n 200 "$_LOG" 2>/dev/null \
| awk '{print $1}' \
| while read ip; do
mmdblookup --file "$MMDB" --ip "$ip" country names en 2>/dev/null \
| awk -F'"' '/"/{print $2}'
done \
| sort \
| uniq -c \
| sort -rn \
| head -5)
else
ATTACK_COUNTRY="(請先安裝 GeoLite2 資料庫:/usr/share/GeoIP/GeoLite2-Country.mmdb)"
fi

# 熱門 URL
TOPURL=$(tail -n 5000 "$_LOG" 2>/dev/null | awk '{print $7}' | sort | uniq -c | sort -rn | head -5)

# 論壇線上人數 (Invision Community)
ONLINE=$(mysql forum -e "SELECT COUNT(*) FROM core_sessions WHERE login_type != 0;" 2>/dev/null | tail -1)
[ -z "$ONLINE" ] && ONLINE="N/A"

# 磁碟 IO
if command -v iostat &>/dev/null; then
DISKIO=$(iostat -dx 1 2 2>/dev/null | awk 'NR>3 && NF' | head -5)
else
DISKIO="(未安裝 sysstat)"
fi

# CPU 佔用前五
TOPCPU=$(ps -eo comm,%cpu --sort=-%cpu 2>/dev/null | head -6)

# 可用更新
UPDATES=$(apt list --upgradable 2>/dev/null | grep -c upgradable 2>/dev/null || echo 0)

# ========== 輸出 ==========
echo ""
echo -e "${CYAN}══════════════════════════════════════════════════════════════════${RESET}"
echo -e "${WHITE} 論壇伺服器 看板${RESET}"
echo -e "${CYAN}══════════════════════════════════════════════════════════════════${RESET}"
printf "主機名稱 : %s\n" "$HOST"
printf "伺服器 IP : %s\n" "$IP"
printf "作業系統 : %s\n" "$OS"
printf "核心版本 : %s\n" "$KERNEL"
printf "系統運行 : %s\n" "$UPTIME"
echo ""
printf "CPU 核心 : %s\n" "$CPU"
printf "負載平均 : %s\n" "$LOAD"
printf "IO 等待 : %s%%\n" "$IOWAIT"
echo ""
printf "記憶體 : %sMB / %sMB (%s%%)\n" "$MEM_USED" "$MEM_TOTAL" "$MEM_PERCENT"
printf "Swap : %sMB / %sMB\n" "$SWAP_USED" "$SWAP_TOTAL"
if safe_num_compare "$MEM_PERCENT" 85 "gt"; then
echo -e "${RED} 記憶體使用率過高${RESET}"
fi
echo ""
printf "磁碟 / : %s\n" "$DISK_DISPLAY"
if safe_num_compare "$DISK" 80 "gt"; then
echo -e "${RED} 磁碟空間不足${RESET}"
fi
echo ""
echo -e "${CYAN}── 網路 ─────────────────────────────────────────────────────────${RESET}"
printf "TCP 連線 : %s\n" "$TCP"
printf "SYN_RECV : %s\n" "$SYN"
printf "HTTP 連線 : %s\n" "$HTTP_CONN"
printf "Nginx QPS : %s req/s(RPM: %s)\n" "$QPS" "$RPM"
if safe_num_compare "$SYN" 50 "gt"; then
echo -e "${YELLOW} SYN_RECV 偏高,可能遭受 SYN Flood 攻擊${RESET}"
fi
echo ""
echo -e "${CYAN}── Web 服務狀態 ─────────────────────────────────────────────────${RESET}"
_check_service() {
if systemctl is-active --quiet "$1"; then
printf "${GREEN} %-14s 運行中${RESET}\n" "$1"
else
printf "${RED} ✘ %-14s 已停止 ← 請立即檢查!${RESET}\n" "$1"
fi
}
_check_service nginx
_check_service php8.4-fpm
_check_service mariadb
_check_service redis-server
_check_service fail2ban
echo ""
printf "Nginx 工作進程 : %s\n" "$NGINX_WORKERS"
printf "PHP-FPM 進程 : %s\n" "$PHP_PROC"
echo ""
echo -e "${CYAN}── 資料庫(MariaDB)────────────────────────────────────────────${RESET}"
printf "目前連線數 : %s\n" "$MYSQL_THREADS"
printf "每秒查詢數 : %s QPS\n" "$MYSQL_QPS"
printf "慢查詢數 : %s\n" "$MYSQL_SLOW"
if [[ "$MYSQL_SLOW" =~ ^[0-9]+$ && "$MYSQL_SLOW" -gt 100 ]]; then
echo -e "${YELLOW} 慢查詢偏多${RESET}"
fi
echo ""
echo -e "${CYAN}── Redis 快取 ───────────────────────────────────────────────────${RESET}"
printf "服務狀態 : %s\n" "$REDIS_STATUS"
printf "快取命中率 : %s\n" "$HITRATE"
echo ""
echo -e "${CYAN}── 論壇 ─────────────────────────────────────────────────────────${RESET}"
printf "線上人數 : %s\n" "$ONLINE"
echo ""
echo -e "${CYAN}── 資安 ─────────────────────────────────────────────────────────${RESET}"
printf "Fail2ban 封鎖 IP : %s\n" "$FAIL2BAN"
if [ -n "$RECENT_BANS" ]; then
echo " 最近封鎖記錄:"
echo "$RECENT_BANS" | while IFS= read -r line; do
echo " $line"
done
fi
echo ""
echo -e "${CYAN}── 攻擊來源 IP(依請求數排序)──────────────────────────────────${RESET}"
echo "$TOPIP"
echo ""
echo -e "${CYAN}── 攻擊來源國家 ─────────────────────────────────────────────────${RESET}"
echo "$ATTACK_COUNTRY"
echo ""
echo -e "${CYAN}── 熱門請求 URL ─────────────────────────────────────────────────${RESET}"
echo "$TOPURL"
echo ""
echo -e "${CYAN}── CPU 佔用排行 ─────────────────────────────────────────────────${RESET}"
echo "$TOPCPU"
echo ""
echo -e "${CYAN}── 磁碟 IO ──────────────────────────────────────────────────────${RESET}"
echo "$DISKIO"
echo ""
if safe_num_compare "$UPDATES" 0 "gt"; then
echo -e "${YELLOW} 有 $UPDATES 個套件可升級,建議執行 apt upgrade${RESET}"
fi
echo -e "${CYAN}══════════════════════════════════════════════════════════════════${RESET}"
echo ""







儲存檔案並離開vi編輯器
按 Esc,輸入 :wq,按 Enter

-----------------
賦予執行權限
-----------------


確保腳本有執行權限
chmod +x /etc/update-motd.d/10-system-info



確認所有權
chown root:root /etc/update-motd.d/10-system-info





--------------------
停用預設的腳本
--------------------

Debian 13 已有預設腳本,如 10-uname

若不需要可移除執行權限

chmod -x /etc/update-motd.d/10-uname 2>/dev/null || true




------------------
確認PAM設定
------------------

Debian使用PAM控制MOTD顯示,編輯PAM設定檔


編輯
vi /etc/pam.d/sshd


找到這兩行,確保這兩行存在且未被註解 (無 # 符號)


session    optional     pam_motd.so  motd=/run/motd.dynamic
session    optional     pam_motd.so noupdate





儲存檔案並離開vi編輯器
按 Esc,輸入 :wq,按 Enter





-------------------------
開啟 SSH 主配置檔
-------------------------


編輯
vi /etc/ssh/sshd_config


## 將 PrintMotd no 改 yes
PrintMotd yes


# 加入 或 修改
UseDNS no
GSSAPIAuthentication no
PrintLastLog yes




儲存檔案並離開vi編輯器
按 Esc,輸入 :wq,按 Enter







----------------------------
強制重新產生MOTD快取
----------------------------

清除快取
rm -f /var/run/motd.dynamic


重新產生
run-parts /etc/update-motd.d/ > /var/run/motd.dynamic


查看結果
cat /var/run/motd.dynamic





-------------------------
完整的SSH與PAM重啟
-------------------------

重啟SSH服務
systemctl restart sshd


確認SSH設定
sshd -T | grep -E "(printmotd|printlastlog)"


預期輸出應該包含:

printmotd yes

printlastlog yes







------------------
驗證
------------------

驗證設定檔語法
sshd -t



如果語法正確,重啟 SSH 服務
systemctl restart sshd







----------------
立即測試腳本
----------------

直接執行腳本檢查輸出

bash /etc/update-motd.d/10-system-info





-----------------------
驗證SSH登入效果
-----------------------

登出
exit


重新SSH登入,確認動態MOTD正常顯示

------------------------

前往 Part 2

------------------------

SSH登入提示 Part 2 安裝MaxMind GeoLite2並建立自動更新腳本

本帖最后于,由Jack编辑

创建帐户或登录后发表意见

帐户

导航

搜索

配置浏览器推送通知

Chrome (安卓)
  1. 轻敲地址栏旁的锁形图标。
  2. 轻敲权限 → 通知。
  3. 调整你的偏好。
Chrome (台式电脑)
  1. 点击地址栏中的挂锁图标。
  2. 选择网站设置。
  3. 找到通知选项并调整你的偏好。