3-1. VPS セットアップ - 初期 hardening まで30分

所要時間: 40-60分 ゴール: 新規 VPS を一台借りて、本番運用に耐える初期 hardening を一通り終える コミット内容: ~/learn/infra/vps01/ に hardening 手順を書いた setup.shREADME.md を残す


このレッスンのゴール

  • VPS とクラウド (IaaS) の違いを語れる
  • SSH 鍵認証・パスワード認証無効・root SSH 無効までを設定できる
  • ufw + fail2ban の3点セットで最低限の hardening ができる
  • swap 設定の意義と書き方を理解した
  • auth.log から攻撃元 IP を判定できる

なぜ学ぶか(実務悩みベース)

  • 月 500 円の VPS で本番が立てられると個人開発の幅が広がる
  • マネージドが壊れた時に「裏で何が起きているか」が見える人になる
  • 面接「Linux に SSH して何ができますか?」に即答できる
  • 「サーバー乗っ取り」の事故を最初から防ぐ

前章とのつながり

2-6 までで「動くアプリ Compose」が完成した。Level 3 はそれを インターネットに出す 旅。最初の関門が VPS の初期 hardening。攻撃 bot が秒単位で来る世界で、Compose を起動する前にやることがある。


大前提: なぜ VPS を「自分で」立てるのか

クラウドのマネージドサービス(Heroku, Vercel, Render など)だけ使っていれば「サーバーを直接触る」機会はゼロに近い。ではなぜ VPS を扱えるべきか。

  1. コスト: マネージドが月 5,000 円のところ、VPS なら月 500 円〜で同じ要件を満たせる
  2. 自由度: cron、systemd、独自ポート、独自ミドルウェア、何でも入る
  3. デバッグ力: マネージドが壊れた時に「裏で何が起きているか」が見える人と見えない人で復旧速度が10倍違う
  4. 面接で問われる: 「Linux に SSH して何ができますか?」は技術面接の頻出質問

そして、VPS を立てた瞬間から インターネット上のすべての攻撃者のターゲット になる。SSH ポート 22 を開けて1時間放置すると、bot による総当たりログイン試行が数百回〜数千回記録されるのが普通。初期 hardening をやらないサーバーは数日で乗っ取られる。これは脅しではなく観測事実。

このレッスンでは、新規 VPS を借りてから「本番ワークロードを乗せていい状態」までを 30 分で持っていく標準手順を身につける。


セッション①: VPS を選んで借りる(15-20分)

1. VPS プロバイダの選び方

国内・海外の主要 VPS プロバイダの比較(2026年時点の感覚値)。

プロバイダ最安プラン拠点特徴
さくらの VPS月 600 円〜(1GB)東京/大阪/石狩国内、請求が円、初心者向け
さくらクラウド従量課金東京/石狩API 完備、Terraform 対応、本気の本番向け
Vultr月 $3.5 〜東京/大阪含む32拠点API 充実、安い、米ドル決済
Linode (Akamai)月 $5 〜東京含む老舗、ドキュメントが優秀
DigitalOcean月 $4 〜シンガポール(東京なし)チュートリアルが世界一充実
Hetzner月 €3.79 〜独/フィンランド/米コスパ最強、ただし日本から遠い

VPS とクラウド (IaaS) の違い

どちらも「インターネット越しに使える Linux マシン」だが、思想が違う。

  • VPS (Virtual Private Server): 「物理マシン1台分の権利を、月額固定で売る」モデル。シンプル、定額、最初から決まったスペック
  • クラウド (IaaS): 「使った分だけ秒単位課金」モデル。サイズ変更・スナップショット・複数台連携・マネージド DB 等のコンポーネント連携が前提

学習・個人開発・常時起動の小規模サービス = VPS が圧倒的に安い。スパイク対応や本番大規模サービス = クラウド一択。両方触れる人材 = 最強。

料金と性能のトレードオフ

月 500 円クラス(CPU 1 core / RAM 1GB / SSD 20-30GB)でできること:

  • 個人ブログ(WordPress / 静的サイト)
  • Discord / Slack の bot
  • 小規模な Go/Node API + SQLite or PostgreSQL
  • 自前 Mastodon / Misskey インスタンス(人数次第)

