Kiến thức Hữu ích 😍

Hướng Dẫn Triển Khai Flask Với Gunicorn & Nginx Trên Ubuntu 20.04


Triển khai một ứng dụng web không chỉ đơn thuần là viết mã xong và cho nó chạy. Để đảm bảo ứng dụng hoạt động ổn định, an toàn và có khả năng mở rộng, việc lựa chọn một kiến trúc triển khai vững chắc là vô cùng quan trọng. Nhiều nhà phát triển khi mới bắt đầu thường gặp khó khăn khi đưa ứng dụng Flask từ môi trường lập trình ra môi trường sản xuất thực tế. Chạy ứng dụng trực tiếp bằng máy chủ phát triển tích hợp của Flask là một giải pháp tiện lợi khi lập trình, nhưng lại tiềm ẩn nhiều rủi ro về hiệu năng và bảo mật.

Vậy làm thế nào để giải quyết vấn đề này? Câu trả lời nằm ở sự kết hợp mạnh mẽ giữa Gunicorn và Nginx là gì. Gunicorn đóng vai trò là một máy chủ WSGI (Web Server Gateway Interface) mạnh mẽ, giúp chạy ứng dụng Python của bạn với nhiều tiến trình song song, tăng khả năng xử lý đồng thời. Trong khi đó, Nginx hoạt động như một reverse proxy, đứng ở tuyến đầu tiếp nhận tất cả yêu cầu từ người dùng, xử lý các tệp tĩnh và chuyển tiếp các yêu cầu động đến Gunicorn một cách hiệu quả. Bài viết này sẽ hướng dẫn bạn chi tiết từng bước để triển khai ứng dụng Flask trên Ubuntu 20.04 với Gunicorn và Nginx, tạo ra một hệ thống hiệu quả, an toàn và dễ quản lý.

Hình minh họa

Cài đặt môi trường Ubuntu 20.04 cho ứng dụng Flask

Để bắt đầu hành trình triển khai, bước đầu tiên và quan trọng nhất là chuẩn bị một môi trường sạch sẽ và đầy đủ công cụ trên máy chủ Ubuntu 20.04 của bạn. Một nền tảng vững chắc sẽ giúp quá trình cài đặt và cấu hình sau này diễn ra suôn sẻ hơn.

Chuẩn bị hệ thống và cập nhật gói

Trước khi cài đặt bất kỳ phần mềm nào, bạn nên cập nhật danh sách gói của hệ thống để đảm bảo rằng bạn đang sử dụng các phiên bản mới và an toàn nhất. Hãy mở terminal và chạy các lệnh sau:

sudo apt update
sudo apt upgrade

Sau khi hệ thống đã được cập nhật, chúng ta cần cài đặt các công cụ cần thiết để xây dựng và chạy ứng dụng Python, bao gồm Python 3, pip (trình quản lý gói của Python), và các thư viện phát triển.

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

Bước tiếp theo, và cũng là một thực hành tốt nhất (best practice) trong lập trình Python, là tạo một môi trường ảo (virtual environment). Môi trường ảo giúp cô lập các thư viện và gói phụ thuộc của dự án, tránh xung đột với các dự án khác hoặc với các gói hệ thống.

mkdir myproject
cd myproject
python3 -m venv venv

Lệnh này sẽ tạo một thư mục tên venv chứa các tệp thực thi Python và một bản sao của thư viện pip. Để bắt đầu sử dụng môi trường ảo này, bạn cần kích hoạt nó:

source venv/bin/activate

Bạn sẽ thấy tên môi trường ảo (venv) xuất hiện ở đầu dòng lệnh, cho biết bạn đang làm việc bên trong nó.

Hình minh họa

Cài đặt Flask và tạo ứng dụng mẫu

Khi môi trường ảo đã được kích hoạt, mọi gói Python bạn cài đặt bằng pip sẽ chỉ thuộc về môi trường này. Bây giờ, chúng ta sẽ cài đặt Flask:

pip install flask

Để kiểm tra việc triển khai, chúng ta cần một ứng dụng Flask đơn giản. Hãy tạo một tệp mới tên là app.py bằng trình soạn thảo văn bản bạn yêu thích (ví dụ: nano app.py) và thêm đoạn mã sau:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1>Xin chào từ ứng dụng Flask!</h1>"

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

Đoạn mã này tạo ra một ứng dụng web vô cùng cơ bản với một trang duy nhất, trả về dòng chữ “Xin chào từ ứng dụng Flask!”. Để thử nghiệm, bạn có thể chạy máy chủ phát triển tích hợp của Flask. Tuy nhiên, hãy nhớ rằng máy chủ này chỉ dành cho mục đích gỡ lỗi và không nên được sử dụng trong môi trường sản xuất.

