A previous version of this tutorial was written by Kathleen Juell.
介紹
在本指南中,您將使用 Flask 微框架在 Ubuntu 22.04 上構建一個 Python 應用程序。本教程的大部分內容將涉及如何設置 Gunicorn 應用服務器,以及如何啟動應用程序並配置 Nginx 作為前端反向代理。
先決條件
在開始本指南之前,您應該擁有:
-
已安裝 Ubuntu 22.04 並擁有具有 sudo 權限的非根用戶的服務器。請參考我們的 初始服務器設置指南 進行指引。
-
已安裝 Nginx,按照 在 Ubuntu 22.04 上安裝 Nginx 的第 1 和第 2 步進行操作。
-
配置指向您服务器的域名。您可以在Namecheap购买一个,或者在Freenom上免费获取一个。您可以通过查阅相关的域名和DNS文档了解如何将域名指向DigitalOcean。确保创建以下DNS记录:
- 一个A记录,指向您服务器的公共IP地址
your_domain
。 - 一个A记录,指向您服务器的公共IP地址
www.your_domain
。
- 一个A记录,指向您服务器的公共IP地址
-
熟悉WSGI规范,Gunicorn服务器将使用该规范与您的Flask应用程序通信。这篇讨论更详细地介绍了WSGI。
步驟 1 — 從 Ubuntu 倉庫安裝組件
首先,您需要從 Ubuntu 倉庫安裝所有必需的組件。這包括 pip
,Python 套件管理器,它將管理 Python 組件。您還將獲得構建一些 Gunicorn 組件所需的 Python 開發文件。
首先,更新本地套件索引並安裝將使您能夠構建 Python 環境的套件。這些將包括 python3-pip
,以及一些其他套件和開發工具,這些對於構建強大的編程環境是必要的:
安裝完這些套件後,下一步是為您的項目創建一個虛擬環境。
步驟 2 — 建立 Python 虛擬環境
接下來,您將設置一個虛擬環境,以便將 Flask 應用程序與系統上的其他 Python 文件隔離開來。
首先安裝 python3-venv
套件,這將安裝 venv
模組:
接下來,為您的 Flask 專案建立一個父目錄。在創建完後,使用 cd
命令進入該目錄:
為您的 Flask 專案的 Python 需求創建一個虛擬環境,輸入以下命令:
這將在您的專案目錄中安裝一個名為 myprojectenv
的目錄,其中包含一個本地的 Python 複本和 pip
。
在虛擬環境中安裝應用程式之前,您需要先啟用它。輸入以下命令:
您的提示符會更改,指示您現在正在虛擬環境中操作。它會類似於這樣:(myprojectenv)user@host:~/myproject$
。
第三步 — 設置 Flask 應用程式
現在您已經進入虛擬環境,您可以安裝 Flask 和 Gunicorn 並開始設計您的應用程式。
首先,使用本地的 pip
安裝 wheel
,以確保即使缺少 wheel 存檔,您的套件也能安裝成功:
注意:
無論您使用哪個版本的 Python,當虛擬環境啟用時,應該使用 pip
命令(而不是 pip3
)。
接下來,安裝 Flask 和 Gunicorn:
創建示範應用程式
現在您已經可以使用Flask創建一個簡單的應用程序。Flask是一個微框架。它不包含許多更全功能的框架可能包含的工具,主要是作為一個模塊存在,您可以將其導入到您的項目中,以幫助您初始化 Web 應用程序。
雖然您的應用程序可能更加複雜,但我們將在一個名為myproject.py
的單個文件中創建我們的Flask應用程序:
應用程序代碼將存在於此文件中。它將導入Flask並實例化一個Flask對象。您可以使用這個對象來定義當請求特定路由時應運行的函數:
這基本上定義了在訪問根域時要呈現的內容。完成後保存並關閉文件。
如果您遵循了初始的服務器設置指南,應該已經啟用了UFW防火牆。要測試應用程序,您需要允許訪問端口5000
:
現在,您可以通過鍵入以下命令來測試您的Flask應用程序:
您將看到以下類似的輸出,其中包括一個有用的警告,提醒您不要在生產環境中使用此服務器設置:
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
:
在此文件中,從我們的應用程式中導入 Flask 實例,然後運行它:
完成後保存並關閉文件。
第 4 步 — 配置 Gunicorn
您的應用程式現在已經具有了一個入口點。現在可以繼續配置 Gunicorn。
在繼續之前,請確保 Gunicorn 可以正確地提供應用程式。
您可以通過將應用程式的入口點名稱傳遞給它來執行此操作。此名稱構造方式為模塊的名稱(去除了 .py
擴展名),加上應用程式中的可調用物件的名稱。在這種情況下,它是 wsgi:app
。
同時,指定要綁定到的介面和端口,使用 0.0.0.0:5000
參數,這樣應用程式將在公開可用的介面上啟動:
您應該會看到以下輸出:
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
結束終端窗口中的程序。
完成使用虛擬環境後,您可以停用它:
現在,任何 Python 命令將再次使用系統的 Python 環境。
接下來,創建 systemd 服務單元文件。創建一個 systemd 單元文件將使 Ubuntu 的 init 系統在服務器啟動時自動啟動 Gunicorn 並提供 Flask 應用程序:
在/etc/systemd/system
目錄中創建一個以.service
結尾的單元文件:
在其中,您將從[Unit]
部分開始,該部分用於指定元數據和依賴項。在這裡添加您服務的描述並告訴 init 系統僅在達到網絡目標後才啟動此服務:
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target
接下來,添加一個[Service]
部分。這將指定您希望進程在其中運行的用戶和組。將常規用戶帳戶指定為進程的擁有者,因為它擁有所有相關文件。同時,將組擁有權指定為www-data
組,以便 Nginx 與 Gunicorn 進程輕鬆通信。請記得將此處的用戶名替換為您的用戶名:
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target
[Service]
User=sammy
Group=www-data
接下來,映射出工作目錄並設置 PATH
環境變量,以便 init 系統知道進程的可執行文件位於我們的虛擬環境中。同時指定啟動服務的命令。該命令將執行以下操作:
- 啟動 3 個工作進程(您可以根據需要進行調整)
- 在我們的項目目錄中創建並綁定到一個 Unix socket 文件,
myproject.sock
,我們將設置 umask 值為007
,這樣 socket 文件將只給所有者和組提供訪問權限,同時限制其他人的訪問 - 指定 WSGI 入口文件名,以及該文件中的 Python 可調用(
wsgi:app
)
Systemd 要求您提供 Gunicorn 可執行文件的完整路徑,該文件安裝在您的虛擬環境中。
請記住用您自己的信息替換用戶名和項目路徑:
[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 如果啟用了啟動,要將此服務鏈接到什麼。您希望此服務在常規多用戶系統啟動並運行時啟動:
[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 服務並啟用它,以便在啟動時啟動:
讓我們檢查一下狀態:
您應該會看到如下輸出:
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 將 Web 請求傳遞到該套接字。
首先,在 Nginx 的 sites-available
目錄中創建一個新的伺服器塊配置文件。將其命名為 myproject
,以配合本指南的其餘部分:
打開一個伺服器塊並告訴 Nginx 監聽默認端口 80
。同時告訴它將此塊用於我們伺服器的域名的請求:
server {
listen 80;
server_name your_domain www.your_domain;
}
接下來,添加一個匹配每個請求的位置塊。在此塊中,您將包含 proxy_params
文件,該文件指定需要設置的一些一般代理參數。然後,您將使用 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;
}
}
完成後保存並關閉文件。
要啟用您剛剛創建的 Nginx 伺服器塊配置,請將該文件鏈接到 sites-enabled
目錄:
將文件放入該目錄後,您可以測試語法錯誤:
如果沒有指示任何問題,請重新啟動 Nginx 進程以讀取新的配置:
最後,再次調整防火牆。 您不再需要通過端口5000
訪問,因此可以刪除該規則。 然後,您可以允許對Nginx服務器的完全訪問:
現在,您應該能夠在網頁瀏覽器中導航到您服務器的域名:
http://your_domain
您應該能夠看到您應用程序的輸出:
注意:如果Nginx無法訪問gunicorn的套接字文件,您將收到HTTP 502網關錯誤。 通常是因為用戶的主目錄不允許其他用戶訪問其中的文件。
如果您的套接字文件名為/home/sammy/myproject/myproject.sock
,請確保/home/sammy
具有至少0755
權限。 您可以使用像chmod
這樣的工具來更改權限:
然後重新加載頁面,看看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 獲取免費憑證,生成自簽名憑證,或者 從其他供應商購買 並按照《如何在 Ubuntu 22.04 中為 Nginx 創建自簽名 SSL 憑證》的步驟 2 到 6 進行配置 Nginx 使用它。出於速度的考慮,我們將使用選項一(Let’s Encrypt)。
使用 apt
安裝 Certbot 的 Nginx 套件:
Certbot 通過插件提供了多種獲取 SSL 憑證的方式。Nginx 插件將負責在必要時重新配置 Nginx 並重新加載配置。要使用此插件,請輸入以下命令:
這將運行 certbot
並使用 --nginx
插件,使用 -d
指定我們希望憑證有效的名稱。
如果這是您第一次運行 certbot
,系統將提示您輸入電子郵件地址並同意服務條款。完成後,certbot
將與 Let’s Encrypt 伺服器通訊,然後運行驗證挑戰以確認您控制請求證書的域名。
如果成功,certbot
將詢問您想如何配置 HTTPS 設置:
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):
選擇您的選擇,然後按下 ENTER
。配置將更新,Nginx 將重新加載以應用新的設置。certbot
將以成功的訊息結束,並告訴您證書存儲的位置:
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 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 配置允許:
為驗證配置,再次進入您的域名,使用 https://
:
https://your_domain
您應該再次看到應用程序的輸出,以及您瀏覽器的安全指示器,該指示器應該顯示網站已經被保護。
結論
在這個指南中,您在 Python 虛擬環境中創建並保護了一個簡單的 Flask 應用程序。 您創建了一個 WSGI 入口點,以便任何支援 WSGI 的應用程序服務器都可以與之接口,然後配置了 Gunicorn 應用程序服務器以提供此功能。之後,您創建了一個 systemd 服務文件,以便在啟動時自動啟動應用程序服務器。您還創建了一個 Nginx 服務器塊,將 Web 客戶端流量傳遞到應用程序服務器,轉發外部請求,並使用 Let’s Encrypt 保護對您的服務器的流量。
Flask 是一個非常簡單但極其靈活的框架,旨在為您的應用程序提供功能,而不會對結構和設計過於嚴格。您可以使用本指南中描述的通用堆棧來提供您設計的 Flask 應用程序。