足りなくなるライン: メモリ食う JVM 系、Elasticsearch、本格的な MySQL レプリカ、コンテナを多数同時起動するケース。RAM が枯渇すると swap で延命できるが I/O が激重になる。最初は RAM 2GB 以上を選ぶと事故が減る。

「無料 VPS」「永久無料」の罠

Oracle Cloud の Always Free や AWS Free Tier の無料枠は確かに存在するが、請求設定を間違えると無料枠を超えた瞬間に従量課金で月数万円の事故が起きる。学習用途なら 絶対上限の見える定額 VPS が安全。

2. OS 選び

ほぼ全プロバイダで以下から選べる。本書では Ubuntu 24.04 LTS を前提に進める。

OSおすすめ度理由
Ubuntu LTS (24.04)鉄板情報量最多、deb 系、サポート5年
Debian玄人向け安定性最高、Ubuntu より保守的
Rocky Linux / AlmaLinuxRHEL系旧 CentOS の後継。yum/dnf 文化
Alpine上級者向け軽量だが musl libc で罠多い、コンテナ用途で使う

なぜ Ubuntu LTS を選ぶか

LTS = Long Term Support。通常 2 年ごとの偶数年に LTS がリリースされ、5 年のセキュリティパッチ提供がある(拡張で10年)。

個人サーバーでも LTS 一択。通常版(interim release)は 9 か月でサポート終了するので、サポート切れ後の脆弱性放置 = 自動的に乗っ取りリスク。


セッション②: 初回 SSH と一般ユーザー作成(15-20分)

3. 初回 SSH ログイン

VPS 契約後、コントロールパネルに「IP アドレス」「root パスワード」または「初回 SSH 鍵」が表示される。

# root でログイン(推奨されないが最初だけ)
ssh root@203.0.113.42
 
# プロバイダによっては最初から SSH 鍵方式
ssh -i ~/.ssh/vps_initial root@203.0.113.42

SSH 鍵認証の本質

SSH 鍵 = 公開鍵暗号によるパスワードレス認証。

  • 公開鍵 (~/.ssh/id_ed25519.pub): サーバーに置く。漏れてもOK
  • 秘密鍵 (~/.ssh/id_ed25519): 手元に置く。絶対に漏らさない。GitHub にコミットしたら即終了

ログイン時、サーバーが乱数を秘密鍵で署名させ、公開鍵で検証する。秘密鍵を持っている人だけログインできる。

生成コマンド(まだ作っていなければ):

ssh-keygen -t ed25519 -C "your_email@example.com"

RSA より ed25519 が新しく短くて強い。2026 年に新規生成するなら ed25519 一択

root で SSH ログインしてはいけない

root = 何でもできるユーザー。これが万一乗っ取られると 「サーバー初期化以外に復旧手段なし」 になる。

攻撃者は世界中の VPS の IP レンジを舐めて root ユーザーへの総当たりを仕掛けている。/var/log/auth.log を見れば、契約直後から Failed password for root from 185.x.x.x が秒間数十件並ぶ。

対策の順序:

  1. 一般ユーザーを作る
  2. 一般ユーザーに sudo 権限を与える
  3. 一般ユーザーで SSH ログインできるか確認
  4. root の SSH ログインを禁止する
  5. パスワード認証も禁止する(鍵認証のみに)

4. パッケージを最新化

# パッケージリスト更新(インストール可能なリストを取りに行く)
apt update
 
# 実際にアップグレード
apt upgrade -y
 
# 不要パッケージ削除
apt autoremove -y

apt updateapt upgrade の違い

初心者が混同しがちな最頻出ポイント。

  • apt update: パッケージリスト(カタログ)を最新に取得するだけ。実際のソフトウェアは何も変わらない
  • apt upgrade: カタログに従って実際のソフトウェアを更新する

つまり 必ず apt update && apt upgrade の順番でセット実行する。update だけだと何も上がらない、upgrade だけだとカタログが古いままで最新が降ってこない。

