この記事にはアフィリエイト広告が含まれています。

冒頭まとめ

ConoHa VPS で Docker を動かすとき、通信を止めたり通したりする設定は2か所にあります。ひとつは OS の中にある ufw、もうひとつは VPS の外側にあるセキュリティグループです。

ここで噛み合わなくなる理由が1つあります。Docker が -p で公開したポート宛の通信は、ufw が使う規則を迂回します。Docker の公式ドキュメントは、Docker と ufw が互いに相容れない使い方でファイアウォールの規則を使うと明記しており、公開されたコンテナへの通信は nat テーブルで転送されるため、ufw が使う INPUT と OUTPUT のチェーンに到達する前に迂回する、と説明しています(Packet filtering and firewalls)。

この性質から2つのことが言えます。第一に、ufw allow だけでは Docker の公開ポートを制御できません。第二に、ufw deny で拒否しても、Docker の公開ポートを塞いだことにはなりません。

したがって、ufw を変更したのに外部から接続できない場合は、ConoHa のセキュリティグループ側を確認する必要があります。逆に、ufw で塞いだつもりのポートについては、ufw の設定を根拠に安全だと判断できません。

症状の概要

現れ方は2通りあります。

ひとつは、開けたつもりで繋がらない状態です。ufw allow 8080 を実行し、ufw status の一覧にも出ているのに、外部のブラウザや curl から接続できません。

もうひとつは、塞いだつもりで開いている状態です。ufw deny 8080 を設定しても、docker run -p 8080:80 で公開したコンテナには通信が届きうる、という状態です。

どちらも、ufw の表示と実際の通信経路がずれていることから生じます。ufw の一覧はあくまで ufw が管理している規則を示すもので、Docker が別に作る規則は含まれません。

前提として、ConoHa の Docker テンプレートの仕様を押さえておきます。公式ドキュメントによれば、OS は Ubuntu 24.04、Docker CE は 29.2.1 で、OS 内のファイアウォールは既定で22番ポート(SSH)のみ許可となっています。また Minimum RAM は 1024 MB と明記されています(Docker|ConoHaドキュメントサイト)。512 MB のプランはこの最小要件を下回ります。

まず最初に:どちらの層を触っているのかを確定する

推測の前に、2つの層を分けて確認します。

OS の中の状態は ufw で見ます。

sudo ufw status verbose

ここに出るのは ufw が管理している規則だけです。Docker が公開したポートは、この一覧に現れなくても通信が成立しうる、という点を踏まえて読んでください。

外側の状態は ConoHa のコントロールパネルで見ます。ConoHa VPS(Ver.3.0) では、サーバーごとに IP アドレスやポート、プロトコルで通信を制御するホワイトリスト形式のセキュリティグループが標準で設定されます。公式ドキュメントは、標準では各テナントごとの default セキュリティグループがアタッチされているサーバーからのみ通信を許可する設定になっていること、外部からの通信を許可したい場合はサーバーのネットワークごとに許可設定が必要であることを述べています(セキュリティグループ|ConoHaドキュメントサイト)。

同じページには、イメージテンプレートによっては OS 内にもソフトウェアファイアウォールが設定されているため、セキュリティグループとは別に OS 内の設定もあわせて確認するように、という案内もあります。2か所を分けて見る必要があるのは、この構成によります。

よくある原因と解決手順

原因1:外側の許可設定が入っていない

ufw allow を実行したのに外部から接続できない場合です。OS の中は通す設定になっていても、外側で止まっていれば届きません。

確認方法はコントロールパネル側です。対象サーバーのネットワークに、どのセキュリティグループが割り当てられているかを見ます。公式ドキュメントによれば、ConoHa が用意しているセキュリティグループはルールの設定変更ができず、独自のルールが必要な場合はセキュリティグループを追加して設定する必要があります。用意されているものとしては、SSH 用の IPv4v6-SSH が22番、Web 用の IPv4v6-Web が80番と443番を解放する構成です(セキュリティグループ)。

Before(OS 内だけを開けて確認を終える):

sudo ufw allow 443
sudo ufw status verbose

