Django備忘録：シェルスクリプトでNginx + Djangoのリバースプロキシ環境を自動構築してみた

## はじめに
まず、大前提として、ここから先は現在キャッチアップしている reverse-proxy-django プロジェクトのために、シェルスクリプトを活用しながら、さまざまなコードを書いていきます。

:::note alert
**※補足事項**
***そのため、内容は完全に自分向けとなっています。***
:::

また、このブログ投稿サイトも、自分自身の備忘録として活用する予定です。

**ここに記録を積み重ねながら、メモを残していきます。**

## ディレクトリ構成

```bash
reverse-proxy-django/
│── .env                   # 環境変数ファイル（SECRET_KEY など）
│── docker-compose.yml     # Docker Compose ファイル
│── nginx/
│   ├── default.conf       # Nginx 設定ファイル（リバースプロキシ設定）
│── django_app/
│   ├── Dockerfile         # Django の Dockerfile
│   ├── requirements.txt   # Django の依存関係（Django, Gunicorn）
│   ├── manage.py          # Django 管理コマンド
│   ├── templates/         # Django のテンプレートディレクトリ（将来的に使用）
│   └── mysite/            # Django プロジェクト
│       ├── __init__.py    
│       ├── settings.py    # Django の設定ファイル
│       ├── urls.py        # ルーティング設定
│       ├── wsgi.py        # WSGI アプリケーションのエントリーポイント
│── nginx.Dockerfile       # Nginx の Dockerfile
│── deploy/                # 将来のデプロイ用スクリプトや設定を格納
```

## 各ファイルの役割

| ファイル/フォルダ                  | 役割 |
|----------------------------------|----------------------------------------------------|
| `.env`                           | Django の環境変数（SECRET_KEY など） |
| `docker-compose.yml`             | Docker Compose の設定ファイル |
| `nginx/`                         | Nginx の設定ファイルを格納 |
| `nginx/default.conf`             | Nginx のリバースプロキシ設定 |
| `django_app/`                    | Django アプリのルートディレクトリ |
| `django_app/Dockerfile`          | Django の Docker イメージを作成 |
| `django_app/requirements.txt`    | Django の依存パッケージ一覧 |
| `django_app/manage.py`           | Django の管理コマンドスクリプト |
| `django_app/templates/`          | Django のテンプレートを格納するディレクトリ |
| `django_app/mysite/`             | Django のメインアプリケーション |
| `django_app/mysite/settings.py`  | Django の設定ファイル |
| `django_app/mysite/urls.py`      | Django の URL ルーティング設定 |
| `django_app/mysite/wsgi.py`      | WSGI アプリケーションのエントリーポイント |
| `nginx.Dockerfile`               | Nginx の Docker イメージを作成 |
| `deploy/`                        | 将来のデプロイ用スクリプト（ECS, ECR 用） |

**参考**

https://github.com/free-honda/reverse-proxy-django

## このスクリプトを実行した後にできること

1. **`http://localhost/` にアクセスすると `"Hello, World!"` が表示される**
2. **`docker compose ps` を実行し、Django (`django_app`) と Nginx (`nginx`) が起動していることを確認**
3. **`docker exec -it django_app bash` でコンテナ内に入り、`python manage.py` コマンドが実行可能**

## シェルスクリプトメモ

