우분투 22.04에서 Flask 애플리케이션을 Gunicorn 및 Nginx로 제공하는 방법

A previous version of this tutorial was written by Kathleen Juell.

소개

이 안내서에서는 우분투 22.04에서 Flask 마이크로프레임워크를 사용하여 Python 애플리케이션을 빌드할 것입니다. 대부분의 튜토리얼은 Gunicorn 애플리케이션 서버를 설정하고 애플리케이션을 시작하고 Nginx를 전면 역방향 프록시로 구성하는 방법에 대해 다룰 것입니다.

필수 준비물

이 가이드를 시작하기 전에 다음이 있어야 합니다:

  • 우분투 22.04가 설치된 서버 및 sudo 권한이 있는 비 관리자 사용자. 지침은 초기 서버 설정 가이드를 따르십시오.

  • 우분투 22.04에 Nginx가 설치되어 있어야 합니다. 우분투 22.04에 Nginx 설치하는 방법의 1단계와 2단계를 따르세요.

  • 서버를 가리키도록 구성된 도메인 이름입니다. Namecheap에서 구매하거나 Freenom에서 무료로 얻을 수 있습니다. 관련 도메인 및 DNS 설명서를 따라 DigitalOcean에 도메인을 가리키는 방법을 배울 수 있습니다. 다음 DNS 레코드를 생성해야 합니다:

    • your_domain을(를) 서버의 공용 IP 주소로 가리키는 A 레코드입니다.
    • www.your_domain을(를) 서버의 공용 IP 주소로 가리키는 A 레코드입니다.
  • Gunicorn 서버가 Flask 애플리케이션과 통신할 때 사용할 WSGI 사양에 대한 이해가 필요합니다. 이 토론에서 WSGI에 대해 자세히 다룹니다.

단계 1 — 우분투 저장소에서 구성 요소 설치

첫 번째 단계는 우분투 저장소에서 필요한 모든 구성 요소를 설치하는 것입니다. 이에는 Python 패키지 관리자인 pip과 일부 Gunicorn 구성 요소를 빌드하는 데 필요한 Python 개발 파일이 포함됩니다.

먼저 로컬 패키지 인덱스를 업데이트하고 Python 환경을 구축하는 데 필요한 패키지를 설치합니다. 이러한 패키지에는 python3-pip과 몇 가지 추가 패키지 및 개발 도구가 포함되어 있습니다:

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

이러한 패키지가 설치되면 다음 단계는 프로젝트용 가상 환경을 만드는 것입니다.

단계 2 — Python 가상 환경 만들기

다음으로 Flask 애플리케이션을 시스템의 다른 Python 파일과 격리하기 위해 가상 환경을 설정합니다.

먼저 venv 모듈을 설치하는 python3-venv 패키지를 설치합니다:

  1. sudo apt install python3-venv

다음으로 플라스크 프로젝트를 위한 상위 디렉토리를 만드세요. 그리고 만든 후에는 cd 명령어를 사용하여 해당 디렉토리로 이동하세요:

  1. mkdir ~/myproject
  2. cd ~/myproject

플라스크 프로젝트의 Python 요구 사항을 저장할 가상 환경을 만들어주세요. 다음 명령어를 입력하세요:

  1. python3 -m venv myprojectenv

이 명령은 프로젝트 디렉토리 내에 myprojectenv라는 디렉토리에 Python과 pip의 로컬 복사본을 설치합니다.

가상 환경에 응용 프로그램을 설치하기 전에 활성화해야 합니다. 다음 명령어를 입력하여 활성화하세요:

  1. source myprojectenv/bin/activate

프롬프트가 변경되어 가상 환경 내에서 작동 중임을 나타내게 됩니다. 이는 다음과 같이 보일 것입니다: (myprojectenv)user@host:~/myproject$.

단계 3 — 플라스크 애플리케이션 설정

이제 가상 환경 내에 있으므로 플라스크와 Gunicorn을 설치하고 애플리케이션 설계를 시작할 수 있습니다.

먼저, 로컬 인스턴스의 pip를 사용하여 wheel을 설치하여 패키지가 누락된 경우에도 설치되도록 합니다:

  1. pip install wheel

참고

가상 환경이 활성화된 경우 Python의 버전과 관계없이 pip 명령을 사용해야 합니다(pip3이 아님).

다음으로 Flask와 Gunicorn을 설치하세요:

  1. pip install gunicorn flask

샘플 앱 만들기

이제 Flask를 사용하여 간단한 애플리케이션을 만들 수 있습니다. Flask는 마이크로 프레임워크입니다. 다른 풀 기능을 갖춘 프레임워크에 포함되어 있는 많은 도구가 포함되어 있지 않으며, 주로 프로젝트에 가져와 웹 애플리케이션을 초기화하는 데 도움이 되는 모듈로 존재합니다.