flask run --host=0.0.0.0

Bây giờ, ứng dụng của bạn đã sẵn sàng để được phục vụ bởi một máy chủ mạnh mẽ hơn.

Hình minh họa

Cài đặt và cấu hình Gunicorn làm máy chủ WSGI

Sau khi đã có một ứng dụng Flask mẫu và môi trường được chuẩn bị, bước tiếp theo là cài đặt Gunicorn. Gunicorn (Green Unicorn) là một máy chủ HTTP WSGI dành cho Python, được thiết kế để phục vụ các ứng dụng Python một cách hiệu quả và ổn định. Nó hoạt động như một cầu nối giữa máy chủ web (như Nginx) và ứng dụng Flask của bạn.

Cài đặt Gunicorn

Đảm bảo rằng bạn vẫn đang ở trong môi trường ảo đã kích hoạt ở bước trước. Việc cài đặt Gunicorn cũng đơn giản như cài đặt Flask, chỉ cần sử dụng pip:

pip install gunicorn

Sau khi cài đặt hoàn tất, bạn có thể kiểm tra xem Gunicorn đã hoạt động đúng cách chưa. Để làm điều này, chúng ta cần một điểm vào (entry point) cho Gunicorn. Tạo một tệp mới tên là wsgi.py:

nano wsgi.py

Và thêm nội dung sau vào tệp:

from app import app

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

Tệp wsgi.py này chỉ đơn giản là nhập biến app từ tệp app.py của bạn. Đây là một thực hành tốt để tách biệt điểm vào của ứng dụng cho các máy chủ WSGI.

Chạy Flask ứng dụng qua Gunicorn

Bây giờ, bạn có thể sử dụng Gunicorn để chạy ứng dụng của mình. Từ thư mục dự án (myproject), hãy chạy lệnh sau:

gunicorn --bind 0.0.0.0:5000 wsgi:app

Lệnh này yêu cầu Gunicorn khởi động, lắng nghe trên tất cả các địa chỉ IP của máy chủ ở cổng 5000, và phục vụ đối tượng app từ tệp wsgi. Bạn sẽ thấy kết quả trên terminal cho biết Gunicorn đang chạy.

Tuy nhiên, để tối ưu cho môi trường sản xuất, chúng ta sẽ không sử dụng cổng TCP mà thay vào đó là Unix socket. Unix socket cung cấp một cơ chế giao tiếp giữa các tiến trình trên cùng một máy chủ nhanh hơn và an toàn hơn. Chúng ta cũng sẽ cấu hình số lượng “worker” (tiến trình xử lý) để tăng hiệu suất. Một công thức phổ biến để xác định số lượng worker là (2 * số lõi CPU) + 1. Ví dụ, nếu máy chủ của bạn có 2 lõi CPU, bạn nên sử dụng 5 worker.

Hãy dừng Gunicorn bằng cách nhấn Ctrl+C và chạy lại với lệnh tối ưu hơn:

gunicorn --workers 5 --bind unix:myproject.sock -m 007 wsgi:app

Trong đó:

  • --workers 5: Khởi động 5 tiến trình worker để xử lý yêu cầu song song.
  • --bind unix:myproject.sock: Yêu cầu Gunicorn tạo và lắng nghe trên một tệp socket tên là myproject.sock ngay trong thư mục dự án.
  • -m 007: Đặt quyền truy cập cho tệp socket để máy chủ Nginx sau này có thể đọc và ghi vào nó.

Lúc này, ứng dụng Flask của bạn đang được Gunicorn phục vụ hiệu quả, sẵn sàng để kết nối với Nginx.

Hình minh họa

Cấu hình Nginx làm reverse proxy cho ứng dụng Flask

Đến đây, ứng dụng Flask của bạn đã được Gunicorn quản lý, nhưng nó vẫn chưa thể truy cập từ bên ngoài một cách an toàn và hiệu quả. Đây là lúc Nginx là gì phát huy vai trò của mình. Nginx sẽ hoạt động như một reverse proxy, nhận yêu cầu từ internet, xử lý các tác vụ như phục vụ tệp tĩnh, nén dữ liệu, và sau đó chuyển tiếp các yêu cầu cần xử lý bởi Flask đến Gunicorn thông qua Unix socket.

Cài đặt và thiết lập Nginx trên Ubuntu

Đầu tiên, hãy cài đặt Nginx trên máy chủ Ubuntu của bạn. Rất may, Nginx có sẵn trong kho lưu trữ mặc định của Ubuntu.

sudo apt install nginx

