이전에 Nginx 정리하면서 해보지는 않았지만 간단히 포스팅 한 적 있는데 오늘 따라해보니깐 완전 산전수전~
낼 회사가야 되는데 분노의 새벽 3시에 글써버리기
HTTP 프로토콜을 이용해 정적 파일을 반환하는 일은 원래 웹서버가 하는 아주 큰 장점 중 하나입니다. 정적과 동적 처리를 따로 할 수 있는 웹서버에서 정적 파일을 찾을 때 여러 경로를 거치는 것이 아니라 하나의 경로로 아주 빠르고 신속하게 응답해주기 위해 모아주는 것입니다.
이걸 나는 왜 장고에서 URL로 연결지어서 반환하고 있지라는 의문이 생겼고 찾아봤다. 그랬더니 역시나 별도로 설정해줘야 하더라~
그럼 냉큼 설정해보자,,
Django 개발할 때는 static 파일이 잘 전송되는 것을 볼 수 있다. 이것은 INSTALLED_APPS
의 django.contrib.staticfiles이라는 모듈이 담당하고 있으며, 그마저도 settings.py의 DEBUG 속성을 False로 바꾸면 동작하지 않게된다.
이때부터는 static 파일의 처리는 웹서버가 담당하게 되는 것이다.
collectstatic을 실행하기 위해서는 먼저 파일들을 모을 경로를 지정해주어야 하며 이 경로는 settings.py 의 STATIC_ROOT
라는 변수로 지정한다.
STATIC_ROOT
경로는 원하는 대로 설정해주면 된다. 그러면 설정한 경로로 프로젝트 내 static 파일들이 모이게 된다.
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ROOT_DIR = os.path.dirname(BASE_DIR)
# Static files
STATIC_URL = '/static_root/'
STATICFILES_DIRS = []
STATIC_ROOT = '/static_files/files/static/' # 요기
# Media files
MEDIA_ROOT = "/static/files/uploaded_files/"
MEDIA_URL = "/uploads/"
Javascript, CSS, Image, Font 파일처럼 웹 서비스에서 사용하려고 미리 준비해 놓은 정적 파일입니다. 파일 자체가 고정되어 있고, 서비스 중에도 수시로 추가되거나 변경되지 않고 고정되어 있습니다.
실 서버 배포 시 static 파일을 collectstatic
하기위한 절대 경로이다. 기본 값은 None이며 다음과 같이 설정할 수 있습니다.
⭐이게 static file 경로를 장고 플젝 안에 넣으면 인식을 못하는거 같은데 확인 필요⭐
STATIC_ROOT = "/static/files/static_files/"
URL로써 static 파일의 위치를 가르킬 때 사용하는 위치이다. 마찬가지로 기본값은 None이며 아래와 같이 설정합니다.
이 STATIC_URL
이 추후에 Nginx 연동할 때 이어줘야 할 주소입니다.
STATIC_URL = "static/"
해당 부분을 설정해주게 되면 static 파일들은 STATIC_URL
로 설정해놓은 static/
으로 연결됩니다.
앱에 포함된 static 파일의 위치를 추가할 수 있다. 기본값은 [](비어있는 리스트) 이고, 아래와 같이 설정합니다.
STATICFILES_DIRS
는 개발 환경에서만 쓰이고, 우선 우리는 Debug=False
일 때의 환경을 구축하는게 목표니 STATICFILES_DIRS
는 주석처리 해줘도 됩니다.
# Django Docs example
STATICFILES_DIRS = [
"/home/special.polls.com/polls/static",
"/home/polls.com/polls/static",
"/opt/webfiles/common",
]
⭐ 결론 ⭐
개발 환경에 중요한건 - STATIC_URL & STATICFILES_DIRS
상용 환경에 중요한건 - STATIC_URL & STATIC_ROOT
이용자가 웹에서 올리는(upload) 파일입니다. 파일 자체는 고정되어 이지만, 언제 어떤 파일이 정적 파일로 제공되고 준비되는지 예측할 수 없습니다.
MEDIA_ROOT
는 이름이 STATIC_ROOT
와 비슷한데, 업로드가 끝난 파일을 배치할 최상위 경로를 지정하는 설정 항목입니다.MEDIA_ROOT
는 STATIC_ROOT
와 다른 경로를 지정해야 합니다. MEDIA_URL
은 STATIC_URL
과 이름도 비슷하고 역할도 비슷합니다.MEDIA_URL
도 MEDIA_ROOT
와 마찬가지로 STATIC_URL과 URL 경로가 달라야 합니다.# Media files
MEDIA_ROOT = "/static/files/uploaded_files/"
MEDIA_URL = "/uploads/"
해당 명령을 입력하면 프로젝트 내에 STATIC_ROOT 설정했던 경로로
css, font 등 Static file들을 몽땅 모아줍니다.
# <BAES_DIR>/static_root/ # 경로에 생기게 되는 것!
python manage.py collectstatic
이제 /static/
URL로 정적 파일 요청이 들어오면 모든 정적 파일을 모아놓은 폴더인 static_root/ 폴더
에서 찾아 되돌려 보내게 됩니다.
server {
#listen 80;
listen 443;
ssl on;
ssl_certificate /etc/ssl/oddong.tk/certificate.crt;
ssl_certificate_key /etc/ssl/oddong.tk/private.key;
server_name www.oddong.tk;
server_name oddong.tk;
access_log /var/log/nginx/nginx.oddong.access.log;
error_log /var/log/nginx/nginx.oddong.error.log;
location / {
include proxy_params;
proxy_pass http://127.0.0.1:8000;
}
location /{{본인 static_url 값}}/ {
alias /static/files/static_files/; # 자기 static root 경로 적어주면 됩니다.
}
location /{{본인 MEDIA_URL 값}}/ {
alias /static/files/uploaded_files/; # 자기 media file 경로 적어주면 됩니다.
}
}
nginx 재실행 해주고
systemctl restart nginx
gunicorn 실행해주면 이제 되어야 하는게 맞는데
gunicorn --bind 0:8000 config.wsgi:application
Nginx log 파일 살펴보고, 에러 로그 살펴보면 404(왜??), 500(server error), 403 error
로 난리났다. 경로를 잘못 설정해준 것도 아닌데 정적 파일을 전혀 찾지 못하고 있었다. 이거를 6시간동안 헤맸는데ㄷㄷ 결국 찾았다!
403 난거를 확인하고 분명 서버에서는 권한 에러가 날 것이 없는데 유추하고 찾아봤는데 Nginx 설정에서 수정해주지 않아서 일어났던 문제였다.
우선 Nginx 에러 로그는 위에 설정에서 설정했는데 나는 아래 경로로 설정했다.
# Nginx error or access log 확인 방법
# /var/log/nginx/nginx.oddong.error.log
tail /var/log/nginx/nginx.oddong.error.log
# /var/log/nginx/nginx.oddong.access.log
tail /var/log/nginx/nginx.oddong.access.log
setting에서 경로 로그를 수십번 찍고 수정하고 또 찍고 반복하고 Nginx 설정 바꿔보고 그랬는데 원인은 이게 아니였다.
나중에 log중에 403 에러를 보고 추측했는데 Nginx conf 파일 설정때문에 그랬던 거다ㅠㅠ
# vi /etc/nginx/nginx.conf
user www-data; ############# 이부분 #################
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
.
.
.
↓↓↓↓↓↓↓↓ 변경 ↓↓↓↓↓↓↓↓↓↓
user ubuntu # 본인 user 이름으로 수정
user로 설정되어 있던 www-data
때문인데, 이 부분을 현재 사용하고 있는 user ubuntu
로 변경하였더니 정상적으로 정적 파일을 불러오는 것을 확인할 수 있었습니다. 해당 부분은 작업자 프로세스에서 사용하는 사용자 및 그룹 자격 증명을 정의해주는 부분입니다. 그룹을 생략하면 사용자와 이름이 같은 그룹이 사용됩니다.
해당 부분의 user를 root
로 설정하면 Nginx 워커 프로세스를 root 권한으로 동작하게 되고, 워커 프로세스를 악의적 사용자가 제어하게 된다면 해당 머신을 루트 사용자의 권한으로 원격 제어하게 되는 셈이니깐 root로는 하지 않도록 조심해줍니다!
암튼 덕분에 앞으로는 오늘 해왔던 정적 파일 부분에서 실수할 일은 없을 거 같습니다... 허헣🤦♂️
우리는 지금 웹서버(Nginx)에서 static file을 찾아주는 것은 성공적으로 잘 작동할 것입니다.
하지만 동적 처리가 필요해 Django를 들렸다가 필요한 static file들은 어디에 있는지 아무도 알려주는 것이 없어 그대로 깨지게 됩니다.
따라서 우리는 Django가 static file 경로를 알 수 있게 설정해주어야 합니다.
# config/urls.py
if settings.DEBUG is False:
urlpatterns += [
re_path(r'^{{본인 media_url 값}}/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), # 나는 uploads
re_path(r'^{{본인 static_url 값}}/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}) # 나는 static
]
위의 코드는 예를 들어 {{본인 static_url 값}}
저는 위에서 static/
이라고 지정해두었기 때문에 static file 들은 아래처럼 static 경로를 찾아가게 됩니다.
그때 Django에서 static/
으로 들어가면 STATIC_ROOT
경로로 서빙해라라는 의미입니다. STATIC_ROOT
경로는 /static/files/static_files/
이기 때문에 해당 경로로 가 static file들을 찾게되는 구조입니다.
그럼 이제 진짜 끄읏~ 다들 정적 파일은 웹서버로 처리해 조금이나마 속도를 높여봅시다~!!
- STATIC_URL & STATIC_ROOT 설정 + Media도 똑같이~
- collectstatic 해서 STATIC_ROOT로 모아주는 작업 진행
- Nginx 설정 - STATIC_URL로 들어오면 STATIC_ROOT 경로로 서빙 처리
- Django url 라우팅 - 장고 내에서도 정적 파일을 바라보는 경우를 위해 라우팅 처리
- 서버 재시작
참고자료 📩
Django 공식문서 - static file
static file 설정 방법
Nginx Docs - static file serve 방법
Nginx Docs - conf 구성 요소
감사합니다 static 때문에 하루종일 삽질하던거 덕분에 해결했습니다ㅎㅎ