Cách cung cấp các ứng dụng Flask với Gunicorn và Nginx trên Ubuntu 18.04
Trong hướng dẫn này, bạn sẽ xây dựng một ứng dụng Python bằng cách sử dụng vi khung Flask trên Ubuntu 18.04. Phần lớn bài viết này sẽ nói về cách cài đặt server ứng dụng Gunicorn cũng như cách chạy ứng dụng và cấu hình Nginx hoạt động như một Reverse Proxy phía trước.Yêu cầu
Trước khi bắt đầu hướng dẫn này, bạn nên có:
- Server đã cài đặt Ubuntu 18.04 và user không phải root có quyền sudo. Làm theo hướng dẫn cài đặt server ban đầu của ta để được hướng dẫn.
- Đã cài đặt Nginx, làm theo các Bước 1 và 2 của Cách cài đặt Nginx trên Ubuntu 18.04 .
Tên domain được cấu hình để trỏ đến server của bạn. Bạn có thể mua một cái trên Namecheap hoặc nhận một cái miễn phí trên Freenom . Bạn có thể tìm hiểu cách trỏ domain đến DigitalOcean theo tài liệu liên quan về domain và DNS . Đảm bảo tạo các bản ghi DNS sau:
- Một bản ghi với
your_domain
trỏ đến địa chỉ IP công cộng của server của bạn. - Một bản ghi A với
www. your_domain
trỏ đến địa chỉ IP công cộng của server của bạn.
- Một bản ghi với
Quen thuộc với đặc tả WSGI mà server Gunicorn sẽ sử dụng để giao tiếp với ứng dụng Flask của bạn. Cuộc thảo luận này bao gồm WSGI chi tiết hơn.
Bước 1 - Cài đặt các thành phần từ repository Ubuntu
Bước đầu tiên của ta sẽ là cài đặt tất cả các phần ta cần từ repository Ubuntu. Điều này bao gồm pip
, trình quản lý gói Python, sẽ quản lý các thành phần Python của ta . Ta cũng sẽ nhận được các file phát triển Python cần thiết để xây dựng một số thành phần Gunicorn.
Đầu tiên, hãy cập nhật index gói local và cài đặt các gói cho phép ta xây dựng môi trường Python của bạn . Chúng sẽ bao gồm python3-pip
, cùng với một số gói và công cụ phát triển khác cần thiết cho một môi trường lập trình mạnh mẽ:
- sudo apt update
- sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools
Với các gói này, ta hãy chuyển sang tạo môi trường ảo cho dự án của ta .
Bước 2 - Tạo môi trường ảo Python
Tiếp theo, ta sẽ cài đặt một môi trường ảo để cô lập ứng dụng Flask của ta với các file Python khác trên hệ thống.
Bắt đầu bằng cách cài đặt gói python3-venv
, gói này sẽ cài đặt module venv
:
- sudo apt install python3-venv
Tiếp theo, hãy tạo một folder mẹ cho dự án Flask của ta . Di chuyển vào folder sau khi bạn tạo:
- mkdir ~/myproject
- cd ~/myproject
Tạo một môi trường ảo để lưu trữ các yêu cầu Python của dự án Flask của bạn bằng lệnh :
- python3.6 -m venv myprojectenv
Điều này sẽ cài đặt một bản sao local của Python và pip
vào một folder gọi là myprojectenv
trong folder dự án của bạn.
Trước khi cài đặt các ứng dụng trong môi trường ảo, bạn cần kích hoạt nó. Làm như vậy bằng lệnh :
- source myprojectenv/bin/activate
Dấu nhắc của bạn sẽ thay đổi để cho biết rằng bạn hiện đang hoạt động trong môi trường ảo. Nó trông giống như sau : ( myprojectenv ) user @ host :~/ myproject $
.
Bước 3 - Cài đặt ứng dụng flask
Đến đây bạn đang ở trong môi trường ảo của bạn , bạn có thể cài đặt Flask và Gunicorn và bắt đầu thiết kế ứng dụng của bạn .
Đầu tiên, hãy cài đặt wheel
với version local của pip
đảm bảo rằng các gói của ta sẽ cài đặt ngay cả khi chúng thiếu repository bánh xe:
- pip install wheel
pip
(không phải pip3
).Tiếp theo, hãy cài đặt Flask và Gunicorn:
- pip install gunicorn flask
Tạo ứng dụng mẫu
Đến đây bạn đã có sẵn Flask, bạn có thể tạo một ứng dụng đơn giản. Flask là một microframework. Nó không bao gồm nhiều công cụ mà các khung công tác đầy đủ tính năng hơn có thể có và chủ yếu tồn tại dưới dạng module mà bạn có thể nhập vào các dự án của bạn để hỗ trợ bạn khởi tạo ứng dụng web.
Mặc dù ứng dụng của bạn có thể phức tạp hơn, nhưng ta sẽ tạo ứng dụng Flask của bạn trong một file duy nhất, được gọi là myproject .py
:
- nano ~/myproject/myproject.py
Mã ứng dụng sẽ nằm trong file này. Nó sẽ nhập Flask và khởi tạo một đối tượng Flask. Bạn có thể sử dụng điều này để xác định các chức năng sẽ được chạy khi một tuyến đường cụ thể được yêu cầu:
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')
Về cơ bản, điều này xác định nội dung sẽ hiển thị khi domain root được truy cập. Lưu file khi bạn hoàn tất.
Nếu bạn đã làm theo hướng dẫn cài đặt server ban đầu, bạn nên bật firewall UFW. Để kiểm tra ứng dụng, bạn cần cho phép truy cập vào cổng 5000
:
- sudo ufw allow 5000
Đến đây bạn có thể kiểm tra ứng dụng Flask của bạn bằng lệnh :
- python myproject.py
Bạn sẽ thấy kết quả như sau, bao gồm một cảnh báo hữu ích nhắc bạn không sử dụng cài đặt server này trong production :
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)
Truy cập địa chỉ IP của server của bạn, sau đó là :5000
trong trình duyệt web :
http://your_server_ip:5000
Bạn sẽ thấy thông tin như thế này:
Khi bạn hoàn tất, nhấn CTRL-C
trong cửa sổ terminal của bạn để dừng server phát triển Flask.
Tạo điểm vào WSGI
Tiếp theo, hãy tạo một file sẽ đóng role là điểm nhập cho ứng dụng của ta . Điều này sẽ cho server Gunicorn của ta biết cách tương tác với ứng dụng.
Hãy gọi file wsgi.py
:
- nano ~/myproject/wsgi.py
Trong file này, hãy nhập version Flask từ ứng dụng của ta và sau đó chạy nó:
from myproject import app if __name__ == "__main__": app.run()
Lưu file khi bạn hoàn tất.
Bước 4 - Cấu hình Gunicorn
Đơn của bạn bây giờ đã được viết với một điểm nhập cảnh đã được cài đặt . Bây giờ ta có thể chuyển sang cấu hình Gunicorn.
Trước khi tiếp tục, ta nên kiểm tra xem Gunicorn có thể phân phát ứng dụng một cách chính xác hay không.
Ta có thể làm điều này bằng cách chỉ cần chuyển cho nó tên của điểm vào của ta . Điều này được xây dựng như tên của module (trừ phần mở rộng .py
), cộng với tên của phần có thể gọi trong ứng dụng. Trong trường hợp của ta , đây là wsgi:app
.
Ta cũng sẽ chỉ định giao diện và cổng để liên kết để ứng dụng sẽ được khởi động trên giao diện có sẵn công khai:
- cd ~/myproject
- gunicorn --bind 0.0.0.0:5000 wsgi:app
Bạn sẽ thấy kết quả như sau:
Output[2018-07-13 19:35:13 +0000] [28217] [INFO] Starting gunicorn 19.9.0 [2018-07-13 19:35:13 +0000] [28217] [INFO] Listening at: http://0.0.0.0:5000 (28217) [2018-07-13 19:35:13 +0000] [28217] [INFO] Using worker: sync [2018-07-13 19:35:13 +0000] [28220] [INFO] Booting worker with pid: 28220
Truy cập lại địa chỉ IP server của bạn với :5000
thêm vào cuối trong trình duyệt web :
http://your_server_ip:5000
Bạn sẽ thấy kết quả ứng dụng của bạn :
Khi bạn đã xác nhận nó hoạt động bình thường, hãy nhấn CTRL-C
trong cửa sổ dòng lệnh của bạn.
Bây giờ ta đã hoàn tất với môi trường ảo của bạn , vì vậy ta có thể hủy kích hoạt nó:
- deactivate
Mọi lệnh Python bây giờ sẽ sử dụng lại môi trường Python của hệ thống.
Tiếp theo, hãy tạo file đơn vị dịch vụ systemd. Tạo một file đơn vị systemd sẽ cho phép hệ thống init của Ubuntu tự động khởi động Gunicorn và phục vụ ứng dụng Flask khi nào server khởi động.
Tạo một file đơn vị kết thúc bằng .service
trong folder /etc/systemd/system
để bắt đầu:
- sudo nano /etc/systemd/system/myproject.service
Bên trong, ta sẽ bắt đầu với phần [Unit]
, được sử dụng để chỉ định metadata và phần phụ thuộc. Hãy đặt mô tả về dịch vụ của ta ở đây và yêu cầu hệ thống init chỉ bắt đầu điều này sau khi đã đạt được mục tiêu mạng:
[Unit] Description=Gunicorn instance to serve myproject After=network.target
Tiếp theo, hãy mở phần [Service]
. Điều này sẽ chỉ định user và group mà ta muốn quá trình chạy dưới đó. Hãy cấp cho account regular user của ta quyền sở hữu quy trình vì nó sở hữu tất cả các file có liên quan. Hãy cũng cấp quyền sở hữu group cho group www-data
để Nginx có thể giao tiếp dễ dàng với các quy trình Gunicorn. Hãy nhớ thay thế tên user ở đây bằng tên user của bạn:
[Unit] Description=Gunicorn instance to serve myproject After=network.target [Service] User=sammy Group=www-data
Tiếp theo, hãy lập bản đồ folder làm việc và đặt biến môi trường PATH
để hệ thống init biết rằng các file thực thi cho quy trình được đặt trong môi trường ảo của ta . Hãy cũng chỉ định lệnh để bắt đầu dịch vụ. Lệnh này sẽ làm như sau:
- Bắt đầu 3 quy trình công nhân (mặc dù bạn nên điều chỉnh điều này nếu cần)
- Tạo và liên kết với file socket Unix,
myproject .sock
, trong folder dự án của ta . Ta sẽ đặt giá trị umask là007
để file socket được tạo cấp quyền truy cập cho chủ sở hữu và group , đồng thời hạn chế quyền truy cập khác - Chỉ định tên file điểm nhập WSGI, cùng với Python có thể gọi trong file đó (
wsgi:app
)
Systemd yêu cầu ta cung cấp đường dẫn đầy đủ đến file thực thi Gunicorn, file này được cài đặt trong môi trường ảo của ta .
Hãy nhớ thay thế tên user và đường dẫn dự án bằng thông tin của bạn :
[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
Cuối cùng, hãy thêm phần [Install]
. Điều này sẽ cho systemd biết những gì để liên kết dịch vụ này nếu ta cho phép nó khởi động khi server khởi động . Ta muốn dịch vụ này bắt đầu khi hệ thống nhiều regular user được cài đặt và chạy:
[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
Như vậy, file dịch vụ systemd của ta đã hoàn tất. Lưu và đóng nó ngay bây giờ.
Bây giờ ta có thể bắt đầu dịch vụ Gunicorn mà ta đã tạo và kích hoạt nó để nó bắt đầu khi server khởi động :
- sudo systemctl start myproject
- sudo systemctl enable myproject
Hãy kiểm tra trạng thái:
- sudo systemctl status myproject
Bạn sẽ thấy kết quả như thế này:
Output● myproject.service - Gunicorn instance to serve myproject Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2018-07-13 14:28:39 UTC; 46s ago Main PID: 28232 (gunicorn) Tasks: 4 (limit: 1153) CGroup: /system.slice/myproject.service ├─28232 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 ├─28250 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 ├─28251 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 └─28252 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007
Nếu bạn thấy bất kỳ lỗi nào, hãy nhớ giải quyết chúng trước khi tiếp tục với hướng dẫn.
Bước 5 - Cấu hình Nginx cho các yêu cầu proxy
Server ứng dụng Gunicorn của ta bây giờ sẽ được cài đặt và đang chạy, đang chờ các yêu cầu trên file socket trong folder dự án. Bây giờ hãy cấu hình Nginx để chuyển các yêu cầu web đến socket đó bằng cách thực hiện một số bổ sung nhỏ vào file cấu hình của nó.
Bắt đầu bằng cách tạo file cấu hình khối server mới trong folder sites-available
của Nginx. Hãy gọi này myproject
để giữ phù hợp với phần còn lại của hướng dẫn:
- sudo nano /etc/nginx/sites-available/myproject
Mở khối server và yêu cầu Nginx lắng nghe trên cổng mặc định 80
. Cũng hãy yêu cầu nó sử dụng khối này cho các yêu cầu đối với domain của server của ta :
server { listen 80; server_name your_domain www.your_domain; }
Tiếp theo, hãy thêm một khối vị trí phù hợp với mọi yêu cầu. Trong khối này, ta sẽ bao gồm file proxy_params
chỉ định một số thông số proxy chung cần được đặt. Sau đó, ta sẽ chuyển các yêu cầu đến socket mà ta đã xác định bằng cách sử dụng chỉ thị proxy_pass
:
server { listen 80; server_name your_domain www.your_domain; location / { include proxy_params; proxy_pass http://unix:/home/sammy/myproject/myproject.sock; } }
Lưu file khi bạn hoàn tất.
Để bật cấu hình khối server Nginx mà bạn vừa tạo, hãy liên kết file với folder sites-enabled
:
- sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
Với file trong folder đó, bạn có thể kiểm tra lỗi cú pháp:
- sudo nginx -t
Nếu điều này trả về mà không chỉ ra sự cố nào , hãy khởi động lại tiến trình Nginx để đọc cấu hình mới:
- sudo systemctl restart nginx
Cuối cùng, hãy điều chỉnh lại firewall . Ta không cần truy cập thông qua cổng 5000
, vì vậy ta có thể xóa luật đó. Sau đó, ta có thể cho phép toàn quyền truy cập vào server Nginx:
- sudo ufw delete allow 5000
- sudo ufw allow 'Nginx Full'
Đến đây bạn có thể chuyển đến domain của server trong trình duyệt web của bạn :
http://your_domain
Bạn sẽ thấy kết quả ứng dụng của bạn :
Nếu bạn gặp bất kỳ lỗi nào, hãy thử kiểm tra những điều sau:
-
sudo less /var/log/nginx/error.log
: kiểm tra log lỗi Nginx. -
sudo less /var/log/nginx/access.log
: kiểm tra log truy cập Nginx. -
sudo journalctl -u nginx
: kiểm tra log tiến trình Nginx . -
sudo journalctl -u myproject
: kiểm tra log Gunicorn của ứng dụng Flask của bạn.
Bước 6 - Bảo mật ứng dụng
Để đảm bảo lưu lượng truy cập đến server của bạn vẫn an toàn, hãy lấy certificate SSL cho domain của bạn. Có nhiều cách để thực hiện việc này, bao gồm nhận certificate miễn phí từ Let's Encrypt , tạo certificate tự ký hoặc mua chứng chỉ từ nhà cung cấp khác và cấu hình Nginx để sử dụng theo các Bước từ 2 đến 6 của Cách tạo certificate tự ký Chứng chỉ SSL cho Nginx trong Ubuntu 18.04 . Ta sẽ đi với tùy chọn một vì lợi ích hiệu quả.
Đầu tiên, thêm repository Certbot Ubuntu:
- sudo add-apt-repository ppa:certbot/certbot
Bạn cần nhấn ENTER
để chấp nhận.
Cài đặt gói Nginx của Certbot với apt
:
- sudo apt install python-certbot-nginx
Certbot cung cấp nhiều cách khác nhau để lấy certificate SSL thông qua các plugin. Plugin Nginx sẽ xử lý việc cấu hình lại Nginx và reload cấu hình khi nào cần thiết. Để sử dụng plugin này, hãy nhập như sau:
- sudo certbot --nginx -d your_domain -d www.your_domain
Điều này chạy certbot
với plugin --nginx
, sử dụng -d
để chỉ định tên mà ta muốn certificate hợp lệ.
Nếu đây là lần đầu tiên bạn chạy certbot
, bạn sẽ được yêu cầu nhập địa chỉ email và đồng ý với các điều khoản dịch vụ. Sau khi làm như vậy, certbot
sẽ giao tiếp với server Let's Encrypt, sau đó chạy thử thách để xác minh bạn kiểm soát domain mà bạn đang certificate request .
Nếu thành công, certbot
sẽ hỏi bạn muốn cấu hình cài đặt HTTPS của bạn như thế nào:
OutputPlease 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):
Chọn lựa chọn của bạn rồi nhấn ENTER
. Cấu hình sẽ được cập nhật và Nginx sẽ reload để chọn cài đặt mới. certbot
sẽ kết thúc bằng một thông báo cho bạn biết quá trình đã thành công và nơi lưu trữ certificate của bạn:
OutputIMPORTANT 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 2018-07-23. 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
Nếu bạn đã làm theo hướng dẫn cài đặt Nginx trong yêu cầu , bạn sẽ không cần phụ cấp profile HTTP dự phòng nữa:
- sudo ufw delete allow 'Nginx HTTP'
Để xác minh cấu hình, hãy chuyển đến domain của bạn, sử dụng https://
:
https://your_domain
Bạn sẽ thấy kết quả ứng dụng của bạn , cùng với chỉ báo bảo mật của trình duyệt, chỉ báo này sẽ cho biết rằng trang web được bảo mật.
Kết luận
Trong hướng dẫn này, bạn đã tạo và bảo mật một ứng dụng Flask đơn giản trong môi trường ảo Python. Bạn đã tạo một điểm nhập WSGI để bất kỳ server ứng dụng nào có khả năng WSGI đều có thể giao tiếp với nó, sau đó cấu hình server ứng dụng Gunicorn để cung cấp chức năng này. Sau đó, bạn đã tạo file dịch vụ systemd để tự động chạy server ứng dụng khi khởi động. Bạn cũng đã tạo một khối server Nginx để chuyển lưu lượng client web đến server ứng dụng, chuyển tiếp các yêu cầu bên ngoài và lưu lượng truy cập an toàn đến server của bạn bằng Let's Encrypt.
Flask là một khung công tác rất đơn giản nhưng cực kỳ linh hoạt nhằm cung cấp cho các ứng dụng của bạn chức năng mà không quá hạn chế về cấu trúc và thiết kế. Bạn có thể sử dụng ngăn xếp chung được mô tả trong hướng dẫn này để phục vụ các ứng dụng flask mà bạn thiết kế.
Các tin liên quan
Cách di chuyển web root Nginx đến vị trí mới trên Ubuntu 18.042018-07-12
Cách cấu hình Jenkins với SSL bằng Nginx Reverse Proxy trên Ubuntu 18.04
2018-07-10
Cách thiết lập Django với Postgres, Nginx và Gunicorn trên Ubuntu 18.04
2018-07-09
Cách tạo chứng chỉ SSL tự ký cho Nginx trong Ubuntu 18.04
2018-07-05
Cách bảo mật Nginx bằng Let's Encrypt trên FreeBSD
2018-07-02
Cách bảo mật Nginx bằng Let's Encrypt trên Ubuntu 18.04
2018-04-27
Cách cài đặt và bảo mật phpMyAdmin với Nginx trên Ubuntu 16.04
2018-04-12
Cách lưu trữ trang web bằng Cloudflare và Nginx trên Ubuntu 16.04
2018-03-15
Nginx Essentials: Khắc phục sự cố cài đặt và cấu hình
2017-12-12
Cách thiết lập Let's Encrypt với Nginx Server Blocks trên Ubuntu 16.04
2017-10-27