본문 바로가기
개발/웹

Flask 블로그 제작기 (2) - Nginx와 Gunicorn로 Flask 배포

by pandatta 2022. 9. 13.

플라스크로 서비스되던 구버전 블로그에서 옮겨왔습니다.


이 Dwarf in the Flask 웹사이트를 Flask로 만든 것은 이름으로부터도 알 수 있습니다만, 이러한 웹 사이트, 다른 말로는 웹 어플리케이션은 Flask와 같은 웹 프레임워크만으로 구동되지는 않습니다. NginxApache같은 웹서버는 필수적이고, Flask나 Django, FastAPI같은 python 웹 프레임워크의 경우에는 Gunicorn이나 uWSGI같은 WSGI 서버가, 웹서버의 기능을 일부 대체해주기 위해 필요합니다.

웹서버, WSGI 서버, 어플리케이션

(1) 웹서버, (2) WSGI 서버, (3) Flask 어플리케이션이 모두 실행되어야 웹사이트를 배포할 수 있습니다. Flask 튜토리얼을 따라가면서 flask run 명령어를 통해 웹사이트를 실행시켜보긴 했지만, Flask에서 내부적으로 구동하는, Flask 개발팀이 만든 Werkzeug WSGI는 테스트용이라 조금이라도 큰 어플리케이션에서는 잘 구동되지 않습니다. 자세한 사항은 제가 웹사이트를 만들 때 참고했던 레퍼런스를 참고해주세요.

그래서 우리는 웹서버와 WSGI 서버를 설치하고 실행한 뒤 Flask와 연결해야하는데요, 저는 웹서버로는 Nginx(엔진엑스), WSGI 서버로는 Gunicorn(유니콘)을 선택했습니다. Nginx VS Apache의 대결에서는 Nginx의 가벼움을 선택했고, Gunicorn VS uWSGI의 대결에서는 Gunicorn의 속도가 미세하게 빠르다는 레퍼런스를 어디선가 봤기 때문에 Gunicorn을 선택했습니다. 그와 별개로, Flask는 많은 경우에 Nginx와 Gunicorn의 조합을 선택하는 경우가 많아, 참고하기에도 좋았습니다. 대표적인 예시로 이 튜토리얼이 있었는데요, 비록 영어지만 정말 상세히 설명되어있어 해당 사이트만 참조하더라도 Flask를 거의 배포할 수 있었습니다.

물론 지금 설명은 도메인이 연결되었다는 전제 하에 이루어졌긴 합니다. 이 웹사이트의 도메인 연결은 이 튜토리얼을 따라 GoDaddy에서 도메인을 사서 Route53으로 호스팅했습니다. 도메인이 연결되지 않았다면, 도메인이 적혀있는 모든 부분을 서버의 IP로 바꾸면 됩니다.

Gunicorn 세팅

pip install gunicorn을 통해 Gunicorn을 설치하고 나면, 사실 Gunicorn이 해줄 것은 별로 없습니다. 일단 이런 명령어가 있다는 것만 알고 넘어갑시다. 실행은 아래에서 따로 해줍니다. 다음과 같은 명령어인데요,

gunicorn --workers 3 --bind 0.0.0.0:5000 -m 007 "dwarf_in_the_flask:create_app()"

여기서 dwarf_in_the_flask는 Flask 어플리케이션을 실행하는 메인 모듈 dwarf_in_the_flask.py의 basename이고, create_app()은 Flask 어플리케이션을 반환하는 메인 메써드의 이름입니다. 이를0.0.0.0:5000 IP에 실행한다는 뜻이겠죠. -m 007은 bitmask 007, 즉 gunicorn이 이제부터 해당 앱으로 작성하는 파일들의 권한을 chmod로 제한한다는 것이고, --workers 3은 프로세스를 3개만 쓴다는 뜻입니다. 조금 복잡해보이지만, 사실 Flask application을 Gunicorn이 wrapping해서 실행한다고 생각해도 무방합니다.

Service 세팅

이제 여러분의 ubuntu 서버가 실행되면 자동으로 gunicorn 명령어가 실행되도록 세팅합니다. /etc/systemd/system/dwarf-in-the-flask.service와 같은 경로에 .service 파일을 만들어줍니다. 내용은 다음과 같이 작성합니다.

[Unit]
Description=Gunicorn instance to serve dwarf-in-the-flask
After=network.target  # 이 서버가 네트워크 접속의 타겟이 되었을 때,