Sau khi cài đặt xong, bạn nên cho phép lưu lượng truy cập qua tường lửa. Nếu bạn đang sử dụng UFW (Uncomplicated Firewall), hãy chạy lệnh:

sudo ufw allow 'Nginx Full'

Bây giờ, hãy kiểm tra trạng thái của dịch vụ Nginx để đảm bảo nó đang chạy:

sudo systemctl status nginx

Tiếp theo, chúng ta cần tạo một tệp cấu hình server block mới cho ứng dụng của mình. Tệp này sẽ chỉ cho Nginx cách xử lý các yêu cầu đến tên miền của bạn.

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

Thao tác này sẽ mở một tệp trống, nơi bạn sẽ dán cấu hình của mình.

Hình minh họa

Kết nối Nginx với Gunicorn

Bên trong tệp /etc/nginx/sites-available/myproject, hãy thêm nội dung cấu hình sau. Đừng quên thay thế your_domain bằng tên miền hoặc địa chỉ IP của máy chủ bạn.

server {
    listen 80;
    server_name your_domain www.your_domain;

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

Hãy cùng phân tích các chỉ thị quan trọng:

  • listen 80: Nginx sẽ lắng nghe các yêu cầu HTTP trên cổng 80.
  • server_name: Chỉ định tên miền mà server block này sẽ áp dụng.
  • location /: Áp dụng khối cấu hình này cho tất cả các yêu cầu (/).
  • proxy_pass http://unix:/home/user/myproject/myproject.sock;: Đây là phần quan trọng nhất. Nó ra lệnh cho Nginx chuyển tiếp tất cả yêu cầu đến Unix socket mà Gunicorn đã tạo. Hãy chắc chắn rằng bạn đã thay /home/user/myproject/ bằng đường dẫn chính xác đến thư mục dự án của bạn.

Sau khi lưu tệp cấu hình, bạn cần kích hoạt nó bằng cách tạo một liên kết tượng trưng (symbolic link) từ thư mục sites-available đến thư mục sites-enabled:

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

Để đảm bảo không có lỗi cú pháp trong cấu hình, hãy chạy lệnh kiểm tra của Nginx:

sudo nginx -t

Nếu mọi thứ đều ổn, bạn sẽ thấy thông báo “syntax is ok” và “test is successful”. Cuối cùng, khởi động lại Nginx để áp dụng các thay đổi:

sudo systemctl restart nginx

Bây giờ, Nginx đã được cấu hình để làm việc nhịp nhàng với Gunicorn.

Chạy và kiểm tra hoạt động ứng dụng Flask trên Ubuntu

Sau khi đã hoàn tất các bước cấu hình Gunicorn và Nginx, đã đến lúc chúng ta khởi động toàn bộ hệ thống và kiểm tra thành quả. Đây là khoảnh khắc quan trọng để đảm bảo mọi thành phần đang giao tiếp với nhau một cách chính xác.

Đầu tiên, hãy quay lại thư mục dự án của bạn và kích hoạt môi trường ảo nếu bạn đã thoát ra.

cd ~/myproject
source venv/bin/activate

Tiếp theo, khởi động Gunicorn để nó tạo ra tệp socket và bắt đầu lắng nghe các kết nối từ Nginx.

gunicorn --workers 5 --bind unix:myproject.sock -m 007 wsgi:app

Bạn sẽ thấy Gunicorn khởi động và sẵn sàng nhận yêu cầu. Lúc này, Gunicorn đang chạy ở foreground của terminal. Để nó tiếp tục chạy sau khi bạn đóng cửa sổ terminal, chúng ta sẽ sử dụng một công cụ quản lý tiến trình như systemd (sẽ được đề cập chi tiết hơn ở phần Best Practices).

Trong khi Gunicorn đang chạy, dịch vụ Nginx cũng đã được khởi động lại ở bước trước. Bây giờ, mọi thứ đã sẵn sàng. Hãy mở trình duyệt web trên máy tính của bạn và truy cập vào địa chỉ IP hoặc tên miền mà bạn đã cấu hình trong tệp server block của Nginx.

Nếu mọi thứ được thiết lập chính xác, bạn sẽ thấy thông điệp “Xin chào từ ứng dụng Flask!” hiện ra trên trình duyệt. Điều này xác nhận rằng:

  1. Nginx đã nhận được yêu cầu của bạn.
  2. Nginx đã chuyển tiếp thành công yêu cầu đến Gunicorn thông qua tệp myproject.sock.
  3. Gunicorn đã nhận yêu cầu, đưa nó cho ứng dụng Flask xử lý.
  4. Ứng dụng Flask đã trả về phản hồi, và chu trình diễn ra theo chiều ngược lại để hiển thị kết quả cho bạn.

Nếu bạn gặp lỗi, đừng lo lắng. Hãy kiểm tra các tệp log của Nginx để tìm manh mối.

sudo tail -f /var/log/nginx/error.log

Việc kiểm tra log là kỹ năng quan trọng nhất khi gỡ lỗi trong môi trường sản xuất, giúp bạn nhanh chóng xác định nguyên nhân và khắc phục sự cố.

Hình minh họa

Xử lý sự cố và tối ưu hiệu năng cho Gunicorn và Nginx

Ngay cả với một cấu hình chuẩn, bạn vẫn có thể gặp phải một số vấn đề phổ biến. Việc hiểu rõ nguyên nhân và cách khắc phục sẽ giúp bạn tiết kiệm rất nhiều thời gian và duy trì ứng dụng hoạt động ổn định.

Các lỗi phổ biến khi chạy Gunicorn và Nginx

Một trong những lỗi thường gặp nhất khi kết hợp Nginx và Gunicorn là 502 Bad Gateway. Lỗi này có nghĩa là Nginx đã cố gắng chuyển tiếp yêu cầu nhưng không nhận được phản hồi hợp lệ từ Gunicorn. Nguyên nhân có thể là:

  • Gunicorn không chạy: Hãy đảm bảo rằng tiến trình Gunicorn của bạn đang hoạt động. Nếu bạn chạy nó thủ công trong terminal, nó sẽ dừng lại khi bạn đóng cửa sổ.
  • Sai đường dẫn socket: Kiểm tra lại đường dẫn đến tệp socket trong tệp cấu hình Nginx (proxy_pass) và đảm bảo nó khớp chính xác với nơi Gunicorn tạo ra tệp socket.
  • Vấn đề về quyền (Permission Denied): Người dùng chạy Nginx (thường là www-data) cần có quyền đọc và ghi trên tệp socket, cũng như quyền thực thi trên các thư mục cha của nó. Lệnh chmod hoặc chown có thể giúp giải quyết vấn đề này.

Một lỗi khác là tường lửa (firewall) chặn kết nối. Hãy chắc chắn rằng bạn đã cho phép lưu lượng truy cập HTTP (cổng 80) và HTTPS (cổng 443) thông qua ufw như đã đề cập ở các bước trước. Nếu bạn không thấy gì khi truy cập trang web, hãy kiểm tra lại các quy tắc tường lửa của bạn.

Hình minh họa

Tối ưu và bảo trì

Sau khi ứng dụng đã chạy ổn định, bạn có thể thực hiện một số tinh chỉnh để tối ưu hiệu năng và dễ dàng bảo trì hơn.

  • Điều chỉnh số worker và timeout: Số lượng worker của Gunicorn nên được điều chỉnh dựa trên tài nguyên CPU và loại tác vụ của ứng dụng. Nếu ứng dụng của bạn có nhiều tác vụ I/O (chờ đợi database, API), bạn có thể cân nhắc sử dụng worker không đồng bộ như gevent hoặc eventlet. Ngoài ra, hãy đặt giá trị timeout hợp lý (ví dụ: gunicorn --timeout 60 ...) để ngăn các yêu cầu chạy quá lâu làm treo worker.
  • Cải thiện bộ nhớ: Giám sát việc sử dụng bộ nhớ của các tiến trình Gunicorn. Nếu ứng dụng của bạn tiêu thụ quá nhiều bộ nhớ, hãy xem xét tối ưu mã nguồn hoặc nâng cấp tài nguyên máy chủ.
  • Quản lý log (Log Rotation): Theo thời gian, các tệp log của Nginx và Gunicorn sẽ ngày càng lớn, chiếm dụng không gian đĩa. Hãy cấu hình logrotate để tự động nén và xoay vòng các tệp log cũ, giúp việc quản lý trở nên dễ dàng hơn.
  • Giám sát dịch vụ: Sử dụng các công cụ như htop để theo dõi tài nguyên hệ thống theo thời gian thực. Đối với một hệ thống sản xuất nghiêm túc, bạn nên thiết lập các giải pháp giám sát chuyên dụng như Prometheus, Grafana, hoặc các dịch vụ của bên thứ ba để nhận cảnh báo khi có sự cố xảy ra.

Best Practices

Để xây dựng một hệ thống triển khai chuyên nghiệp và bền vững, việc tuân thủ các thực hành tốt nhất là điều không thể thiếu. Dưới đây là những khuyến nghị quan trọng bạn nên áp dụng cho dự án Flask của mình.

  • Luôn chạy ứng dụng trong môi trường ảo: Điều này đã được nhấn mạnh từ đầu nhưng vẫn cần được nhắc lại. Môi trường ảo (venv) giúp cô lập các gói phụ thuộc, đảm bảo tính nhất quán và tránh xung đột phiên bản, giúp việc triển khai và bảo trì trở nên đơn giản hơn rất nhiều.
  • Sử dụng systemd để quản lý Gunicorn: Chạy Gunicorn trực tiếp từ dòng lệnh chỉ phù hợp cho việc kiểm thử. Trong môi trường sản xuất, bạn cần một cách để tự động khởi động Gunicorn khi máy chủ bật, tự khởi động lại khi nó bị lỗi. systemd là công cụ quản lý dịch vụ tiêu chuẩn trên hầu hết các bản phân phối Linux hiện đại. Hãy tạo một tệp dịch vụ systemd tại /etc/systemd/system/myproject.service:
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=user
Group=www-data
WorkingDirectory=/home/user/myproject
Environment="PATH=/home/user/myproject/venv/bin"
ExecStart=/home/user/myproject/venv/bin/gunicorn --workers 5 --bind unix:myproject.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target
  • Sau đó, bạn có thể quản lý Gunicorn như một dịch vụ hệ thống: sudo systemctl start myproject, sudo systemctl enable myproject.
  • Thiết lập firewall phù hợp: Nguyên tắc bảo mật cơ bản là “tối thiểu hóa bề mặt tấn công”. Chỉ mở những cổng thực sự cần thiết. Đối với một máy chủ web tiêu chuẩn, đó là cổng 80 (HTTP) và 443 (HTTPS). Mọi cổng khác nên được đóng lại nếu không có lý do đặc biệt.
  • Không bao giờ sử dụng server phát triển của Flask: Máy chủ tích hợp sẵn của Flask (app.run()) là một công cụ tuyệt vời cho việc lập trình và gỡ lỗi. Tuy nhiên, nó không được thiết kế để xử lý nhiều yêu cầu đồng thời, không an toàn và không có hiệu năng cao. Hãy luôn sử dụng một máy chủ WSGI chuyên dụng như Gunicorn hoặc uWSGI trong môi trường sản xuất.
  • Định kỳ kiểm tra logs và cập nhật bảo mật: Hãy tạo thói quen kiểm tra các tệp log của Nginx và ứng dụng của bạn để phát hiện sớm các hoạt động bất thường hoặc lỗi. Đồng thời, luôn giữ cho hệ điều hành và tất cả các gói phần mềm được cập nhật lên phiên bản mới nhất để vá các lỗ hổng bảo mật.
sudo apt update && sudo apt upgrade

Hình minh họa

Kết luận

Qua các bước hướng dẫn chi tiết, bạn đã cùng AZWEB xây dựng thành công một kiến trúc triển khai ứng dụng Flask mạnh mẽ, hiệu quả và an toàn trên nền tảng Ubuntu 20.04. Bằng cách kết hợp Gunicorn làm máy chủ ứng dụng WSGI và Nginx làm reverse proxy, chúng ta đã giải quyết được những nhược điểm cố hữu của việc chạy ứng dụng trực tiếp bằng máy chủ phát triển, đồng thời mang lại nhiều lợi ích vượt trội: khả năng mở rộng thông qua các worker, tăng cường bảo mật bằng cách che giấu ứng dụng sau một lớp proxy, và tối ưu hóa hiệu suất bằng cách để Nginx xử lý các tác vụ nặng như phục vụ tệp tĩnh.

Việc nắm vững quy trình này không chỉ giúp ứng dụng của bạn hoạt động ổn định hơn mà còn là một kỹ năng nền tảng quan trọng cho bất kỳ nhà phát triển web nào. Chúng tôi khuyến khích bạn áp dụng mô hình này cho các dự án của mình để đảm bảo chất lượng và sự chuyên nghiệp ngay từ khâu triển khai.

Hành trình của bạn chưa dừng lại ở đây. Bước tiếp theo để hoàn thiện hệ thống là thiết lập chứng chỉ SSL/TLS bằng Let’s Encrypt để mã hóa lưu lượng truy cập, bảo vệ dữ liệu người dùng. Ngoài ra, bạn có thể tìm hiểu về việc tự động hóa quy trình triển khai bằng các công cụ như Ansible hoặc container hóa ứng dụng với Docker để việc quản lý và mở rộng trở nên dễ dàng hơn nữa. AZWEB với các dịch vụ VPS tốt nhất chất lượng cao sẽ là nền tảng lý tưởng để bạn thực hành và triển khai các dự án web chuyên nghiệp của mình.

Đánh giá