こんにちは、てつです!
今回は、サーバーのファイアウォールの設定をしていこうと思います。
自宅のサーバーに監視ツールや管理ツールを入れたのはいいものの、通信に使っているポート以外もすべて開いている状態です。
※ポート:サーバーが外部とデータをやり取りするための「玄関口」や「窓」のようなものです。通常、Webサーバーなら80番や443番など、必要な窓だけを開けて他はすべて鍵を閉めて(閉じ通話を遮断して)おきます。
これでは、家のすべてのドアや窓に鍵をかけず、外から誰でも中を覗いたり侵入したりできる状態にしておくのと同じような状態です。
現状は、VPNサーバー経由でしかサーバーとの通信ができないようになっているのでまだ危険性は少ないです。しかし、これから外部にサーバーを公開していくときに恰好の攻撃対象になってしまうので今のうちに対策をしていこうと思います。
そのために使うのが、Ubuntuに標準で搭載されているツールの UFW (Uncomplicated Firewall) です。
今回の記事は、このツールの設定行うことメインとして取り扱っていきます。各用語についても少し解説を交えていくので、セキュリティに興味がある方は是非見ていってください。
関連記事は以下に掲載しておきます。

-scaled.png)
記事のポイント
- サーバーを「ただ動く」から「安全に守られた」状態にアップデートできます。
- Docker特有のセキュリティの穴(UFW無視問題)を確実に塞げます。
- 自分のサーバーがどう守られているか、ログやスキャンツールで「見える化」できます。
なぜファイアウォールが必要なのか(セキュリティの基本)
ファイアウォールが必要な理由は、一言で言うと「信頼できない外部のネットワーク(インターネット)から届く悪意ある通信を遮断し、安全な内部ネットワークを守るための『関所(検問所)』が必要だから」です。
先ほど「ポートを開けっ放しにすることは、家のドアや窓を開けっ放しにすることと同じ」といいました。
ファイアウォールは、その家全体の敷地の入り口に置く「24時間運用の有人警備ゲート(検問所)」の役割を果たします。
3つに分けて解説していきます。
1.通信の「送信元」と「中身」を厳しくチェックして追い返すため
サーバーのポートを閉じたり開けたりするだけでは、「ポートが空いている場所への通信」はすべて通してしまいます。
ファイアウォールがあると、ポートが開いてるかどうかに関わらず、手前で以下のようなチェック(検問)を行います。
- 「この通信は、許可されていない怪しいIPアドレス(送信元)から来ているからブロックしよう」
- 「Webサイトを見たい(80番ポートへの通信)と言っているが、中身のデータがおかしいから通さない」
これにより、許可された正しい相手からの正しい通信だけを中に通すことができます。
2.サーバーやパソコンの「身代わり(盾)」になって攻撃を防ぐため
インターネット上には、24時間いつでも、サーバーの弱点を探して自動で攻撃を仕掛けてくるプログラム(ボット)が大量に飛び交っています。
もしファイアウォールがないと、これらの攻撃通信がすべてサーバー本体に直接届いてしまいます。
サーバーは攻撃を受けるたびに「これは安全な通信か?」を自分で判断して処理しなければならず、それだけで負荷がかかってパンクしたり、一瞬の隙(脆弱性)を突かれて乗っ取られたりします。
ファイアウォールをネットワークの境界線に置くことで、怪しい通信をサーバーに届く前に手前で全ブロックし、サーバーの身代わりとして守ることができます。
3.中から外への「秘密の通信」を監視・制限するため
多くの人が「外からの攻撃を防ぐもの」と思いがちですが、セキュリティ系の現場では「中から外への通信をコントロールする」役割も同じくらい重要視されます。
万が一、社内のパソコンやサーバーがウイルス(マルウェア)に感染してしまったとします。
ウイルスは、盗んだ機密データを外部の犯人のサーバー(C&Cサーバー)へ送信しようとします。
このとき、ファイアウォールが「中から外への怪しい通信」を監視していれば、データの不正連れ出しを水際で阻止することができます。
UFWの基本設定:すべてを拒否することから始まる
「すべてを拒否するところから始まる」とはどういうことか?
それは、「まず、すべてを拒否することから始める」という情報セキュリティにおける最も基本的かつ強力な考え方に基づく設計思想です。
これを「ホワイトリスト方式(最小権限の原則)」と呼びます。
多くの人が「怪しい通信だけをブロックしよう(ブラックリスト方式)」と考えがちですが、これでは「まだ見ぬ新しい攻撃」や「うっかり開けっ放しにしていたポート」を防げません。
1. サーバーを「窓のない部屋」にするイメージ
最初にすべての入力を拒否することで、サーバーを「外からの侵入経路が一つもない、完全に密閉された箱」にします。この状態が、セキュリティ上の「スタート地点」です。
2. 「許可したもの以外はすべて悪」とみなす
密閉した後に、「SSH(22番)」「Web(80番)」といった、運用にどうしても必要なドアだけを内側から開けていきます。
これにより、意図しないサービスが勝手に外部と通信するのを防ぎ、攻撃者が侵入を試みる隙間(アタックサーフェス)を最小限に抑えることができます。
3.「Dockerの落とし穴」への対策
実はDockerは、標準設定だとOSのファイアウォールを無視してポートを公開してしまうことがあります。
最初にUFWで「原則拒否」を宣言し、Nginx Proxy Managerのような「玄関口」だけを明示的に開ける運用を徹底することで、Dockerコンテナが意図せず世界中に公開されてしまう事故を防ぐことができます。
※Nginx Proxy Managerについては下記記事にて取り扱っておりますので、詳しくはこっちを読んでいただけるとイメージがつかみやすいと思います。

