본문 바로가기
Python/Django

AWS EC2를 이용하여 Django + Uwsgi + Nginx 서버 세팅하기

by _촌촌 2023. 10. 21.

거의 며칠간의 우여곡절끝에 서버를 세 번이나 다시 세팅하고.. 이제서야 작동이 되어서 처음부터 끝까지 모든 절차를 기록해보려고 한다. 

- 에러가 명확하지 않다보니 원인을 찾는게 너무 어려워서 모든 절차를 하나씩 순서대로 기록 후 에러가 날 때는 해당 지점을 잘 살펴본다

- 자세한 내용은 레퍼런스 링크에 있음

레퍼런스

- AWS EC2 인스턴스 설정 및 리눅스 기본 세팅 : 영상 링크
- Putty 설정 :  https://velog.io/@heejung/AWS-EC2에-PuTTY로-접속하기
- Nginx Https 인증서 설정 : https://nginxstore.com/blog/nginx/lets-encrypt-%EC%9D%B8%EC%A6%9D%EC%84%9C%EB%A1%9C-nginx-ssl-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0/
- Uwsgi, Nginx 설정 : https://tonyteaches.tech/django-nginx-uwsgi-tutorial/
- Uwsgi, Nginx 설정 (영상) : https://www.youtube.com/watch?v=ZpR1W-NWnp4&t=1669s&ab_channel=TonyTeachesTech

1. AWS EC2 인스턴스 설정

1) 인스턴스 시작
2) 보안 그룹 설정 (80, 433, 8000 포트 열어주기)
3) 탄력적 IP 할당 (인스턴스 재시작 시에도 IP를 동일하게 유지함)

2. Putty 설정하기

1) Private Key를 다운로드 후 Putty 에 설정.
2) 세션 등록 후 인스턴스 접속

3. 리눅스 세팅

1) 리눅스 환경 업데이트

$ sudo apt-get update

2) 필수 모듈 설치

sudo apt-get install build-essential

3) 파이썬 설치

sudo apt-get install python3

4) pip 설치

 sudo apt-get install python3 pip

5) pip 업그레이드

 sudo pip3 install --upgrade pip

6) Public Key 발급 (+ 비밀번호 설정)

 ssh-keygen -t rsa

7) Publick Key 확인 및 깃허브 연동

cat /home/ubuntu/.ssh/id_rsa.pub

=> 깃허브 deploy Key 에서 퍼블릭 키 등록

8) Git pull

git clone 코드 ssh 키

=> ssh-key 는 깃허브에서 확인 가능

9) 가상환경 설치

 sudo apt-get install virtualenv

10) 가상환경 생성

virtualenv -p python3 venv

=> 'venv'라는 이름의 가상환경을 만듦.

11) 가상환경 활성화

source venv/bin/activate

12) 파이썬 패키지 설치

pip install -r requirements.txt

** mysqlclient 설치 중 항상 아래와 같은 에러가 발생함 

"Exception: Can not find valid pkg-config name.
Specify MYSQLCLIENT_CFLAGS and MYSQLCLIENT_LDFLAGS env vars manually"

아래 두 패키지 설치하면 오류 해결 (참고 : https://stackoverflow.com/questions/76585758/mysqlclient-cannot-install-via-pip-cannot-find-pkg-config-name)

sudo apt-get install python3-dev default-libmysqlclient-dev build-essential
sudo apt install pkg-config

13) 서버 구동 테스트

python3 manage.py runserver 0.0.0.0:8000

=> 이전에 열어두었던 8000포트로 서버를 테스트 함.

**참고) 배포전 이슈 체크하는 법

python manage.py check --deploy

4. Uwsgi 세팅

1) Uwsgi 설치 

sudo apt-get install python3.8-dev #파이썬 버전에 맞게 설치
sudo apt-get install gcc
pip install uwsgi

2) Uwsgi 설정 파일 작성

vi uwsgi.ini

아래 내용 작성

[uwsgi]
# full path to Django project's root directory
chdir            = /home/ubuntu/[폴더 이름]/
# Django's wsgi file
module           = config.wsgi:application
# full path to python virtual env / 가상환경 경로
home             = /home/ubuntu/[폴더 이름]/venv
# enable uwsgi master process
master          = true
# maximum number of worker processes
processes       = 10
# the socket (use the full path to be safe / 소켓 이름은 자유
socket          = /home/ubuntu/[폴더 이름]/[소켓 이름].sock
# socket permissions
chmod-socket    = 666
# clear environment on exit
vacuum          = true
# daemonize uwsgi and write messages into given log / 로그 위치
daemonize       = /home/ubuntu/uwsgi-emperor.log

5. Nginx

1) Nginx 설치

sudo apt-get install nginx

2) Nginx Configuration 파일 만들기

vim /etc/nginx/sites-available/[파일이름].conf
# the upstream component nginx needs to connect to
upstream django {
    server unix:///home/ubuntu/[폴더 이름]/[소켓이름].sock;
}
# configuration of the server
server {
    listen      80;
    server_name micro.domains www.micro.domains; / 내 도메인 주소
    charset     utf-8;
    # max upload size
    client_max_body_size 75M;
    # Django media and static files
    location /media  {
        alias /home/ubuntu/[폴더 이름]/media;
    }
    location /static {
        alias /home/udoms/[폴더 이름]/static;
    }
    # Send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /home/ubuntu/[폴더 이름]/uwsgi_params;
    }
}

3) uwsgi_params 만들기

