Nginx + Gunicorn으로 Django 배포하기

장윤성·2024년 3월 5일
1
post-thumbnail

왜..?

일단, python manage.py runserver 는 배포할 때는 사용하면 안된다. 간단하게 말하자면 runserver 로 실행하는 것이 보안에 매우 취약하기 때문이다.

"""
HTTP server that implements the Python WSGI protocol (PEP 333, rev 1.21).

Based on wsgiref.simple_server which is part of the standard library since 2.5.

This is a simple server for use in testing or debugging Django apps. It hasn't
been reviewed for security issues. DON'T USE IT FOR PRODUCTION USE!
"""

더 자세한 내용은 https://twowix.me/85 여기에 참고하면 좋다.

참고

참고로 [] 대괄호 안에 있는 것들은 사용자 환경에 맞춰서 다르게 입력해줘야 하는 것이니깐 그대로 복붙하면 안된다.

작동 방식

Spring이랑은 다르게 Django는 gunicorn이라는 wsgi 기술을 사용한다. 그나저나 wsgi가 뭐냐면 파이썬 어플리케이션이 웹 서버와 통신하기 위한 인터페이스다.

쉽게 말해서 웹서버에서 오는 요청을 해석해서 파이썬 애플리케이션으로 던져준다고 생각하면 된다.

대충 뭐 이런 느낌이다.

Django 주소, 포트 설정

내가 작업하고 있는 서버의 ip랑 서비스 도메인 주소를 추가로 넣어준다. 아니면 오류 뜸

# setting.py
ALLOWED_HOSTS = ['127.0.0.1','www.recommendu.kro.kr',...]

Gunicorn 설정

pip3 install gunicorn

설치한 이후에 gunicorn이 제대로 작동하는지 체크한다.

cd [manage.py 있는 디렉토리]
gunicorn --bind 0.0.0.0:8000 [project name].wsgi:application

이렇게 나오면 잘 작동하는거다. 만약에 실패했으면 Worker failed to boot 라는 메시지가 나온다. 아마 실패했을 때는 디렉토리 위치랑 프로젝트 이름을 잘못 입력한거다

참고로 [project name].wsgi:application 이거는 프로젝트 내의 wsgi.py안에 있는 application을 실행하는 코드다.

Gunicorn service 만들기

잘 돌아가는거 확인했으니깐 이제 Gunicorn.service를 통해서 만들어보자 service를 만드는 이유는 nginx를 연결하기 위함이다.

일단 두 가지 방법이 있는데 첫번째 방법은 socket을 사용하는 방법, 나머지 하나는 socket을 사용하지 않는 방법이 있다. socket으로 통신하는 방법이 속도 측면에서 성능이 더 좋기 때문에 먼저 socket으로 해보고 만약에 실행이 안되면 두번째 방법으로 하는 것을 추천한다.

Gunicorn.socket 만들기

socket 만드는 코드가 없어서 찾는데 진짜 애먹었다. 자동으로 만들어 주는 거인줄 알았는데 사실 내가 만들어야되는거였음..;;; 일단 파일 위치가 굉장히 중요하다. 서버 제일 상위 폴더로 이동하면 etc/ 라는 폴더가 있을 텐데 거기서부터 시작하면 된다. (폴더 새로 만드는거 아님)

cd /etc/systemd/system
vi gunicorn.socket

이후에 이렇게 만들어주면 된다. vi 사용법은 여기 참고하면 좋다.https://blockdmask.tistory.com/25

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

Gunicorn.service 만들기

얘도 마찬가지로 같은 위치에 만들어준다.

cd /etc/systemd/system
vi gunicorn.service

이후에 이렇게 만들어준다.

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket (조금전에 직접 만든 socket 파일 이름)
After=network.target

[Service]
User=user
Group=user
WorkingDirectory=[project directory]
ExecStart=[virtual environment directory] --workers 1 --bind unix:/run/gunicorn.sock 
					\ [project name].wsgi:application

[Install]
WantedBy=multi-user.target

나는 이렇게 입력했다. 혹시나 [] 이 안에 부분이 헷갈리면 참고했으면 좋겠다.

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket (조금전에 직접 만든 socket 파일 이름)
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=/home/recommendu/recommendu
ExecStart=/home/recommendu/first/bin/gunicorn --workers 1 --bind 0.0.0.0:30001 recommendu.wsgi:application