実践!UFW設定法とSSH、Webサービスのポートだけをピンポイント開放
Ubuntuの標準ファイアウォール「UFW」を使い、サーバーを鉄壁の要塞に変える手順を解説します!
1.デフォルトポリシーの設定
まずは、前述したすべての通信に対する「基本姿勢」を決めます。
サーバーで以下のコマンドを実行します。
#Bash
# ① すべての「受信(Incoming)」を拒否
sudo ufw default deny incoming
# ② すべての「送信(Outgoing)」を許可
sudo ufw default allow outgoing
コマンドの説明
Default Deny Incoming: 外部からあなたのサーバーに話しかけてくる通信は、原則すべて無視します。これで「勝手に侵入される」リスクをゼロに近づけます。
Default Allow Outgoing: サーバーの中から外(アップデートの取得など)へ行く通信は許可します。これにより、サーバーの運用利便性を保ちます。
これで外部からの通信は原則すべて無視、サーバーから外への通信は許可という基本的な姿勢が確立されました。
しかし、このままだとSSH接続も拒否されてしまいます。なので、これらの設定を有効化する前に、SSH接続で使う22番のポートは開いておきましょう。
2.SSHの許可
以下のコマンドを実行して、SSH接続の許可をしましょう。
#Bash
sudo ufw allow 22/tcp
詳細解説:
22: SSHの標準ポート番号。/tcp: 通信プロトコルの指定。SSHは確実なやり取りが必要なためTCPを使います。
※Tips: もしSSHのポート番号をセキュリティのために変更している場合は、その番号を正確に指定してください。
これを忘れると、設定を有効化した瞬間にSSH接続が切れ、二度とログインできなくなっちゃうのでお気を付けください。
3.公開サービスの「窓口」を開ける
ここの手順は必要な人とそうではない人がいます。
今回は前回の記事で構築したリバースプロキシ(NPM)が外部とやり取りするための通り道を作ります。
以下のコマンドを実行して設定をします。
#Bash
#通常のウェブアクセス(HTTP)用
sudo ufw allow 80/tcp
#NPMの管理画面(Dashboard)用
sudo ufw allow 81/tcp
暗号化された安全なアクセス(HTTPS)用
sudo ufw allow 443/tcp
前回の記事を読んでくれた方は、9000番(Portainer)ポートは開けないのか?となりますよね?
これは、「80番(玄関)」を通れば、中にあるNPMがPortainerへ案内してくれるため、9000番という「個別の窓」をわざわざ開けておく必要はないんですよね。
なので最小限のポートしか開かないという設計思想から今回は開きません。
4.設定の「下書き」を最終確認する
これまでした設定を有効化(Enable)する前に、現在の「予約リスト」を確認します。
以下のコマンドを実行します。
#Bash
sudo ufw show added
出力例:このリストに 22/tcp が入っていることを、親の顔よりしっかり確認してください!
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 81/tcp
ufw allow 443/tcp
5.UFWの有効化
いよいよ、ファイアウォールを稼働させます!以下のコマンドを実行して設定の有効化しましょう!
#Bash
sudo ufw enable
警告への対処:
Command may disrupt existing ssh connections. Proceed with y/n? (このコマンドは現在のSSH接続を切断する可能性があります。続行しますか?) という怖いメッセージが出ますが、ステップ2で22番を許可していれば大丈夫です。落ち着いて y を入力します。
6.最終結果のチェック:verbose(詳細)モード
最後に正しく動いているか、詳細モードで確認します。
#Bash
sudo ufw status verbose
出力の結果がStatus: active となっており、各ポートの右側が ALLOW IN になっていれば成功です。
これ以外の通信はすべて自動的に DENY(拒否)されます。
動作確認:ポートスキャンで「鉄壁」を確認する
この章では、本当に外部から見て「窓が閉まっているか」を確認します。
自分自身のPCから、サーバーに対して擬似的なスキャン(攻撃のシミュレーション)を行ってみましょ!
1.サーバーの「外」から叩いてみる
まず、ブラウザで直接ポート番号を指定してアクセスしてみます。
検証例: http://192.168.11.1:9000(Portainerのポート)
僕はDockerで環境を構築したので通信が成功しちゃいました(笑)
なのでこの失敗について少し解説していこうと思います。
なぜUFWを有効にしたのに9000番が開いてしまうのか
「UFWの基本設定:すべてを拒否することから始まる」の章にて少し解説しましたが、改めて解説しますね。
9000番が開いてしまうその理由は、Wi-Fiが同じだからではなく、「DockerがUFWを無視して勝手に穴を開けてしまうから」です。
Ubuntu上でDockerを動かすと、Dockerは通信速度を速めるためにOSの標準ファイアウォール(UFW)をバイパスして、直接「iptables」という深い階層の設定を書き換えてしまいます。
つまり、UFWで「9000番は閉じろ!」と言っても、Dockerが「いや、俺が使うから開けるぜ!」と裏口を勝手にこじ開けている状態なんですよね。
これを「本当の意味で」閉じるには?
今回は、コンテナを「localhost」だけに縛るという方法を使おうかなと思います。
※この設定をする場合は、必ずNginx Proxy Managerなどのリバースプロキシをセットで運用してくださいね。そうしないと、あなた自身もアクセスできなくなります(笑)
実際に何をやるかというと、docker-compose.yml を少し書き換えて、外部からは見えないようにします。
コードの書き換え例
services:
portainer:
# ...略...
ports:
- "127.0.0.1:9000:9000" # 外からの直接アクセスを遮断し、自分自身だけに縛る
nginx-proxy-manager:
# ...略...
ports:
- "80:80" # これは外からアクセスしてほしいのでそのまま
- "81:81" # これも同様
- "443:443" # これも同様
これをやってから sudo docker compose up -d をすると、以下の状態になります:
例:http://192.168.11.1:9000→ 拒否される(耳を塞いでいるから)例:http://portainer.local→ 繋がる(NPMが中で案内してくれるから)
僕はこれでちゃんと通信が拒否られるようになりました(笑)
2.コマンドで「開いている穴」を一斉点検する
一応さっきの手順でも確認は終わってますが、よりプロフェッショナルな方法として、nmap(エヌマップ)というポートスキャンツールを紹介します。
※ポートスキャンとは、サーバーのポート(窓口)を一つずつ叩いてみて、「返事があるか(開いているか)」を確認する作業のことです。
「一つずつ調べるのは面倒だ、全部のポートをスキャンしたい!」という時に使うのが nmap という有名なツールです。
1番から65535番まで、すべてのポートを高速で叩き、「開いているポートのリスト」をズラッと表示してくれます。
注意点: Windowsには標準で入っていないので、インストールが必要です。
今回は、このサーバーを構築する前に使っていたLinuxサーバー上からスキャンツールを動かしていこうと思います。