당신의 애플리케이션이 더 복잡할 수 있지만, 우리는 Flask 앱을 단일 파일인 myproject.py에 만들 것입니다:

  1. nano ~/myproject/myproject.py

이 파일에 애플리케이션 코드가 존재할 것입니다. Flask를 가져와 Flask 객체를 인스턴스화합니다. 이를 사용하여 특정 경로가 요청될 때 실행되어야 하는 함수를 정의할 수 있습니다:

~/myproject/myproject.py
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')

이것은 기본적으로 루트 도메인에 액세스할 때 표시할 내용을 정의합니다. 작업이 완료되면 파일을 저장하고 닫으십시오.

초기 서버 설정 가이드를 따랐다면 UFW 방화벽이 활성화되어 있어야 합니다. 애플리케이션을 테스트하려면 포트 5000에 액세스를 허용해야 합니다:

  1. sudo ufw allow 5000

이제 Flask 앱을 테스트할 수 있습니다. 다음을 입력하십시오:

  1. python myproject.py

다음과 같은 출력이 표시됩니다. 이 서버 설정을 제품에서 사용하지 말아야 한다는 유용한 경고가 포함되어 있습니다:

Output
* Serving Flask app "myproject" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

웹 브라우저에서 서버의 IP 주소 뒤에 :5000을 입력하십시오:

http://your_server_ip:5000

다음과 같은 내용이 표시되어야 합니다:

작업을 완료하면 터미널 창에서 CTRL-C를 눌러 Flask 개발 서버를 중지합니다.

WSGI 진입점 생성

다음으로, 응용 프로그램의 진입점으로 작동할 파일을 만듭니다. 이 파일은 Gunicorn 서버가 응용 프로그램과 상호 작용하는 방법을 알려줍니다.

파일 이름을 wsgi.py로 지정하십시오:

  1. nano ~/myproject/wsgi.py

이 파일에서 응용 프로그램에서 Flask 인스턴스를 가져온 다음 실행합니다:

~/myproject/wsgi.py
from myproject import app

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

작업을 마치면 파일을 저장하고 닫으십시오.

단계 4 — Gunicorn 구성

이제 응용 프로그램에 진입점이 설정되어 있습니다. 이제 Gunicorn을 구성하는 단계로 넘어갈 수 있습니다.

계속하기 전에 Gunicorn이 응용 프로그램을 올바르게 제공할 수 있는지 확인하십시오.

이를 위해 응용 프로그램의 진입점 이름을 전달하여 확인할 수 있습니다. 이는 모듈의 이름(확장자 .py 빼고)과 응용 프로그램 내의 호출 가능한 이름으로 구성됩니다. 이 경우에는 wsgi:app입니다.

또한 응용 프로그램이 공개 인터페이스에서 시작되도록 인터페이스와 포트를 바인딩할 수 있도록 0.0.0.0:5000 인수를 사용하십시오:

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

다음과 같은 출력이 표시됩니다:

Output
[2020-05-20 14:13:00 +0000] [46419] [INFO] Starting gunicorn 20.0.4 [2020-05-20 14:13:00 +0000] [46419] [INFO] Listening at: http://0.0.0.0:5000 (46419) [2020-05-20 14:13:00 +0000] [46419] [INFO] Using worker: sync [2020-05-20 14:13:00 +0000] [46421] [INFO] Booting worker with pid: 46421

웹 브라우저에서 서버의 IP 주소에 :5000을 추가하여 다시 방문하십시오:

http://your_server_ip:5000

응용 프로그램 출력이 표시되어야합니다:

정상 작동을 확인했으면 터미널 창에서 CTRL-C를 누르십시오.

가상 환경을 사용한 후에는 비활성화할 수 있습니다:

  1. deactivate

이제 Python 명령은 시스템의 Python 환경을 다시 사용합니다.

다음으로 systemd 서비스 단위 파일을 생성하십시오. systemd 단위 파일을 생성하면 Ubuntu의 init 시스템이 서버 부팅 시 Gunicorn을 자동으로 시작하고 Flask 애플리케이션을 제공할 수 있습니다.

/etc/systemd/system 디렉터리 내에 .service로 끝나는 단위 파일을 생성하십시오:

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

내부에는 메타데이터 및 종속성을 지정하는 [Unit] 섹션으로 시작합니다. 여기에 서비스에 대한 설명을 추가하고 네트워킹 대상에 도달한 후에만 이를 시작하도록 init 시스템에 알립니다:

/etc/systemd/system/myproject.service
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