[Service]
User=ubuntu
Group=www-data  # www-data 그룹에게 Gunicorn 커뮤니케이션 권한을 주고,
WorkingDirectory=/home/ubuntu/dwarf-in-the-flask
Environment="PATH=/home/ubuntu/miniconda3/bin/"  # 이 python 환경에서, 다음과 같은 명령어를 실행한다.
ExecStart=/home/ubuntu/miniconda3/bin/gunicorn --workers 3 --bind unix:dwarf-in-the-flask.sock -m 007 "ditf:create_app()"

[Install]
WantedBy=multi-user.target  # ubuntu 실행 시 자동실행

이제 systemctl 명령어를 이용해서 이 파일을 서비스로 실행시켜보겠습니다. Ubuntu 서버를 껐다 켤 때마다 자동실행될 것이고, 잘 실행되고 있는지 상태도 확인할 수 있습니다.

sudo systemctl start dwarf-in-the-flask  # 서비스 실행
sudo systemctl enable dwarf-in-the-flask  # 서비스 자동실행가능
sudo systemctl status dwarf-in-the-flask  # 서비스 상태 확인

Nginx 세팅

위와 같이 Gunicorn을 세팅하고 나면, 이제 Gunicorn이 외부로부터 들어오는 네트워크 접속 요청에 반응해 Flask를 건드릴 수 있습니다. 네트워크 접속 요청을 받아와주는 Nginx를 세팅해봅시다. /etc/nginx/sites-available/dwarf-in-the-flask와 같은 경로에 파일을 하나 만들어줍니다.

server {
        listen 80 default_server;
        return 403;  # 도메인이 아닌 IP로 접속하고자 하는 시도는 차단
}
server {
        listen 80;  # 80번, 즉 HTTP 포트로 들어오는 접속에 대해,
        listen [::]:80;
        server_name dwarfintheflask.xyz www.dwarfintheflask.xyz;  # 다음과 같은 도메인 요청이라면,
        access_log /var/log/nginx/dwarf-in-the-flask-access.log;  # 이 파일에 로그를 할 것이며,

        location / {  # 프록시 정보를 소켓 형태로 전달
                include proxy_params;
                proxy_pass http://unix:/home/ubuntu/dwarf-in-the-flask/dwarf-in-the-flask.sock;
        }
}

ln -s /etc/nginx/sites-available/dwarf-in-the-flask /etc/nginx/sites-enabled 와 같이 sites-enabled 폴더에 링크를 생성해주면, 이제 해당 ubuntu 서버에 dwarfintheflask.xyz 도메인을 타고 들어오는 요청은 소켓에 저장되며, 해당 소켓을 통해 Gunicorn이 소통하게 됩니다.

sudo systemctl daemon-reload
sudo systemctl restart nginx
sudo systemctl status nginx

Nginx도 마찬가지로 systemctl로 서비스를 재시작하면, 이제 해당 도메인 접근 시 /var/log/nginx/dwarf-in-the-flask-access.log 로그가 쌓이면서 접속이 가능해질 것입니다.

방화벽(ufw)

접속이 불가능하다면 아마 방화벽 차단 문제일 것입니다. 저처럼 AWS EC2를 구매하시고 접속하신 분들은, 처음에는 방화벽이 활짝 열려있을 것입니다. 당연히 열려있으니 SSH, 즉 22번 port 접속도 가능하실 거구요. 이제 방화벽을 활성화해보도록 합시다.

sudo ufw enable
sudo ufw allow 22

22번 포트는 바로 열어주도록 합시다. 저는 닫혀있는 상태로 작업하다가 다시 EC2에 못들어가는 낭패를 보았습니다... 해결책은 이 블로그 포스트에 있지만, 여러분들은 저처럼 바보짓을 하지 않도록 합시다.

그 외의 건드려야할 방화벽 설정은 다음과 같습니다. 만약 HTTP allow인데도 웹사이트 접속이 안된다면, AWS EC2 보안그룹 설정에 0.0.0.0:80이 열려있는지 확인해주세요.

sudo ufw status  # 방화벽 현재 상태
sudo ufw allow 5000  # gunicorn 테스트를 위한 5000번 포트
sudo ufw allow 'Nginx HTTP'  # HTTP 포트
sudo ufw allow 'Nginx HTTPS'  # HTTPS 포트, 지금은 SSL 인증이 없어 불필요합니다.
sudo ufw allow 'Nginx Full'  # HTTP + HTTPS
sudo ufw delete allow 'Nginx HTTP'  # 방화벽 허용을 다시 차단합니다.

웹사이트를 만드는 과정에서 가장 복잡한 부분이지만, 한 번 이해하면 은근 단순한 부분이니 여러분 웹사이트에도 예쁘게 적용해보도록 합시다!

댓글