sudo vi uwsgi_params

그대로 붙여 넣기

uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;
uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;
uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

4) sites-enabled로 심링크 만들기

sudo ln -s /etc/nginx/sites-available/파일이름.conf /etc/nginx/sites-enabled/

5) Static / Media 파일 설정하기

** 배포시에는 static 파일들을 collectstatic 명령어를 통해서 만들어준 후 경로를 설정해줘야 하는데, 자세한 내용은 생략하였음. 검색시 많은 정보가 있으며 대충 위 레퍼런스나 https://iam.jesse.kim/study/django-deploy/6 참고.

나는 Django Restframework 로 Media 파일은 필요하지 않아서 생략함.

6) Nginx 재시작

sudo /etc/init.d/nginx restart

 

6. Nginx + Uwsgi 구동하기

1) Uwsgi 테스트 실행

uwsgi --socket 파일이름.conf --module 폴더이름.wsgi --chomod-socket=666

=> socket 파일이 생성됨을 확인

uwsgi --ini 파일 이름.ini

=> 백그라운드에서 uwsgi 실행

7. Uwsgi Emperor 세팅

uWSGI는 Emperor mode 에서 실행할 수 있다. 이 모드에서는 uWSGI 설정 파일의 디렉토리를 감시하고 발견된 각각의 인스턴스 ('vassals')를 생성한다. 설정 파일이 수정 될 때마다 Emperor는 vassal을 다시 시작한다.

1) Emperor 가 생성할 Vassals를 위한 폴더를 생성 (+ 추가로 참고)

sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals

2) uwsgi.ini 파일의 심링크 설정

sudo ln -s home/ubuntu/artiscore_prod/uwsgi.ini /etc/uwsgi/vassals

=> 위에서 생성한 vassals로 uwsgi.ini 를 모아주는 것

(** 심링크 생성 이후 파일이 빨간이름으로 표시되어있었는데 이 때문에 작동이 안됐다. 파일이름이 하늘색으로 표시되는지 확인할 것 - 심링크 재생성하니 해결됨)

3) Emperor 실행

uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data

8. 시스템 부팅시 Emperor 실행 설정

1) Systemd service 파일 만들기

sudo vi /etc/systemd/system/uwsgi.service

=> 아래 내용 입력

[Unit]
Description=uwsgi emperor for micro domains website
After=network.target
[Service]
User=ubuntu
Restart=always
ExecStart=/home/ubuntu/[폴더이름]/venv/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data
[Install]
WantedBy=multi-user.target

=> ExecStart 에는 가상환경에 uwsgi 이 설치된 경로와 이전에 만들어준 vassals 폴더의 경로를 지정해주면 된다.
** User 이름 잘못 입력해서 1시간 고생..

2) system service 파일 활성화

systemctl enable uwsgi
systemctl start uwsgi

3) 상태 확인

systemctl status uwsgi

+ 정지 후 서버 재부팅

systemctl stop uwsgi
sudo reboot

=> 시스템 부팅시 실행되는지 확인

**수정 후 로드시

systemctl daemon-reload


9. Nginx Https 설정하기

프론트엔드와의 통신에서 http 연결이 호환이 안되는 것을 발견해서 https 로 설정해줘야할 필요가 생김

1) Certbot 설치

$ sudo apt-get install certbot
$ apt-get install python3-certbot-nginx

2) 인증서 발급

$ sudo certbot --nginx -d example.com -d www.example.com

=> 해당 도메인이 nginx로 운영되는 서버를 가리키고 있어야 한다.

=> 이제 IP 주소가 아닌 설정한 도메인을 통해 접속이 가능함.

3) 자동갱신 설정하기

Letsencrpyt 에서 발급하는 인증서는 90일 이후 자동 만료되기 때문에, renew 해줘야한다. 
crontab 을 이용해 자동화 해주기

# crontab config 편집기 실행.
sudo crontab -e

# 매월 1일 새벽 3시(서버시간 18시) 실행 설정.
0 18 1 * * sudo certbot renew --pre-hook "sudo systemctl stop nginx" --post-hook "sudo systemctl restart nginx"

# crontab 보기
sudo crontab -l

# crontab 로그 보기
sudo cat /var/log/cron

 

** 에러 핸들링

1) Nginx 설치 이후 ip 로 접속시 Nginx 웰컴 페이지는 나오나, 다른 페이지로는 이동이 안됨 (Not Found 에러)
=> conf 파일에서 server_name 에 ip를 명시해줘보니 해결 됨

2) Nginx 에서 Permission 에러가 뜬 경우가 있어 nginx.conf 파일의 user를 www-data 에서 ubuntu 로 바꿔줌. (스택오버플로우 참고함)

3) uwsgi.ini 파일에서 module 이름을 config.wsgi:application 으로 설정하는 경우도 있던데 무슨 차이인지는 모르겠지만 이렇게 진행함 (:application 빼도 무방한듯)

4) Settings.py에서 추가 보안 설정들은 일단 주석처리 해둠 (추후 필요시 기능 확인 후 활성화)

# SESSION_COOKIE_SECURE = True
# CSRF_COOKIE_SECURE = True
# SECURE_SSL_REDIRECT = True
# SECURE_HSTS_SECONDS = 31536000
# SECURE_HSTS_PRELOAD = True
# SECURE_HSTS_INCLUDE_SUBDOMAINS = True

 

5) *** 파이썬 코드 수정시 uwsgi 재기동 필요

sudo service uwsgi restart