다음으로 [Service] 섹션을 추가합니다. 여기에는 프로세스가 실행될 사용자 및 그룹을 지정합니다. 모든 관련 파일을 소유하는 프로세스를 보유하고있는 사용자 계정에 프로세스 소유권을 부여하십시오. 또한 Nginx가 Gunicorn 프로세스와 쉽게 통신 할 수 있도록 www-data 그룹에 그룹 소유권을 부여하십시오. 여기서 사용자 이름을 교체하십시오:

/etc/systemd/system/myproject.service
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data

다음으로 작업 디렉토리를 매핑하고 init 시스템이 프로세스에 대한 실행 파일이 가상 환경 내에 위치함을 인식할 수 있도록 PATH 환경 변수를 설정하십시오. 또한 서비스를 시작하는 명령을 지정하십시오. 이 명령은 다음을 수행합니다:

  • 3개의 워커 프로세스를 시작합니다(필요에 따라 조정하십시오)
  • 프로젝트 디렉토리 내에 Unix 소켓 파일 myproject.sock을 생성하고 바인딩합니다. 우리는 소켓 파일이 소유자와 그룹에 대한 액세스를 부여하면서 다른 액세스를 제한하기 위해 umask 값을 007로 설정할 것입니다
  • WSGI 진입점 파일 이름을 지정하고 해당 파일 내의 Python callable을 지정합니다(wsgi:app)

Systemd는 가상 환경 내에 설치된 Gunicorn 실행 파일의 전체 경로를 제공해야 합니다.

사용자 이름과 프로젝트 경로를 여러분의 정보로 대체하는 것을 잊지 마십시오:

/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

마지막으로, [Install] 섹션을 추가하십시오. 이것은 이 서비스가 부팅 시 시작되도록 허용하려면 systemd에게 어떤 것에 이 서비스를 링크할지 알려줍니다. 일반적인 다중 사용자 시스템이 실행 중일 때 이 서비스를 시작하려면 이를 원할 것입니다:

/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

[Install]
WantedBy=multi-user.target

이렇게 하면 systemd 서비스 파일이 완성됩니다. 이제 저장하고 닫으십시오.

이제 만든 Gunicorn 서비스를 시작하고 부팅 시 시작되도록 활성화할 수 있습니다:

  1. sudo systemctl start myproject
  2. sudo systemctl enable myproject

상태를 확인해 봅시다:

  1. 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 Tue 2022-05-10 19:40:41 UTC; 9s ago Main PID: 17300 (gunicorn) Tasks: 4 (limit: 2327) Memory: 56.0M CPU: 514ms CGroup: /system.slice/myproject.service ├─17300 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─17301 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─17302 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app └─17303 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app May 10 19:40:41 r systemd[1]: Started Gunicorn instance to serve myproject. . . .

오류가 발생하면 튜토리얼을 계속하기 전에 해결하십시오.

단계 5 — Nginx를 프록시 요청으로 구성하기

귀하의 Gunicorn 애플리케이션 서버는 현재 프로젝트 디렉토리의 소켓 파일에서 요청을 기다리고 있습니다. 이제 몇 가지 작은 추가를하여 Nginx를 구성하여 해당 소켓으로 웹 요청을 전달할 수 있습니다.

먼저 Nginx의 sites-available 디렉토리에 새로운 서버 블록 구성 파일을 만듭니다. 이 파일의 이름을 myproject로 지정하여 가이드의 나머지 부분과 일관성 있게 유지합니다:

  1. sudo nano /etc/nginx/sites-available/myproject

서버 블록을 열고 Nginx에 기본 포트 80에서 수신 대기하도록 지시합니다. 또한 이 블록을 서버의 도메인 이름에 대한 요청에 사용하도록 지정합니다:

/etc/nginx/sites-available/myproject
server {
    listen 80;
    server_name your_domain www.your_domain;
}

다음으로 모든 요청과 일치하는 위치 블록을 추가합니다. 이 블록 내에서 일반적인 프록시 매개변수를 지정하는 proxy_params 파일을 포함합니다. 그런 다음 proxy_pass 지시문을 사용하여 정의한 소켓으로 요청을 전달합니다:

/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 서버 블록 구성을 활성화하려면 파일을 sites-enabled 디렉토리에 링크합니다:

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

그 디렉토리에 파일이 있으면 구문 오류를 확인할 수 있습니다:

  1. sudo nginx -t

이 작업이 문제 없이 완료되면 새 구성을 읽기 위해 Nginx 프로세스를 다시 시작합니다.

  1. sudo systemctl restart nginx

마침내 방화벽을 다시 조정하세요. 더 이상 포트 5000을 통한 액세스가 필요하지 않으므로 해당 규칙을 제거할 수 있습니다. 그런 다음 Nginx 서버에 대한 완전한 액세스를 허용할 수 있습니다.

  1. sudo ufw delete allow 5000
  2. sudo ufw allow 'Nginx Full'