After(外側の割り当ても確認する):

コントロールパネル → 対象サーバー → ネットワーク情報 → セキュリティグループ

80番と443番であれば IPv4v6-Web を割り当てることで対応できます。

原因2:80番と443番以外を使おうとしている

8080番や3000番のような任意のポートを公開したい場合です。ConoHa が用意しているセキュリティグループは用途ごとに解放ポートが決まっており、任意のポート番号に対応するものはありません。

公式ドキュメントは、独自のセキュリティグループが必要な場合はセキュリティグループを追加してルールを設定する、と明記しています。追加できるルールの項目は、通信方向、イーサタイプ、プロトコル、1から65535のポート、そして IP アドレスまたは CIDR 形式の接続元です(セキュリティグループ)。

したがって対処は、必要なポートと接続元を絞った独自グループを作ることです。接続元を CIDR で限定できるので、開発中の管理画面のように公開範囲を狭めたい用途では、全開放ではなく接続元の指定を併用してください。

原因3:外部公開が不要なポートを全体へ公開している

-p 8080:80 の書き方は、ホストのすべてのアドレスで待ち受けます。手元からしか使わない管理画面やデータベースでも、この書き方をすると外へ出る構成になります。

Docker の公式ドキュメントは、公開フラグに 127.0.0.1::1 を含めると、Docker ホストだけがその公開ポートへアクセスできると説明しています(Port publishing)。

Before(すべての宛先で待ち受ける):

docker run -d -p 8080:80 nginx

After(ホスト自身からのみ届く形にする):

docker run -d -p 127.0.0.1:8080:80 nginx