nmapインストール
スキャンする側のサーバーにnmapが入っていないので、インストールするところやっていきます。
#Bash
sudo apt update
sudo apt install nmap -y
インストールが終わり、バージョン確認ができれば準備完了です。
よく使われる主要ポートを一斉点検
まずは、一般的なポート(SSH, HTTP, HTTPS, DBなど)が開いていないか確認します。
#Bash
nmap <サーバーのIPアドレス>
実行結果は以下となります。9000番(Portainer)がリストに「ない」ことが確認できましたね。

特定のポート(9000番)を狙い撃ちで確認
次に、ピンポイントで状態を確認します。以下のコマンドを実行していきます。
nmap -p 9000 <サーバーのIPアドレス>
実行結果は以下の通りになりました。

closed: ポートは開いていない(成功!)
filtered: UFWなどがパケットを無視している(さらに成功!=ステルス状態)
open: まだ穴が開いています。
これで必要なポート以外開いていないことは確認できましたね。
※注意: ポートスキャンは自分の管理下にあるサーバーに対してのみ行ってください。 他人のサーバーや企業のサイトに対して行うと、**「サイバー攻撃の予兆(下調べ)」**とみなされ、法的な問題やプロバイダからの警告に繋がる恐れがあります。あくまで自分の城を守るための「点検」として使いましょう。
3.「 stealth 」(ステルス)という鉄壁の状態
UFWのデフォルト設定(Deny)のすごいところは、単に「拒否」するだけでなく、「無視(DROP)」することにあります。
- 解説: * 「拒否(REJECT)」は、「ここは閉まってます!」と返事をしてしまいます。
- 「無視(DROP)」は、パケットが届いても完全にシカトします。
- 攻撃者への影響: 攻撃者から見ると「そこにサーバーが存在するのかどうかすら分からない」という状態になります。これが「鉄壁」と呼ばれる理由です。
4.ログを見て「攻撃を防いだ瞬間」を目撃する
最後に、実際にブロックした記録(ログ)を見ていきましょう。
以下のコマンドで、システムログの中から UFW に関連するものだけを抽出して表示できます。
# カーネルログから [UFW BLOCK] という文字を探して表示
sudo grep "\[UFW BLOCK\]" /var/log/kern.log
出力結果は以下の通りになります。すごいログの数ですね。