웹 브라우저에서 서버의 도메인 이름으로 이동할 수 있어야 합니다:

http://your_domain

애플리케이션의 출력을 확인해야 합니다:

참고: Nginx가 gunicorn의 소켓 파일에 액세스할 수 없는 경우 HTTP 502 게이트웨이 오류가 발생합니다. 일반적으로 이는 사용자의 홈 디렉터리가 내부의 파일에 대한 다른 사용자의 액세스를 허용하지 않기 때문입니다.

소켓 파일이 /home/sammy/myproject/myproject.sock로 지정된 경우 /home/sammy에 최소 0755 권한이 있는지 확인하십시오. 이렇게 권한을 변경하려면 chmod와 같은 도구를 사용할 수 있습니다:

  1. sudo chmod 755 /home/sammy

그런 다음 페이지를 새로 고치면 HTTP 502 오류가 해결되었는지 확인할 수 있습니다.

오류가 발생하는 경우 다음을 확인하십시오:

  • 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 — 애플리케이션 보안

서버로의 트래픽이 안전하게 유지되도록 당신의 도메인에 대한 SSL 인증서를 가져오겠습니다. 이를 위한 여러 가지 방법이 있습니다. 이 중에는 Let’s Encrypt에서 무료 인증서를 받는 것, 자체 서명된 인증서 생성, 또는 다른 공급업체에서 구매하고 단계 2에서 6까지 따라 Ubuntu 22.04에서 Nginx를 위한 자체 서명된 SSL 인증서 생성하는 방법을 구성합니다. 우리는 편의상 옵션 하나( Let’s Encrypt)를 사용할 것입니다.

apt를 사용하여 Certbot의 Nginx 패키지를 설치하십시오:

  1. sudo apt install python3-certbot-nginx

Certbot은 플러그인을 통해 다양한 방법으로 SSL 인증서를 얻을 수 있습니다. Nginx 플러그인은 Nginx를 다시 구성하고 필요할 때마다 구성을 다시로드하는 작업을 담당합니다. 이 플러그인을 사용하려면 다음을 입력하십시오:

  1. sudo certbot --nginx -d your_domain -d www.your_domain

이 명령은 --nginx 플러그인을 사용하여 -d를 사용하여 인증서가 유효해야 하는 이름을 지정하여 certbot을 실행합니다.

만약 이것이 certbot를 처음 실행하는 경우, 이메일 주소를 입력하고 서비스 약관에 동의하라는 메시지가 나타납니다. 이후에, certbot는 Let’s Encrypt 서버와 통신한 다음, 도메인을 제어하는지 확인하기 위해 도전 과제를 실행합니다.

만약 이 과정이 성공하면, certbot은 HTTPS 설정을 어떻게 구성할지 물어봅니다:

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):

원하는 설정을 선택하고 ENTER를 누릅니다. 설정이 업데이트되고, Nginx가 새로운 설정을 반영하기 위해 다시로드됩니다. certbot은 프로세스가 성공적으로 완료되었음을 알리는 메시지와 인증서가 저장된 위치를 안내합니다:

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

설치하기 전에 Nginx 설치 지침을 따랐다면, 중복된 HTTP 프로필 허용이 더 이상 필요하지 않습니다:

  1. sudo ufw delete allow 'Nginx HTTP'

구성을 확인하려면 다시 한번 도메인으로 이동하여 https://를 사용합니다:

https://your_domain

브라우저의 보안 표시기와 함께 애플리케이션 출력을 다시 확인해야 합니다. 이 표시기는 사이트가 보안되었음을 나타내어야 합니다.

결론

이 안내서에서는 Python 가상 환경 내에서 간단한 Flask 애플리케이션을 생성하고 보안을 설정했습니다. WSGI 진입점을 생성하여 모든 WSGI 호환 애플리케이션 서버가 해당 서버와 상호 작용할 수 있도록하고, 이 기능을 제공하기 위해 Gunicorn 앱 서버를 구성했습니다. 그 후에는 부팅 시 자동으로 애플리케이션 서버를 시작하도록 systemd 서비스 파일을 생성했습니다. 또한 웹 클라이언트 트래픽을 애플리케이션 서버로 전달하는 Nginx 서버 블록을 생성하여 외부 요청을 중계하고 Let’s Encrypt로 서버 트래픽을 보안했습니다.

Flask는 매우 간단하지만 구조와 디자인에 대해 너무 제한적이지 않고 애플리케이션에 기능을 제공하기 위한 유연한 프레임워크입니다. 이 안내서에서 설명한 일반 스택을 사용하여 설계한 Flask 애플리케이션을 제공할 수 있습니다.

Source:
https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-ubuntu-22-04