Gunicorn と nginx を使って VPS に Django アプリをデプロイする方法
Django アプリを VPS にデプロイするには、本番用サーバーで実行し、手前にリバースプロキシを置き、データベースを接続して HTTPS を設定します。 このガイドでは Ubuntu 24.04 LTS、Django 5.2、PostgreSQL、Gunicorn、systemd、nginx を使用します。パスとモジュール名は自分のプロジェクトに合わせて調整してください。
SSH と sudo アクセスがある VPS、それを指すドメイン、動作する Django リポジトリ、依存関係のロックまたは固定された requirements.txt が必要です。例ではプレースホルダーとして example.com、/srv/myapp、myproject.wsgi:application を使用します。対象は WSGI アプリケーションです。アプリで必要な場合は ASGI 構成を使用してください。参照先は 2026年9月9日 に確認しています。
1. サーバーとアプリケーションユーザーを準備する
新しい Ubuntu サーバーに基本パッケージをインストールします:
sudo apt update
sudo apt install -y python3-venv python3-dev build-essential libpq-dev postgresql nginx git
sudo adduser --system --group --home /srv/myapp django
sudo install -d -o django -g django /srv/myappdjango ユーザーは root 権限なしでアプリケーションを実行します。管理用の SSH アクセスは通常のアカウントで維持してください。ファイアウォールのルールを有効にする前に、SSH 接続をファイアウォールで許可し、受信 HTTP と HTTPS を許可してください。PostgreSQL には、アプリが必要とする場所からのみ到達できるようにしてください。
2. PostgreSQL の認証情報を作成する
プロンプトで選んだパスワードでデータベースロールを作成し、そのデータベースを作成します:
sudo -u postgres createuser --pwprompt myapp
sudo -u postgres createdb --owner=myapp myappアプリケーションは 127.0.0.1 に接続します。これは通常の Ubuntu の PostgreSQL セットアップではパスワード認証を使用します。接続に失敗する場合は、pg_hba.conf を確認してください。ローカル認証の問題を解決するために、データベースポートを公開しないでください。
3. アプリケーションと依存関係をインストールする
例のリポジトリ URL は置き換えてください。プライベートリポジトリの場合は、URL やコミット済みファイルにトークンを入れずに読み取りアクセスを用意してください。
sudo -u django git clone https://github.com/your-org/your-app.git /srv/myapp/app
sudo -u django python3 -m venv /srv/myapp/venv
sudo -u django /srv/myapp/venv/bin/pip install -r /srv/myapp/app/requirements.txtrequirements には、Django のバージョン、Gunicorn、およびプロジェクトで使用する PostgreSQL ドライバーを含める必要があります。プロジェクトに別の lockfile がある場合は、既存のパッケージマネージャーを使ってください。settings モジュールと WSGI の import パスがリポジトリと一致していることを確認してください。
4. 本番設定を明示的に読み込む
エディタで /etc/myapp.env を作成します。実際の値は Git ではなくそこに保存してください。この例では、settings がこれらの名前を読み取る前提です:
DJANGO_SECRET_KEY='replace-with-a-long-random-secret'
DJANGO_ALLOWED_HOSTS='example.com'
DJANGO_CSRF_TRUSTED_ORIGINS='https://example.com'
DB_NAME='myapp'
DB_USER='myapp'
DB_PASSWORD='replace-with-the-password-you-set'
DB_HOST='127.0.0.1'
DB_PORT='5432'shell と systemd の environment-file 構文の両方に互換性がある、単純な引用付きの値を使ってください。ファイルを保護します:
sudo chown root:django /etc/myapp.env
sudo chmod 640 /etc/myapp.env本番 settings では、対応する読み取りを設定します。この断片では、BASE_DIR がすでに存在する前提です:
import os
DEBUG = False
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
ALLOWED_HOSTS = os.environ['DJANGO_ALLOWED_HOSTS'].split(',')
CSRF_TRUSTED_ORIGINS = os.environ['DJANGO_CSRF_TRUSTED_ORIGINS'].split(',')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ['DB_NAME'],
'USER': os.environ['DB_USER'],
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': os.environ['DB_HOST'],
'PORT': os.environ['DB_PORT'],
}
}
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'アップロードされたメディアは、collect した static アセットとは分けてください。アップロードされたコンテンツに応じて、耐久性のあるストレージ、バックアップ方針、アクセス制御を選んでください。Django のデプロイチェックリストを参照してください。
5. 設定を確認し、データベースを準備する
サービスと同じ環境で、アプリユーザーとして管理コマンドを実行します:
sudo -u django bash -c 'set -a; . /etc/myapp.env; set +a; cd /srv/myapp/app; /srv/myapp/venv/bin/python manage.py check --deploy'
sudo -u django bash -c 'set -a; . /etc/myapp.env; set +a; cd /srv/myapp/app; /srv/myapp/venv/bin/python manage.py migrate --noinput'
sudo -u django bash -c 'set -a; . /etc/myapp.env; set +a; cd /srv/myapp/app; /srv/myapp/venv/bin/python manage.py collectstatic --noinput'デプロイ警告を確認してください。HTTPS 関連の設定は、プロキシで証明書が正しく動作してから行います。既存の本番データベースがある場合は、スキーマ変更を適用する前にバックアップを取得し、テストしてください。マイグレーションは各 Gunicorn worker ではなく、リリースの一部として一度だけ実行してください。
6. systemd 配下で Gunicorn を実行する
/etc/systemd/system/myapp.service を作成します:
[Unit]
Description=Django application
After=network.target postgresql.service
[Service]
User=django
Group=django
WorkingDirectory=/srv/myapp/app
EnvironmentFile=/etc/myapp.env
ExecStart=/srv/myapp/venv/bin/gunicorn myproject.wsgi:application --bind 127.0.0.1:8001 --workers 2 --access-logfile - --error-logfile -
Restart=on-failure
RestartSec=5
PrivateTmp=true
NoNewPrivileges=true
[Install]
WantedBy=multi-user.targetworker 数 2 は初期例であり、サイジングの公式ではありません。増やす前に、メモリ、データベース接続、応答時間を計測してください。Gunicorn は loopback に bind するので、訪問者は nginx 経由でアプリに到達します。
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myapp --no-pager
curl -I -H 'Host: example.com' http://127.0.0.1:8001/プロセスエラーには journalctl -u myapp を使ってください。通常、import の失敗はモジュールパス、作業ディレクトリ、または依存関係のインストールを示しています。Django の WSGI ガイダンスとGunicornを参照してください。
7. 手前に nginx を置く
/etc/nginx/sites-available/myapp を作成します:
server {
listen 80;
server_name example.com;
location /static/ {
alias /srv/myapp/app/staticfiles/;
}
location / {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}新しいサイトを一度有効にし、設定をテストしてからリロードします:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp
sudo nginx -t
sudo systemctl reload nginxnginx が collect した static ファイルを読み取れ、それらの親ディレクトリをたどれることを確認してください。デフォルトのサイト設定は、他のホスト中ドメインと整合するように保ってください。無関係なサイトを削除しないでください。nginx ガイドでは、リバースプロキシと static ファイルの設定を説明しています。
8. HTTPS を追加し、Django を再確認する
選んだ ACME クライアントとその最新の手順を使って証明書をインストールします。nginx 用に Certbot がインストールされている場合、この例の証明書リクエストは次のとおりです:
sudo certbot --nginx -d example.com
sudo certbot renew --dry-runOS へのインストールは Certbot の手順を使ってください。TLS の完了と見なす前に、ドメイン DNS、HTTP 到達性、更新を確認してください。
HTTPS が動作したら、これらの Django オプションを設定します:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True転送プロトコルヘッダーを信頼するのは、nginx がそれを制御し、Gunicorn が直接公開されていないためです。サービスを再起動し、check --deploy を再実行して、HTTPS でログインとフォーム送信をテストしてください。影響を受けるすべてのホストで HTTPS を確認した後に、HSTS は別途確認してください。
9. 今後のリリースを再現可能にする
各リリースでは、レビュー済みのリビジョンを選び、そのロックされた依存関係をインストールし、互換性のあるマイグレーションを適用し、static ファイルを collect し、サービスを再起動してください。ライブアプリケーションをテストし、変更後にエラーを監視してください。
前のリビジョンは利用可能なままにしてください。ただし、コードを戻してもデータベースマイグレーションが元に戻るとは限りません。スキーマ変更の復旧手順を文書化し、別のデータベースへのデータ復元をテストしてください。
アプリが Celery を使う場合は、別のサービス定義、コマンド、broker 設定を用意してください。Gunicorn サービス内で worker をバックグラウンドの shell コマンドとして実行しないでください。
代わりにマネージドホスティングを選ぶべきとき
サーバーを制御したく、自分で保守できるなら VPS は妥当です。ホスト運用をさらに任せたいなら、Python アプリホスティングの選択肢を比較してください。Lizard では、アプリケーションはManaged Postgresと別の worker を使いながら、コードと設定の制御を維持できます。
デプロイドキュメントでは、その方法を扱っています。それでも、正しい Django 設定、リリース手順、検証済みのデータ復旧計画は必要です。
FAQ
なぜ 502 エラーが出るのですか? Gunicorn が実行中で 127.0.0.1:8001 を listen しているか確認し、その後でそのログと nginx の error log を調べてください。リバースプロキシでは、起動に失敗するプロセスは修正できません。
なぜ static ファイルが見つからないのですか? STATIC_ROOT、collectstatic の出力、nginx の alias パス、ファイル権限を確認してください。アップロードされたメディアには別の設定が必要です。
PostgreSQL の代わりに SQLite を使えますか? 使えるアプリケーションもありますが、並行性、永続性、バックアップ要件を評価してください。アプリケーションのワークロードをテストせずにデータベースエンジンを変更しないでください。
デプロイチェックの成功だけで十分ですか? いいえ。実際のユーザーフロー、データベースへの書き込み、ファイルアクセス、復旧をテストしてください。設定チェックで捕捉できるのは本番動作の一部だけです。
AI で構築。Lizard で公開。
本番公開にプラットフォームチームは必要ありません。クラウド全体が、1 つの CLI コマンドですぐ使えます。
- ワークスペース
- —
- サービス
- —
- アドオン
- —
- デプロイ
- —