View on GitHub

バックエンドのデプロイ

Home

バックエンドのデプロイ

バックエンドサーバ側

CertbotによるSSL証明書の発行

既に、サーバ側で下記のドメインの設定が完了していることを前提とします。

rsl@*:$ less /etc/nginx/sites-enabled/default
rsl@*:$ sudo certbot --nginx -d recsys-full.recsyslab.org
rsl@*:$ sudo certbot renew --dry-run
rsl@*:$ less /etc/nginx/sites-enabled/recsys_full

Nginx の設定

rsl@*:$ ls /etc/nginx/sites-available/
rsl@*:$ less /etc/nginx/sites-available/default
rsl@*:$ sudo vi /etc/nginx/sites-available/recsys_full

/etc/nginx/sites-available/recsys_full

server {
    server_name recsys-full.recsyslab.org; # managed by Certbot

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/recsys-full.recsyslab.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/recsys-full.recsyslab.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    root /usr/share/nginx/html;

    # --- Static (collectstatic の出力先) ---
    # Django settings.py の STATIC_ROOT と一致させること
    location /static/ {
        alias /home/rsl/dev/recsys-full/src/backend/static/;
        access_log off;
        expires 30d;
        add_header Cache-Control "public, max-age=2592000";
    }

    # --- Media (MEDIA_ROOT) ---
    # Django settings.py の MEDIA_ROOT と一致させること
    location /media/ {
        alias /home/rsl/dev/recsys-full/src/backend/media/;
        access_log off;
        expires 30d;
        add_header Cache-Control "public, max-age=2592000";
    }

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X_Forwarded-Proto $scheme;

        proxy_pass http://127.0.0.1:8000;
    }

    error_page 404 /404.html;
    location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }

    # index.html等はファイル名の指定なしで実行
    index index.html index.htm index.nginx-debian.html;
}
rsl@*:$
 ls /etc/nginx/sites-available/
 less /etc/nginx/sites-available/recsys_full
 ls -al /etc/nginx/sites-enabled/
 sudo ln -s /etc/nginx/sites-available/recsys_full /etc/nginx/sites-enabled/
 sudo unlink /etc/nginx/sites-enabled/default
 ls -al /etc/nginx/sites-enabled/
 cd ~/dev/recsys-full/src/backend/

rsl@*:backend$ source ~/venv/recsys_full/bin/activate
(recsys_full) rsl@*:backend$ python manage.py collectstatic
(recsys_full) rsl@*:backend$ ls static/
(recsys_full) rsl@*:backend$ deactivate

rsl@*:backend$ namei -l /home/rsl/dev/recsys-full/src/backend/static/rest_framework/css/bootstrap.min.css
f: /home/rsl/dev/recsys-full/src/backend/static/rest_framework/css/bootstrap.min.css
drwxr-xr-x root root /
drwxr-xr-x root root home
drwxr-x--- rsl  rsl  rsl
drwxrwxr-x rsl  rsl  dev
drwxrwxr-x rsl  rsl  recsys-full
drwxrwxr-x rsl  rsl  src
drwxrwxr-x rsl  rsl  backend
drwxrwxr-x rsl  rsl  static
drwxrwxr-x rsl  rsl  rest_framework
drwxrwxr-x rsl  rsl  css
-rw-r--r-- rsl  rsl  bootstrap.min.css

rsl@*:backend$ sudo chmod o+rx /home/rsl/
rsl@*:backend$ namei -l /home/rsl/dev/recsys-full/src/backend/static/rest_framework/css/bootstrap.min.css
f: /home/rsl/dev/recsys-full/src/backend/static/rest_framework/css/bootstrap.min.css
drwxr-xr-x root root /
drwxr-xr-x root root home
drwxr-xr-x rsl  rsl  rsl
drwxrwxr-x rsl  rsl  dev
drwxrwxr-x rsl  rsl  recsys-full
drwxrwxr-x rsl  rsl  src
drwxrwxr-x rsl  rsl  backend
drwxrwxr-x rsl  rsl  static
drwxrwxr-x rsl  rsl  rest_framework
drwxrwxr-x rsl  rsl  css
-rw-r--r-- rsl  rsl  bootstrap.min.css

