ようやく、セキュリティでの効果的な一歩である「SSHポート変更」を行いましたので、そのメモです。
例によって前置きは長いです。
変えようとしたきっかけ:怪しいログ
かなり怪しいログを見つけたというのがきっかけ。
不審に思ったログ
198.51.100.120 - - [09/Jun/2026:08:10:12 +0900] "GET /projects/zettel/knowledgebase/categories?tag=Linux%2CAnsible%2Cnginx HTTP/1.1" 200 41768 "https://example.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
203.0.113.185 - - [09/Jun/2026:08:10:15 +0900] "GET /projects/zettel/knowledgebase/categories?tag=cron%E8%A8%AD%E5%AE%9A%2CUbuntu HTTP/1.1" 200 41212 "https://example.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
なぜこれが怪しいと思ったのかを述べる前に、普通のログを示します。
通常のアクセスログ
203.0.113.50 - - [09/Jun/2026:08:05:43 +0900] "GET /issues/96 HTTP/1.1" 200 50538 "https://example.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Mobile Safari/537.36"
203.0.113.50 - - [09/Jun/2026:08:05:44 +0900] "GET /plugin_assets/theme/style.css?1754 HTTP/1.1" 200 22610 "https://example.com/issues/96" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Mobile Safari/537.36"
203.0.113.50 - - [09/Jun/2026:08:05:44 +0900] "GET /images/logo.png HTTP/1.1" 200 18871 "https://example.com/issues/96" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Mobile Safari/537.36"
- 普通のアクセスログ:
- HTML(1行目)を読み込んだ直後の1秒以内に、ページに必要なCSSやロゴ画像(2〜3行目)を自動で一斉にロードしています。
- 美しいリファラ・チェーン:
- 2行目以降の画像などのリファラ(リンク元)に、直前に開いたページログにあります。
それに対して、怪しいログは以下の通りです。
- 数秒ごとに「IPアドレスが変わる」: 1行目は 198.51.100.120、その3秒後の2行目は 203.0.113.185 です。
- プロキシのプールから「一般人のIP」を次々に切り替えながらリクエストを送っているため、多くのWAFが取り入れているIP制限をすり抜けてきます。
- アセットの完全無視:
- HTML(カテゴリページ)だけにアクセスし、付随する画像やCSS、JavaScriptなどは1文字もダウンロードしません(プログラムにとって不要だからです)。
- リファラ(リンク元)の不自然さ:
- どちらのリファラもトップページになっています。何もないトップ画面から、いきなり長大な検索クエリ(?tag=…)へ直接ジャンプする人間はいません。ヘッダーを「それっぽく偽装」した結果、逆にガタ(不自然さ)が出ています。
そして、問題は、この怪しいアクセスログはAbusedIPDB(筆者解説記事) でも普通の一般のISPしか出てきません。
この理由を調べたところ、Residential Proxyの存在が浮かび上がりました。
Residential Proxy(住宅用プロキシ)とは?
一言で言うと、「一般家庭のインターネット回線(光回線やスマホのキャリア回線など)のIPアドレスを借りて、そこを経由してWebにアクセスする仕組み」です。
通常、ハッカーやスクレイピング(自動データ収集)ボットは、データセンター(AWSやGCP、あるいは筆者が用いているようなVPSなど)のIPアドレスから攻撃を仕掛けます。しかし、データセンターのIPは「ボットっぽい」として一発でブロックされやすいという弱点があります。(事実、筆者もこれを利用してブロックしています)
そこで、「一般家庭のPCやスマホ、ルーターなどを踏み台にすれば、普通の人が家からアクセスしているように偽装できるのでは?」という発想で生まれたのがResidential Proxyです。
なぜ一般人の回線が使われてしまうのか?
一般家庭の回線をが利用されるのか。主に以下の2つのパターンがあります。
合法的な報酬・同意(ユーザーが知ってて提供)
「このアプリを入れると、あなたの余った帯域(通信量)をお金やギフト券に換えます」というお小遣い稼ぎアプリ(Pawn.streamやHoneygainなど)を一般人が自らインストールしているケース。
マルウェアや不適切なアプリ(ユーザーが知らずに加担)
無料のVPNアプリや、海賊版ソフト、スマート家電の脆弱性を突くマルウェアなどに「プロキシの中継プログラム」が仕込まれており、本人が気づかないうちに「攻撃の踏み台(中継サーバー)」に仕立て上げられているケース。
私は過日、ASNとは何か?インターネットの“住所録”を支える番号と「盗人宿」の把握
という記事で、
なぜなら、多くの攻撃者は海外の規制が緩いプロバイダ/組織を隠れ蓑にしています。
という見解を述べました。Residential Proxyはこれの超・拡大解釈版です。
どうやって対策していくか? SSHのアクセスポートの変更
規制が緩いVPSはその大本のアクセス元を断ってしまえば対策は可能。しかし、一般人向けのISPとなると話は違います。
- IPアドレスが極めて多く
- そのISPからのアクセスを断ってしまうと他の善良なアクセス者が利用できない
という、利用者を人質に取った隠れ蓑です。(尤も、筆者は不正アクセスがあった瞬間、そのIPは二度目のアクセスをさせないのですが)
なので、手っ取り早く「SSHのアクセスポート(22番)」の変更から始めることになりました。
いくらFail2banにより不審なアクセスを弾き、鍵交換形式でセキュリティは担保されると言ったところで:
「攻撃者のアクセス元が数千倍に膨れ上がってきた」のでは話は別です。
Linuxのデフォルトである「22番ポート」を開放し続けることは、要塞の本丸の門の前に、毎日数百万人のゾンビ(ボット)が群がってドアノブをガチャガチャ回し続けているのと同じ状態です。
これがサーバーに与える実害は、単に「ハッキングのリスク」だけではありません。物理的なリソース(パフォーマンス)を極悪なまでに食いつぶします。
- 暗号計算によるCPUの無駄遣い
- SSHの接続要求が来ると、OSは律儀に重たい暗号処理や鍵の検証、認証チェックを走らせます。ボットが何重にも同時アタックしてくるだけで、CPU・メモリ・ディスクI/Oを継続的に消費します。
- メモリの圧迫 SSHは接続が来るたびに、個別の
sshd子プロセスをメモリ上に生成します。- ボットの同時訪問により、メモリ空間がジワジワと侵食されていきます。
- ストレージ(I/O)のボトルネック化 ボットが認証に失敗するたび、システムは「認証失敗(Failed password…)」のログをディスクに猛烈な勢いで書き込み続けます。
- この連続的な書き込み処理(ディスクI/O)のせいで、本来のWebサーバーのためのディスクの読み書き速度が奪われます。
- セキュリティを高める
- パフォーマンスを上げる
の一挙両得を狙っていきます。
作業の前の注意点:
- これはSSHのポートを変更する作業です。
- そして、SSHのサービスを再起動します。
つまり、心臓に悪い作業です。下手したら自分自身がアクセスできなくなる事態も十分発生します。
- 実サーバの場合は実機で作業する
- VPSの場合はシリアルコンソールで接続する
が必須です。この環境が用意できない方はここから先は作業をしないでください。
※筆者が上手くいったという手順です。参考にする方は必ず裏取りを取ってください※
環境
- XServer VPSを利用
- Ubuntu 24.04
- UFW導入済み
- Fail2ban導入済み
サクッとはしているけど心臓に悪い手順
- UFWが開放するポートを別に変えます。(ここでは22→36878)
- XServer側のパケットフィルターを変更します。
- Fail2banの設定を変更します。
- SSHの待ち受けを変更します。
- systemd SSHソケットアクティベーションの書き換えを行います。
- 設定を反映して別ポートに変更します。
- サーバそのものを再起動して再確認を行います。
Step 0. 推奨:ディスクイメージのバックアップ
何かあったときのために、ディスクそのもののバックアップ(スナップショット)を取っておくことを強く推奨します。
Step 1. OS内ファイアウォール(UFW)の解放
※ここからは実機/シリアルコンソールで作業を行います※
※平行して自分の端末とSSHセッションを張っておきます※
まずはOSの内部で、新ポート(36878)を通すようにルールを追加しました。
他のポートとバッティングしないものを選んでください。
- 36878番ポート(TCP)へのアクセスを許可
sudo ufw allow 36878/tcp comment 'SSH新ポート'
- 古い22番ポートの許可ルールを削除
sudo ufw delete allow 22/tcp
- 設定を反映
sudo ufw reload
- 設定反映確認
sudo ufw verbose
22/tcpが消えていることと、以下のようなメッセージがあることを確認します。
36878/tcp ALLOW Anywhere SSH新ポート
自端末から新しいSSHセッションを立ち上げ、端末とSSH通信ができないことを確認します。
この段階では既存SSHセッションを絶対に閉じないでください
Step 2. インフラ(XServer)側パケットフィルターの変更
OSにボットのパケットが届く前に、XServerのインフラレベルで遮断するための設定です。
- XServer VPSパネル > パケットフィルター設定 を開く。
[ +パケットフィルター設定を追加する ]をクリック。- 以下の内容で追加:
- フィルター: 手動で設定
- プロトコル: TCP
- ポート番号: 単一ポート /
36878 - 許可する送信元IPアドレス: 全て許可
- メモ:
SSHのポート変更等を付与。
[ 追加する ]を押して確定。- 既存のルール一覧から、古い
SSH TCP 22の横にある[ 削除 ]ボタンを押し、不要なポートを完全に塞ぐ。
Step 3. Fail2ban(検知ツール)の設定変更
ポートが変わっても、Fail2banが正しく不正アクセスを監視・検知できるように設定を追従させました。
- バックアップ取得
sudo cp /etc/fail2ban/jail.local /path/to/backup/directory/jail.local.$(date +%Y%m%d)
→ 自分の環境に合わせます。
- バックアップ取得確認
diff -u /path/to/backup/directory/jail.local.$(date +%Y%m%d) /etc/fail2ban/jail.local
→ エラーがないことを確認します。
/etc/fail2ban/jail.localを編集し、[sshd]セクションのポートを書き換え:
[sshd]
enabled=true
filter=sshd
mode=normal
#port=22
#Port変更
port=36878
protocol=tcp
- 編集後確認
diff -u /path/to/backup/directory/jail.local.$(date +%Y%m%d) /etc/fail2ban/jail.local
- port=22
+ #port=22
+ #Port変更
+ port=36878
Step4. SSHコンフィグの変更
- バックアップ
sudo cp -pi /etc/ssh/sshd_config /path/to/backup/sshd_config.$(date +%Y%m%d)
- バックアップ取得確認
diff -u /path/to/backup/sshd_config.$(date +%Y%m%d) /etc/ssh/sshd_config
→ エラーがないことを確認します。
- ファイル編集(筆者例)
#Port 22
Port 36878
編集後に保存。
- 差分確認
diff -u /path/to/backup/sshd_config.$(date +%Y%m%d) /etc/ssh/sshd_config
- Port 22
+ #Port 22
+ Port 36878
Step 5. systemd SSHソケットアクティベーションの書き換え
筆者が一番詰まったところです。
これをやらなかったためにSSH接続できませんでした。
Ubuntuには1/init が22番ポートを掴んでしまう仕様があります。
それを回避し、IPv4/IPv6の両方で新しく設定したポート(36878番)を待ち受けさせるための確実な設定です。
- 設定上書き用のディレクトリを作成:
sudo mkdir -p /etc/systemd/system/ssh.socket.d
- 設定ファイル
/etc/systemd/system/ssh.socket.d/listen.confを新規作成し、以下の 4行 を記述:
[Socket]
ListenStream=
ListenStream=36878
ListenStream=0.0.0.0:36878
※ ポート番号は自分が設定したものです。
※
ListenStream=(右側空欄)で、デフォルトの22番の待ち受けを一度綺麗にクリアするのがポイントです。
Step 6. 設定の反映と確認
- systemdの設定をリロード
sudo systemctl daemon-reload
- ssh再起動
sudo systemctl stop ssh.service
- 新しい設定でソケットとFail2banを再起動
sudo systemctl restart ssh.socket
sudo systemctl restart fail2ban
- UFW(ファイアウォール)を有効化
sudo ufw enable
sudo netstat -lntp | grep 36878
以下のように、36878 番ポートが 1/init によって正常に LISTEN されていれば成功です。
tcp6 0 0 :::36878 :::* LISTEN 1/init
- 自環境内でのSSH接続確認
ssh -p 36878 localhost
自分の端末からSSH接続できることを確認します。
- サーバ再起動
sudo reboot
この段階でサーバそのものを再起動します。なぜなら、ここで「SSH接続できるはず」としても、不慮の再起動で設定が違うなどがあり得るからです。
Step 7. 設定反映確認
※ここからはSSH接続クライアントからの接続確認です。※
SSH接続クライアントの接続ポートを22から設定したポート(上記例では36878)に変更して接続します。
接続できれば設定完了です。
まとめ
この作業はサーバ初期設定からやっておくべきものでしたが、ようやく心臓に悪い作業から解放です。
ポート変更後、筆者環境ではWebサーバのレスポンス改善を確認したました。
これは「22番だから侵入される」という話ではありません。
日々押し寄せる大量の自動化ボットによるSSH接続試行そのものをOSへ到達させないことで、限られたサーバ資源を本来のサービス提供へ集中させられたためと考えています。
なお:半ば筆者のVPSは公開情報ではありますが、上記設定とは異なるポート番号で設定されていることは補足しておきます。