なんでこんな量のログが出るのかというと、、これらは攻撃ではなく、「同じネットワーク内の機器同士の雑談(ブロードキャスト/マルチキャスト)」をUFWが律儀にブロックしているからなんですよね。
ログを見ると DST=224.0.0.1 という数字が並んでいるんですけど、これはマルチキャストという仕組みで、同じWi-Fiやネットワーク内にいる機器(スマホ、プリンタ、スマート家電、ルーターなど)が、「誰かいるー?」「私はここにいるよー!」と一斉に呼びかけている通信です。
「ログが大量に出ていて驚くかもしれませんが、心配いりません。これは『外部からの攻撃』ではなく、『家の中の賑やかさ』を記録しているだけです。
ルーターやスマホが投げかける無数の『あいさつ』を、UFWが『君の相手をするルールはないよ』と一蹴してくれているのです。この大量の [UFW BLOCK] こそ、あなたのサーバーが外界から隔離され、静寂を保っている証拠なのです。」
まとめ
ここまで読んでくださりありがとうございました!
セキュリティとは、設定して終わりではありません。
今回のようにスキャンツール(nmap)で外から確認したり、ログ(kern.log)を覗いて『ブロックされている証拠』を見つける。
この一連の検証作業こそが、自分のサーバーを真にコントロールする楽しさだと感じました。
少し難しい説明が今回は多かった気がしますが、自分で手を動かしながらやることで理解が進むと思うので実践していただければ幸いです。
ご精読ありがとうございました。また次回よろしくお願いします。

コメント