上線你的寶貝服務
最近常常看到有人分享自己「vibe coding」 (憑感覺、用 AI 寫)出來的網站或應用程式,這很棒!如果給自己用的話還行,但當你興高采烈地想要分享給朋友,迎面而來的問題就是:「所以…我要怎麼把它放到網路上,讓大家都能用?」
如果 你是剛入門的開發者,或許正在使用像是 Google AI Studio 這類的工具,通常 AI 的建議(例如 Gemini)會告訴你:
對於第一個專案,不要直接挑戰手動設定伺服器。優先選擇「平台即服務 (PaaS)」或「無伺服器 (Serverless)」平台,它們能幫你處理掉大部分繁瑣的底層設定。例如 Google Cloud Run 或是 Render 讓 AI 無腦幫你部署。
但其實我更推薦的是你可以租一個自己的虛擬主機(VM),就像是一台雲端的電腦,你想在上面裝什麼、灌什麼服務,沒有人會管你。例如,我自己就在 linode 上面租了一個最最最便宜的伺服器,光應付個課程作業或是和家人朋友分享綽綽有餘。
我們將會詳細說明如何在 Linode 這類的虛擬伺服器上,手動設定、管理並上線你的 Python 後端服務!(一方面也是讓我自己可以回來看😏)
你可以跑我的 Python 檔案...?
當你滿心歡喜地寫出一個 Python 服務,例如你寫了一個點餐程式,想和朋友分享時,你可能會跟朋友說:「嘿,你執行一下這個 main.py 檔就可以用了!」。你可能會收到一句無情的回應:「...啥是 Python?」
為了避免這種尷尬的情境,我們需要將 Python 邏輯包裝成一個「後端服務」,並透過一個任何人(或任何程式)都能輕易存取的「API」來提供功能。簡單來說,API 就像是餐廳的菜單,讓你的朋友(或前端網站)可以透過 API 點餐,而不用進到廚房自己按烤箱按鈕(執行你的 Python 程式碼)。
在 Python 的世界裡,最 常用來建立後端服務的兩個框架就是 Flask 和 FastAPI。我們會一起走過這兩種框架的部署流程,並比較它們的差異。讓我們先從 Flask 開始,這是最簡單把自己的應用程式啟動的方式!
Neurosynth: Flask + Gunicorn 部署範例
Flask 是一個非常輕量的 Python 網路框架,因為它不綁定任何特定的工具或外掛,這使得 Flask 非常適合開發小型應用程式,歷年來一直是非常熱門的選擇(直到 FastAPI 出現...)。
我會用 Neurosynth 這個範例(一個查詢腦功能和文字關聯的服務),一步步說明如何讓你的應用程式成為一個不用下班的服務生😏。
部署的藍圖:我們要做什麼?
在我們一頭栽進指令之前,先來看看我們的計畫。我們的目標是讓 Flask 應用程式變成一個穩定、可靠、而且開機就能自己運行的「服務」。
為了達成這個目標,我們會使用三個關鍵工具:
- Gunicorn:一個專業的「程式管理員」,專門負責運行我們的 Python 程式,比 Flask 內建的測試伺服器強大許多。
- Systemd:這是 Linux 系統內建的「總管」,它可以幫我們看管 Gunicorn,確保 Gunicorn 一直活著。如果 Gunicorn 不小心掛了,Systemd 會立刻把它叫醒。(如果你不知道什麼是 Linux...,歡迎去看鳥哥的 Linux 私房菜)
- 環境檔案:一個安全的「密碼保險箱」,用來存放資料庫密碼這類敏感資訊,避免它們直接寫在程式碼裡。(你可能聽過有人把密碼或是 OpenAI API key 上傳,資料被盜或是卡片被刷爆的故事...)
好了,藍圖清楚了,我們就開始動手吧!
步驟 1:準備好我們的「執行環境」
在正式部署前,我們需要先準備好一些東西。
1.1) 一個專門跑程式的「系統使用者」
什麼是 Root 權限?
Root 是 Linux 系統裡的「上帝」,擁有對系統所有檔案和設定的完整控制權。我們接下來要建立使用者或是一些系統層級的設定檔,所以必須暫時化身為 Root。在指令前面加上 sudo,就是向上帝借用權力。
為了安全起見,我們不會用最高權限的 root 帳號來跑我們的網路服務。你應該要有一個專門的、權限較低的系統使用者,例如 flaskuser。如果還沒有,可以透過:
sudo adduser flaskuser
來建立一個(sudo 這個指令代表「用最高權限來執行我接下來的指令」)。
1.2) 建立獨立的「Python 虛擬環境」
什麼是虛擬環境 (Virtual Environment)?
想像一下,你同時開發兩個 Python 專案:一個是你的「點餐 App」,它可能需要舊版的 requests 函式庫來跟某個老舊的 API 溝通;另一個是「Neurosynth 服務」,它可能需要最新版的 scikit-learn 來處理複雜的資料分析。如果你把這些不同版本的函式庫都裝到你電腦唯一的 Python 環境裡,它們就會「打架」,導致其中一個專案無法正常運行。
虛擬環境就像是為每個專案建立一個獨立、乾淨的「Python 小房間」。你在「點餐 App」的小房間裡裝了舊版的 requests,在「Neurosynth 服務」的小房間裡裝了新版的 scikit-learn,它們互不干擾。這樣,每個專案都能擁有自己專屬的運行環境,你可以安心開發,不用擔心函式庫版本衝突的問題。
請切換到你的專門使用者,然後在你的專案資料夾裡,建立一個虛擬環境:
# 切換到你的專門使用者
su - flaskuser
# -m venv 代表我們要用內建的 venv 模組來建立環境
# myvenv 是我們給這個虛擬環境資料夾取的名字
python3 -m venv myvenv
接著,啟動它:
source myvenv/bin/activate
啟動後,你會看到指令列前面出現 (myvenv) 的字樣,代表你已經在這個小房間裡了。現在,用 pip 把你的專案需要的套件(包括 Flask 和 Gunicorn)都裝進去。
pip install flask gunicorn
pip install -r requirements.txt # 如果你有 requirements.txt 的話
1.3) 為什麼需要 Gunicorn?
什麼是 Gunicorn?
你在開發時用的 flask run 其實是一個「開發用伺服器」。它很方便,但非常脆弱,不適合應付真實世界的網路流量。Gunicorn (Green Unicorn) 則是一個「生產級 WSGI 伺服器」。
什麼是 WSGI (Web Server Gateway Interface)?
簡單來說,WSGI 是一個「溝通標準」,它定義了像 Gunicorn 這樣的「網頁伺服器」,應該如何與像 Flask 這樣的「Python 應用程式」進行對話。Gunicorn 負責接收來自外部世界的網路請求,然後將這些請求按照 WSGI 標準打包,傳遞給 Flask。Flask 處理完畢後,再將回應按照 WSGI 標準打包,交還給 Gunicorn,最後由 Gunicorn 回傳給使用者。
把它想像成一個身經百戰、非常可靠的餐廳經理,專門負責接待客人(網路請求),並將他們的需求轉達給廚房(你的 Flask 應用程式)。為了應付大量的客人,Gunicorn 會啟動多個「工作進程」來同時處理請求,確保你的服務在高流量下也能穩定運行,不會輕易中斷。然而,如果你的應用程式有大量的 I/O 等待時間(例如,等待資料庫回應、呼叫外部 API),那麼 FastAPI + Uvicorn 的非同步模式(asynchronous)通常會是更有效率的選擇,這點我們會在後面的章節詳細比較。
步驟 2:用「環境檔案」來保管秘密
什麼是環境檔案 (Environment File)?
這是一個專門用來存放「環境變數」的檔案。你可以把所有敏感資訊,像是資料庫的帳號密碼、API 金鑰等,都寫在這個檔案裡。我們的程式會從這個檔案讀取這些變數。
為什麼要這麼做?
安全!安全!安全! 絕對不要把密碼寫死在程式碼裡,否則只要你的程式碼被別人看到(例如上傳到 GitHub),你的秘密就全都曝光了(而且如果是公開的,通常是一上傳的瞬間)。把設定和程式碼分離,是一個非常重要的好習慣。
接下來的操作,我們會需要「最高管理員權限」,也就是 Root 權限(sudo)。
讓我們來建立這個保險箱。這個檔案會放在 /etc/default/ 這個系統設定目錄下。
為什麼是 /etc/default/ 呢?
在 Linux 系統中,/etc/ 目錄通常用來存放系統層級的設定檔。而 /etc/default/ 這個子目錄,則習慣用來存放各種服務或程式的「預設值」或「環境變數」設定。這樣做的好處是,這些設定檔不會和服務本身的程式碼混在一起,而且可以方便系統管理員在同一個地方找到並修改這些預設設定。
# 用 nano 這個文字編輯器,以 root 權限建立檔案
sudo nano /etc/default/neurosynth
然後,把下面的內容貼進去。DB_URL 就是你的資料庫連線字串。
# /etc/default/neurosynth
DB_URL='postgresql://<readonly_user>:<StrongPassword>@127.0.0.1:5432/neurosynth'
# 你也可以加上 FLASK_ENV=production
寫好之後,按 Ctrl+X,接著按 Y(Yes!),最後按 Enter 存檔離開。
最後,我們要設定這個檔案的權限,確保只有 root 使用者才能讀取它,其他人連偷看都不行。
為什麼需要 sudo?
因為 /etc/default/ 是一個系統級的目錄,裡面存放的檔案都是由 root 管理。所以,當我們要修改這些檔案的權限和擁有者時,就需要像前面建立環境變數檔案一樣,借用 root 的權力來執行這些指令。
sudo chmod 600 /etc/default/neurosynth
sudo chown root:root /etc/default/neurosynth
這些指令是用來設定檔案的權限和擁有者,以確保我們的機密資訊不會被不相關的使用者讀取到:
chmod 600:chmod用來修改檔案的權限。數字600代表:6:檔案擁有者(root)有讀(4)+ 寫(2)的權限。0:同群組使用者沒有任何權限。0:其他使用者也沒有任何權限。- 簡單來說,就是只有檔案的「主人」
root可以讀寫這個檔案,其他人都不能動。
sudo chown root:root:chown(change owner) 用來修改檔案的「擁有者」和「所屬群組」。這裡我們將它們都設定為root。
這樣一來,我們就能確保檔案的權限設定是有效的,且無法被權限較低的使用者(例如服務帳號)讀取或修改。