XServer VPS セキュリティ復旧&n8n/Dify再構築ノウハウ

XServer VPS セキュリティ復旧&n8n/Dify再構築ノウハウ

何が起きたか

2026年1月10日、VPSが不正アクセスを受けマルウェア(XMRig仮想通貨マイナー)に感染。XServerがアウトバウンド通信を全ブロック。約2ヶ月間、外部通信が不通の状態が続いた。

侵入経路

感染の証拠

ps aux | grep -v "\["
# uid=1001のプロセスが実行中:
# pkill -f donate-level   ← XMRig(仮想通貨マイナー)の競合排除
# pkill -f curl

教訓

脆弱性通知メールは即日対応

XServerからの通知メールを見逃したことが最終的な原因。
仕組みで防ぐことが重要。

監視の仕組み化

# /usr/local/bin/security_check.sh
SUSPICIOUS=$(ps aux | grep -E "xmrig|minerd|donate-level" | grep -v grep)
if [ -n "$SUSPICIOUS" ]; then
  echo "$SUSPICIOUS" | mail -s "【警告】VPSに不審なプロセスを検知" your@email.com
fi
# crontabで1時間ごとに実行

Watchtowerで自動更新+通知

watchtower:
  image: containrrr/watchtower
  environment:
    - WATCHTOWER_NOTIFICATIONS=email
    - WATCHTOWER_SCHEDULE=0 0 2 * * *  # 毎日深夜2時
    - WATCHTOWER_CLEANUP=true

復旧手順

1. データのバックアップ(SSH経由)

# n8nワークフローのエクスポート
docker exec n8n n8n export:workflow --all --output=/tmp/workflows.json
docker cp n8n:/tmp/workflows.json /root/workflows_backup.json

# ローカルPCにダウンロード
scp root@210.131.212.67:/root/workflows_backup.json ~/Desktop/

2. OS再インストール

XServerコントロールパネルから実行。SSH公開鍵をこの時点で登録する。

3. SSH接続時の警告対処

# ホストキーが変わるため古い情報を削除
ssh-keygen -R 210.131.212.67
ssh -i ~/.ssh/xvps_ed25519 root@210.131.212.67

4. SSHセキュリティ強化

# /etc/ssh/sshd_config
PermitRootLogin prohibit-password   # 鍵認証のみ許可
PasswordAuthentication no           # パスワード認証を無効化

Note: パスワード認証を無効にしてもブルートフォース攻撃自体は来る。ただし全て弾かれるので問題なし。Fail2banを入れるとさらに安全。


Dify + n8n 再構築

構成

foresthill.xvps.jp/        → Dify
foresthill.xvps.jp/n8n/    → n8n

Nginxがパスで振り分けるため互いに干渉しない。

docker-compose.yamlへのn8n追加

# services セクションの末尾に追加
  n8n:
    image: n8nio/n8n:latest
    container_name: docker-n8n
    restart: always
    ports:
      - "5678:5678"
    environment:
      - N8N_RUNNERS_ENABLED=true
      - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
      - N8N_PATH=/n8n/
      - WEBHOOK_URL=https://foresthill.xvps.jp/n8n/
      - N8N_EDITOR_BASE_URL=https://foresthill.xvps.jp/n8n/
    volumes:
      - n8n_data:/home/node/.n8n

# volumes セクションの末尾に追加
  n8n_data:

NginxへのLocation追加

重要ポイント:

# conf.d/n8n.conf は単体では動かない(server{}ブロックが必要)
# templateに直接追加する方式が正解

nano ~/dify/docker/nginx/conf.d/default.conf.template

追加するlocationブロック(location / の直前):

    location /n8n/ {
        proxy_pass http://n8n:5678/;
        include proxy.conf;
    }

Gotcha: WebSocket用に proxy_set_header Upgrade $http_upgrade; を追加すると envsubst で空に置換されてNginxが起動失敗する。proxy.conf に必要なヘッダーが含まれているのでそれで十分。

再起動

cd ~/dify/docker
docker compose up -d n8n
docker compose restart nginx
docker ps | grep -E "n8n|nginx"

ワークフローのインポート

docker cp ~/workflows_backup.json docker-n8n:/tmp/
docker exec docker-n8n n8n import:workflow --input=/tmp/workflows_backup.json

SSL証明書について

XServerの「ドメイン・SSLクイック設定」または2025年1月22日以降のDifyアプリイメージを使用している場合、自動更新されるため手動対応不要

アウトバウンド通信が回復すれば自動的に証明書が更新され、HTTPSの鍵が閉まる。


診断コマンド集

# 不審プロセス確認
ps aux | grep -E "xmrig|minerd|donate-level|kworkerds"

# アウトバウンド通信確認
curl -I https://google.com --max-time 10

# certbot接続確認
curl -v https://acme-v02.api.letsencrypt.org/directory --max-time 10

# Nginxエラーログ
docker logs docker-nginx-1 --tail 20

# SSH攻撃ログ
grep "Failed\|Accepted" /var/log/auth.log | tail -30

関連リンク