본문 바로가기
코딩 연습

리눅스 가상서버 환경에서 장고(django) 서버 구동을 위한 nginx, gunicorn 설치해보기

by good4me 2022. 8. 21.

goodthings4me.tistory.com

리눅스 서버 설치에 필요한 명령어 몇 개만 알고 있는 수준에서 서버를 세팅하고 Gunicorn과 Nginx를 설치하는 것이 쉽지는 않았지만, 구글에서 열심히 찾아가며 여러 번의 시행착오 끝에 설치를 마무리했고 정상적으로 작동하는 것을 확인했다.

 

 

파이썬 장고(django) 구동을 위한 gunicorn, nginx 설치

이전 포스팅에서 카페 24 가상 서버 호스팅 신청과 가상 환경을 설정하고 장고(django)를 설치했고, VS Code에서 원격서버를 설정을 했다. 이번에는 django 기반 웹 개발 코드를 배포하기 위해 리눅스 환경에서 Gunicorn과 Nginx를 설치하고 django를 구동시켜 본 초보자의 경험을 작성해본다.

 

[장고 설치 후 로컬 테스트 서버 구동 확인]

서버에 장고 설치 후 
ALLOWED_HOSTS = [ ]을 ALLOWED_HOSTS = ['*']로 수정 후
python manage.py runserser 0.0.0.0:8000 또는 0:80 으로 개발 서버 구동 테스트

root@kdjango:~# cd ktest
root@kdjango:~/ktest# cd venv/
root@kdjango:~/ktest/venv# ls
bin  include  lib  lib64  pyvenv.cfg
root@kdjango:~/ktest/venv# cd bin/
root@kdjango:~/ktest/venv/bin# ls
activate      activate.fish  django-admin     pip   pip3.8       python   python3.8
activate.csh  Activate.ps1   django-admin.py  pip3  __pycache__  python3  sqlformat
root@kdjango:~/ktest/venv/bin# source activate
(venv) root@kdjango:~/ktest/venv/bin# python -V
Python 3.8.13
(venv) root@kdjango:~/ktest/venv/bin# django-admin --version
3.2
(venv) root@kdjango:~/ktest/venv/bin# 

(venv) root@kdjango:~/ktest# python manage.py runserver 0.0.0.0:8000
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
August 20, 2022 - 14:44:03
Django version 3.2, using settings 'config.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
[20/Aug/2022 14:44:08] "GET / HTTP/1.1" 200 10773
[20/Aug/2022 14:44:08] "GET /static/admin/css/fonts.css HTTP/1.1" 304 0
[20/Aug/2022 14:44:10] "GET /static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 304 0
[20/Aug/2022 14:44:10] "GET /static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 304 0
[20/Aug/2022 14:44:10] "GET /static/admin/fonts/Roboto-Bold-webfont.woff HTTP/1.1" 304 0
Not Found: /favicon.ico
[20/Aug/2022 14:44:10] "GET /favicon.ico HTTP/1.1" 404 1995

브라우저로 http://localhost:8000 접속 결과, 정상 작동 확인

아래 명령들도 이상없이 수행됨

(venv) root@kdjango:~/ktest# python manage.py runserver 0:8000

(venv) root@kdjango:~/ktest# python3 manage.py runserver 0:8000

(venv) root@kdjango:~/ktest# python manage.py runserver 210.xxx.xxx.xxx:80

(venv) root@kdjango:~/ktest# python3 manage.py runserver 210.xxx.xxx.xxx:80

settings.py를 아래처럼 하고
ALLOWED_HOSTS = ['210.xxx.xxx.xxx', '*']

아래처럼 테스트 서버 구동 시

(venv) root@kdjango:~/ktest# python manage.py runserver 0.0.0.0:80

(venv) root@kdjango:~/ktest# python3 manage.py runserver 0.0.0.0:80

http://localhost/ 또는 http://210.xxx.xxx.xxx/ 모두 접속이 됨

 

good4me.co.kr

 

[gunicorn 설치했으나 실행 오류]

