AWS, Nginx, Gunicorn을 통해 베어메탈 서버 배포 해보기

devkev00·2024년 12월 30일

🔥 What I've Learned

목록 보기
1/9

피로그래밍 최종 프로젝트 중 개인적인 욕심(!)으로 베어메탈 서버를 통한 3-tier 배포를 도맡아 하게 되었는데, 여러가지로 우여곡절이 많았던 부분이라 블로그에 정리하고자 한다.

배포 과정을 설명하기 전에 간단한 사전 지식을 먼저 알고 가자!

1. 배포란?

  1. 사용자에게 소프트웨어(서비스)를 제공하는 것이다.
    다른 사람이 접속할 수 있도록 인프라(AWS)를 통해 공개하는 것이다.

2. ~~티어 아키텍쳐?

  1. 1티어 아키텍처 (1-Tier Architecture)
  • 로컬 환경
  • 사용자 인터페이스, 비즈니스 로직, DB가 하나의 단일 시스템에 존재
  • 우리가 개발 단계에서 보통 localhost라고 하는 그것
  1. 2티어 아키텍처 (2-Tier Architecture)
  • 로컬과 배포 사이 그 어딘가 (하이브리드 샘이솟아 리오레이비)
  • 클라이언트(사용자 인터페이스)와 서버가 분리되어 있음
  • AWS EC2 인스턴스 생성 (배포 환경)
  • EC2에 DB 서버 설치
  • 로컬 Django 서버(client)와 EC2 DB 서버 연결
  • 로컬에서 Django 실행
  1. 3티어 아키텍처 (3-Tier Architecture)
  • 본격적인, 완전한 배포
  • 클라이언트(사용자 인터페이스)와 앱 서버, 데이터베이스 서버가 모두 분리되어 있음
  • 앱 서버용 AWS EC2 인스턴스 추가 생성
  • 앱 서버용 인스턴스에 프로젝트 코드 클론
  • 앱 서버의 Django와 DB 서버의 DB 연결
  • 앱 서버에서 Django 실행

가만히 보면, 단계별로 차근차근 따라가는 것임을 알 수 있다!

이제 본격적으로 배포를 해 봅시다!

3. 인스턴스 생성하기

1티어 배포는 개발 환경 그 자체이므로 2티어 배포부터 설명하겠다.
우선 AWS에 접속해서 DB용 인스턴스를 하나 생성하자!



AWS에 처음 회원가입하면 AWS 프리 티어 요금제를 1년 동안 쓸 수 있게 해주는데, 이 요금제에서 t2.micro 인스턴스 하나만 파면 한 달 750시간 무료라 사실상 공짜로 쓸 수 있다! 물론 인스턴스가 두 개 이상 되면 늘어난 인스턴스들이 750시간을 나눠 쓰게 되므로 과금이 발생할 수도 있다. 필자는 인스턴스 하나로 했다!

(엄밀히 말하면 앱이랑 서버가 한 인스턴스에 들어 있는 셈이니까 완전한 3티어 배포는 아닌 셈이다)
네트워크 설정까지 마치고 launch instance를 누르면 인스턴스가 생성된다.

4. 서버에 접속하기

이제 인스턴스가 생성되었을 건데, 생성된 인스턴스를 체크하고 connect to instance를 누른다.
그 후 터미널을 켜고 프라이빗 키 파일이 있는지 확인한다(프라이빗 키 생성시 자동으로 다운로드 되므로, 경로를 찾아주면 된다.)

(선택)

chmod 400 "프라이빗 키 이름.pem"

을 입력해서 보안적으로 강화할 수 있다. 그런 다음

ssh -i "프라이빗 키 이름.pem" ubuntu@ec2-아이피.리전.compute.amazonaws.com

명령어를 입력하면 서버를 켤 수 있다!

5. 서버 컴퓨터에 DB 설치하기

그 후 이 ubuntu 서버 컴퓨터에 사용할 데이터베이스를 받아준다. 필자는 postgresql로 했다!

아 참, 생성한 인스턴스의 Security로 넘어가서 인바운드 규칙을 수정해줘야 한다. 필자는 앱(Django)과 디비를 한 인스턴스에서 열었으므로, 각각 8000 포트와 5432포트를 열어주었다.

요렇게.

6. 내 프로젝트 코드 클론 받기

이제 ubuntu에 내 소중한 프로젝트 코드를 클론 받는다.

git clone 당신의 레포 주소!!

이때 SSH로 하면 오류가 발생할 수 있으니 반드시 레포 주소를 HTTP로 변경해서 입력하자!

클론을 받았다면 환경 변수 파일이 없을 테니, .env 파일을 만들어서 내 로컬 앱에 있던 환경 변수 내용들을 복붙해준다. 터미널 환경이니 vim을 써야 한다! 가상환경도 없을 테니 venv도 받아주자! venv를 받은 다음에는? 의존성 파일들을 받아 주어야 내 작고 이쁜 프로젝트가 잘 작동할 것이다! 여기까진 역사적으로 흘러가듯 가야 한다~