aptapt-get の違い

歴史的経緯で 2 つある。

  • apt-get: 古参。スクリプト向け、出力が安定
  • apt: 2014 年に登場。人間向け、プログレスバーが出る、推奨

対話的に使うなら apt、スクリプト内なら apt-get が無難。本番デプロイスクリプトに apt を書くと将来出力フォーマット変更で壊れる可能性があるため。

5. 一般ユーザー作成と sudo 化

# ユーザー作成(パスワードや氏名を聞かれる。氏名等は空Enter可)
adduser deploy
 
# sudo グループに追加
usermod -aG sudo deploy
 
# 確認
groups deploy
# deploy : deploy sudo

sudo グループとは

Ubuntu/Debian では sudo グループに属するユーザーが sudo コマンドを使える。RHEL 系では wheel グループ。

sudo の本質: 「一時的に root として実行する」。実行ログが /var/log/auth.log に残るため、root 直接ログインより監査性が高い。複数人運用なら 誰がいつ何を sudo したか追跡できる

root ログインで初期 hardening を進める標準手順

# 1. パッケージ最新化
apt update && apt upgrade -y
 
# 2. 一般ユーザー作成
adduser deploy
usermod -aG sudo deploy
 
# 3. 公開鍵を一般ユーザーにコピー
mkdir -p /home/deploy/.ssh
cp /root/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
 
# 4. 別ターミナルで deploy ユーザーでログインできることを確認
#    (これを確認せずに root を閉じると詰む)

.ssh ディレクトリの権限

SSH は ~/.ssh および authorized_keys の権限が緩いと鍵認証を拒否する。仕様。

必須権限:

  • ~/.ssh700(自分のみ rwx)
  • ~/.ssh/authorized_keys600(自分のみ rw)

これが守られていないと「鍵を置いたのにログインできない、なぜ?」となる初心者の最頻出トラップ。

6. SSH の hardening

/etc/ssh/sshd_config を編集する(または /etc/ssh/sshd_config.d/99-hardening.conf に追記)。

# 編集
sudo vim /etc/ssh/sshd_config.d/99-hardening.conf
# /etc/ssh/sshd_config.d/99-hardening.conf
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
# ポート変更を行う場合(後述)
# Port 22022
# 設定構文チェック
sudo sshd -t
 
# 再起動
sudo systemctl restart ssh

設定項目の意味

  • PermitRootLogin no: root 直接ログイン禁止。最重要
  • PasswordAuthentication no: パスワード認証禁止。総当たり攻撃が物理的に成功しなくなる
  • PubkeyAuthentication yes: 公開鍵認証のみ許可
  • MaxAuthTries 3: 1接続あたりの認証試行回数上限
  • ClientAliveInterval 300: 5分間アイドル接続を確認、応答なければ切断(ゾンビセッション防止)

sshd_config の編集事故

設定ミスで sshd が再起動失敗 → SSH 接続が切れる → 二度と入れない という事故が定番。

必須の手順:

  1. 既存の SSH 接続は維持したまま、新しいターミナルで設定変更を試す
  2. sudo sshd -t で構文チェック(エラーなければ無出力)
  3. sudo systemctl restart ssh
  4. 既存接続を切らずに、別ターミナルから新規ログインできるか確認
  5. 新規ログインが成功して初めて、元のセッションを閉じる

プロバイダの「コンソールアクセス」(Web 画面から物理キーボード相当の操作)も最後の保険。場所を確認しておく。

SSH ポート番号を変えるべきか

「Port 22 から 22022 などに変更すると攻撃が激減する」という説。

事実: 確かに bot の総当たりは激減する(多くの bot が 22 番にしか来ない) 反論: 真剣な攻撃者には無意味(nmap でポートスキャンすればすぐ見つかる)。security by obscurity に過ぎない 実害: ログがノイズで埋まらないので調査しやすくなる、というメリットは実在

結論: 鍵認証 + パスワード認証無効 + fail2ban があれば 22 番のままでも実害はない。ただし「ログのノイズが気持ち悪い」「組織方針」などの理由で変える選択は正当。変えるならファイアウォール設定と同時に(新ポートを開け、旧ポートを閉じる順)。


