[DjangoAWS] AWS Django 파일 업로드 적용하기
이번 포스트에서는 static
파일과 media
파일을 서버에 업로드하여 적용시키는 방법에 대해 알아본다.
Static 파일 설정
아래 주소를 통해 Django 관리자 페이지로 접속하자.
ec2-13-209-42-132.ap-northeast-2.compute.amazonaws.com/admin
css파일이 적용되지 않은 모습을 볼 수 있다.
우선 장고에서 static 파일들을 처리할 수 있도록 settings.py
를 설정을 해주자.
# settings.py
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__)))
# static files
STATIC_URL = '/static/'
STATIC_DIR = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = [
STATIC_DIR,
]
지금까지는 위와 같이 설정해주고 static
폴더 안에 정적 파일들을 넣어 적용시켰었다.
이제 이 상태로 scp
로 서버에 업로드하면 css가 적용되어 있을까?
프로젝트 폴더(mydjango
)에 static
폴더를 만들고 아무 내용이나 작성한 test.txt
파일을 하나 넣어두자.
일단 로컬에서 runserver
를 실행하고 localhost:8000/static/test.txt
로 접속하면 아래와 같이 test.txt
의 내용을 확인할 수 있다.
이 상태 그대로를 AWS 서버에 올리고나서 test.txt
를 불러와보자.
ec2-13-209-42-132.ap-northeast-2.compute.amazonaws.com/static/test.txt
404 에러가 발생한다.
정적 파일 모으기
css파일 등과 같은 정적 파일들은 장고 내에 여러 폴더에 분산되어 있다.
예를 들어, 장고 관리자 페이지에 적용되는 정적 파일들은 아래 경로에 저장되어 있다.
/home/ubuntu/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/django/contrib/admin/static/admin/
또, 우리가 만든 정적 파일들은 아래 경로에 저장된다.
/home/che1/Projects/Django/EC2_Deploy_Project/mysite/static
이렇게 하나의 프로젝트에서 사용하는 정적 파일들은 여기저기에 분산되어 있기 때문에 요청이 들어왔을 때 필요한 정적 파일을 돌려주려면 많은 경로들을 다 찾아보아야 하며 이는 매우 비효율적일 것이다.
그래서 사용하는 모든 정적 파일을 하나의 경로로 모아주는 작업이 필요하다.
runserver
는 개발자가 개발에만 집중할 수 있도록 이 작업을 알아서 해준다. runserver는 알게모르게 알아서 해주는 편의기능이 아주 많다.
하지만 실제 서비스를 배포할때는 runserver를 사용하지 않으므로 직접 모아주어야 하며, 이 때 사용하는 것이 collectstatic
명령이다.
collectstatic
collectstatic
파일은 프로젝트에서 사용하는 css, font, javascript 등 모든 정적 파일들을 모아서 하나의 경로에 모아준다.
collectstatic을 실행하기 위해서는 먼저 파일들을 모을 경로를 지정해주어야 하며 이 경로는 settings.py
의 STATIC_ROOT
라는 변수로 지정한다.
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/'
STATIC_DIR = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = [
STATIC_DIR,
]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles/')
프로젝트 루트의 상위 폴더에 .static_root
라는 숨김 폴더를 생성하고 그곳으로 모든 정적 파일들을 모으도록 설정하였다.
Django
├── .config
│ ├── nginx
│ └── uwsgi
├── .gitignore
├── .static_root <-- collectstatic을 실행하면 생성될 폴더
├── mydjango
│ ├── config
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── db.sqlite3
│ ├── manage.py
│ └── static
│ └── test.txt
└── requirements.txt
collectstatic은 settings.py
의 INSTALLED_APPS
목록에 등록된 앱이 사용하는 모든 정적 파일들과 STATICFILES_DIRS
리스트에 명시된 경로에 있는 모든 정적 파일들을 한 곳에 모은다.
AWS 서버에 접속한 뒤 manage.py
가 있는 경로로 이동한 다음 아래 명령을 실행하여 정적 파일들을 모아보자.
python manage.py collectstatic
(venv) ➜ mydjango git:(master) ✗ python manage.py collectstatic
120 static files copied to '/Users/kang/Documents/Portfolio/Django/.static_root'.
(venv) ➜ mydjango git:(master) ✗
.static_root
라는 폴더가 생성된 것을 볼 수 있으며 그 내용물은 아래와 같다.
├── admin
│ ├── css
│ ├── fonts
│ ├── img
│ └── js
└── test.txt
장고 관리자 페이지의 정적 파일들은 물론이고 우리가 만들었던 static
폴더 내의 내용물인 test.txt
파일도 가져와진 것을 볼 수 있다.
이 폴더의 내용물들은 이미 어딘가에 있는 정적 파일들을 복사해온 것이므로, 버전 컨트롤에서 제외시켜야 한다. .gitignore
파일을 열어 .static_root/
를 추가해준다.
이제 서버에서 정적 파일을 요청하는 URL을 처리할 수 있게 해주어야한다.
Nginx 설정
runserver는 STATIC_URL
에 지정된 URL을 통해 정적 파일 요청을 받아온다.
하지만 서버에 배포를 하고나면 Nginx가 요청을 받게되므로 정적 파일 요청을 처리할 수 있도록 정적 파일 URL을 지정해주어야 한다.
mydjango.conf
파일을 열어 아래와 같이 새로운 location
을 추가해주자.
server {
listen 80;
server_name *.compute.amazonaws.com;
charset utf-8;
client_max_body_size 128M;
location / {
uwsgi_pass unix:///tmp/mydjango.sock;
include uwsgi_params;
}
location /static/ {
alias /srv/Django/staticfiles/;
}
}
이제 /static/
URL로 정적 파일 요청이 들어오면 모든 정적 파일을 모아놓은 폴더인 /.static_root/
폴더에서 찾아 되돌려보낸다.
scp
명령을 통해 변경사항을 AWS 서버로 전송하고, 서버에서 daemon-reload
, restart nginx uwsgi
를 실행하여 변경사항을 적용시켜주자.
scp -i ~/.ssh/EC2-kangpro.pem -r ~/Documents/Portfolio/Django ubuntu@ec2-13-209-42-132.ap-northeast-2.compute.amazonaws.com:/srv/
ssh -i ~/.ssh/EC2-kangpro.pem ubuntu@ec2-13-209-42-132.ap-northeast-2.compute.amazonaws.com
# 하루 걸림 ㅜㅜ 세팅 다시 다 바꿔줘야함...
➜ ~ sudo cp -f /srv/Django/.config/nginx/mydjango.conf /etc/nginx/sites-available/mydjango.conf
➜ ~ sudo ln -sf /etc/nginx/sites-available/mydjango.conf /etc/nginx/sites-enabled/mydjango.conf
➜ ~ sudo ln -f /srv/Django/.config/uwsgi/uwsgi.service /etc/systemd/system/uwsgi.service
➜ ~ sudo systemctl daemon-reload
➜ ~ sudo systemctl enable uwsgi
➜ ~ sudo systemctl | grep nginx
nginx.service loaded active running A high performance web server and a reverse proxy server
➜ ~ sudo systemctl | grep uwsgi
uwsgi.service loaded active running uWSGI service
➜ ~ sudo systemctl daemon-reload
sudo systemctl restart nginx uwsgi
➜ ~
이제 다시 관리자 페이지로 접속해보자.
http://ec2-13-209-42-132.ap-northeast-2.compute.amazonaws.com/admin
css가 적용된 모습을 볼 수 있다.
우리가 넣어둔 test.txt
도 한 번 확인해보자.
http://ec2-13-209-42-132.ap-northeast-2.compute.amazonaws.com/static/test.txt
Nginx는 장고를 거치지 않고 직접 정적 파일 요청을 처리하여 정적 파일들을 되돌려준다.
Media 파일 설정
정적 파일들과 마찬가지로 미디어 파일도 Nginx가 직접 처리할 수 있다.
runserver를 이용한 미디어 파일 요청처리는 아래와 같이 해주었었다.
# settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ROOT_DIR = os.path.dirname(BASE_DIR)
# media files
# 각 media 파일에 대한 URL Prefix
MEDIA_URL = '/media/'
# 업로드된 파일을 저장할 디렉토리 경로
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
장고에서는 미디어 파일 요청을 받을 URL 주소는 MEDIA_URL
변수에 설정하고,
실제 미디어 파일을 저장할 폴더는 MEDIA_ROOT
변수에 설정해주었다.
미디어 파일은 분산되어있지 않으므로, 따로 모아줄 필요없이 MEDIA_ROOT
내에 모이게 된다.
그리고 urls.py
에 아래와 같이 추가하여 미디어 파일 요청을 처리하도록 해주었다.
from django.contrib import admin
from django.urls import path
from django.conf import settings # 추가
from django.conf.urls.static import static # 추가
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += static(
settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT
)
이제 이 작업을 Nginx 웹 서버가 수행하도록 해준다.
mydjango.conf
를 열어 아래와 같이 location
을 추가해준다.
# mydjango.conf
server {
listen 80;
server_name *.compute.amazonaws.com;
charset utf-8;
client_max_body_size 128M;
location / {
uwsgi_pass unix:///tmp/mydjango.sock;
include uwsgi_params;
}
location /static/ {
alias /srv/Django/staticfiles/;
}
location /media/ {
alias /srv/Django/mydjango/media/;
}
}
이제 Nginx에서 직접 /media/
가 붙은 URL로 들어오는 미디어 파일 요청을 받아 /media/
폴더의 미디어 파일을 되돌려주게된다.
위의 설정을 완료했으면, 장고 프로젝트 폴더 아래의 media
폴더에 아무 파일이나 넣어준 다음 scp
명령을 통해 변경사항을 AWS 서버로 전송하고, 서버에서 daemon-reload
, restart nginx uwsgi
를 실행하여 변경사항을 적용시켜주자.
이제 넣어준 미디어파일을 브라우저에서 요청해보자.
scp -i ~/.ssh/EC2-kangpro.pem -r ~/Documents/Portfolio/Django ubuntu@ec2-13-209-42-132.ap-northeast-2.compute.amazonaws.com:/srv/
ssh -i ~/.ssh/EC2-kangpro.pem ubuntu@ec2-13-209-42-132.ap-northeast-2.compute.amazonaws.com
sudo cp -f /srv/Django/.config/nginx/mydjango.conf /etc/nginx/sites-available/mydjango.conf
sudo ln -sf /etc/nginx/sites-available/mydjango.conf /etc/nginx/sites-enabled/mydjango.conf
sudo ln -f /srv/Django/.config/uwsgi/uwsgi.service /etc/systemd/system/uwsgi.service
sudo systemctl daemon-reload
sudo systemctl enable uwsgi
sudo systemctl | grep nginx
sudo systemctl | grep uwsgi
sudo systemctl daemon-reload
sudo systemctl restart nginx uwsgi
이제 다시 관리자 페이지로 접속해보자.
http://ec2-13-209-42-132.ap-northeast-2.compute.amazonaws.com/media/profile.jpg
미디어 파일 요청이 잘 처리되는 것을 볼 수 있다.
참고
AWS 유저 가이드 : https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/concepts.html
나채원님 블로그 : https://nachwon.github.io/django-deploy-1-aws/
개발자님들 덕분에 많이 배울 수 있었습니다. 감사의 말씀 드립니다.
환경
macOS Mojave 10.14.5, python 3.7.3, django 2.2.3, PyCharm CE 2018.3.7, AWS ubuntu 16.04.