Docker Composeで
データベースを外部に公開しない設定
Docker Composeで構築したWebアプリケーション、データベースのポートを外部に公開していませんか?
PostgreSQL、MySQL、Redisなどのデータベースは、外部に公開する必要がないサービスです。
この記事では、データベースを安全に内部ネットワークだけに閉じる3つの方法を解説します。
こんな人向けの記事です
- Docker ComposeでWebアプリ + データベースを運用している
docker-compose.ymlでデータベースにportsを書いている- データベースを外部に公開したくないが、どう設定すればいいかわからない
なぜデータベースを外部に公開してはいけないのか
データベースが外部に公開されていると、以下のリスクがあります。
| リスク | 内容 |
|---|---|
| ブルートフォース攻撃 | パスワードを総当たりで試行され、突破される |
| 脆弱性の悪用 | データベースの既知の脆弱性を突かれて侵入される |
| データ漏洩 | ユーザー情報や機密データが外部に流出する |
| ランサムウェア | データを暗号化され、身代金を要求される |
Step 1現状を確認する
まず、あなたの docker-compose.yml を確認しましょう。以下のようにデータベースに ports が設定されていたら危険です。
services:
web:
build: .
ports:
- "80:80"
db:
image: postgres:16
ports:
- "5432:5432" # 全世界に公開されている
environment:
POSTGRES_PASSWORD: mypassword
redis:
image: redis:7
ports:
- "6379:6379" # 全世界に公開されている
サーバー上で実際にポートが公開されているか確認します。
ss -tlnp | grep -E '(5432|3306|6379|27017)'
0.0.0.0 にバインドされていたら、外部から直接アクセス可能な状態です。すぐに対策しましょう。
Step 2方法1: ports を削除する(推奨)
最もシンプルで安全な方法です。データベースの ports を削除するだけです。
修正前(危険)
services:
db:
image: postgres:16
ports:
- "5432:5432"
environment:
POSTGRES_PASSWORD: mypassword
修正後(安全)
services:
db:
image: postgres:16
# ports は書かない(Docker内部ネットワークのみ)
environment:
POSTGRES_PASSWORD: mypassword
web コンテナからは db:5432 でアクセスできますが、ホストマシンや外部からはアクセスできません。ports はホストのポートにマッピングする設定なので、書かなければ外部に公開されません。
完全な構成例
services:
web:
build: .
ports:
- "80:80" # Webサーバーのみ外部公開
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
# ports なし = 外部非公開
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: myapp
POSTGRES_USER: myapp
POSTGRES_PASSWORD: mypassword
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myapp"]
interval: 5s
timeout: 3s
retries: 5
redis:
image: redis:7-alpine
# ports なし = 外部非公開
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
この設定では、web コンテナからは db:5432 や redis:6379 に接続できますが、外部からは一切アクセスできません。
Step 3方法2: 127.0.0.1 にバインドする
開発時にホストマシンからデータベースに直接接続したい場合(GUIツールでの確認等)、127.0.0.1 にバインドする方法があります。
services:
db:
image: postgres:16
ports:
- "127.0.0.1:5432:5432" # ローカルホストからのみ接続可
environment:
POSTGRES_PASSWORD: mypassword
127.0.0.1:5432:5432 と書くと、サーバー自身(localhost)からのみ 5432 ポートにアクセスできます。外部ネットワークからは到達できません。ホストマシンから psql -h 127.0.0.1 でDBに接続しつつ、外部には非公開にできます。
ports 自体を書かない方法1が最も安全です。ホストからの接続が必要な開発環境でのみ、この方法を使いましょう。
Step 4方法3: internal ネットワークを使う
より厳密に制御したい場合、Docker の internal ネットワークを使う方法があります。internal: true を指定したネットワークは、外部との通信が完全に遮断されます。
services:
web:
build: .
ports:
- "80:80"
networks:
- frontend # 外部アクセス用
- backend # DB接続用
db:
image: postgres:16
networks:
- backend # 内部ネットワークのみ
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: mypassword
networks:
frontend: # 外部通信可能
backend:
internal: true # 外部通信を完全遮断
volumes:
postgres_data:
internal: true のネットワークに接続されたコンテナは、同じネットワーク内のコンテナとのみ通信できます。外部ネットワーク(インターネット)への接続も遮断されるため、データベースコンテナからの外部通信(例えば、乗っ取られた場合のデータ送信)も防止できます。
| 方法 | 安全性 | 用途 |
|---|---|---|
| 方法1: ports を削除 | 高い | ほとんどの本番環境で推奨 |
| 方法2: 127.0.0.1 バインド | 中程度 | ホストからDB接続が必要な開発環境 |
| 方法3: internal ネットワーク | 最も高い | 厳格なセキュリティが求められる環境 |
Step 5環境変数でパスワードを管理する
データベースのパスワードを docker-compose.yml に直接書くのは危険です。Gitにコミットされると、パスワードが流出します。.env ファイルを使って管理しましょう。
.env ファイルを作成する
POSTGRES_DB=myapp
POSTGRES_USER=myapp
POSTGRES_PASSWORD=ここに強力なパスワード
docker-compose.yml から参照する
services:
db:
image: postgres:16
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
.gitignore に追加する
.env
.env ファイルは必ず .gitignore に追加してください。代わりに .env.example をコミットして、必要な環境変数のテンプレートを共有しましょう。
Step 6設定を検証する
変更を反映する
docker compose down
docker compose up -d
ポートが公開されていないことを確認する
ss -tlnp | grep -E '(5432|3306|6379|27017)'
方法1(ports 削除)の場合、何も表示されなければ成功です。データベースのポートはホストにマッピングされていません。
Webアプリからデータベースに接続できることを確認する
# Webコンテナからデータベースに接続できるか確認
docker compose exec web python -c "
import psycopg2
conn = psycopg2.connect(host='db', dbname='myapp', user='myapp', password='mypassword')
print('接続成功')
conn.close()
"
外部からアクセスできないことを確認する
# タイムアウトまたは接続拒否になればOK
psql -h サーバーのIPアドレス -p 5432 -U myapp -d myapp
Connection refused または応答なし(タイムアウト)になれば、外部からのアクセスは遮断されています。
まとめ
Docker Composeでデータベースを安全に運用するためのポイントをまとめます。
- データベースに
portsを書かない — 同一Composeファイル内のサービスは、ports なしでもサービス名で接続できる - 開発時に直接接続が必要なら
127.0.0.1にバインドする — 外部には公開されない - 厳格なセキュリティには
internalネットワークを使う — DBからの外部通信も遮断できる - パスワードは
.envファイルで管理する — Gitには.env.exampleのみコミットする
「とりあえず ports でポートを公開しておく」という習慣は、本番環境では非常に危険です。データベースは外部に公開する必要がないサービスであることを忘れずに、必ず内部ネットワークに閉じた設定にしましょう。