역사적으로 흘러가듯 가~

여기까지 하고 터미널에 python(3) manage.py runserver를 입력하면 이전과 똑같이 로컬 환경으로 서버를 열 수 있다. 하지만 python(3) manage.py runserver 0.0.0.0:8000 이렇게 하면? 외부 접속을 8000번 포트로 가능하게 해주는 것으로, 본인 AWS EC2 페이지에 있는 퍼블릭 IPv4 주소:8000 이렇게 검색하면 들어갈 수 있게 된다!

이 단계에서 사실 3-tier 배포 자체는 완료한 것으로 볼 수 있다.

다만 Django의 경우 DisallowedHost 에러가 발생할 텐데, 이는 당연한 것으로 이제 이걸 해결해보러 가보자!!

7. 호스트 접근 권한 수정하기

DisallowedHost 에러는 말 그대로 현재 접근한 호스트가 권한이 허락되지 않았다는 것을 뜻한다! 이걸 해결하기 위해선 Django 앱의 config/settings.py의 ALLOWED_HOSTS를 수정해줘야 한다.

// 자신의 프로젝트 디렉토리 내에서
sudo vi config/settings.py

그럼 settings.py가 뜰 텐데, 기본값은 DEBUG = True에 ALLOWED_HOSTS는 비어 있을 것이다. 여기다가 ALLOWED_HOSTS를 일단 *로 설정해둔다. 의미는 모든 호스트를 허용한다는 뜻으로, 개발 환경에서는 편의를 위해 사용하지만 실제 배포 단계에 가면 본인의 도메인으로 바꿔 설정해줘야 하고, DEBUG도 False로 바꿔줘야 한다.

이렇게 설정해주고 서버를 0.0.0.0:8000으로 다시 열면 접속 가능해질 것이다~!

8. Gunicorn 연결하기

실제 서버를 배포할 때는 runserver 명령을 사용하는 것이 아닌, WSGI를 사용해야 한다!

위스기가 뭐냐면,

위스기는 Web Server Gateway Interface인데, Nginx, Apache와 같은 서버들은 django, flask로 작성한 web application을 이해하지 못한다. 이 때 WSGI를 이용해 웹 서버와 우리가 작성한 애플리케이션이 서로 통신할 수 있다. (외국인과 나 사이에 번역가가 필요한 것과 비슷하다)

출처: 🤔WSGI는 무엇일까?

우리가 사용할 Gunicorn은 WSGI 기능을 가진 라이브러리이다~

사용하려면, 설치해야겠지?

pip install gunicorn

설치가 된 후에는 wsgi.py 파일이 존재하는 config 폴더가 존재하는 디렉토리로 이동한다.

gunicorn --bind 0:8000 config.wsgi:application

이건 뭐냐면 방금까지 runserver로 실행시켰던 서버를 gunicorn으로 실행시킨 것이다!! 다만 스타일이 깨질 것인데, 이것도 좀 이따 해결할거다!! 우선은

python manage.py collectstatic

를 통해 css 등 정적 파일들을 모은 staticfiles 디렉토리만 생성해놓자.

이제부터 중요하다!

cd /etc/systemd/system
sudo vi 프로젝트명.service

해당 경로에 프로젝트명.service 파일을 생성하고 다음 내용을 작성하자!

