個人開発のサービスを「とりあえず動く」から「人に見せられる」状態にするとき、
最初にぶつかるのがデプロイです。ここでは PaaS を使わず、VPS 1台で Django を
本番稼働させる最小構成をまとめます。
全体像
[ブラウザ]
↓ HTTPS
Nginx … TLS終端 / 静的ファイル配信 / リバースプロキシ
↓ UNIXソケット
Gunicorn … Django アプリ本体(systemd で常駐)
↓
SQLite または PostgreSQL
ポイントは Nginx と Gunicorn を UNIX ソケットでつなぐことです。
TCP ポートを開けずに済むので、外部から直接アプリへ到達される経路が減ります。
Gunicorn を systemd で常駐させる
個人開発でいちばん多い事故が「サーバーを再起動したらサービスが上がってこない」
「プロセスが落ちたまま気づかない」です。nohup で起動していると確実に起こります。
systemd に任せると、この2つが同時に解決します。
[Unit]
Description=My Django App
After=network.target
[Service]
User=www-data
Group=www-data
RuntimeDirectory=gunicorn-myapp
WorkingDirectory=/srv/myapp
ExecStart=/srv/myapp/venv/bin/gunicorn config.wsgi:application \
--bind unix:/run/gunicorn-myapp/gunicorn.sock \
--workers 3
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
重要なのは最後の2行です。
Restart=on-failure… プロセスが異常終了したら自動で起動し直すWantedBy=multi-user.target… サーバー再起動時に自動で立ち上がる
RuntimeDirectory を指定しておくと、ソケットを置く /run/... を systemd が
権限つきで作ってくれます。手で mkdir すると再起動時に消えて起動に失敗します。
Nginx 側
upstream myapp {
server unix:/run/gunicorn-myapp/gunicorn.sock fail_timeout=0;
}
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 /static/ { alias /srv/myapp/staticfiles/; expires 30d; }
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://myapp;
}
}
X-Forwarded-Proto を渡すのを忘れると、Django 側が「HTTP で来ている」と誤認します。
SECURE_SSL_REDIRECT = True と組み合わせるとリダイレクトループになるので、
settings 側で必ず次を入れておきます。
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
証明書の自動更新で忘れがちなこと
Let's Encrypt は certbot が自動更新してくれますが、更新後に Nginx をリロード
しないと古い証明書を配信し続けます。certbot の nginx プラグインを使っていない
場合は、更新フックを自分で置く必要があります。
# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/sh
/usr/sbin/nginx -t && /bin/systemctl reload nginx
まとめ
- Gunicorn は必ず systemd 管理にする(自動復旧と自動起動が同時に手に入る)
- Nginx と Gunicorn は UNIX ソケットでつなぐ
X-Forwarded-ProtoとSECURE_PROXY_SSL_HEADERはセットで入れる- 証明書更新後の Nginx リロードをフックで自動化する
この4つを最初に押さえておくと、後から「なぜか落ちている」という時間を大幅に減らせます。