セッション③: ネットワーク・swap・監視(15-20分)

7. swap の設定

# 現状確認
free -h
swapon --show
 
# 2GB の swap ファイルを作成
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
 
# 永続化(再起動時も有効)
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
 
# swappiness 調整(RAM 優先度)
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl --system

swap とは何か、なぜ小さい VPS で重要か

swap = ディスクを「擬似的な RAM」として使う仕組み。RAM が足りなくなった時に、使用頻度の低いメモリ内容を一時的にディスクに退避する。

小さい VPS(RAM 1GB / 2GB)では事実上必須。理由:

  • OOM Killer(メモリ不足時に Linux がプロセスを問答無用で kill する機能)の発動を避けられる
  • ピーク時に瞬間的にメモリ超過しても落ちない
  • 普段使わない常駐プロセス(systemd 系の小さいデーモン)を swap に逃がして RAM を空ける

デフォルトで swap が無い VPS が多い。クラウド系(AWS の EC2 など)は特に。意識的に作る必要がある。

swappiness のデフォルト値

vm.swappiness は「どれくらい積極的に swap を使うか」(0-100)。

  • デフォルト 60: デスクトップ Linux 向け。サーバーには積極的すぎる
  • 推奨 10: サーバー用途。「本当に RAM が足りない時だけ swap」
  • 0 にしない: swap を完全無効化と同義になり、OOM Killer が暴れる

swap を使い始めると I/O 性能が激落ちする(ディスクは RAM の数百倍遅い)ため、「swap がガリガリ使われている = RAM 不足」のシグナルとして監視すべき。

8. ufw(Uncomplicated Firewall)の初期設定

# インストール(Ubuntu には標準で入っているはず)
sudo apt install -y ufw
 
# デフォルトポリシー: すべて拒否、外向きは許可
sudo ufw default deny incoming
sudo ufw default allow outgoing
 
# SSH を許可(これを忘れると自分も入れなくなる)
sudo ufw allow 22/tcp
 
# HTTP/HTTPS(Web サーバーを置くなら)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
 
# 有効化(SSH の確認が出る)
sudo ufw enable
 
# 状態確認
sudo ufw status verbose

ufw は iptables のラッパー

Linux のパケットフィルタは元々 iptables(最近は nftables)。だが構文が難解で初心者が事故りやすい。

ufw = Uncomplicated Firewall。「ポート番号で許可/拒否を書くだけ」のシンプルなフロントエンド。内部で nftables / iptables ルールに変換される。

Debian/Ubuntu の事実上の標準。RHEL 系には firewalld がある(こちらも nftables のラッパー)。

SSH を許可する前に ufw を有効化する事故

順番を間違えて以下のようにやると即終了。

sudo ufw default deny incoming
sudo ufw enable             # SSH を allow する前に!
# → 既存の SSH も切られる、新規接続も拒否される、コンソールアクセスがないと復旧不可

必ず順番: SSH を allow → enable。ufw enable 実行時には「既存の SSH 接続が切れるかも、いいか?」と確認が出る。確認に Yes と答える前に別ターミナルで SSH を許可していることを確認

9. fail2ban インストール

sudo apt install -y fail2ban
 
# デフォルト設定をコピーして編集
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

/etc/fail2ban/jail.local を編集。

