FastAPI 網站應用
以下以 Ubuntu 22.04/24.04 為例,說明從 SSH 登入後,建置並以正式服務方式啟動 FastAPI 應用。假設:
- 網域:`api.example.com`
- 專案路徑:`/home/ubuntu/fastapi-app`
- FastAPI 程式入口:`main.py`
- FastAPI 物件名稱:`app`
---
## 1. SSH 遠端登入 Ubuntu
在本機終端機執行:
```bash
ssh ubuntu@伺服器IP
```
若使用指定私鑰:
```bash
ssh -i ~/.ssh/my-server-key.pem ubuntu@伺服器IP
```
登入後確認系統資訊:
```bash
whoami
hostname
lsb_release -a
```
建議不要長期直接使用 `root` 執行網站服務。
---
## 2. 更新系統並安裝 Python
```bash
sudo apt update
sudo apt upgrade -y
sudo apt install -y python3 python3-pip python3-venv nginx git curl
```
確認版本:
```bash
python3 --version
pip3 --version
```
---
## 3. 建立 FastAPI 專案
建立專案目錄:
```bash
mkdir -p ~/fastapi-app
cd ~/fastapi-app
```
建立虛擬環境:
```bash
python3 -m venv .venv
source .venv/bin/activate
```
啟用後,命令列通常會出現:
```text
(.venv) ubuntu@server:~/fastapi-app$
```
安裝 FastAPI 與 Uvicorn:
```bash
pip install --upgrade pip
pip install fastapi uvicorn[standard] gunicorn
```
若專案已有 `requirements.txt`,則使用:
```bash
pip install -r requirements.txt
```
可將目前套件版本保存起來:
```bash
pip freeze > requirements.txt
```
---
## 4. 建立 FastAPI 程式
建立 `main.py`:
```bash
nano main.py
```
填入:
```python
from fastapi import FastAPI
app = FastAPI(title="My FastAPI App")
@app.get("/")
def read_root():
return {"message": "FastAPI is running"}
@app.get("/health")
def health_check():
return {"status": "ok"}
```
儲存後,先以開發模式測試:
```bash
uvicorn main:app --host 127.0.0.1 --port 8000
```
其中:
- `main`:代表 `main.py`
- `app`:代表程式中的 `app = FastAPI()`
- `127.0.0.1`:只允許伺服器本機存取
- `8000`:應用程式使用的連接埠
另開一個 SSH 視窗測試:
```bash
curl http://127.0.0.1:8000/
curl http://127.0.0.1:8000/health
```
應看到類似:
```json
{"message":"FastAPI is running"}
```
FastAPI 自動產生的文件網址為:
```text
http://伺服器IP:8000/docs
```
測試完成後,按下:
```text
Ctrl + C
```
停止開發伺服器。
---
## 5. 使用 systemd 建立正式服務
正式環境不建議直接在 SSH 視窗中執行 Uvicorn,因為登出 SSH 後程序可能停止。可使用 `systemd` 管理服務。
先確認目前使用者名稱:
```bash
whoami
```
假設使用者是 `ubuntu`,建立服務檔:
```bash
sudo nano /etc/systemd/system/fastapi.service
```
內容如下:
```ini
[Unit]
Description=FastAPI application
After=network.target
[Service]
User=ubuntu
Group=ubuntu
WorkingDirectory=/home/ubuntu/fastapi-app
Environment="PATH=/home/ubuntu/fastapi-app/.venv/bin"
ExecStart=/home/ubuntu/fastapi-app/.venv/bin/gunicorn \
--workers 2 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 127.0.0.1:8000 \
main:app
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
如果不是使用者 `ubuntu`,請修改以下項目:
```ini
User=你的使用者
Group=你的使用者
WorkingDirectory=/home/你的使用者/fastapi-app
Environment="PATH=/home/你的使用者/fastapi-app/.venv/bin"
ExecStart=/home/你的使用者/fastapi-app/.venv/bin/gunicorn ...
```
載入並啟動服務:
```bash
sudo systemctl daemon-reload
sudo systemctl enable fastapi
sudo systemctl start fastapi
```
檢查狀態:
```bash
sudo systemctl status fastapi
```
若看到 `active (running)`,表示服務已啟動。
查看即時日誌:
```bash
sudo journalctl -u fastapi -f
```
查看最近的日誌:
```bash
sudo journalctl -u fastapi --no-pager -n 100
```
常用控制指令:
```bash
sudo systemctl restart fastapi
sudo systemctl stop fastapi
sudo systemctl start fastapi
sudo systemctl status fastapi
```
修改程式或安裝新套件後,通常需要重新啟動:
```bash
sudo systemctl restart fastapi
```
---
## 6. 使用 Nginx 反向代理
正式環境通常讓:
```text
使用者 → Nginx :80/:443 → FastAPI :8000
```
好處包括:
- 使用標準 HTTP/HTTPS 埠
- 可設定 HTTPS 憑證
- 可處理靜態檔案
- 不需要直接暴露 FastAPI 的 8000 埠
建立 Nginx 設定:
```bash
sudo nano /etc/nginx/sites-available/fastapi
```
填入以下內容,將 `api.example.com` 換成自己的網域:
```nginx
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
啟用設定:
```bash
sudo ln -s /etc/nginx/sites-available/fastapi \
/etc/nginx/sites-enabled/fastapi
```
若預設網站造成衝突,可移除:
```bash
sudo rm -f /etc/nginx/sites-enabled/default
```
測試 Nginx 設定:
```bash
sudo nginx -t
```
重新載入:
```bash
sudo systemctl reload nginx
```
此時可使用:
```text
http://api.example.com/
http://api.example.com/docs
```
若尚未設定 DNS,也可以先用伺服器 IP 測試:
```text
http://伺服器IP/
```
---
## 7. 設定防火牆
若 Ubuntu 使用 UFW,建議只開放必要埠:
```bash
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status
```
`Nginx Full` 會開放:
- TCP 80:HTTP
- TCP 443:HTTPS
因為 FastAPI 綁定在 `127.0.0.1:8000`,所以不需要對外開放 8000。
若只是臨時測試、要直接從外部連接 8000,才需要:
```bash
sudo ufw allow 8000/tcp
```
並將服務綁定改為:
```text
--bind 0.0.0.0:8000
```
但正式環境通常不建議這樣做。
---
## 8. 設定 HTTPS
若網域已經指向伺服器,可使用 Let’s Encrypt:
```bash
sudo apt install -y certbot python3-certbot-nginx
```
執行:
```bash
sudo certbot --nginx -d api.example.com
```
Certbot 通常會自動:
- 申請 SSL 憑證
- 修改 Nginx 設定
- 將 HTTP 轉址至 HTTPS
- 設定自動續期
測試自動續期:
```bash
sudo certbot renew --dry-run
```
---
## 9. 更新程式的常見流程
假設程式以 Git 管理:
```bash
cd ~/fastapi-app
git pull
source .venv/bin/activate
pip install -r requirements.txt
sudo systemctl restart fastapi
```
確認服務狀態:
```bash
sudo systemctl status fastapi
```
若無法啟動,先查看日誌:
```bash
sudo journalctl -u fastapi -n 100 --no-pager
```
也可以測試本機服務:
```bash
curl http://127.0.0.1:8000/health
```
---
## 10. 常見問題
### `ModuleNotFoundError`
通常是套件沒有安裝在正確的虛擬環境:
```bash
cd ~/fastapi-app
source .venv/bin/activate
pip install -r requirements.txt
```
確認 systemd 使用的是虛擬環境內的 Gunicorn:
```ini
ExecStart=/home/ubuntu/fastapi-app/.venv/bin/gunicorn ...
```
### `502 Bad Gateway`
通常代表 Nginx 無法連到 FastAPI,檢查:
```bash
sudo systemctl status fastapi
curl http://127.0.0.1:8000/health
sudo tail -f /var/log/nginx/error.log
```
### 修改程式後沒有生效
重新啟動服務:
```bash
sudo systemctl restart fastapi
```
### 連接埠已被使用
```bash
sudo ss -ltnp | grep 8000
```
找出程序後停止或更換埠號。
---
## 最終架構
完成後的服務架構通常如下:
```text
瀏覽器
│
│ HTTPS :443
▼
Nginx
│
│ http://127.0.0.1:8000
▼
Gunicorn + Uvicorn Workers
│
▼
FastAPI main:app
```
最重要的檔案包括:
```text
/home/ubuntu/fastapi-app/
├── .venv/
├── main.py
└── requirements.txt
/etc/systemd/system/fastapi.service
/etc/nginx/sites-available/fastapi
```
相關學習地圖、教學課程
Python 後端工程、資料庫