project root 폴더(root@kdjango:~/ktest# )에서 가상 환경이 아닌 상태에서 gunicorn을 설치해서 명령을 줬으나 failed가 났음

root@kdjango:~/ktest# pip3 install gunicorn
Collecting gunicorn
  Downloading https://files.pythonhosted.org/packages/e4/dd/5b190393e6066286773a67dfcc2f9492058e9b57c4867a95f1ba5caf0a83/gunicorn-20.1.0-py3-none-any.whl (79kB)
    100% |████████████████████████| 81kB 9.1MB/s 
Requirement already satisfied: setuptools>=3.0 in /usr/lib/python3/dist-packages (from gunicorn)
Installing collected packages: gunicorn
Successfully installed gunicorn-20.1.0
root@kdjango:~/ktest#

# gunicorn 위치 확인
root@kdjango:~/ktest# whereis gunicorn
gunicorn: /usr/local/bin/gunicorn
root@kdjango:~/ktest#

 

gunicorn의 내용이 궁금해서 아래 명령으로 확인을 해보니 다음과 같았다.
vi /usr/local/bin/gunicorn

#!/usr/bin/python3

# -*- coding: utf-8 -*-
import re
import sys

from gunicorn.app.wsgiapp import run

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(run())
~                                                                                                                     
"/usr/local/bin/gunicorn" 11L, 221C

 

 

 

가상 환경에서 gunicorn을 설치하다

(venv) root@kdjango:~/ktest# pip install gunicorn
Collecting gunicorn
  Using cached gunicorn-20.1.0-py3-none-any.whl (79 kB)
Requirement already satisfied: setuptools>=3.0 in ./venv/lib/python3.8/site-packages (from gunicorn) (56.0.0)
Installing collected packages: gunicorn
Successfully installed gunicorn-20.1.0
(venv) root@kdjango:~/ktest#

# gunicorn 위치 확인
(venv) root@kdjango:~/ktest# whereis gunicorn
gunicorn: /root/ktest/venv/bin/gunicorn
(venv) root@kdjango:~/ktest#
(venv) root@kdjango:~/ktest/venv/bin# ls
activate      activate.fish  django-admin     gunicorn  pip3    __pycache__  python3    sqlformat
activate.csh  Activate.ps1   django-admin.py  pip       pip3.8  python       python3.8
(venv) root@kdjango:~/ktest/venv/bin# cd ~

# gunicorn 명령 실행
(venv) root@kdjango:~/ktest# gunicorn --bind 0:8000 config.wsgi:application
[2022-08-20 17:50:42 +0900] [28286] [INFO] Starting gunicorn 20.1.0
[2022-08-20 17:50:42 +0900] [28286] [INFO] Listening at: http://0.0.0.0:8000 (28286)
[2022-08-20 17:50:42 +0900] [28286] [INFO] Using worker: sync
[2022-08-20 17:50:42 +0900] [28288] [INFO] Booting worker with pid: 28288
Not Found: /favicon.ico

gunicorn을 설치했으니 장고를 불러오는지 확인하기 위해 manage.py가 있는 경로에서 gunicorn --bind 0:8000 config.wsgi:application 와 같이 명령을 실행하고 브라우저로 http://210.xxx.xxx.xxx:8000/ 접속하니 정상 작동했다.

 

위 명령을 풀어서 보면,

--bind 0:8000은 8000번 포트로 WSGI 서버를 수행한다는 의미이고, 
config.wsgi:application은 WSGI 서버와 연결된 WSGI 애플리케이션이 config/wsgi.py 파일의 application이라는 의미이다.

 

여기서 주지해야 할 사항은,

--bind 0:8000 포트 방식이 아닌 유닉스 소켓 방식인 --bind unix:/tmp/gunicorn.sock 으로 Gunicorn 서버를 단독으로 실행할 수 없다고 하며, 이를 해결하기 위해서  Nginx와 같은 웹 서버가 반드시 필요하고 Gunicorn 서비스를 서버에 등록해야 한다고 한다.

 

 

[서버에 Gunicorn 서비스로 등록해보기]

/etc/systemd/system/ 디렉토리에 gunicorn.service 파일을 아래와 같은 내용으로 생성한다.
(/etc/systemd/system/gunicorn.service)

 

(venv) root@kdjango:~# vi /etc/systemd/system/gunicorn.service

vi 에디터에서
i 누르고 <insert mode>, 
아래 내용을 복사 & 붙여넣기 후

# 입력 내용
-----------------------------------------------
[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=/root/ktest
ExecStart= /root/ktest/venv/bin/gunicorn \
        --workers 2 \
        --bind unix:/tmp/gunicorn.sock \
        config.wsgi:application

[Install]
WantedBy=multi-user.target
--------------------------------------------------

저장하기 위해서는
ESC 누르고 :wq! 엔터
(그냥 나갈 때는 :q! 엔터)

위 내용을 설명하면,

  • User, Group은 <서버 계정>
  • WorkingDirectory는 작업 디렉토리로 manage.py가 있는 폴더이고,
  • ExecStart는 gunicorn 설치 경로 (가상 환경에서 설치했기 때문에 위와 같이 되며, whereis gunicorn 명령으로 알 수 있음)
  • --workers 2 는 CPU 코어(Core) 개수를 의미하는 것으로 Gunicorn 프로세스를 2개 사용하라는 의미 (gunicorn Document에서 권장하는 worker process 개수는 Core 수 * 2 +1개이며, grep -c processor /proc/cpuinfo 명령으로 확인 가능)
  • --bind unix:/tmp/gunicorn.sock은 bind 할 소켓을 지정함 (unix:PATH를 사용하면 소켓 파일을 생성하는 것으로 PATH 즉, /tmp/gunicorn.sock/ 파일이 생성되며, 이 소켓 파일은 nginx에서 gunicorn으로의 reverse proxy를 구성할 때 path로 지정할 수 있음)
  • config.wsgi:application 즉, [프로젝트명].wsgi:application로 wsgi가 있는 위치와 wsgi 애플리케이션을 지정함

위 명령 실행 후 /etc/systemd/system/에 gunicorn.service 파일이 생성되며,

(venv) root@kdjango:~# ls /etc/systemd/system/
dbus-fi.w1.wpa_supplicant1.service     gunicorn.service             sysinit.target.wants
dbus-org.freedesktop.resolve1.service  multi-user.target.wants      syslog.service
dbus-org.freedesktop.thermald.service  network-online.target.wants  systemd-resolved.service.wants
default.target.wants                   paths.target.wants           timers.target.wants
getty.target.wants                     sockets.target.wants
graphical.target.wants                 sshd.service
(venv) root@kdjango:~#

 

gunicorn 서비스를 시작해려면,

systemctl start gunicorn.service 명령을 주고,

서비스 상태는 systemctl status gunicorn.service 명령으로 확인하고,

서버가 다시 시작될 때 Gunicorn이 자동 실행되도록 enable 옵션(systemctl enable gunicorn.service)을 주어 서비스로 등록한다.

(venv) root@kdjango:~# sudo systemctl daemon-reload
(venv) root@kdjango:~# sudo systemctl start gunicorn.service
(venv) root@kdjango:~# sudo systemctl status gunicorn.service
● gunicorn.service - gunicorn daemon
   Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled)
   Active: active (running) since Sat 2022-08-20 18:32:40 KST; 27s ago
 Main PID: 29637 (gunicorn)
    Tasks: 3 (limit: 1123)
   CGroup: /system.slice/gunicorn.service
           ├─29637 /root/ktest/venv/bin/python3.8 /root/ktest/venv/bin/gunicorn --workers 2 --bind unix:/tmp/gunicorn.
           ├─29639 /root/ktest/venv/bin/python3.8 /root/ktest/venv/bin/gunicorn --workers 2 --bind unix:/tmp/gunicorn.
           └─29640 /root/ktest/venv/bin/python3.8 /root/ktest/venv/bin/gunicorn --workers 2 --bind unix:/tmp/gunicorn.

Aug 20 18:32:40 kdjango.cafe24.com systemd[1]: Started gunicorn daemon.
Aug 20 18:32:40 kdjango.cafe24.com gunicorn[29637]: [2022-08-20 18:32:40 +0900] [29637] [INFO] Starting gunicorn 2
Aug 20 18:32:40 kdjango.cafe24.com gunicorn[29637]: [2022-08-20 18:32:40 +0900] [29637] [INFO] Listening at: unix:
Aug 20 18:32:40 kdjango.cafe24.com gunicorn[29637]: [2022-08-20 18:32:40 +0900] [29637] [INFO] Using worker: sync
Aug 20 18:32:40 kdjango.cafe24.com gunicorn[29637]: [2022-08-20 18:32:40 +0900] [29639] [INFO] Booting worker with
Aug 20 18:32:40 kdjango.cafe24.com gunicorn[29637]: [2022-08-20 18:32:40 +0900] [29640] [INFO] Booting worker with
lines 1-16/16 (END)

 

NginX를 설치하고 구동시켜보기

 

[Nginx  설치]

(venv) root@kdjango:~/ktest# sudo apt install nginx

nginx를 설치하면 /etc/nginx/sites-available 디렉터리에 설정 파일을 저장하는데, 실제 nginx는 /etc/nginx/sites-enabled 경로에 있는 파일을 보고 있다고 한다.

sites-enabled 디렉터리는 site-available 디렉터리에 있는 설정 파일 중에서 활성화하고 싶은 것을 링크로 관리하는 디렉터리이다.

부연 설명을 하면, sites-available 폴더는 설정을 저장하는 곳이고, 이 안의 설정 파일은 실제로 반영이 되지는 않기 때문에 실제로 반영이 되는 폴더인 sites-enabled 폴더로 설정 파일을 복사해주어야 한다. (sites-enabled 디렉터리는 site-available 디렉터리에 있는 설정 파일 중에서 활성화하고 싶은 것을 링크로 관리하는 디렉터리임)

이런 이유로 인해 /etc/nginx/sites-available/ 경로에 원하는 사이트(내용)를 입력한 뒤 /etc/nginx/sites-enabled로 링크를 걸어주는 게 정석이라고 한다.

 

[Nginx 설정]

내 프로젝트 서비스에 대한 Nginx의 설정 파일(sites-available 디렉터리에 설정 파일)을 생성하고 관리자 권한으로 내용 입력 후 저장한다.

그리고 sites-available 폴더는 설정을 저장하는 곳이기 때문에, 이 안의 설정 파일은 실제로 반영이 되지는 않는다. 따라서 실제로 반영이 되는 폴더인 sites-enabled 폴더로 설정 파일을 복사해주어야 한다.

(venv) root@kdjango:~/ktest# vi /etc/nginx/sites-available/ktest

# 입력 내용은 아래와 같다
---------------------------------------------------
server {
    listen 80;
    server_name 210.xxx.xxx.xxx;

    location /favicon.ico { access_log off; log_not_found off; }

    location / {
        include proxy_params;
        proxy_pass http://unix:/tmp/gunicorn.sock;
    }
}
---------------------------------------------------

(venv) root@kdjango:~/ktest# ls  /etc/nginx/sites-enabled/
default
(venv) root@kdjango:~/ktest# ls /etc/nginx/sites-available
default  ktest
(venv) root@kdjango:~/ktest#

위 코드의 의미는

  • 클라이언트에서 IP주소 80으로 요청을 보내면 gunicorn의 유닉스 소켓으로 보내서(즉, gunicorn으로 연결되어) 요청이 처리된다는 의미이고,
  • listen 80은 웹 서버를 HTTP 프로토콜의 기본 포트인 80 포트로 서비스한다는 의미임
  • 따라서 이제 http://210.xxx.xxx.xxx:8000/ 대신 포트를 생략하여 http://210.xxx.xxx.xxx 처럼 웹 브라우저에서 접속할 수 있다.

이제 작성한 ktest 파일을 Nginx가 환경 파일로 읽을 수 있도록 설정해야 한다.
nginx - gunicorn - django 연결을 위해서 sites-enabled 디렉터리로 설정 파일을 복사해야 한다.

이제 default 링크는 삭제하고 ktest 파일을 링크하도록 변경해보자.
먼저 다음처럼 /etc/nginx/sites-enabled 디렉터리로 이동해서 default 링크를 삭제하자

(venv) root@kdjango:~/ktest# cd /etc/nginx/sites-enabled
(venv) root@kdjango:/etc/nginx/sites-enabled# ls
default
(venv) root@kdjango:/etc/nginx/sites-enabled# sudo rm default
(venv) root@kdjango:/etc/nginx/sites-enabled# ls
(venv) root@kdjango:/etc/nginx/sites-enabled#

# 그리고 다음처럼 ktest 파일을 링크하자
(venv) root@kdjango:/etc/nginx/sites-enabled# sudo ln -s /etc/nginx/sites-available/ktest /etc/nginx/sites-enabled(venv) root@kdjango:/etc/nginx/sites-enabled# ls
ktest
(venv) root@kdjango:/etc/nginx/sites-enabled#
(venv) root@kdjango:/etc/nginx/sites-enabled# cd ~
(venv) root@kdjango:~# cd ktest/
(venv) root@kdjango:~/ktest# ls
accounts  config  db.sqlite3  layout  manage.py  shortener  venv
(venv) root@kdjango:~/ktest#

# 내용이 맞는지 확인해보기
(venv) root@kdjango:~/ktest# cat /etc/nginx/sites-enabled/ktest
server {
    listen 80;
    server_name 210.xxx.xxx.xxx;

    location /favicon.ico { access_log off; log_not_found off; }

    location / {
        include proxy_params;
        proxy_pass http://unix:/tmp/gunicorn.sock;
    }
}
(venv) root@kdjango:~/ktest#

 

[Nginx 실행]

Nginx는 설치할 때 자동으로 실행되므로 앞에서 작성한 Nginx 설정을 적용하려면 Nginx를 sudo systemctl restart nginx 명령으로 다시 시작해야 한다.

또한 시작 전에 먼저 수행해야 하는 사항으로 nginx 설정 파일 문법 검사 명령(sudo nginx -t)을 주어야 한다.

(venv) root@kdjango:~/ktest# sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
(venv) root@kdjango:~/ktest#

설정 파일에 문제가 없다면, nginx를 재시작해서 설정 파일을 적용하자

(venv) root@kdjango:~/ktest# sudo systemctl restart nginx.service
(venv) root@kdjango:~/ktest# sudo systemctl status nginx.service
● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: active (running) since Sat 2022-08-20 19:00:19 KST; 7s ago
     Docs: man:nginx(8)
  Process: 31432 ExecStop=/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid (code=exited,
  Process: 31435 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
  Process: 31434 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
 Main PID: 31436 (nginx)
    Tasks: 7 (limit: 1123)
   CGroup: /system.slice/nginx.service
           ├─31436 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
           ├─31437 nginx: worker process
           ├─31438 nginx: worker process
           ├─31439 nginx: worker process
           ├─31440 nginx: worker process
           ├─31441 nginx: worker process
           └─31442 nginx: worker process

Aug 20 19:00:19 kdjango.cafe24.com systemd[1]: Starting A high performance web server and a reverse proxy server..
Aug 20 19:00:19 kdjango.cafe24.com systemd[1]: Started A high performance web server and a reverse proxy server.
lines 1-20/20 (END)

Nginx를 중지/시작/상태 확인 명령은 다음과 같다.
sudo systemctl stop nginx
sudo systemctl start nginx
sudo systemctl status nginx

 

 

※ Gunicorn & Nginx 실행 명령어 정리

# 가상환경 진입
---------------
root@kdjango:~/ktest# cd venv/bin/
root@kdjango:~/ktest/venv/bin# source activate


# Gunicorn 실행 명령어
-----------------------
(venv) root@kdjango:~/ktest# sudo systemctl daemon-reload
(venv) root@kdjango:~/ktest# sudo systemctl start gunicorn.service
(venv) root@kdjango:~/ktest# sudo systemctl status gunicorn.service
(venv) root@kdjango:~/ktest# sudo systemctl enable gunicorn.service

(venv) root@kdjango:~/ktest# sudo systemctl enable gunicorn.service
Created symlink /etc/systemd/system/multi-user.target.wants/gunicorn.service → /etc/systemd/system/gunicorn.service.
(venv) root@kdjango:~/ktest#

# Gunicorn 서비스 종료
-------------------------
(venv) root@kdjango:~/ktest# sudo systemctl stop gunicorn.service

# Gunicorn 서비스 재 시작
-------------------------
(venv) root@kdjango:~/ktest# sudo systemctl restart gunicorn.service

Django framework 사용 시, views.py 등 django 내부 파일 수정 후에는 
sudo systemctl restart gunicorn 명령어로 gunicorn 재시작 해주어야 서버에 반영된다.


# Nginx 재시작 전
-----------------
(venv) root@kdjango:~/ktest# sudo nginx -t

# Nginx 재시작
-------
(venv) root@kdjango:~/ktest# sudo systemctl restart nginx
 
# Nginx 중지/시작/상태 명령
----------------------------
(venv) root@kdjango:~/ktest# sudo systemctl stop nginx
(venv) root@kdjango:~/ktest# sudo systemctl start nginx
(venv) root@kdjango:~/ktest# sudo systemctl status nginx

 

댓글