보안연결(HTTPS)이 가능한 웹페이지를 만들어보자(Ubuntu 20.04 + Gunicorn + Nginx + Flask)

Halo·2021년 10월 8일
2

Web

목록 보기
1/1
post-thumbnail
post-custom-banner

시작하기에 앞서 Instance에서 작업시 80,443,5000번 포트가 개방되어 있어야합니다.

1. 구성요소 설치

sudo apt update
sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools

2. Python 가상환경

패키지 설치

sudo apt install python3-venv

폴더 생성 후 이동

mkdir ~/myproject
cd ~/myproject

가상환경 생성

python3 -m venv myprojectenv

가상환경 접속

source myprojectenv/bin/activate

성공시 아래처럼 앞부분에 가상환경명이 추가된다.

(myprojectenv)user@host:~/myproject$

3. Flask 앱 생성

wheel 아카이브가 없는 경우에도 패키지가 설치되도록 하기 위해 설치

pip install wheel

Flask, Gunicorn 패키지 설치

pip install gunicorn flask

테스트앱 생성

nano ~/myproject/myproject.py
# CODE
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:blue'>Hello There!</h1>"

if __name__ == "__main__":
    app.run(host='0.0.0.0')

앱 접속을 위한 리눅스 포트 오픈(Flask 기본 5000)

sudo ufw allow 5000

Flask앱 - wsgi 연결

nano ~/myproject/wsgi.py
# CODE
from myproject import app

if __name__ == "__main__":
    app.run()

4. Gunicorn 설정

접속 가능 여부 확인

cd ~/myproject
gunicorn --bind 0.0.0.0:5000 wsgi:app

정상 동작 확인 후 가상환경 종료

deactivate

우분투 시작시 자동으로 시작할 수 있게 데몬에 등록
파일생성

sudo nano /etc/systemd/system/myproject.service

파일내부 복붙

[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy(우분투계정이름)
Group=www-data
WorkingDirectory=/home/sammy/myproject(작업하고있는경로)
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"(환경경로)
ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app

서비스파일을 위와같이 작성 후 부팅시 시작할 수 있게 등록하는 과정

sudo systemctl start myproject
sudo systemctl enable myproject
sudo systemctl status myproject

성공적으로 등록시 아래와 같이 에러가 없어야 합니다.

Output
● myproject.service - Gunicorn instance to serve myproject
     Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2020-05-20 14:15:18 UTC; 1s ago
   Main PID: 46430 (gunicorn)
      Tasks: 4 (limit: 2344)
     Memory: 51.3M
     CGroup: /system.slice/myproject.service
             ├─46430 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
             ├─46449 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
             ├─46450 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
             └─46451 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app

5. 들어온 요청을 Nginx로 프록시하는 설정

sudo nano /etc/nginx/sites-available/myproject
server {
    listen 80;
    server_name your_domain www.your_domain;(본인의 도메인 작성)

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/sammy/myproject/myproject.sock;
    }
}

위에서 작성한 Nginx서버블록을 활성화 하기위해 /etc/nginx/sites-enabled에 연결

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

정상적으로 등록시 아래의 명령에 에러가 없어야합니다.

sudo nginx -t

Nginx가 정상 동작시 설정 적용을 위해 Nginx 재시작

sudo systemctl restart nginx

위의 모든 과정을 정상적으로 등록했다면 방화벽을 설정해줍니다.
5000포트는 Flask의 기본 포트로 필요하지 않고 'Nginx Full'을 이용해 80,443 포트를 이용할 수 있게 설정합니다.

sudo ufw delete allow 5000
sudo ufw allow 'Nginx Full'

모든 설정이 완료되면 도메인접속시 웹페이지가 정상적으로 열립니다.

http://your_domain

오류 발생시 로그 확인법

sudo less /var/log/nginx/error.log: Nginx 오류 로그를 확인합니다.
sudo less /var/log/nginx/access.log: Nginx 액세스 로그를 확인합니다.
sudo journalctl -u nginx: Nginx 프로세스 로그를 확인합니다.
sudo journalctl -u myproject: Flask 앱의 Gunicorn 로그를 확인합니다.

6. 보안웹페이지로 구성하기

현재까지 작업으로는 웹페이지가 http로 설정되어 보안에 취약한 상태입니다.
이를 보안접속인 https를 이용하기 위해선 도메인에 SSL인증을 받아야하는데,
1. 직접인증서를 만드는 방법 과
2. 다른 공급자에게 구매하는 방법 이 있습니다.
여기서는 간편하게 무료로 SSL 인증을 받는 2번 방법을 이용하겠습니다.

sudo apt install python3-certbot-nginx
sudo certbot --nginx -d your_domain -d www.your_domain

성공적으로 완료하면 처음 작업시 1. 이메일 주소를 입력하고 2. 약관에 동의하라는 안내가 나오니 안내에 따라 작성합니다. 그럼 아래와 같은 안내를 받을 수 있습니다.

Output
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
-------------------------------------------------------------------------------
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

이 설정은 웹페이지를 80포트(HTTP)로 접속한 사람을 443포트(HTTPS)로 자동으로 변경하여 접속시켜주길 원한다면 2번 아니라면 1번을 설정하라는 안내인데 여기선 2번으로 진행하겠습니다.

Output
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/your_domain/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/your_domain/privkey.pem
   Your cert will expire on 2020-08-18. 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"
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - 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

설정이 완료되면 위와같은 결과를 확인할 수 있습니다.
이제 HTTP의 접속은 필요하지 않으니 방화벽에 등록된 HTTP 연결을 지워주고 HTTPS로 도메인 연결을 확인합니다.

sudo ufw delete allow 'Nginx HTTP'
https://your_domain

출처

출처1

profile
일단 해보자 !
post-custom-banner

2개의 댓글

comment-user-thumbnail
2022년 3월 27일

도움 많이 됐습니다. 감사합니다.
Lightsail에서 해봤는데, 이상하게 www만 dns를 찾고 www가 안붙은건 dns를 못찾더라구요.. 제가 중간에 뭘 빠트렸나봅니다.

1개의 답글