同じページには、28.0.0 より前の版では同じ L2 セグメントにいるホストから、localhost へ公開したポートに到達できるという注意も書かれています(moby/moby#45610)。ConoHa の Docker テンプレートに入っている 29.2.1 はこれより新しい版です。

外部から使う予定がないなら、まずこの書き方に変えるのが確実です。外側の設定に依存せず、公開範囲そのものを狭められます。

原因4:ホスト側でも制限したいが ufw で書いている

外側の設定に加えて、ホストの中でも通信を絞りたい場合です。ufw に書いても Docker の公開ポートには適用されません。

Docker の公式ドキュメントは、利用者が独自の規則を書く場所として DOCKER-USER チェーンを用意しており、ここに置いた規則が DOCKER-FORWARDDOCKER の各チェーンより先に処理される、と説明しています。FORWARD チェーンへ追加した規則は Docker の規則より後に処理されるため、この目的には DOCKER-USER を使うように、とも書かれています(Docker and iptables)。

同じページには注意点もあります。DOCKER-USER チェーンへ到達した時点で、パケットは既に宛先アドレスの変換を通過しているため、iptables の一致条件ではコンテナ側の内部アドレスとポートしか照合できません。元の宛先で照合したい場合は conntrack の拡張を使う必要があります。

この方法は書き方を誤るとコンテナの通信全体を止めます。まずは原因3の公開範囲の限定と、外側のセキュリティグループでの制限を検討し、それでもホスト側の制御が必要な場合に取り組んでください。

補足:似ているが別のもの

ufw の一覧に規則が出ていること自体は誤りではありません。ufw が管理する範囲、たとえばコンテナを経由しないホスト上のプロセスへの通信には、そのまま効きます。効かないのは Docker が公開したポート宛の通信です。

docker run を使わずホスト上で直接起動したプロセスは、この話の対象外です。ufw の設定がそのまま適用されます。

ConoHa の公式ドキュメントに載っている ufw allow の手順は、テンプレート全般に共通する OS 内ファイアウォールの操作方法として書かれています。Docker が公開するポートに関しては、上記の Docker 側の仕様と合わせて読む必要があります。

なお、swap の設定、プライベートネットワークと Docker の既定アドレス帯の衝突、IPv6 固有の挙動については、本記事では確認できていないため扱いません。

切り分けの順序

  1. 対象のポートが Docker の -p で公開されたものかどうかを確認する。そうでなければ ufw の話として扱える。
  2. docker ps で、公開の指定に待ち受けアドレスが含まれているかを見る。0.0.0.0 から始まっていれば全体へ公開している。
  3. sudo ufw status verbose を確認する。ここに出るのは ufw が管理する規則だけだと理解したうえで読む。
  4. コントロールパネルで、対象サーバーに割り当てられているセキュリティグループを確認する。
  5. 外部から接続できない場合は、まず4のグループに必要なポートが含まれるかを見る。
  6. 80番と443番以外であれば、独自のセキュリティグループを追加する必要がある。
  7. 外部公開が不要なポートについては、公開の指定を 127.0.0.1 へ限定する。
  8. ホスト側でも制限が必要な場合に限り、DOCKER-USER チェーンの利用を検討する。

確認コマンド集

# 1. 公開されているポートと待ち受けアドレスを一覧する(最初に行う)
docker ps --format '{{.Names}}\t{{.Ports}}'

# 2. ホスト上で実際に待ち受けている宛先を確認する
sudo ss -ltnp

# 3. ufw が管理している規則を確認する(Docker の公開ポートは含まれない)
sudo ufw status verbose

# 4. Docker が作った転送用の規則を確認する
sudo iptables -t nat -L DOCKER -n

# 5. 利用者が追加できるチェーンの現在の内容を確認する
sudo iptables -L DOCKER-USER -n --line-numbers

# 6. Docker のバージョンを確認する(公開ポートの挙動が版で変わるため)
docker version --format '{{.Server.Version}}'

# 7. 特定のコンテナの公開設定だけを取り出す
docker inspect <コンテナ名> --format '{{json .NetworkSettings.Ports}}'

# 8. 外部からの到達性を、VPS の外にある別の端末から確認する
curl -sS -o /dev/null -w '%{http_code}\n' http://<VPSのIPアドレス>:8080/

Editor’s Note

この記事の内容は、2つの公式ドキュメントを突き合わせると読み取れます。どちらも単体では誤っていませんが、対象としている範囲が違います。

ConoHa 側の Docker テンプレート解説は、最終更新が2026年2月25日です。OS 内のファイアウォール設定として ufw status verbose での確認と ufw allow 443 での開放を案内しています。これはテンプレート全般に共通する OS 内の操作方法の説明であり、Docker が公開するポートに限定した記述ではありません(Docker|ConoHaドキュメントサイト)。

Docker 側のドキュメントは、Docker と ufw が互いに相容れない使い方で規則を使うこと、公開されたコンテナ宛の通信が nat テーブルで転送され ufw の INPUT と OUTPUT チェーンに届く前に迂回することを述べています(Packet filtering and firewalls)。

この性質は、以前から繰り返し報告されてきたものです。Docker の開発リポジトリには2014年3月18日に docker and ufw serious problems という報告が出ています。報告者は受信を既定で拒否する設定にしていたにもかかわらず、Docker がホストへ割り当てたポートへ外部から到達できた、と述べています。この報告は完了として閉じられています。

同じ内容が2021年6月24日に Docker does not honor ufw rules. として改めて提起され、こちらは現在も開いたままです。提起者はこれを繰り返し起きる落とし穴だと書き、先の2014年の報告を参照しています。仕様の説明としてだけでなく、長期にわたって同じ行き違いが起きてきた点も踏まえて読んでください。

したがって、ConoHa の手順に従って ufw を設定した状態でも、Docker で公開したポートについては ufw allow だけでは制御できません。読み替えとしては、ufw の操作は Docker を経由しない通信に対する設定として扱い、Docker の公開ポートについては公開の指定とセキュリティグループの側で考える、という分け方になります。

なお、実際にどの通信が到達するかは、外側のセキュリティグループ、OS 内の各種規則、Docker が作る規則といった複数の層で決まります。本記事は公式ドキュメントの記述にもとづく整理であり、個別の環境での挙動を確認したものではありません。構成を変更する際は、変更前の状態を控えたうえで、限定した範囲から試してください。

ConoHa VPSのDockerテンプレートと料金を公式サイトで確認する(PR)


免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。