이 글에서는 웹에 실제 flask 앱을 배포하는데 있어, ssl인증을 받고 https 프로토콜로 배포하는 방법에 대해서 설명합니다.
플라스크 | flask - python을 nginx에 올려서 https 프로토콜로 배포하기 7 단계
홈 디렉토리에 flask라는 디렉토리 하부에 flask 앱을 개발해 놓았습니다. 이제 flask 앱을 nginx를 통해 https 프로토콜로 배포하려고 합니다.
flask/app.py가 개발해 놓은 flask 앱입니다.
Flask 애플리케이션을 NGINX 웹 서버에서 HTTPS 프로토콜로 배포하려면 다음 절차 대로 진행합니다.
1. 가상 환경 구축:
Flask 애플리케이션에는 여러 종속성이 있을 수 있으며, 이를 시스템에 직접 설치하는 대신 가상 환경을 사용하는 것이 좋습니다.
$ sudo apt install python3.8-venv $ python3 -m venv venv $ ls flask venv work ... $ source venv/bin/activate (venv) $ pip install Flask gunicorn
2. Gunicorn 설치 및 실행
Gunicorn은 Flask 애플리케이션을 WSGI로 서빙하는데 사용됩니다. Gunicorn을치한 후 애플리케이션을 실행하세요.
(venv) ~/flask$ gunicorn app:app [2023-06-03 18:58:38 +0900] [264] [INFO] Starting gunicorn 20.1.0 [2023-06-03 18:58:38 +0900] [264] [INFO] Listening at: http://127.0.0.1:8000 (264) [2023-06-03 18:58:38 +0900] [264] [INFO] Using worker: sync [2023-06-03 18:58:38 +0900] [266] [INFO] Booting worker with pid: 266
3. NGINX 설치 및 설정:
NGINX를 설치한 후, HTTP를 위한 설정을 생성하고 반영합니다.
$ sudo apt-get install nginx $ sudo vi /etc/nginx/sites-available/myflaskapp
설정 파일에 다음을 입력하세요:
your_domain_or_ip에는 사용하는 도메인 주소나 IP 주소를 입력합니다.
server {listen 80;server_name your_domain_or_ip; location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://localhost:8000; } }
4. 심볼릭 링크 생성 및 NGINX 구성 테스트:
설정 파일에 대한 심볼릭 링크를 생성하고 구성이 올바른지합니다.
$ sudo ln -s /etc/nginx/sites-available/myflaskapp /etc/nginx/sites-enabled
$ sudo nginx -t
nginx: [warn] conflicting server name "yt.2story.org" on 0.0.0.0:80, ignored
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
5. nginx 시작 및 앱 정상 서비스 테스트
nginx의 default 설정은 지우고 테스트 확인합니다.
(venv) $ sudo rm /etc/nginx/sites-enabled/default (venv) $ sudo /etc/init.d/nginx restart (venv) $ sudo rm /etc/nginx/sites-enabled/default
6. SSL 인증서 발급 및 설치:
HTTPS를 사용하려면 SSL 인증서가 필요합니다. Let's Encrypt의 인증서 발급 도구인 Certbot을 사용할 수 있습니다.
$ sudo apt-get install certbot python3-certbot-nginx
$ sudo certbot --nginx
Certbot은 설정에 따라 /etc/letsencrypt/live/your_domain_or_ip 경로에 SSL 인증서 저장합니다. 이것을 NGINX 설정 파일 내의 ssl_certificate( 및 ssl_certificate_key 항목에 입력합니다.
(venv) eeddyit@linux-debian:~/flask$ sudo certbot --nginx Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator nginx, Installer nginx Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): xxxx@gmail.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must agree in order to register with the ACME server. Do you agree? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Y - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Would you be willing, once your first certificate is successfully issued, to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Y Account registered. Which names would you like to activate HTTPS for? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1: yt.2story.org - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the appropriate numbers separated by commas and/or spaces, or leave input blank to select all options shown (Enter 'c' to cancel): 1 Requesting a certificate for yt.2story.org Performing the following challenges: http-01 challenge for yt.2story.org Waiting for verification... Cleaning up challenges Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/myflaskapp Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/myflaskapp - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Congratulations! You have successfully enabled https://yt.2story.org - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Subscribe to the EFF mailing list (email: lsw0075@gmail.com). IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/yt.2story.org/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/yt.2story.org/privkey.pem Your certificate will expire on 2023-09-01. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le (venv) eeddyit@linux-debian:~/flask$ sudo ls /etc/letsencrypt/live/ README yt.2story.org (venv) eeddyit@linux-debian:~/flask$ sudo ls /etc/letsencrypt/live/yt.2story.org README cert.pem chain.pem fullchain.pem privkey.pem
7. NGINX 및 Gunicorn 실행:
실제 nginx 설정 파일은 아래와 같은 형태로 자동 수정되어있습니다.
server {
listen 80;
server_name your_domain_or_ip;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name your_domain_or_ip;
ssl_certificate /path/to/your/fullchain.pem;
ssl_certificate_key /path/to/your/privkey.pem;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:8000;
}
}
이제 gunicorn을 다시 실행하는지 확인 후 nginx를 재시작 합니다.
(venv) $ gunicorn app:app (venv) $ sudo /etc/init.d/nginx restart
위의 과정이 완료되면 이제 브라우저에서 https://your_domain_or_ip로 접속해 Flask 애플리케이 실행되고 있는지 확인할 수 있습니다.
gunicorn 재시작 하기
위와 같이 모두 수행하면 서비스가 가능합니다. 그러나, gunicorn을 foreground로 수행하였으므로 다음과 같이 재수행 해줍니다.
gunicorn <application_module>:<application_name> --bind 0.0.0.0:<port_number> --workers <number_of_workers> --access-logfile <access_logfile_name> --error-logfile <error_logfile_name> --capture-output --log-level <log_level> --daemon
gunicorn app:app --bind 0.0.0.0:8000 --workers 4 --access-logfile access.log --error-logfile error.log --capture-output --log-level info --daemon