本記事は、本連載の 実践パート です。
これまでの記事で、
- AWS の前提設計
- コスト感の整理
- IAM / ネットワーク / EC2 構築
- Docker を使える実行基盤
が揃いました。
本記事では、それらを土台にして、
- Docker で nginx コンテナを起動し
- 設定ファイルを自前で管理し
- リバースプロキシを設定し
- 本番を意識した設定分割を行い
- HTTPS 化まで実装する
という、
「実際にインターネット公開できる状態」
までを一気に仕上げます。
最初は最小構成から始め、
章を追うごとに nginx の役割が
単なる Web サーバ → アプリ全体の入口
へと進化していく流れを体験してください。
第6章:Docker / docker-compose による最小Webコンテナ構築
— ブラウザからアクセスできることを確認する —
1. この章の目的
この章の目的は 1つだけ です。
- クライアント(ブラウザ)からアクセスし、
EC2上で動くコンテナがレスポンスを返すことを確認する
ここでは、以下が理解できれば十分です。
- Docker は「アプリを閉じ込めた実行単位」
- docker-compose は「コンテナ起動手順の定義」
- EC2・Docker・nginx がどうつながっているか
👉
複雑なアプリ構成に入る前の“基礎体験”フェーズです。
2. 今回構築する最小構成
構成イメージ
[ Browser ]
|
HTTP
|
[ EC2 ]
|
[ Docker ]
|
[ nginx コンテナ ]
|
[ 静的HTML ]
- コンテナは 1つだけ
- nginx の公式イメージを使用
- 自作の HTML が表示されることを確認する
3. 作業ディレクトリの準備
EC2 に SSH 接続後、以下を実行します。
cd ~/app
mkdir docker-nginx-sample
cd docker-nginx-sample
4. 表示確認用 HTML ファイルを作成
index.html
vi index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Docker Test</title>
</head>
<body>
<h1>Docker + nginx が動いています</h1>
<p>EC2上のコンテナから配信されています。</p>
</body>
</html>
👉
内容は重要ではありません。
「自分で書いたファイルが表示される」ことが重要です。
5. docker-compose.yml を作成
docker-compose.yml
vi docker-compose.yml
version: "3.9"
services:
nginx:
image: nginx:latest
container_name: nginx-sample
ports:
- "80:80"
volumes:
- ./index.html:/usr/share/nginx/html/index.html:ro
6. docker-compose.yml の設定を理解する
image
image: nginx:latest
- nginx の公式イメージ
- OS や nginx のインストールは不要
ports
ports:
- "80:80"
- 左:EC2 側のポート
- 右:コンテナ内のポート
👉
EC2 の 80 番に来た通信をコンテナへ転送
volumes
volumes:
- ./index.html:/usr/share/nginx/html/index.html:ro
- 左:EC2 上のファイル
- 右:コンテナ内の配置先
-
:ro:読み取り専用
👉
コンテナにファイルを渡している感覚を掴む。
7. コンテナを起動する
docker-compose up -d
成功すると以下のように表示されます。
Creating nginx-sample ... done
8. 起動確認
コンテナ一覧を確認
docker ps
CONTAINER ID IMAGE PORTS
xxxxxx nginx:latest 0.0.0.0:80->80/tcp
9. ブラウザからアクセスする
アクセスURL
http://<Elastic-IP>
表示内容
Docker + nginx が動いています
EC2上のコンテナから配信されています。
👉
この画面が表示されれば 第6章は成功です。
10. 内部で起きていることの整理
- ブラウザが EC2 の 80 番へアクセス
- EC2 が Docker に通信を渡す
- nginx コンテナがリクエストを受信
- volume 経由で index.html を返す
👉
EC2 は単なる「箱」、主役は Docker
11. コンテナの停止・再起動
停止
docker-compose down
再起動
docker-compose up -d
12. 初学者がやりがちなNG例
❌ ports を指定し忘れる
- 外部からアクセスできない
- コンテナは動いているが見えない
❌ セキュリティグループで 80 番を開けていない
- Docker 側が正しくても通信不可
- EC2 側の設定ミス
❌ localhost にアクセスしてしまう
- 自分の PC を見ている
- EC2 ではない
13. この章のまとめ
- docker-compose は起動定義ファイル
- コンテナは EC2 上で動く
- volume でファイルを渡せる
- nginx は最小構成の入口
- ブラウザで表示できれば成功
第7章:nginx 設定ファイルを自前で管理する
— 「動いた」から「制御できる」nginx へ —
1. この章の目的
この章では、以下をゴールとします。
- nginx が どの設定ファイルを、どの順番で読み込むか を理解する
- デフォルト設定に頼らず、自分で書いた設定ファイルを使う
- 将来の拡張(API / HTTPS / 複数サービス)に耐えられる形にする
👉
この章が、学習用途と実務用途の分かれ目です。
2. nginx 公式イメージの基本構造
まず、nginx コンテナ内部の構造を整理します。
/etc/nginx/
├─ nginx.conf
├─ conf.d/
│ └─ default.conf
/usr/share/nginx/html/
└─ index.html
重要ポイント
-
nginx.conf
→ nginx 全体の共通設定 -
conf.d/*.conf
→ 実際の Web / API の設定を書く場所 -
/usr/share/nginx/html
→ 静的ファイルの配置先
👉
実務では default.conf をそのまま使わないのが普通です。
3. なぜ設定ファイルを自前管理するのか
デフォルト設定の問題点
- 中身が見えない
- 変更履歴が残らない
- 複数人で触れない
- 構成が複雑になると破綻する
👉
「設定もコード」= Git 管理前提
4. ディレクトリ構成の整理
第6章の構成を以下のように拡張します。
docker-nginx-sample/
├─ docker-compose.yml
├─ index.html
└─ nginx/
└─ default.conf
5. nginx 設定ファイルを作成する
nginx/default.conf
mkdir nginx
vi nginx/default.conf
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
6. 設定内容の解説
server ブロック
server {
listen 80;
server_name _;
-
listen 80
→ 80番ポートで待ち受ける -
server_name _;
→ すべてのホスト名を受ける(最小構成)
root / index
root /usr/share/nginx/html;
index index.html;
- 静的ファイルの配置先
-
/にアクセスした際にindex.htmlを返す
location /
location / {
try_files $uri $uri/ =404;
}
- ファイルが存在すれば返す
- 無ければ 404
👉
静的サイト配信の基本形
7. docker-compose.yml を修正する
修正後の docker-compose.yml
version: "3.9"
services:
nginx:
image: nginx:latest
container_name: nginx-sample
ports:
- "80:80"
volumes:
- ./index.html:/usr/share/nginx/html/index.html:ro
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
ポイント
-
default.confを 上書きしている - nginx は起動時にこの設定を読む
8. 設定を反映する
コンテナ再起動
docker-compose down
docker-compose up -d
ログ確認(任意)
docker logs nginx-sample
9. ブラウザで動作確認
http://<Elastic-IP>
第6章と同じ画面が表示されれば成功です。
👉
見た目は同じでも、中身は完全に別物。
10. よくあるミスと対処
❌ 設定ファイルの配置先を間違える
- 正解:
/etc/nginx/conf.d/default.conf -
nginx.confを直接触らない
❌ 設定を書き換えたのに反映されない
原因:
- volume マウントしていない
- コンテナを再起動していない
対処:
docker-compose down
docker-compose up -d
❌ nginx が起動しない
確認:
docker logs nginx-sample
→ 構文エラーが原因のことがほとんど。
11. この章のまとめ
- nginx は設定ファイルで動く
- 実務では設定を自前管理する
- conf.d 配下で Web 設定を書く
- docker-compose で設定を注入する
- 将来の拡張に耐えられる構成になる
第8章:nginx でリバースプロキシを設定する
— 「入口」と「内部サービス」を分離する —
1. この章の目的
この章では、以下をゴールとします。
- リバースプロキシとは何かを構造で理解する
- nginx を「静的配信サーバ」から
**アプリ全体の入口(ゲートウェイ)**として使えるようにする - 将来の API(Node / Python 等)を
安全に内部接続する前提構成を作る
👉
この章を理解すると、
**「なぜ nginx が最前段に置かれるのか」**が腹落ちします。
2. リバースプロキシとは何か
一言で言うと
クライアントからのリクエストを nginx が受け取り、
内部の別サービスへ代理で転送する仕組み
構成イメージ
[ Browser ]
|
HTTP
|
[ nginx ]
|
/api/
|
[ backend コンテナ ]
- ブラウザは nginx しか知らない
- backend は外部公開しない
- nginx が通信の振り分け役になる
3. なぜ API を直接公開しないのか
理由① ポート管理が破綻する
- APIごとに 3000 / 8000 / 8080 …
- セキュリティグループが複雑化
理由② URL設計が汚くなる
http://<IP>:3000/api
nginx 経由なら:
http://<IP>/api
理由③ HTTPS 化が困難になる
- APIごとに証明書?
- 非現実的
👉
外部公開は nginx だけが正解
4. 今回の構成方針(APIはダミー)
この章では以下を方針とします。
- 本物の Node / Python は使わない
- **「APIっぽく振る舞うだけの軽量コンテナ」**を使用
- 目的は「流れの理解」
5. 作業ディレクトリの準備
cd ~/app
mkdir docker-nginx-proxy
cd docker-nginx-proxy
mkdir nginx
6. docker-compose.yml を作成する
vi docker-compose.yml
version: "3.9"
services:
nginx:
image: nginx:latest
container_name: nginx-proxy
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- backend
backend:
image: hashicorp/http-echo
container_name: backend-api
command: ["-text=Hello from backend API"]
7. ダミーAPIコンテナの説明
hashicorp/http-echo とは
- HTTP リクエストを受けると
- 指定した文字列を返すだけのコンテナ
command: ["-text=Hello from backend API"]
👉
APIの中身は重要ではない
重要なのは「nginx が中継している」こと。
8. nginx のリバースプロキシ設定
nginx/default.conf
vi nginx/default.conf
server {
listen 80;
server_name _;
location / {
return 200 "nginx is running\n";
}
location /api/ {
proxy_pass http://backend:5678/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
9. 設定の重要ポイント
proxy_pass の指定
proxy_pass http://backend:5678/;
-
backendは docker-compose の service 名 - Docker 内部 DNS により自動解決される
- IP アドレス指定は不要・非推奨
ヘッダ転送
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
- 元のホスト名
- クライアントIP
を backend 側で参照できるようにする
👉
実務では必須に近い設定
10. コンテナを起動する
docker-compose up -d
確認:
docker ps
11. 動作確認
nginx 単体
http://<Elastic-IP>/
表示:
nginx is running
API 経由
http://<Elastic-IP>/api/
表示:
Hello from backend API
👉
この表示が出れば リバースプロキシ成功。
12. 内部で起きていること
- ブラウザ → nginx(80番)
- nginx が
/api/を検知 - backend コンテナへ転送
- レスポンスを受け取り返却
👉
外部からは backend が見えない
13. 初学者がやりがちなNG例
❌ proxy_pass に localhost を書く
proxy_pass http://localhost:5678;
- コンテナ内の localhost は自分自身
- 通信できない
❌ backend の ports を公開する
ports:
- "5678:5678"
- 外部公開不要
- セキュリティリスク
❌ IP アドレスで backend を指定する
- 再起動で変わる
- Docker DNS を使うべき
14. この章のまとめ
- nginx は「入口」として使う
- API は外部公開しない
- リバースプロキシで内部転送する
- service 名で通信する
- 本番構成への重要な一歩
第9章:nginx 設定の分割と本番向け構成
— 保守・拡張に耐える nginx 設計 —
1. この章の目的
この章では、以下をゴールとします。
- nginx 設定を 役割ごとに分割する理由を理解する
- 小規模でも 本番を意識した設定構成を作る
- 将来の HTTPS 化・複数サービス化に備える
👉
「設定が1ファイルに全部書いてある」状態は、実務では早晩破綻します。
2. なぜ nginx 設定を分割するのか
1ファイル運用の問題点
- どこに何が書いてあるか分からない
- 差分レビューが困難
- HTTPS・API追加時に事故りやすい
- 複数人で触れない
👉
設定もアプリと同じで「構造化」が必要
3. nginx の設定読み込み順序
nginx は以下の順で設定を読み込みます。
/etc/nginx/nginx.conf-
nginx.conf内のinclude指定 /etc/nginx/conf.d/*.conf
👉
Web / API 設定は conf.d 配下に置くのが定石
4. 推奨ディレクトリ構成(実務寄り)
第8章の構成を以下に整理します。
docker-nginx-proxy/
├─ docker-compose.yml
└─ nginx/
├─ nginx.conf
└─ conf.d/
├─ web.conf
└─ api.conf
役割分担
| ファイル | 役割 |
|---|---|
| nginx.conf | 全体共通設定 |
| web.conf | Web(静的) |
| api.conf | API(proxy) |
5. nginx.conf(全体共通設定)
nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}
ポイント
- server は書かない
- 全体挙動・ログ・パフォーマンスのみ定義
- アプリ固有設定は持たせない
6. Web 用設定(web.conf)
nginx/conf.d/web.conf
server {
listen 80;
server_name _;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
- 静的配信専用
- API と責務を分離
7. API 用設定(api.conf)
nginx/conf.d/api.conf
server {
listen 80;
server_name _;
location /api/ {
proxy_pass http://backend:5678/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
👉
Web と API を別ファイルにすることで、変更影響を局所化
8. docker-compose.yml の修正
修正後の docker-compose.yml
version: "3.9"
services:
nginx:
image: nginx:latest
container_name: nginx-proxy
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
depends_on:
- backend
backend:
image: hashicorp/http-echo
container_name: backend-api
command: ["-text=Hello from backend API"]
9. 設定反映と確認
docker-compose down
docker-compose up -d
確認ポイント
-
/→ Web 表示 -
/api/→ API 応答
10. 実務でこの構成が評価される理由
- 設定差分が追いやすい
- 機能追加時に影響範囲が明確
- HTTPS 化時に server ブロック追加だけで済む
- 設定レビューがしやすい
👉
「この構成にしている理由」を説明できる
11. 初学者がやりがちなNG例
❌ nginx.conf に全部書く
- 責務が混ざる
- 読めない・直せない
❌ conf.d を使わない
- nginx の思想に反する
- 本番構成から乖離する
❌ Web / API を同一 server に詰め込む
- 見通しが悪い
- HTTPS 移行時に地獄
12. この章のまとめ
- nginx 設定は分割が前提
- nginx.conf は共通設定のみ
- server 定義は conf.d 配下
- Web / API を責務で分ける
- 小規模でも本番設計を意識する
第10章:HTTPS 化(Let’s Encrypt + nginx)
— 実務で必須の通信暗号化を自動更新まで含めて実装する —
1. この章の目的
この章では、以下をゴールとします。
- HTTP 通信を HTTPS(TLS) に切り替える
- Let’s Encrypt を用いて 無料で証明書を取得する
- 証明書の 自動更新 を設定する
- 実務で通用する HTTPS 構成を理解する
👉
インターネット公開サービスで HTTPS なしは失格です。
2. なぜ HTTPS が必須なのか
理由① 通信内容の盗聴防止
- ID / パスワード
- セッション情報
- API トークン
👉
HTTP は 平文。盗聴可能。
理由② なりすまし防止
- DNS / Wi-Fi 偽装
- 中間者攻撃(MITM)
👉
HTTPS は サーバの正当性を証明する。
理由③ ブラウザ・API の制約
- Chrome:HTTP は「安全でない」表示
- Cookie の
Secure属性 - 一部 API(Service Worker 等)は HTTPS 必須
3. Let’s Encrypt とは何か
Let’s Encrypt の特徴
- 無料
- 世界的に利用されている認証局
- 証明書の有効期限は 90日
- 自動更新前提
👉
手動更新は運用事故の元
4. 今回の HTTPS 化方針
- ドメインを使用(IP直指定は不可)
- Certbot を使用
- nginx と連携
- EC2 上で証明書を管理
- Docker nginx から証明書を参照
5. 事前準備(必須)
5.1 ドメインの準備
- Route53 以外でも可
- A レコードを Elastic IP に向ける
例:
example.com → 18.xxx.xxx.xxx
👉
DNS 反映完了後でないと証明書取得不可。
5.2 セキュリティグループ設定
| ポート | 用途 |
|---|---|
| 80 | 認証用 |
| 443 | HTTPS |
6. Certbot のインストール(EC2)
sudo dnf install certbot python3-certbot-nginx -y
確認:
certbot --version
7. nginx を一時的に停止
Certbot が 80 番を使用するため、
Docker nginx を一度停止します。
cd ~/app/docker-nginx-proxy
docker-compose down
8. 証明書の取得
sudo certbot certonly --standalone -d example.com
実行中に聞かれること
- メールアドレス:通知用(必須)
- 利用規約:同意
- メール配信:任意
成功すると以下に生成されます。
/etc/letsencrypt/live/example.com/
├─ fullchain.pem
└─ privkey.pem
9. nginx に HTTPS 設定を追加する
nginx/conf.d/ssl.conf を作成
vi nginx/conf.d/ssl.conf
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /api/ {
proxy_pass http://backend:5678/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
10. HTTP → HTTPS リダイレクト
nginx/conf.d/http.conf
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
👉
HTTP を残したままにしない
11. docker-compose.yml の修正
証明書を nginx コンテナに渡す
volumes:
- /etc/letsencrypt:/etc/letsencrypt:ro
※ nginx サービスに追加
12. nginx を起動する
docker-compose up -d
13. 動作確認
HTTPS アクセス
https://example.com
- 鍵マークが表示される
- 警告が出なければ成功
API 経由
https://example.com/api/
14. 証明書の自動更新設定
dry-run で確認
sudo certbot renew --dry-run
自動更新(systemd timer)
Amazon Linux では 自動で設定済み。
確認:
systemctl list-timers | grep certbot
👉
cron を自分で書く必要はない
15. 実務でよくある落とし穴
❌ IPアドレスで HTTPS 化しようとする
- 証明書はドメイン必須
- IP直指定は不可
❌ 証明書をコンテナ内で管理する
- 再起動で消える
- 更新が壊れる
👉
証明書はホスト側で管理
❌ 自動更新を確認しない
- 90日後に突然死
- 実務事故あるある
16. この章のまとめ
- HTTPS は必須
- Let’s Encrypt は実務標準
- Certbot で自動更新前提
- nginx は HTTPS 終端として使う
- 証明書はホスト管理が基本
おわりに
本連載では、AWS 初学者が
- 理由を説明できる構成で
- 小さく始めて
- 実務につながる形で
Web アプリ実行環境を構築する流れを解説しました。
今回扱った構成は、
あくまで 学習・有志開発向けの最小構成 です。
実務ではここからさらに、
- RDS による DB 分離
- ALB による負荷分散
- ECS / Fargate への移行
- CI/CD の自動化
- 監視・ログ基盤の整備
といったステップが続きます。
ただし、
今回の内容を理解していれば、
それらは「新しい知識」ではなく「拡張」として扱える はずです。
まずはこの構成を
「自分で説明できる」「自分で再現できる」
状態になることを目標にしてみてください。
ここまで読んでいただき、ありがとうございました。