介紹
```bash showLineNumbers 作業環境:Ubuntu + EC2 服務管理:systemctl 主要應用:FastAPI (Python) + S3 功能重點: a. Ubuntu 中安裝 python,開發環境 venv b. 外部請求打到 systemctl 可以調用 python fastapi service 使用 ytdlp 轉換後,上傳 / 下載指定 bucket c. python logger + systemctl log 設置
## Ubuntu 中安裝 python
```bash
# 檢查現有版本
python3 --version
# 更新套件庫
sudo apt update
sudo apt upgrade -y
# 安裝 Python3 + pip
sudo apt install -y python3 python3-pip
# 檢查版本
python3 --version
pip3 --version
建議開發環境 venv (乾淨做法)
用 venv 隔離專案依賴,避免把系統 python 搞髒 venv 不是系統自帶的,你需要安裝 python3-venv
安裝 venv 模組
sudo apt update
sudo apt install python3-venv -y
# 在目前資料夾下建立一個叫 venv/ 的目錄,裡面包含獨立的 Python 解譯器與套件目錄。
python3 -m venv venv
# 啟用這個環境,接下來在 shell 裡打 python 或 pip,
# 都會指向這個 venv 裡的版本,而不是系統的全域 Python。
source venv/bin/activate
# 升級這個 venv 裡的 pip(只影響這個 venv,不會動到系統 pip)。
pip install --upgrade pip
這幾行就是在 當前目錄 建立一個獨立的 Python 開發環境: 1. python3 -m venv venv 1. 在目前資料夾下建立一個叫 venv/ 的目錄,裡面包含獨立的 Python 解譯器與套件目錄。 2. source venv/bin/activate 1. 啟用這個環境,接下來在 shell 裡打 python 或 pip,都會指向這個 venv 裡的版本,而不是系統的全域 Python。 3. pip install --upgrade pip 1. 升級這個 venv 裡的 pip(只影響這個 venv,不會動到系統 pip)。
等於你可以在這個專案目錄下,自己管理需要的套件,跟系統層完全隔離。
每次重開 terminal 都要重新 source venv/bin/activate,不然就會回到系統 Python。
python worker 上傳 / 下載指定 bucket
安裝依賴
用有權限的 bucket,上傳 / 下載指定 bucket
import boto3
import os
s3 = boto3.client("s3")
bucket = os.getenv("S3_BUCKET", "your-bucket-name")
key = "test.txt"
# 上傳
s3.put_object(Bucket=bucket, Key=key, Body=b"hello world")
# 下載
resp = s3.get_object(Bucket=bucket, Key=key)
print(resp["Body"].read().decode())
這樣完全符合最小權限原則 (least privilege),不用給 ListAllMyBuckets。
python fastapi service
目錄結構
建立 systemd unit file
目的: 透過 systemctl 管理一個 FastAPI 服務(以 Python 實作)。 外部請求(HTTP / HTTPS)打到這個服務後,FastAPI 負責處理請求邏輯, 包括調用 yt-dlp 進行影片下載與轉檔,並在完成後將檔案上傳到指定位置(例如 S3 或本地儲存), 同時也提供下載端點讓用戶取得結果。
- ytdlp-check-duration
服務配置文件 ```service title="/etc/systemd/system/ytdlp-check-duration.service" showLineNumbers [Unit] Description=YT-DLP Check Duration API After=network.target
[Service] User=ubuntu WorkingDirectory=/home/ubuntu/project/ytdlp ExecStart=/home/ubuntu/project/ytdlp/venv/bin/uvicorn check_duration_api:app --host 0.0.0.0 --port 8001 Restart=always RestartSec=5 StandardOutput=file:/home/ubuntu/project/ytdlp/logs/check_duration.log StandardError=file:/home/ubuntu/project/ytdlp/logs/check_duration_err.log
[Install] WantedBy=multi-user.target
2. ytdlp-download
服務配置文件
```service title="/etc/systemd/system/ytdlp-download.service" showLineNumbers
[Unit]
Description=YT-DLP Download API
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/project/ytdlp
ExecStart=/home/ubuntu/project/ytdlp/venv/bin/uvicorn download_api:app --host 0.0.0.0 --port 8002
Restart=always
RestartSec=5
StandardOutput=file:/home/ubuntu/project/ytdlp/logs/download.log
StandardError=file:/home/ubuntu/project/ytdlp/logs/download_err.log
[Install]
WantedBy=multi-user.target
uvicorn 用 py.check_duration_api:app 就可以找到 module 保持 WorkingDirectory → module 名稱用 py.check_duration_api,py 內需 init.py
```service title="/etc/systemd/system/ytdlp-check-duration.service" showLineNumbers ExecStart=/home/ubuntu/project/ytdlp/venv/bin/uvicorn py.check_duration_api:app --host 0.0.0.0 --port 8001
### 建立 log 目錄
```bash
mkdir -p /home/ubuntu/project/ytdlp/logs
chown ubuntu:ubuntu /home/ubuntu/project/ytdlp/logs
tail -f /home/ubuntu/project/ytdlp/logs/check_duration.log
tail -f /home/ubuntu/project/ytdlp/logs/check_duration_err.log
tail -f /home/ubuntu/project/ytdlp/logs/download.log
tail -f /home/ubuntu/project/ytdlp/logs/download_err.log
啟動、開機自啟
# 重新讀取 systemd 配置
sudo systemctl daemon-reload
# 啟動服務
sudo systemctl start ytdlp-check-duration
sudo systemctl start ytdlp-download
# 設定開機自啟動
sudo systemctl enable ytdlp-check-duration
sudo systemctl enable ytdlp-download
# 查看狀態
sudo systemctl status ytdlp-check-duration
sudo systemctl status ytdlp-download
重新讀取 systemd 配置
# 重新讀取 systemd 配置
sudo systemctl daemon-reload
# 啟動服務
sudo systemctl restart ytdlp-check-duration
sudo systemctl restart ytdlp-download
python 找不到 yt-dlp 問題
你看到的錯誤:
就是 Python 進程找不到 yt-dlp 可執行檔,不是 FastAPI 或 systemd 的問題。
原因: 1. yt-dlp 沒安裝在系統 PATH 下,或者只安裝在虛擬環境裡。 2. systemd 啟動的服務 沒有讀到你的使用者 PATH,所以找不到 yt-dlp。 用完整路徑找到 yt-dlp 可執行檔:
在 systemd 裡設定 PATH
用 yt-dlp 進行快速測試
URL 無效 / 被 YouTube 阻擋
跑 -j 是最佳 debug 方法: 1. 可以確認 yt-dlp 在 EC2 上能不能連到 YouTube 2. 不會浪費時間下載大檔案
這個 -j 代表輸出 JSON metadata(不會真的下載影片)。你應該會看到一大串 JSON(標題、ID、duration、formats 等資訊)。
YouTube video ID 長度錯誤
YouTube video ID 永遠是 11 個字元,你這個 S38bIAfJTb 只有 10 碼,yt-dlp 才會丟:
/home/ubuntu/project/ytdlp/venv/bin/yt-dlp -j "https://www.youtube.com/watch?v=S38bIAfJTb"
ERROR: [youtube:truncated_id] S38bIAfJTb: Incomplete YouTube ID S38bIAfJTb.
URL https://www.youtube.com/watch?v=S38bIAfJTb looks truncated.
python log 權限設置
服務以 ubuntu 用戶身份運行,無法寫入日誌文件
File "/usr/lib/python3.12/logging/__init__.py", line 1263, in _open
return open_func(self.baseFilename, self.mode,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied: '/home/ubuntu/project/ytdlp/logs/check_duration.log'
修復、檢查日誌目錄權限
# 確保日誌目錄存在且權限正確
sudo mkdir -p /home/ubuntu/project/ytdlp/logs
sudo chown -R ubuntu:ubuntu /home/ubuntu/project/ytdlp/logs
sudo chmod -R 755 /home/ubuntu/project/ytdlp/logs
# 如果日誌文件已存在,也要修復權限
sudo chown ubuntu:ubuntu /home/ubuntu/project/ytdlp/logs/check_duration.log 2>/dev/null || true
sudo chown ubuntu:ubuntu /home/ubuntu/project/ytdlp/logs/check_duration_err.log 2>/dev/null || true
# 檢查,確保整個項目目錄權限正確
sudo chown -R ubuntu:ubuntu /home/ubuntu/project/ytdlp
# 重啟服務
sudo systemctl daemon-reload
sudo systemctl restart ytdlp-check-duration
sudo systemctl status ytdlp-check-duration
python service 補上logger
```py title="/home/ubuntu/project/ytdlp/py/check_duration_api.py" showLineNumbers from fastapi import FastAPI from pydantic import BaseModel import json import os import subprocess import logging from pathlib import Path
確保日誌目錄存在
log_dir = Path("/home/ubuntu/project/ytdlp/logs") log_dir.mkdir(parents=True, exist_ok=True)
設定 log
log_file = log_dir / "check_duration.log"
配置日誌格式
formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")
創建文件處理器
file_handler = logging.FileHandler(log_file) file_handler.setFormatter(formatter)
創建控制台處理器
console_handler = logging.StreamHandler() console_handler.setFormatter(formatter)
配置根日誌器
logger = logging.getLogger() logger.setLevel(logging.INFO) logger.addHandler(file_handler) logger.addHandler(console_handler)
避免重複添加處理器
logger.handlers = [file_handler, console_handler]
cookies_file = os.getenv("YT_DLP_COOKIES", "cookies.txt") app = FastAPI()
class CheckRequest(BaseModel): url: str max_duration: int = 600 # 預設 10 分鐘
@app.post("/check-duration") def check_duration(req: CheckRequest): try: logging.info(f"Received request: url={req.url}, max_duration={req.max_duration}") cmd = [ "yt-dlp", "--cookies", cookies_file, "-j", req.url ] proc = subprocess.run(cmd, capture_output=True, text=True) if proc.returncode != 0: logging.error(f"yt-dlp failed: {proc.stderr}") return {"error": "yt-dlp failed"} info = json.loads(proc.stdout) duration = info.get("duration", 0) logging.info(f"Video duration: {duration}s, title: {info.get('title')}") if duration > req.max_duration: logging.warning(f"Audio too long: {duration}s") return {"error": "Audio too long", "duration": duration} return {"duration": duration, "title": info.get("title")} except Exception as e: logging.exception("Exception occurred during check_duration") return {"error": str(e)}
### 修改 systemd 服務配置文件
確保路徑正確,才抓得到log
```service title="/etc/systemd/system/ytdlp-check-duration.service" showLineNumbers
StandardOutput=file:/home/ubuntu/project/ytdlp/logs/check_duration.log
StandardError=file:/home/ubuntu/project/ytdlp/logs/check_duration_err.log
YouTube 反爬蟲 / 限制存取,帶上登入後的 cookies
印象中當初本地與伺服器上 yt-dlp 版本不同,yt-dlp 更新到最新版似乎可以解決這個問題
/home/ubuntu/project/ytdlp/venv/bin/yt-dlp -j "https://www.youtube.com/watch?v=S38bIAfJTbE"
ERROR: [youtube] S38bIAfJTbE: Sign in to confirm you’re not a bot.
Use --cookies-from-browser or --cookies for the authentication.
See https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp
for how to manually pass cookies. Also see
https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies
for tips on effectively exporting YouTube cookies
https://chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc?hl=zh-tw
cookies 失效
- 嘗試更新 ytdlp 版本至最新 (優先方案)
- 改用活躍帳號的 cookies (平常真的有登入 YouTube 看影片,cookies 壽命會更長)
改用活躍帳號,但建議別使用主帳號,應該開個新 Google 帳號,專門給 yt-dlp 用,避免帳號鎖死,「鎖死」,不是 yt-dlp 不能用而已,而是整個 Google 帳號會進入風險狀態,嚴重一點會 完全被封鎖。yt-dlp 的流量不是人類行為(Google AI 偵測得到)。如果你一直用「主要 Google 帳號」+ EC2 IP(異常地區)去拉,Google 很容易判定為 被盜用 / 濫用 → 鎖帳號。最慘 scenario:你主帳號的 Gmail / Drive 都被鎖,會中風。
快速測試: 跑 -j 是最佳 debug 方法