監視ツールはサーバーや Web サイトのダウンを知らせてくれますが、早期の兆候はログの中に隠れています。日ごとに少しずつ埋まっていくディスク、何百回も繰り返されるエラー、SSH へのブルートフォース攻撃の波、気づかないうちに CPU を消費し続けるプロセスなどです。こうしたログを毎朝読んでいる人はほとんどいません。この記事では、重要な情報を 1 日 1 回収集し、Ollama のローカル言語モデルに確認ポイント付きの読みやすい短いレポートにまとめさせて、Telegram に送信します。モデルは自社のサーバー上で動作するため、ログがサーバーの外に出ることはありません。
「Ollama でローカル LLM を運用する」の手順でセットアップした Ollama と小型モデルに加えて、jq と curl が必要です。Telegram で @BotFather を使ってボットを作成し、そのボットに任意のメッセージを送ってから、チャット ID を確認します。
apt install -y jq curl
ollama pull qwen2.5:7b
# Send any message to your bot first, then:
curl -s "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates" | jq '.result[].message.chat.id'
mkdir -p /opt/aireport
cat > /opt/aireport/report.sh <<'EOF2'
#!/bin/bash
# Daily AI server report: collect facts, summarise them with Ollama, send to Telegram
MODEL="qwen2.5:7b"
LANGUAGE="Simplified Chinese" # language of the report
TG_TOKEN="123456789:replace-with-your-bot-token"
TG_CHAT="123456789"
FACTS=/opt/aireport/facts.txt
{
echo "Host: $(hostname) Uptime: $(uptime -p)"
echo "Load average 1/5/15 min: $(cut -d' ' -f1-3 /proc/loadavg) CPU cores: $(nproc)"
echo; echo "## Memory"; free -h
echo; echo "## Disk usage"; df -h -x tmpfs -x devtmpfs -x overlay
echo; echo "## Failed systemd units"; systemctl --failed --no-legend
echo; echo "## Most frequent error messages in the last 24 hours"
journalctl --since "24 hours ago" -p err --no-pager -o cat | sort | uniq -c | sort -rn | head -20
echo; echo "## Failed SSH password logins in the last 24 hours (count, then top source IPs)"
journalctl --since "24 hours ago" --no-pager -o cat | grep -c "Failed password"
journalctl --since "24 hours ago" --no-pager -o cat | grep -oP "Failed password .* from \K[0-9a-fA-F.:]+" | sort | uniq -c | sort -rn | head -5
if [ -f /var/log/nginx/access.log ]; then
echo; echo "## Nginx HTTP status codes since the last log rotation"
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -8
echo; echo "## URLs with the most 5xx errors"
awk '$9 ~ /^5/ {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -5
fi
echo; echo "## Top processes by CPU"
ps -eo user,pid,%cpu,%mem,etime,comm --sort=-%cpu | head -8
} > "$FACTS" 2>&1
PROMPT="You are an experienced Linux operations engineer. Below are today's facts from a server.
Write a short daily report in $LANGUAGE for the server owner:
1. First line: overall status, one of OK / ATTENTION / PROBLEM.
2. Then at most 5 bullet points about anything unusual, each with the likely cause and one command to check it.
3. If everything looks normal, say so in one sentence.
Only use the facts below. Do not invent numbers.
$(head -c 12000 "$FACTS")"
REPORT=$(jq -n --arg m "$MODEL" --arg p "$PROMPT" \
'{model: $m, prompt: $p, stream: false, options: {temperature: 0.2, num_ctx: 8192}}' \
| curl -s --max-time 900 http://127.0.0.1:11434/api/generate -d @- | jq -r '.response // empty')
[ -z "$REPORT" ] && REPORT="AI summary failed. Raw facts:
$(head -c 3000 "$FACTS")"
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
--data-urlencode "chat_id=${TG_CHAT}" \
--data-urlencode "text=[$(hostname)] daily report
${REPORT:0:3800}" > /dev/null
EOF2
chmod 700 /opt/aireport/report.sh
ボットトークンとチャット ID を実際の値に置き換えてください。スクリプトにはトークンが含まれるため、root だけが読み取れるようにしています。num_ctx は収集データ全体を読み込めるだけのコンテキストをモデルに与える設定で、レポートは Telegram のメッセージ長の上限に収まるように切り詰められます。モデルが応答しなかった場合でも、収集した生データがそのまま届きます。
/opt/aireport/report.sh
cat /opt/aireport/facts.txt # the data the model saw
初回はモデルの読み込みに時間がかかります。何度かレポートと facts.txt を見比べて、自分のサーバーに対する要約がどの程度信頼できるかを判断し、反応が過剰または過小であればプロンプトを調整してください。
echo '0 8 * * * root /opt/aireport/report.sh' > /etc/cron.d/aireport
timedatectl | grep "Time zone" # cron uses the server's time zone
スクリプトの波括弧の中にセクションを追加すると、その出力がすべて収集データに含まれます。便利な例をいくつか紹介します。
echo; echo "## Fail2ban"; fail2ban-client status sshd | grep -E "Currently banned|Total banned"
echo; echo "## Stopped Docker containers"; docker ps -a --filter status=exited --format "{{.Names}}: {{.Status}}"
echo; echo "## Certificates"; for c in /etc/letsencrypt/live/*/cert.pem; do echo "$c $(openssl x509 -enddate -noout -in "$c")"; done
echo; echo "## Last backup file"; ls -lt /backup | head -3
関連記事:「Fail2ban で SSH と Nginx を保護する」、「無料 SSL 証明書の取得と自動更新」、IP ブロックについては「レンタル IP ブロックを自動で監視する」。
Ollama をすべてのサーバーで動かす必要はありません。各サーバーではデータ収集部分だけを実行し、facts.txt を Ollama のあるサーバーにコピーして(例:cron から SSH キーを使って scp で転送)、すべてのレポートをそのサーバーで生成します。中央の Ollama を直接呼び出す場合は、プライベートネットワークか VPN を経由し、ポート 11434 は決してインターネットに公開しないでください。
CPU ではモデルの文章生成に時間がかかりますが、1 日 1 回のジョブであれば問題ありません。より速くレポートを作成したい場合は、qwen2.5:3b のような小さなモデルを使うか、不要なセクションを削除して収集データを短くしてください。
技術的には可能ですが、ログには IP アドレス、ユーザー名、URL、場合によっては顧客データも含まれます。これらを第三者に送信することはプライバシー上の問題につながるため、プロバイダーの利用規約とサービス提供地域に従う必要があります。ローカルモデルであればこの問題を避けられます。
提案されたコマンドを実行し、生データを確認してください。CPU を大量に使う不明なプロセスや想定外のログインが見つかった場合は、「Linux サーバーがハッキングされていないか確認する方法」に沿って対応してください。
上記の手順で解決しない場合は、サポートチケットを送信して IMIDC の 24 時間 365 日対応テクニカルサポートへご連絡ください。サーバー IP、OS バージョン、facts.txt の内容、受信したレポートを添えていただくと、より迅速に調査できます。