[Install]
WantedBy=multi-user.target

이렇게 다 만들었다면 이렇게 명령어를 입력하면 된다.

sudo systemctl enable gunicorn.socket // socket 실행
sudo systemctl start gunicorn.socket // socket 실행
sudo systemctl daemon-reload // 파일을 변경했을때 변경한 내용 적용
sudo systemctl enable gunicorn //서버 재시작시 자동으로 실행
sudo systemctl start gunicorn // 서비스 실행
sudo systemctl status gunicorn //실행한 서비스 상태

여기서 sudo systemctl status gunicorn 이 명령어를 치면

이렇게 잘뜬다.

잘 뜨긴 하는데..

gunicorn이 작동하는거 같긴 한데 막상 사이트에 들어가보면 err connection refused 이렇게 뜨는 경우가 있다. 이런 경우에는 socket이 문제인 경우이기 때문에 socket을 꺼주고 service를 수정해야한다.

sudo systemctl stop gunicorn.socket // socket 정지
sudo systemctl stop gunicorn // service 정지
cd /etc/systemd/system
vi gunicorn.service

socket 쓰는거 대신에 바로 url을 박아준다.

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=[project directory]
ExecStart=[virtual environment directory] --workers 1 --bind 0.0.0.0:[port] 
					\ [project name].wsgi:application

[Install]
WantedBy=multi-user.target

그리고 socket은 냅두고 service만 실행해준다. 대신에 sudo systemctl daemon-reload 이거는 반드시 먼저 입력해줘야지 변경이 적용된다.

sudo systemctl daemon-reload // 파일을 변경했을때 변경한 내용 적용
sudo systemctl enable gunicorn //서버 재시작시 자동으로 실행
sudo systemctl start gunicorn // 서비스 실행
sudo systemctl status gunicorn //실행한 서비스 상태

nginx란?

gunicorn을 연결했으면 거의 다한거다. 사실 gunicorn만 사용해도 되는데 최적화와 정적 파일(img, css 등)을 서비스에 적용하기 위해서 사용한다. 그 외에 이런 역할들을 한다.


정적 파일 제공(이거 때문에 nginx를 사용하긴 했다.)
한 번에 들어오는 많은 요청을 처리
느린 클라이언트 처리
동적 요청을 wsgi에 전달
SSL (https) **(nginx를 사용해야하는 가장 큰이유 중에 하나임)
Python 코드와 비교하여 컴퓨팅 리소스 (CPU 및 메모리) 절약
로드 밸런싱, 캐싱 등

nginx는 pip가 아니라 우분투로 깔아야된다.

sudo apt-get update
sudo apt-get install nginx

nginx 적용하기

nginx는 하나만 생성해주면 된다. sites-available이라는 폴더안에 [project name]파일을 생성해준다/

cd /etc/nginx/sites-available
vi [project name]

이 파일 안에 nginx 세팅을 진행하면 된다. socket을 사용해서 gunicorn을 연결한 경우는 아래꺼


server {
		listen 80;
    server_name [ip address];

    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
		location /static/ {
        alias [project directory]/static/;
    }
}

socket을 사용하지 않은 경우는 이렇게 입력한다.

server {
		listen 80;
    server_name [ip address];

    location / {
        include proxy_params;
        proxy_pass http://0.0.0.0:[port];
    }
		location /static/ {
        alias [project directory]/static/;
    }
}

그나저나 /static/ 이 부분이 뭐냐면 gunicorn에서는 정적 파일이 적용이 안되기 때문에 nginx에 직접 연결 시켜주기 위한 코드이다.

그 다음으로 sites-enabled 를 만들어줄건데 무조건 아래의 코드로 복붙을 해줘야된다.

sudo ln -s /etc/nginx/sites-available/[project name] /etc/nginx/sites-enabled

그 다음으로 nginx 데몬 재부팅만 해주면 끝이다.

sudo systemctl restart nginx
sudo systemctl status nginx

이렇게 입력하고 나서 아래의 화면이 뜨면 된거다.

만약에 에러가 뜨면 아래 명령어로 확인할 수 있다.

tail -f /var/log/nginx/error.log
profile
소개를 어떻게 한줄로 해요..

0개의 댓글