본문 바로가기
  • 실행력이 모든걸 결정한다
Django

[Django] wsgi.py의 역할 및 배포 설정 사항

by 김코더 김주역 2023. 1. 26.
반응형

운영 환경에서는 웹 서버가 클라이언트 요청을 수신하고, 웹 애플리케이션 서버를 통해서 장고의 애플리케이션을 호출하는 식으로 동작한다. 참고로, WSGI 규격을 지킨 웹 애플리케이션 서버를 WSGI 서버라고 부르기도 한다.

이번 포스팅에서는 웹 서버와 장고를 연결해주는 wsgi.py에 대해 알아본 뒤에, 배포 전에 해둬야 할 설정 사항들을 알아볼 것이다.

 

1. wsgi.py

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')

application = get_wsgi_application()

 

- 장고와 웹 서버를 연결하는 데 필요한 파일로, django-admin startproject mysite 명령에 의해 생성된다.

- WSGI 규격을 따라, 호출 가능한 application 객체를 정의하고 있다. 웹 서버는 이 application 객체를 호출하여 장고의 애플리케이션을 실행한다. get_wsgi_application() 메소드는 잠시 후에 들여다보도록 하자.

application = get_wsgi_application()

- application 객체는 운영 웹 서버와 runserver에서 사용된다. runserver에서는 application 객체의 위치를 mysite/settings.py의 WSGI_APPLICATION 속성으로 지정하고, 아파치나 NGINX/uWSGI는 httpd.conf의 WSGIScriptAlias 또는 uwsgi.ini의 module으로 지정한다.

- wsgi.py의 다음 코드는 application 객체를 호출하기 전에 설정 정보를 로딩해주는 코드다. 설정 정보가 담겨 있는 mysite.settings 모듈의 위치를 지정해주고 있다.

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')

또 다른 방법으로, runserver을 실행할 때 settings 실행 옵션으로 settings 모듈의 위치를 지정해주는 방법이 있다. 이 실행 옵션을 생략하면 wsgi.py를 참조한다.

python manage.py runserver --settings=mysite.settings

 

 

 

2. WSGIHandler

- get_wsgi_application() 메소드 내부를 보니 WSGIHandler 객체를 반환하고 있다. 즉, application 객체는 WSGIHandler 객체다.

application = get_wsgi_application()

 

def get_wsgi_application():
    """
    The public interface to Django's WSGI support. Return a WSGI callable.

    Avoids making django.core.handlers.WSGIHandler a public API, in case the
    internal WSGI implementation changes or moves in the future.
    """
    django.setup(set_prefix=False)
    return WSGIHandler()

 

- WSGIHandler 클래스는 WSGI 규격에서 정의한 애플리케이션의 역할을 수행하는 클래스다. WSGIHandler 클래스는 다음과 같이 정의되어 있다.

class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.load_middleware()

    def __call__(self, environ, start_response):
        set_script_prefix(get_script_name(environ))
        signals.request_started.send(sender=self.__class__, environ=environ)
        request = self.request_class(environ)
        response = self.get_response(request)

        response._handler_class = self.__class__

        status = "%d %s" % (response.status_code, response.reason_phrase)
        response_headers = [
            *response.items(),
            *(("Set-Cookie", c.output(header="")) for c in response.cookies.values()),
        ]
        start_response(status, response_headers)
        if getattr(response, "file_to_stream", None) is not None and environ.get(
            "wsgi.file_wrapper"
        ):
            # If `wsgi.file_wrapper` is used the WSGI server does not call
            # .close on the response, but on the file wrapper. Patch it to use
            # response.close instead which takes care of closing all files.
            response.file_to_stream.close = response.close
            response = environ["wsgi.file_wrapper"](
                response.file_to_stream, response.block_size
            )
        return response

WSGIHandler의 __call__() 메소드가 WSGI 규격의 애플리케이션 스펙을 구현한 메소드인데, WSGI 서버에서 WSGIHandler 객체를 호출할 때 실행돼서 마지막에 최종 응답을 반환한다. 정리하자면, 웹 애플리케이션 서버는 wsgi.py를 통해 WSGIHandler 객체를 얻은 뒤에, WSGIHandler 객체를 다시 호출하여 최종 응답을 만들어서 웹 서버에 돌려주는 식으로 동작하는 것이다.

그리고 WSGIHandler의 부모 클래스인 BaseHandler에서는 settings.py의 MIDDLEWARE에 대한 처리를 수행해준다.

 

 

 

3. 장고 프로젝트를 운영 서버에 적용하기 위한 설정 변경 사항

1) 디버그 끄기

- 운영 모드에서는 디버그 정보가 노출되지 않도록 해야 하기 때문에, settings.py의 DEBUG 항목을 False로 지정해두자.

 

 

2) ALLOWED_HOSTS 설정

- settings.py에서 장고가 실행되는 서버의 IP 주소나 도메인명을 등록하는 항목이다. 이 항목을 통해 CSRF 공격을 방지할 수 있다.