[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=ubuntu
Group=ubuntu
WorkingDirectory="자신의 ubuntu 내 작업 디렉토리 경로"
EnvironmentFile="환경변수 위치"
ExecStart="gunicorn 설치 위치(보통 venv 내부)" \
--workers 2 \
--bind unix:/tmp/gunicorn.sock \
config.wsgi:application
[Install]
WantedBy=multi-user.target

WorkingDirectory 경로를 잘 적어주는게 중요하다!!!

ExecStart는 시작 명령어이고, Install은 서버 재시작 시 gunicorn도 재시작해주기 위한 명령어이다.

다 작성했으면 저장하고,

sudo systemctl start 프로젝트명.service

아무것도 안뜨면, 시작이 된 것이다! 그 다음

sudo systemctl enable 프로젝트명.service

를 입력하면 symlink가 생성되었다는 메시지가 출력된다. 참고로 enable은 시스템 부팅 시 서비스가 자동으로 start되도록 설정하는 것이다!! 편하겠다~~

잘 실행되는 지 궁금하다면?

sudo systemctl status 프로젝트명.service

여기서 초록 글씨로 active(running)이 뜨면 정상!!

9. Nginx 연결하기

슬슬 끝이 보인다...!

Nginx를 쓰는 이유는 다양한데, 연습인만큼 여기서는 정적 파일 서빙(staticfiles)을 제1의 목적으로 도입해보겠다~

사용하려면, 설치해야겠지?(2트)

sudo apt install nginx

설치한 후에 nginx에 웹 서버 설정파일을 만들어 줄거다!

sudo vi /etc/nginx/sites-available/

이 경로로 가보면 default 파일이 있는데, 여기서 기본적으로 80 포트에 대한 응대를 해주고 있어서, nginx를 설치하기만 해도 아까 그 포트로 접속하면
"Welcome to Nginx!" 라는 문구가 뜨게 된다~

이제 우리 서비스가 서빙되도록 새로운 설정 파일을 만들자!!

sudo vi /etc/nginx/sites-available/프로젝트명

생성을 하고, vi 편집기를 켜서 다음과 같이 입력한다.

server {
    listen "서버를 열 포트";
    server_name "IP 또는 도메인 이름";

    location = /favicon.ico {
        access_log off;
        log_not_found off;
    }

    location /static/ {
        alias "staticfiles 경로";
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/tmp/gunicorn.sock;
    }
}

이렇게 설정을 마치고,

sudo ln -s /etc/nginx/sites-available/프로젝트명 /etc/nginx/sites-enabled/

이 명령어를 통해 symlink를 연결해준다. 프로젝트명과 /etc 사이 공백에 유의하자!!! 이렇게 되면, 시스템 부팅 시에 nginx도 자동으로 시작하게 되는 것이다~~
(enabled에서 눈치챘다면 훌륭하다 아쎄이!!)

이렇게 해준 후

ls /etc/nginx/sites-enabled/

를 입력하면 디렉 내 폴더 구조가

프로젝트명 default

이렇게 아주 이쁘게 자리하고 있을 것이다. 그 후 start nginx, enable nginx, restart nginx 하면 접속이 될 것이다!!!

물론 아직 끝나지 않았다. 들어가보면 여전히 스타일이 깨져 있을 것이고, 콘솔을 열면 style.css 파일에 403 에러가 떠 있을 거다!! 이제 이걸 해결하러 가보쟈.

10. nginx.conf 파일 수정하기

403 에러는 뭘까? 이것 역시 권한 관련 에러로, nginx가 static 파일들은 찾았지만, 접근을 못하고 있다는 상태를 말한다! 이를 해결하기 위해선 nginx.conf 파일에서 권한을 부여해주면 된다.

sudo vi /etc/nginx/nginx.conf

들어가면, 맨 첫 줄에

user www-data;

이렇게 적혀 있을 건데, 여기에 유저네임을 입력해주자! 우리는 지금 따로 설정해주지 않았기 때문에 ubuntu 서버 기본 유저네임인 ubuntu를 입력하면 된다!

참고로 유저네임은 터미널에

whoami

라고 입력하면 알 수 있다.

그럼 이제 ubuntu를 www-data 옆에 적고 저장해준 뒤 nginx를 재시작해주면 끝!!!

11. SSL 인증을 통해 HTTPS 적용하기

끝인줄 알았는가? 현재 당신의 사이트는 굉장히 취약하다! 왜냐하면 https가 적용되지 않았기 때문이다! HTTPS란 웹 브라우저와 웹 서버 간의 통신을 암호화하는 보안 프로토콜로, 다음과 같은 이점을 제공한다.

  • 데이터 암호화: 클라이언트와 서버 간 전송되는 데이터를 암호화
  • 데이터 무결성: 전송 중 데이터가 변조되지 않았음을 보장
  • 인증: SSL/TLS 인증서를 통해 접속한 웹사이트가 신뢰할 수 있는 곳인지 확인
    http를 https로 바꾸는 것은 아주 간단하다~~ 우리의 certbot이라는 녀석이 알잘딱깔센으로 잘 바꿔주는데, 우리는 명령어 몇 줄만 치면 된다.'

참고로 https로 접근하려면 도메인이 필수인데, 있다고 가정하겠다.
내도메인.한국 이곳에 들어가면 무료 도메인을 받을 수 있는데, 실습이나 테스트 때 아주 유용하다!!

sudo snap install core
sudo snap refresh core
sudo apt remove certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

sudo certbot --nginx

이러면 이메일을 입력하라고 뜨는데, 이는 ssl 인증이 3개월 마다 갱신해야 하는데 이걸 이메일로 보내주기 때문이다. 이메일을 오타 없이 잘 입력하도록 하자!! 이러면 nginx에 설정된 도메인을 자동으로 읽어와서 보여주고, 여기다 ssl 인증 할래? 라고 물어본다!!

YESYESYES!!!

Successfully 어쩌구가 뜨면 끝!!!

이렇게 하면 모든 과정이 끝났다! 축하합니다! 이제 당신도 배포 장인!!!

profile
Focusing on what I can change

0개의 댓글