Django로 웹 홈페이지를 만들고, 이를 웹에 배포하는 와중에 겪은 시행착오를 적어본다.
글을 쓰기 전에 이미 준비된 상황은 다음과 같았다.
- 배포할 웹 페이지가 완성돼있음.
- local과 amazon ec2 에서 각각 django 가
manage.py runserver
로 잘 돌아가는 것을 확인함. python manage.py collectstatic
을 통해 static file을 따로 두었다.- aws elastic IP 설정으로, 해당 ec2에 대한 고정 ip를 연결하였다.
- 도메인 업체 whois에서 사용할 도메인을 구입해두었다.
이후 내가 해야할 상황은 다음과 같았다.
- ec2 콘솔을 끄더라도, django server는 계속해서 run 중이게 해야함.
(기본적으로 ec2 연결을 끊으면, ec2 instance 는 run 중이지만, 실행 중이던 프로세스는 종료되기 때문.) - django 기본 포트인 8000번 포트가 아니라, http 기본 포트인 80 기본 포트로 웹페이지를 볼 수 있어야 함.
즉,http://13.125.138.52:8000
이 아니라,http://13.125.138.52
로 들어올 수 있어야함. - 구매한 도메인을
http://13.125.138.52
에 연동해야함.
위 해결과정을 하나씩 적어보도록 하겠다. 작업환경은 ec2에서 프리티어로 주는 ubuntu 서버다.
1. Screen 을 이용한 서버 run 유지.
screen 은 서버 연결을 꺼도, 실행 중이던 프로그램을 그대로 유지시키는 프로그램이다. 어렵게는 ''물리적인 터미널을 다중화하여 사용할 수 있는 윈도 매니저" 라고 부르나 보다. 아무튼 나한테는 서버에 ssh 연결을 한 putty 를 꺼도 django 가 돌아갈 수 있게 하는 도구다.
사용법은 매우매우 쉽다. 먼저 설치는 다음과 같이 하면 된다.
$ sudo apt-get install screen
설치가 되면 이제 스크린을 하나 만들어보자. 스크린 이름은 ypc django 로 주겠다.
# screen 생성
$ screen -S ypc django
이러고 뭐라 블라블라 뜨는데 그냥 엔터누르면 된다. 이제 현재 프로세스들을 유지시킬 수 있는 하나의 스크린을 만든 것이다. 한번 확인해보자.
# 현재 생성된 screen list 조회
$ screen -ls
There is a screen on:
8134.ypc django (09/20/2018 05:10:13 AM) (Attached)
보면, 8134라는 아이디로 ypc django 라는 스크린이 생성된 것을 볼 수 있다.
Attached
는 현재 저 스크린으로 들어온 상태라는 것이다.
ctrl
+ a
+ d
를 눌르면 해당 스크린을 빠져나올 수 있다. 누른 후 다시 스크린 리스트를 조회하면,
# 현재 생성된 screen list 조회
$ screen -ls
There is a screen on:
8134.ypc django (09/20/2018 05:10:13 AM) (Dettached)
Attach
가 Dettached
로 바뀐 것을 볼 수 있다. 해당 스크린을 빠져나온 것이다.
이제, 저 스크린에 다시 들어가, 우리의 django 서버를 돌리고 빠져나오자. 그러면 서버 연결을 끊어도 해당 스크린에서는 여전히 서버가 돌아가고 있을 것이다.
# 8134 id를 가진 screen으로 다시 attach 한다.
$ screen -r 8134
# 8134.ypc django screen 으로 다시 들어왔다.
$ python3 manage.py runserver
System check identified no issues (0 silenced).
September 30, 2018 - 21:50:28
Django version 2.1.1, using settings 'ypc.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
브라우저에서 ec2 public ip를 통해 들어가보자. 이를테면, http://123.123.123.123:8000 식으로 접속하면 된다.
근데 안된다. 문제를 검색해보니 127.0.0.1 은 localhost 주소이고, 이는 서버 내부에서만 접근할 수 있는 주소라고 한다. 난 당연히 localhost 를 서버에서 띄워놓으면, 서버로 들어오기전 웹서버가 다 처리해서 보내주는 줄 알았는데, 이게 아니였나보다. 127.0.0.1 이 아니라 0.0.0.0 으로 설정해야 어디서든 들어올 수 있다고 한다. runserver를 종료시키고 다시 다음과 같이 입력한다.
$ python3 manage.py runserver 0:8000
System check identified no issues (0 silenced).
September 30, 2018 - 21:50:28
Django version 2.1.1, using settings 'ypc.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
다시 http://123.123.123.123:8000 로 접속하면, 잘 된다. 다시 putty 로 돌아가, ctrl
+ a
+ d
를 눌러 django 를 실행시킨 상태에서 빠져나오자. 그리고 putty를 꺼서 서버와 연결을 끊어보자.
이 상태에서 http://123.123.123.123:8000 로 접속하면 여전히 잘 뜬다. 첫 번째 해결해야할 것을 끝냈다.
스크린 사용법 : https://medium.com/@erwinousy/screen-command-%EC%82%AC%EC%9A%A9%EB%B2%95-linux-mac-62bf5dd23110
+. Gunicorn 을 이용하여 서버 run시키기.
2번 문제를 해결하기 전에, 하나 더 추가할 것이 있다. 기본적으로 django 는 manage.py runserver
를 통해 앱서버를 동작시킬 수 있다. 그런데, 이 서버는 local 에서 test server 용이지, 배포용은 아니라고 한다. 즉 django 내장 server 를 사용해서 배포하지 말라는 것이다. 이는 django 공식 doc 에도 적혀있다.
DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through security audits or performance tests. (And that’s how it’s gonna stay.
from manage.py documentation
django 는 단일 쓰레드로, request가 많이 들어올 때 현저히 느려지고, 전반적인 퍼포먼스가 낮다는게 대략 이유다.
그럼 이제 어떻게하느냐? manage.py runserver
대신 서버를 실행시켜줄 것을 찾아야한다.
1. WSGI (Web Server Gateway Interface)
기본적으로 서버는 크게, 웹서버와 앱서버가 있다. nginx 나 apache 같이, 서버로 들어오는 http request 를 앞단 에서 가장 먼저 처리하는 것이 웹서버 다. 그리고 django 내장 서버와 같이 어플리케이션을 위한 서버가 앱서버다. 클라이언트(예를 들어 브라우저)에서 서버 80포트로 http request 가 오면, 웹서버는 이를 해석하여, 적당한 포트로 요청을 보내, 의도한 특정 앱서버에다가 요청을 전달해준다. 이 때, 웹서버와 앱서버간의 요청에는 http와 같은 일종의 인터페이스가 필요한데, python 에서는 wsgi 라는 인터페이스를 사용한다고 한다. 보다 정확하고 자세한 내용은 아래 링크를 참조하길 바란다.
WSGI 란 무엇인가? : http://paphopu.tistory.com/37
WSGI, WAS, CGI 이해 : http://brownbears.tistory.com/350
2. Gunicorn
gunicorn은 manage.py runsever
를 대신하여 실행할 wsgi 서버다. (gunicorn 외에도 uwsgi 등 다른 wsgi 서버도 있는데, 이게 제일 실행시키가 쉬워보여서 써본다.)
기존 django 서버는 단일 프로세스, 쓰레드인데, gunicorn은 이를 여러개로 만들어준다. 즉 request 가 많이와도 이전보다 더 효율적으로 처리할 수 있도록 한 것이다.
설치와 실행방법은 간단하다.
$ sudo apt-get install gunicorn
설치가 완료되면 해당 스크린에서 manage.py runsever 대신 다음과 같이 서버를 실행하자.
$ gunicorn ypc.wsgi:application -- bind 0:8000
[2018-09-30 13:31:36 +0000] [10836] [INFO] Starting gunicorn 19.9.0
[2018-09-30 13:31:36 +0000] [10836] [INFO] Listening at: http://127.0.0.1:8000 (10836)
[2018-09-30 13:31:36 +0000] [10836] [INFO] Using worker: sync
[2018-09-30 13:31:36 +0000] [10839] [INFO] Booting worker with pid: 10839
그리고 다시 스크린을 빠져나오면 된다. 끝!
2. Nginx 를 이용한 포트 설정
Nginx 는 서버 앞단에서 request를 가장 먼저 처리하는 웹 서버다. 비슷한 다른 소프트웨어론 apache가 있다. Nginx 를 이용하여 기본 포트인 80로 들어와도 우리의 웹사이트를 볼 수 있도록 해보자.
먼저 nginx를 설치해준다.
$ sudo apt-get install nginx
nginx 는 /etc/nginx
에 설치된다. /etc/nginx/nginx.conf
에 기본 설정 정보가 담겨있는데, 잘 보면
http {
...
include /etc/nginx/site-enable/*;
...
}
와 같은 코드가 보인다. 즉 우리는 /etc/nginx/sites-enable/
에서 추가적인 설정 파일을 만들면, nginx.conf 에서 이 파일을 가져와 쓴다는 말인 것이다.
/etc/nginx/
내부 디렉토리를 잘 보면 아래와 같은 두개의 디렉토리가 보인다. 역할은 다음과 같다.
-
/etc/nginx/sites-available
사용 예정인 사이트 및 서버에 대한 설정파일을 보관한다. 다시 말하지만, nginx 은 웹서버 최 앞단에서, request를 어떤 앱서버로 보낼지 정해주는 역할을 한다. 여기서 어디로 보낼지 등에 대한 설정파일을 여기에 담는 것이다. 하지만 이는 '사용 예정' 에 불과하다. -
/etc/nginx/sites-enable
실제로 설정파일에 적용되는 파일은 이 디렉토리에 들어간다. 여기다가 직접 설정파일을 넣어도 되지만, 대게ln -s
명령어(파일 연결, 일종의 바로가기와 같은 기능)를 이용하여/sites-available/
에 있는 설정 파일에 연결한다. 예를 들면 이런식이다.$ ln -s /etc/nginx/sites-available/ypc /etc/nginx/sites-enable/ypc
이렇게
/sites-available/
에 있는 설정파일을/sites-enable/
로 가져다 둔다.이렇게 하는 이유는, site-available에 가능한 사이트를 모두 두고, 실제로 필요에 따라서 ln-s 으로 연결하면 되기 때문이다. 만약 잠깐 특정 설정파일을 안쓰겠다고 하면, site-enable에서만 삭제하면 된다. 나중에 다시 필요하면, 위와 같이 다시 연결하기만 하면 된다. 실제 설정 파일을 안지우고, 연결 혹은 연결해제로 간편하게 설정할 수 있다.
나는 처음에는 /sites-available/
에 파일을 담아놓다가, 안되서 직접 /sites-enable/
에 실제 설정파일을 두었다. ln -s
명령어로 해도 안되는 사람은 이렇게라도 해보길 바란다.
그럼 이제 실제 설정파일을 작성해보자. /etc/nginx/sites-enable/
에서 django-webiste
파일을 만들어서 다음과 같이 작성하자.
server {
listen 80;
server_name 123.123.123.123;
location / {
proxy_pass http://127.0.0.1:8000/;
}
location /static/ {
alias /home/ubuntu/django-website/ypc/staticfiles;
}
}
위 코드는 nginx 문법으로 이루어 져있다.
-
먼저
server {...}
는 nginx 문법 중, server block 이라는 것인데, 우리는 지금 하나의 앱서버로 연결하려고 하는 것이니, 하나의 server block이 필요하다. -
listen 80
은 80 port로 들어오는 요청에 대해서 처리하겠다는 말이다. -
server_name
은 http reqeust 내 header에 담긴 server_name 값이다.예를들어, 브라우저에서
123.123.123.123
을 주소창에다 입력하면, 해당 http request의 server_name 값에123.123.123.123
값이 들어오게 된다. 이러한 요청을 처리하겠다는 것이다. -
location / {...}
은 해당 80 port와 server_name, 그리고/
url로 요청을 어떻게 처리할 것인지에 대해서 적는다.proxy_pass http://127.0.0.1:8000
는 해당 request 를127.0.0.1:8000
으로 보내겠다는 말이다.이제
123.123.123.123
으로 오는 request 는123.123.123.123:8000
으로 보내지게 된다. -
location /static/ {...}
도 역시 위와 마찬가지다.123.123.123.12/static/
으로 들어오는 request 는/home/ubuntu/django-website/ypc/staticfiles
을 참고하게 된다. 참고로 저 폴더에는 django 앱에서python3 manage.py collectstatic
을 통해 모아진 정적파일들이 들어있다.
이렇게 된 설정파일을 이제 저장하고, nginx 을 재 실행한 뒤, 정말 작동하는지 테스트 해보자.
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo sevice nginx restart
이제 브라우저에서 123.123.123.123
을 입력하면, 우리가 원하던 웹페이자가 뜬다. 80 포트로 접속하면 nginx 에서 서버 내부의 8000포트 앱서버로 요청을 보내주는 것이다.
3. ec2 ip 를 내가 구매한 도메인에 연결하기
이제 http://123.123.123.123
으로 접속하는게 아니라, http://www.abcdabcd.com 이런식으로 접속하고 싶다. 이를 위해서는 먼저 도메인 업체에서 http://www.abcdabcd.com 도메인을 산 뒤에, 이를 우리의 ip와 연결해야 한다.
도메인 구입은 whois 와 같은 업체에서 쉽게 구매할 수 있다. 나는 ~.org 로 구매했는데, 2년에 약 5만원 5천원 정도. 더 싼데 있으면 다른 곳에서 해도 된다.
도메인을 ip랑 연결하는 작업은 AWS route53을 이용하면 된다. 다른 방법이 있는지는 잘 모르겠는데, 아무래도 서버를 aws ec2를 쓰니, 도메인 연결 작업도 aws 를 쓰면 좋을거 같다는 생각에 사용하였다. 이 방법은 아래 링크에서 아주 자세히 설명해주니, 읽어보면 된다!
AWS route53 을 이용하여 도메인 연결 : http://wingsnote.com/57
이 설정 후, 실제로 내가 등록한 도메인에 연결되는대는 짧게는 몇시간, 길게는 몇 일 걸린다고 한다. 사실 나도 하라는대로 했는데, 아직까지 안된다 .... 정확하게 해결되면 이후에 또 글을 이어나가겠다.
'시행착오 노트' 카테고리의 다른 글
Pypi 에 내가 만든 패키지 배포하면서 알게된거 (0) | 2019.09.19 |
---|---|
folium HeatMapWitheTime 쓸 때 좀 빡치는거. (0) | 2019.05.31 |
pip3? pip? 및 conda 내 pip 정리 (11) | 2019.03.26 |
git 주요 명령어 및 기타 정리 (0) | 2018.12.16 |
django를 웹사이트 만들며 알게된 점 (4) | 2018.10.12 |