[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
 
[sshd]
enabled = true
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

fail2ban の仕組み

/var/log/auth.log を監視し、失敗ログインを findtime(10分)の間に maxretry(5回)記録した IP を bantime(1時間)だけ ufw / iptables でブロックする。

パスワード認証を切っていても、bot の試行で auth.log が膨らみ続けるのは事実。fail2ban が ban すると IP 単位で接続自体が拒否されるため、ログのノイズも減る。

自分も ban される事故

開発中にパスワードを連打 → 自分の IP が ban される。

対処法: コンソールアクセス(プロバイダの Web 画面)から sudo fail2ban-client unban <自分のIP> で解除。または時間を待つ。

予防: 自宅・オフィスの IP を ignoreip にホワイトリスト登録。

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.10

ただし動的 IP の自宅では使いにくい。

10. タイムゾーンとロケール

# タイムゾーン確認
timedatectl
 
# 日本時間に設定
sudo timedatectl set-timezone Asia/Tokyo
 
# NTP 同期確認(systemd-timesyncd が標準)
timedatectl status
# System clock synchronized: yes であればOK
 
# ロケール
locale
sudo locale-gen ja_JP.UTF-8
sudo update-locale LANG=ja_JP.UTF-8

タイムゾーンを揃える理由

サーバーのタイムゾーンがズレていると ログのタイムスタンプが混乱する

  • アプリログ: 2026-05-14 03:00:00 ← これは JST? UTC?
  • クラウド側ログ: UTC
  • 顧客の問い合わせ: JST

チーム方針:

  • A 案: 全部 UTC(クラウド標準、サーバーは全部 UTC、ログ確認時に JST 変換)
  • B 案: 全部 JST(日本国内サービスの実利、ログがそのまま読める)

どちらでも良いが 混在は最悪。社内で統一する。本書では VPS は JST 設定で進める(ログを直接読む機会が多い学習用途のため)。

NTP 同期が外れている事故

サーバー時刻が数分ズレているだけで:

  • JWT トークンが「有効期限切れ」または「まだ有効になっていない」エラー
  • HTTPS 証明書の有効期限判定がズレる
  • cron が想定時刻と違う時間に走る
  • DB のレコード作成日時がバラつく(レプリカと比較して整合性破綻)

timedatectl statusSystem clock synchronized: yes を必ず確認。

11. 自動セキュリティ更新

sudo apt install -y unattended-upgrades
 
# 設定
sudo dpkg-reconfigure --priority=low unattended-upgrades

unattended-upgrades の役割

セキュリティ更新を 自動で適用する仕組み。デフォルトでは security リポジトリの更新だけが対象(通常パッケージは対象外)。

メリット: 脆弱性が公表されてからパッチ適用までの時間(攻撃者にとっての黄金時間)を最小化 デメリット: 自動更新でアプリが壊れる可能性ゼロではない(稀)。再起動が必要な更新は別途対処

needrestart のプロンプトで本番落ちる事故

Ubuntu 22.04 以降、apt upgrade 時に needrestart がサービス再起動のプロンプトを出す。スクリプト内で apt upgrade -y を実行すると、対話プロンプトで止まるか、サービスが勝手に再起動して短時間ダウンする。

対処: /etc/needrestart/needrestart.conf$nrconf{restart} = 'a';(automatic)または 'l';(list only)に設定。本番では 'l' で「リスト表示のみ、手動再起動」が安全。


アンチパターン総まとめ

よくある初期設定の失敗

# NG: root のままアプリをデプロイする
root@vps:~# git clone https://github.com/my/app.git
root@vps:~# ./app/run.sh

なぜNG: アプリの脆弱性(例: ファイル読み込みの SSRF)が即座にサーバー全体侵害につながる。アプリは必ず非 root ユーザーで動かす

パスワード認証放置

# /etc/ssh/sshd_config(デフォルトのまま)
PasswordAuthentication yes

24時間で平均 1,000-10,000 回の総当たり試行を受ける。123456 admin などの弱いパスワードを使っていたら 1 日で抜かれる。

ファイアウォール無効のまま全ポート公開

# ufw を入れていない、または disable
# → MySQL の 3306 が外から見える、Redis の 6379 が外から見える
# → 認証なしの Redis に書き込まれて暗号通貨マイニングプロセスが仕込まれる

Redis の認証なしホストを狙う攻撃は実在し、観測されている。外部に公開する必要のないサービスは全部ファイアウォールで遮断

自動更新オフでパッチ放置

# apt upgrade を半年やっていない
# → OpenSSL の CVE が公開されているのに古いまま
# → 公知の脆弱性で侵入される

「動いているから触らない」は最悪のセキュリティ戦略。最低限 security update は自動適用しておく。


実例: 新規 VPS を 30 分で hardening するスクリプト

実運用では手順をスクリプト化しておくと、新しい VPS を借りるたびに迷わず適用できる。

#!/usr/bin/env bash
# ~/learn/infra/vps01/setup.sh
# 新規 Ubuntu 24.04 VPS の初期 hardening スクリプト
# 使い方:
#   1. root で SSH ログイン
#   2. このスクリプトをアップロード or 貼り付け
#   3. bash setup.sh deploy 'AAAAC3NzaC1lZD...your_public_key...'
 
set -euo pipefail
 
DEPLOY_USER="${1:?usage: setup.sh <username> <public_key>}"
PUBLIC_KEY="${2:?usage: setup.sh <username> <public_key>}"
 
echo "==> 1. パッケージ更新"
apt update
apt upgrade -y
apt install -y ufw fail2ban unattended-upgrades
 
echo "==> 2. 一般ユーザー作成"
if ! id "$DEPLOY_USER" &>/dev/null; then
    adduser --disabled-password --gecos "" "$DEPLOY_USER"
    usermod -aG sudo "$DEPLOY_USER"
fi
 
echo "==> 3. SSH 鍵設置"
install -d -m 700 -o "$DEPLOY_USER" -g "$DEPLOY_USER" "/home/$DEPLOY_USER/.ssh"
echo "$PUBLIC_KEY" > "/home/$DEPLOY_USER/.ssh/authorized_keys"
chmod 600 "/home/$DEPLOY_USER/.ssh/authorized_keys"
chown "$DEPLOY_USER:$DEPLOY_USER" "/home/$DEPLOY_USER/.ssh/authorized_keys"
 
echo "==> 4. sudo パスワードなし(任意。秘密鍵の管理が厳格なら)"
echo "$DEPLOY_USER ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/90-$DEPLOY_USER"
chmod 440 "/etc/sudoers.d/90-$DEPLOY_USER"
 
echo "==> 5. SSH hardening"
cat > /etc/ssh/sshd_config.d/99-hardening.conf <<'EOF'
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
EOF
sshd -t
systemctl restart ssh
 
echo "==> 6. swap 2GB"
if [ ! -f /swapfile ]; then
    fallocate -l 2G /swapfile
    chmod 600 /swapfile
    mkswap /swapfile
    swapon /swapfile
    echo '/swapfile none swap sw 0 0' >> /etc/fstab
fi
echo 'vm.swappiness=10' > /etc/sysctl.d/99-swappiness.conf
sysctl --system
 
echo "==> 7. ufw"
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
echo "y" | ufw enable
 
echo "==> 8. fail2ban"
cp -n /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
systemctl enable --now fail2ban
 
echo "==> 9. タイムゾーン / NTP"
timedatectl set-timezone Asia/Tokyo
 
echo "==> 10. unattended-upgrades 有効化"
dpkg-reconfigure -f noninteractive unattended-upgrades
 
echo ""
echo "完了。別ターミナルで以下を実行してログインできるか確認せよ:"
echo "  ssh $DEPLOY_USER@$(curl -s ifconfig.me)"
echo ""
echo "ログイン成功を確認してから root を抜けること。"

スクリプト化のメリット

  • 手作業の漏れがなくなる
  • チームで共有できる(GitHub に置く、ただし公開鍵以外の秘密情報は含めない)
  • Ansible / Terraform の cloud-init / user-data に組み込める

Ansible で書き直すと宣言的になり、複数台を同時 hardening できる。が、初学者の段階では bash スクリプトで「何が起きているか」を理解する方が学習効率が高い。


練習課題

実際に VPS を 1 台借りて以下をすべてやる(月数百円なら学習投資として安い)。

  1. VPS を 1 つ契約し、Ubuntu 24.04 をインストール
  2. 初回 root ログインを行い、apt update && apt upgrade を実行
  3. 一般ユーザー deploy を作成、sudo グループに追加
  4. 自分の手元の公開鍵 (~/.ssh/id_ed25519.pub) を deployauthorized_keys に登録
  5. 別ターミナルで ssh deploy@<IP> で鍵認証ログインできることを確認
  6. sshd_config.d/99-hardening.conf を設置して、root 直接ログインとパスワード認証を禁止
  7. swap 2GB を作成し永続化、free -h で確認
  8. ufw で SSH/HTTP/HTTPS のみ許可
  9. fail2ban をインストール、fail2ban-client status sshd で動作確認
  10. tail -f /var/log/auth.log を 5 分眺めて、bot の侵入試行ログを観察(結構来る)

締め: git で証跡を残す

cd ~/learn/infra/vps01
git init
git add setup.sh README.md
git commit -m "feat(infra): VPS 初期 hardening スクリプト整備"

README.md には:

  • 借りたプロバイダ名と理由
  • IP アドレス(プライベートリポなら)
  • 適用した設定の要約
  • ハマったポイント

を書いておくと、3か月後の自分が救われる。


チェックリスト

  • VPS を 1 台借りた
  • 一般ユーザーで SSH 鍵認証ログインできる
  • root の SSH ログインを禁止した
  • パスワード認証を禁止した
  • ufw で必要なポートのみ許可している
  • fail2ban が動いている
  • swap が設定されている
  • タイムゾーンと NTP 同期が正常
  • auth.log で実際の bot 侵入試行を目視した
  • hardening 手順をスクリプト化して git に残した

詰まった時のチートシート

やりたいことコマンド
自分の IP 確認(VPS から)curl ifconfig.me
一般ユーザー作成adduser <name>
sudo 権限付与usermod -aG sudo <name>
SSH 設定構文チェックsshd -t
SSH 再起動systemctl restart ssh
ufw 状態確認ufw status verbose
ufw でポート許可ufw allow 80/tcp
fail2ban 状態fail2ban-client status sshd
ban された IP 解除fail2ban-client unban <IP>
swap 確認free -h && swapon --show
時刻同期確認timedatectl status
認証ログ追跡tail -f /var/log/auth.log

対比表: VPS vs IaaS(クラウド)

観点VPS(さくら、Vultr 等)IaaS(AWS EC2、GCE)
料金モデル月額固定秒単位従量
サイズ変更限定的自由(ストップ→変更→起動)
API限定(プロバイダ次第)充実
マネージド連携なしDB / Queue / Cache 等と統合
適性学習、個人開発、常時起動小規模本番大規模、スパイク対応
学習価値「裏で何が動くか」が見える「マネージド組合せ」を学ぶ

「実務OK」基準

  • 新規 VPS を 30 分以内に hardening 完了できる: 手順を覚えるか、スクリプトを持っている
  • /var/log/auth.log を読んで攻撃を判断できる: どの IP がどんな試行をしているか
  • ufw / fail2ban / SSH 鍵認証の3点セットを暗唱できる: hardening の最低ライン
  • swap と OOM の関係を説明できる: なぜ小さい VPS に swap が必要か
  • 「動かない」時に sshd_config の構文チェックを思い出せる: 自分を閉め出した時の復旧手順

自己評価チェックリスト

知識レベル

  • VPS と IaaS の使い分け基準を語れる
  • SSH 鍵認証の仕組み(公開鍵を server に置く)を説明できる
  • ufw / fail2ban の役割分担を即答できる
  • swap が「OOM 最後の砦」になる理由を腹落ちした

実行レベル

  • 新規 VPS の hardening を手順通りに30分で完了した
  • setup.sh を書き、再現可能な形にした
  • auth.log から攻撃元 IP を1つ特定した

メタ認知

  • 「自分を閉め出した時」の復旧手順をリストアップした
  • 次に同じ作業をする時のために改善点を3つメモした

さらに深掘りするなら

  • 公式: Ubuntu Server Guide
  • 公式: OpenSSH manual (man sshd_config)
  • 書籍: 『入門 Linux のしくみ』(武内覚, 技術評論社)
  • DigitalOcean Tutorials: “Initial Server Setup with Ubuntu” 系の英語チュートリアル群が世界一参考になる
  • Ansible で hardening を宣言的に書き直す: geerlingguy.security ロール

次のレッスン

3-2_DNS.md で、立てた VPS にドメインを向ける DNS の世界へ。