rsl@*:backend$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

rsl@*:backend$ sudo systemctl reload nginx
rsl@*:backend$ curl -I https://recsys-full.recsyslab.org/static/rest_framework/css/bootstrap.min.css
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Date: Tue, 01 Sep 2026 13:11:19 GMT
Content-Type: text/css
Content-Length: 121457
Last-Modified: Fri, 14 Aug 2026 09:14:35 GMT
Connection: keep-alive
ETag: "6a7edc7b-1da71"
Expires: Thu, 01 Oct 2026 13:11:19 GMT
Cache-Control: max-age=2592000
Cache-Control: public, max-age=2592000
Accept-Ranges: bytes

Nginx の起動

rsl@*:$ sudo systemctl start nginx.service
rsl@*:$ systemctl status nginx.service
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Tue 2026-09-01 06:43:37 JST; 15h ago
       Docs: man:nginx(8)
    Process: 2312957 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 2312964 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 2326395 ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload (code=exited, status=0/SUCCESS)
   Main PID: 2312972 (nginx)
      Tasks: 3 (limit: 1060)
     Memory: 4.6M (peak: 7.3M)
        CPU: 793ms
     CGroup: /system.slice/nginx.service
             ├─2312972 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             ├─2326397 "nginx: worker process"
             └─2326398 "nginx: worker process"

Gunicorn の起動

(recsys_full) rsl@*:backend$
 pkill gunicorn
 gunicorn --bind 127.0.0.1:8000 config.wsgi:application -D
 ps ax | grep gunicorn
2326434 ?        Sl     0:00 /home/rsl/venv/recsys_full/bin/python3.12 /home/rsl/venv/recsys_full/bin/gunicorn --bind 127.0.0.1:8000 config.wsgi:application -D
2326435 ?        S      0:00 /home/rsl/venv/recsys_full/bin/python3.12 /home/rsl/venv/recsys_full/bin/gunicorn --bind 127.0.0.1:8000 config.wsgi:application -D
2326438 pts/0    S+     0:00 grep --color=auto gunicorn

Web サーバの動作確認

ブラウザで下記URLにアクセスし、Django REST framework が表示されれば、正常に稼働しています。

ログの確認

サーバにエラーが発生した場合などは、下記コマンドでログを確認できます。

rsl@*:backend$ less logs/django.log

実行確認

Contentフォームに、例えば下記のデータを入力し、POSTボタンをクリックしてください。

{
  "email": "foo@example.com",
  "password": "secret123"
}

データベースで登録されていることを確認してください。

recsys_full=# SELECT * FROM t_users;

更新後の再デプロイ

クライアント側

リポジトリのプッシュ

$
 cd ~/dev/recsys-full/
 git add *
 git add .*
 git commit -m "redeploy"
 git push
 git status

バックエンドサーバ側

リポジトリのプル

rsl@*:$
 cd ~/dev/recsys-full/
 git pull
 git status

マイグレーションの実行

(recsys_full) rsl@*:backend$
 python manage.py makemigrations accounts
 python manage.py makemigrations online
 python manage.py migrate

Nginx の再読込と Gunicorn の再起動

(recsys_full) rsl@*:backend$
 sudo systemctl reload nginx
 pkill gunicorn
 gunicorn --bind 127.0.0.1:8000 config.wsgi:application -D
 ps ax | grep gunicorn

ログの確認

rsl@*:backend$ less logs/django.log

参考

  1. [Django で gunicorn と Nginx を使う(Nginx その 3) Snow Tree in June](https://snowtree-injune.com/2020/11/07/nginx-part3-dj015/)