```bash
#!/bin/bash

set -e

PROJECT_DIR="reverse-proxy-django"

echo "📂 プロジェクトディレクトリを作成: $PROJECT_DIR"
mkdir -p $PROJECT_DIR/nginx $PROJECT_DIR/django_app $PROJECT_DIR/deploy

# ───────────────────────────────────────────────
# 環境変数ファイル（.env）を作成
# ───────────────────────────────────────────────
cat <<EOL > $PROJECT_DIR/.env
DJANGO_DEBUG=True
DJANGO_SECRET_KEY="your-secret-key"
EOL

# ───────────────────────────────────────────────
# Docker Compose ファイル
# ───────────────────────────────────────────────
cat <<EOL > $PROJECT_DIR/docker-compose.yml
services:
  web:
    build: ./django_app
    container_name: django_app
    volumes:
      - ./django_app:/app
    ports:
      - "8000:8000"
    env_file:
      - .env

  nginx:
    build: 
      context: .
      dockerfile: nginx.Dockerfile
    container_name: nginx
    ports:
      - "80:80"
    depends_on:
      - web
EOL

# ───────────────────────────────────────────────
# Django の Dockerfile
# ───────────────────────────────────────────────
cat <<EOL > $PROJECT_DIR/django_app/Dockerfile
FROM python:3.10

WORKDIR /app

COPY requirements.txt /app/

# 環境変数を設定し、pipのバージョンを更新
ENV PIP_NO_CACHE_DIR=off \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_DEFAULT_TIMEOUT=100

RUN pip install --upgrade pip && pip install -r requirements.txt

COPY . /app/

CMD ["gunicorn", "--bind", "0.0.0.0:8000", "mysite.wsgi:application"]
EOL

# ───────────────────────────────────────────────
# Django の requirements.txt
# ───────────────────────────────────────────────
cat <<EOL > $PROJECT_DIR/django_app/requirements.txt
Django==4.2
gunicorn
EOL

# ───────────────────────────────────────────────
# Django アプリの雛形を作成
# ───────────────────────────────────────────────
DJANGO_PROJECT="mysite"
mkdir -p $PROJECT_DIR/django_app/$DJANGO_PROJECT $PROJECT_DIR/django_app/templates

cat <<EOL > $PROJECT_DIR/django_app/manage.py
#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "$DJANGO_PROJECT.settings")
    from django.core.management import execute_from_command_line
    execute_from_command_line(sys.argv)
EOL

chmod +x $PROJECT_DIR/django_app/manage.py

cat <<EOL > $PROJECT_DIR/django_app/$DJANGO_PROJECT/__init__.py
EOL

cat <<EOL > $PROJECT_DIR/django_app/$DJANGO_PROJECT/settings.py
import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = 'your-secret-key'

DEBUG = True

ALLOWED_HOSTS = ["*"]

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = '$DJANGO_PROJECT.urls'

WSGI_APPLICATION = '$DJANGO_PROJECT.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

STATIC_URL = '/static/'

# ✅ `TEMPLATES` 設定を追加（Django管理機能のエラーを防ぐ）
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
EOL

cat <<EOL > $PROJECT_DIR/django_app/$DJANGO_PROJECT/urls.py
from django.urls import path
from django.http import HttpResponse

def hello_world(request):
    return HttpResponse("Hello, World!")

urlpatterns = [
    path('', hello_world),
]
EOL

cat <<EOL > $PROJECT_DIR/django_app/$DJANGO_PROJECT/wsgi.py
import os
from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "$DJANGO_PROJECT.settings")

application = get_wsgi_application()
EOL

# ───────────────────────────────────────────────
# Nginx の Dockerfile
# ───────────────────────────────────────────────
cat <<EOL > $PROJECT_DIR/nginx.Dockerfile
FROM nginx:alpine

COPY nginx/default.conf /etc/nginx/conf.d/default.conf
EOL

# ───────────────────────────────────────────────
# Nginx の設定ファイル
# ───────────────────────────────────────────────
cat <<EOL > $PROJECT_DIR/nginx/default.conf
server {
    listen 80;
    
    location / {
        proxy_pass http://web:8000;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    }
}
EOL

# ───────────────────────────────────────────────
# 実行と確認
# ───────────────────────────────────────────────
echo "🎉 Django プロジェクトの初期化"
cd $PROJECT_DIR/django_app
docker run --rm -v $(pwd):/app python:3.10 bash -c "cd /app && pip install -r requirements.txt && python manage.py migrate"

cd ..
echo "🐳 Docker コンテナをビルドして起動"
docker compose build
docker compose up -d

echo "✅ セットアップ完了！ http://localhost/ にアクセスしてください。"
```

## まとめ
この記事は、自分用の備忘録としてまとめたものです。その点をご理解いただけると幸いです。

:::note info
***もし、この記事の内容が少しでも参考になれば嬉しく思います。***
:::

今後も同様の内容を継続して投稿していきますので、温かく見守っていただけるとありがたいです。