- DEBUG를 False로 설정했다면 반드시 ALLOWED_HOSTS 항목을 설정해야 한다.

ALLOWED_HOSTS = ['192.168.46.103']

 

 

3) STATIC_ROOT 설정

- 운영 모드에서는 웹 서버에게 정적 파일의 루트 경로를 알려줘야 하기 때문에, settings.py의 STATIC_ROOT 항목도 설정해야 한다.

STATIC_ROOT = os.path.join(BASE_DIR, 'www_dir', 'static')

위 디렉토리는 웹 서버의 설정 파일에도 등록해야 한다. 자세한 내용은 각 웹 서버의 문서를 참고하자.

 

 

4) STATICFILES_DIRS 설정

- settings.py의 STATICFILES_DIRS 항목에, STATIC_ROOT 항목에서 정의한 디렉토리가 포함되지 않아야 하기 때문에, 이를 체크해주자. 이 이유는 [5) collectstatic 명령]에서 설명할 것이다.

STATICFILES_DIRS = (BASE_DIR / 'static',)

 

 

5) collectstatic 명령

- STATICFILES_DIRS 항목에 정의된 정적 파일을 STATIC_ROOT 디렉토리에 복사해주는 명령이다. 그래서 STATICFILES_DIRS 항목에, STATIC_ROOT 항목에서 정의한 디렉토리가 포함되지 않아야 한다.

- 4)에서 설명한 내용을 잘 준수 했다면, 아래 명령을 실행해주자.

python manage.py collectstatic

 

 

6) SECRET_KEY 설정

- 프로젝트 내에서 암호화에 사용되는 항목이기 때문에 외부에 노출되어서는 안된다. 그래서 운영 모드에서는 환경 변수나 파일에 저장해두고 settings.py에서 읽어들이도록 하는 것이 좋다.

 

환경 변수를 통해 읽어 들이기

# settings.py

import os
SECRET_KEY = os.environ['SECRET_KEY']

 

파일을 통해 읽어 들이기

# settings.py

with open(os.path.join(BASE_DIR, 'www_dir', 'secret_key.txt')) as f:
    SECRET_KEY = f.read().strip()

 

 

7) 데이터베이스 관련 설정

(1) 데이터베이스 파일 접근 권한 설정

- 운영 모드에서 웹 서버 프로세스의 소유자 권한으로 데이터베이스 파일이나 로그 파일을 액세스 할 수 있도록 설정해야 한다.

settings.py의 DATABASES 항목을 다음과 같이 설정했다고 하면

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db', 'db.sqlite3'),
    }
}

다음과 같이 db 디렉토리와 db/db.sqlite3 파일을 읽고 쓸 수 있게 하기 위해 액세스 권한을 변경해주자.

> mkdir db
> mv db.sqlite3 db/
> chmod 777 db/
> chmod 666 db/db.sqlite3

777, 666이라고 되어있는 부분은 모드 변경식을 의미하는데, 모드 변경식을 모른다면 아래 포스팅을 참고하길 바란다.

https://kimcoder.tistory.com/274

 

[Linux] chmod로 접근 권한 지정하기

chmod : change mode 접근 모드를 변경하는 명령어 chmod 명령어를 설명하기 앞서 접근 모드가 무엇인지 알 필요가 있다. 아래 이미지가 명령어 "ls -l"에 대한 출력에서, 접근 모드에 해당하는 부분이다.

kimcoder.tistory.com

 

(2) 데이터베이스 기밀 정보 숨기기

- 데이터베이스의 패스워드와 같은 기밀 정보들이 settings.py에 하드코딩되어있지는 않은지 확인해보자. 환경 변수나 파일에 따로 저장해두고 settings.py에서 읽어들이도록 하는 것이 좋다.

 

 

8) 로그 파일 접근 권한 설정

- 로그 파일에도 다음과 같이 액세스 권한을 부여해주자.

> chmod 777 logs/
> chmod 666 logs/mysite.log

 

 

9) 메일 서버 발신자 주소 변경

- 이메일을 보내는 기능이 있다면 settings.py의 SERVER_EMAIL 및 DEFAULT_SERVER_EMAIL 항목을 정확히 설정해야 한다. 장고는 기본적으로 webmaster@localhost와 root@localhost를 발신자로 사용하는데, 몇몇 이메일 서비스들은 이 주소로 발송된 이메일을 차단하기도 하기 때문에 발신자 주소를 변경해두는 것이 좋다.

 

 

10) 설정 체크

마지막으로, python manage.py check --deploy 명령을 통해 운영 서버에서 필요한 설정들이 제대로 이루어졌는지 체크해보자.

python manage.py check --deploy

 

 

● 참고할만한 자료

운영 서버 적용 전에 확인할만한 체크리스트를 공식 문서에서 제공하기 때문에 확인해보면 좋을 것같다. 이 포스팅에서 설명한 것 외에도 보안, 성능 등의 항목이 포함되어 있다.

https://docs.djangoproject.com/ko/4.1/howto/deployment/checklist/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

반응형

댓글