SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor

VPS 上安裝 Jellyfin 串流自有媒體

學會用 Docker 在 VPS 部署 Jellyfin,設定 block storage 與媒體權限,避開 CPU 轉碼限制,並安全地從瀏覽器或 app 遠端播放自有影片。

建置內容

在 VPS 上建置 Jellyfin 媒體伺服器:使用一個容器、三個 volume,以及存放電影與影集的 block storage 磁碟,讓您可從任何瀏覽器或 Jellyfin app 存取。安裝只需 15 行的 compose 檔案。之後發生的問題大多來自兩個原因:容器無法讀取檔案權限,以及要求沒有 GPU 的 VPS 轉碼不適合由它處理的影片。本指南大部分篇幅都用於這兩個問題,因為支援工單主要都集中在這裡。

Jellyfin 免費且完全開放原始碼,不需要帳戶,沒有付費功能,也不會蒐集遙測資料,因此幾乎每份 2026 年值得自行代管的服務清單都會列出它。它只能播放您擁有的媒體。Jellyfin 不提供任何內容,本指南也不涵蓋取得媒體的方式。

開始租用前,先了解轉碼的實際限制

先閱讀這段,因為它會影響你的選擇。媒體伺服器在你按下播放後,會執行兩種工作之一。直接播放會原樣串流檔案:VPS 從磁碟讀取位元組,再透過網路傳送出去,幾乎不會消耗 CPU。轉碼則會即時重新編碼影片,例如變更解析度、編解碼器,或將字幕燒錄到影片中;這完全依賴 CPU 運算。

一般 VPS 沒有 GPU。因此,每次影片轉碼都會由 CPU 搭配 libx264/libx265 執行,而軟體編碼的成本很高。單一 1080p H.264 轉碼就可能耗盡數個共用 vCPU;4K 或 HEVC 轉碼通常完全無法跟上即時播放,導致播放停頓並持續緩衝。硬體轉碼是在家用電腦上搭配 Intel iGPU 或 Nvidia 顯示卡即可降低成本的功能;除非供應商提供 GPU 執行個體,否則 VPS 無法使用。

因此,在 VPS 上採用的整體策略是:避免轉碼。 將媒體庫維持在用戶端原生支援的編解碼格式,例如 H.264 影片、AAC 或 AC3 音訊,並使用 MP4 或 MKV 容器。同時選擇支援直接播放的用戶端應用程式,包括 Android TV、iOS 與 Roku 的原生 Jellyfin 應用程式,以及 Infuse、Kodi 和桌面版 Jellyfin Media Player。如此一來,VPS 在播放期間不必執行 ffmpeg 轉碼,規格適中的 2 vCPU 主機也能同時串流給數名使用者。若計畫進行轉碼,就需要更大且更昂貴的主機;即使如此,4K 仍不是理想選擇。

也要計算頻寬,因為這是另一個容易忽略的限制。直接播放會依照檔案本身的位元率傳送資料。壓縮後的 1080p 檔案通常為 8-12 Mbps;1080p Blu-ray remux 為 20-30 Mbps;4K HDR 則為 40-80 Mbps。3 名使用者同時直接播放 10 Mbps 檔案時,VPS 必須持續提供 30 Mbps 的上行流量。請確認方案中的兩項數值:連接埠速度(上行是否能推送 30 Mbps?)以及每月傳輸量上限。單部 2 小時、10 Mbps 的電影上傳流量約為 9 GB,因此每月計量上限為 1 TB 時,每月只能傳送略多於 100 部這類電影;若每天觀看 3 或 4 部,流量就會用盡。家庭觀看 4K 內容時,位元率會增加至 4 到 8 倍,流量消耗也會快得多。凡是透過同一台主機向外傳送的其他流量,也要計入相同的額度,包括 自架 RustDesk relay;當兩個對等端點無法直接連線時,relay 會承載完整的遠端桌面工作階段。

先決條件

  • 全新的 Ubuntu 24.04 KVM VPS,具備 root 或 sudo 權限,並已安裝 Docker 與 Compose plugin。
  • 用於媒體檔案的 block storage volume,容量應符合您的媒體庫需求(請參閱下方的容量規劃)。VPS 隨附的小型 root disk 不適合存放影片。
  • 如果需要公開的 HTTPS 存取,請準備網域名稱;如果希望整體維持私有,則可在同一台 VPS 上使用 WireGuard VPN。
  • 您依法有權串流的媒體,包括您自行擷取的內容、自行錄製的內容,以及您擁有的檔案。

先掛載區塊儲存

先在供應商的控制面板中連接磁碟區,然後找出裝置並掛載。從 lsblk 取得裝置名稱,通常會是 /dev/sdb 或 /dev/vdb 之類的名稱,但絕不會是根磁碟。

lsblk
sudo mkfs.ext4 /dev/sdb          # ONLY on a new, empty volume: this ERASES it
sudo mkdir -p /mnt/media
sudo blkid /dev/sdb              # copy the UUID shown for this device

請使用 UUID 掛載,不要使用 /dev/sdb,因為裝置代號可能在重新開機後重新排序,導致你格式化或掛載錯誤的磁碟。在 /etc/fstab 中加入一行:

UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  /mnt/media  ext4  defaults,nofail  0  2
sudo mount -a
df -h /mnt/media

nofail 很重要:如果沒有這個設定,區塊磁碟區一旦被卸離,主機就會拒絕開機並進入緊急 shell。這裡最嚴重的錯誤,是在已經包含資料的磁碟區上執行 mkfs.ext4,因為這會清除磁碟上的資料。只有新的磁碟區才應格式化;如果磁碟上已經有你的媒體庫,請直接跳到 fstab 設定行。

依照 Jellyfin 的預期整理媒體

Jellyfin 會根據資料夾名稱與檔案名稱比對中繼資料。版面配置錯誤時,電影可能會顯示為沒有片名且沒有海報的檔案,或是集數對應到錯誤的影集。以下 4 項慣例幾乎可以處理所有情況:每部電影放在自己的資料夾中,並使用相符的檔名,命名為 Name (Year)(Jellyfin 將年份視為選填,但加入年份能大幅提高比對可靠性);季資料夾命名為 Season 01,不要命名為 S01;集數檔案使用 S01E01;特別篇放在 Season 00。

/mnt/media
├── Movies
│   ├── Blade Runner (1982)
│   │   └── Blade Runner (1982).mkv
│   └── Arrival (2016)
│       └── Arrival (2016).mkv
└── Shows
    └── Severance (2022)
        ├── Season 01
        │   ├── Severance - S01E01.mkv
        │   └── Severance - S01E02.mkv
        └── Season 00
            └── Severance - The Lexington Letter.mkv

電影名稱中的 (Year) 不是裝飾用途,而是用來區分重拍版本,讓比對器取得正確的片名。請將 Movies 與 Shows 保持為不同的頂層資料夾,因為每個資料夾都會成為指定內容類型的 Jellyfin 媒體庫,混放會讓中繼資料提供者無法正確判斷。Jellyfin 也能正常為另一個相片資料夾建立索引,但與專門的相片伺服器相比,功能較為有限。因此,如果相簿對你很重要,請讓它們使用自己的主機執行 PhotoPrism 或 Immich,而這台主機則專門用於電影與電視節目。

權限:媒體庫顯示空白的首要原因

以下是最容易讓人浪費一個晚上的誤解。官方的 jellyfin/jellyfin image 不會使用 PUID/PGID 環境變數;這些變數屬於 LinuxServer.io image(lscr.io/linuxserver/jellyfin)。在官方 image 中,您可在 compose 內使用 user: 欄位指定使用者;若省略此欄位,container 會以 root 身分執行。無論採用哪種方式,規則都相同:container 執行時使用的 uid/gid 必須能讀取並進入每個媒體目錄。

我們會使用 uid/gid 1000,這是標準 Ubuntu 系統上的第一個非 root 使用者。請確認您的 uid/gid,並設定擁有權:

id                                  # confirm your user is uid=1000 gid=1000
sudo chown -R 1000:1000 /mnt/media
sudo find /mnt/media -type d -exec chmod 755 {} \;
sudo find /mnt/media -type f -exec chmod 644 {} \;
mkdir -p ~/jellyfin/config ~/jellyfin/cache
sudo chown -R 1000:1000 ~/jellyfin

目錄需要 execute 位元(即 755 中的 x),不能只有讀取權限。缺少此位元時,container 即使能列出目錄名稱,也無法進入該目錄。導致整個媒體庫變空的陷阱在於父目錄:如果 container 的 uid 無法進入掛載點本身,就永遠到不了 /media/Movies 或 /media/Shows,而且每個媒體庫都會同時變成空白,log 中則會出現 Access to the path ... is denied。只要有任何媒體資料夾無法讀取,系統就會記錄錯誤並略過該資料夾。因此,以 root 複製進去的一批檔案可能會無聲無息地從媒體庫消失。這就是我們要遞迴執行 chown,並為每個目錄設定 execute 位元,而不是只修正單一資料夾的原因。

Docker Compose 檔案

services:
  jellyfin:
    image: jellyfin/jellyfin:12
    container_name: jellyfin
    user: "1000:1000"
    restart: unless-stopped
    ports:
      - "127.0.0.1:8096:8096"
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /mnt/media:/media:ro
    environment:
      - JELLYFIN_PublishedServerUrl=https://jellyfin.example.com

逐行說明:jellyfin/jellyfin:12 追蹤目前的 12.x 發行系列(截至 2026-10-10 為 12.2)。user: "1000:1000" 設定 Jellyfin 程序執行時使用的 uid/gid。它不會變更任何檔案的擁有者或模式,因為 Docker 會在掛載的目錄上保留主機的 uid/gid,因此上方的 chown 必須與其相符。/config 儲存整個伺服器的資料,包括帳號、媒體庫、中繼資料與觀看狀態,因此必須可寫入,也是需要備份的項目。/cache 是可丟棄的工作空間。媒體掛載點是 :ro(唯讀),這是刻意的設定:Jellyfin 預設會將圖片與中繼資料儲存在 /config 下,因此不需要寫入媒體庫;唯讀設定也能避免誤刪檔案或不良外掛程式造成損害。連接埠刻意繫結至 127.0.0.1。Jellyfin 的網頁登入使用純 HTTP,因此絕不將 8096 發布至公用網際網路。JELLYFIN_PublishedServerUrl 是伺服器用於區域網路自動探索時公告的位址,採用 LAN UDP 廣播,因此網際網路上的用戶端不會看見它,只會使用你在應用程式中輸入的 URL。請將其設為應告知用戶端的位址,並預期在遠端裝置上手動輸入該 URL。

從 compose 目錄啟動:

docker compose up -d
docker logs -f jellyfin

首次執行:設定精靈與媒體庫

由於埠只繫結至 localhost,請從筆記型電腦建立 SSH tunnel 來存取設定精靈,不要開放防火牆埠:

ssh -L 8096:127.0.0.1:8096 you@your-vps-ip

現在瀏覽至 http://localhost:8096。設定精靈會引導您選擇語言,接著建立具備強密碼的 admin 使用者。此帳戶可管理您的伺服器,因此不要重複使用僅供臨時使用的密碼。新增第一個媒體庫:選擇內容類型 Movies,將路徑指定為 /media/Movies(這是容器內的路徑,不是主機路徑),再以 Shows 類型將媒體庫指向 /media/Shows。完成後,Jellyfin 會開始掃描。對於小型媒體庫,正常情況是在 1 或 2 分鐘內顯示海報與標題。之後可在 Dashboard → Libraries 新增或編輯媒體庫,也可使用 Scan All Libraries 強制重新掃描。這些海報也是基礎功能正常後值得試用替代前端的原因,因為 Halcyon 會利用 Jellyfin 已擷取的 artwork,將相同的媒體庫重建成可瀏覽的 90s 影音出租店。

如果您有使用任何 transcoding,請開啟 Dashboard → Playback → Transcoding,並將 transcoding 暫存路徑設為 /cache/transcodes,讓大量暫存資料寫入 cache volume,而不是使 /config 持續膨脹。硬體加速請維持 None,因為沒有 GPU 可用於加速。

遠端存取:TLS 反向代理,或維持在 VPN 內

從外部連線至 Jellyfin 有兩種安全方式,也有一種應避免的不安全方式。不安全的方式是直接將 8096 埠發布到網際網路:登入資訊會以明文傳輸,而且該連接埠會在數小時內遭到暴力破解。

選項 A:TLS 反向代理。 將 Jellyfin 放在子網域後方,使用 為 Docker 應用程式自動設定 TLS 的 Traefik,或搭配 nginx 使用 由 Certbot 核發的 Let's Encrypt 憑證。Jellyfin 使用 WebSockets 傳送即時更新,因此代理伺服器必須轉送升級標頭。Traefik 會自動處理;nginx 則必須明確設定這些標頭,並對上游服務使用 HTTP/1.1,否則升級程序不會執行:

location / {
    proxy_pass http://127.0.0.1:8096;
    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;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

將 JELLYFIN_PublishedServerUrl 設為 https:// 位址,讓本機自動探索功能公布正確的 URL,並讓遠端應用程式使用你提供的位址;另外加入 fail2ban 以降低暴力破解登入的速度。伺服器公開後,將 Uptime Kuma 指向該 URL,這樣就能在觀眾發現服務中斷前得知停機狀況。將通知目的地設為 自架的 ntfy 伺服器,檢查失敗時就會以手機推播通知送達,而不是等到隔天早上才讀到電子郵件。將登入介面公開到網際網路,也是稽核主機其餘部分的好時機,不要假設只有 443 埠正在接聽:sudo ss -tlnp 會列出所有接聽中的連接埠及其背後的程序。如果你也在主機上部署自行撰寫的程式碼,open-kritt 會掃描儲存庫及其相依套件中的漏洞;它稽核的是原始碼,不是接聽中的連接埠。

選項 B:透過 VPN 維持私有。 完全不要將 8096 發布到公開網際網路;只能透過終止於同一台主機上的 WireGuard 通道連線至 Jellyfin。對家庭使用情境而言,這是最簡單的安全選擇,不需要憑證、不會對外公開,也沒有暴力破解的攻擊面。compose 檔案中的 localhost 綁定本身在此並不足夠,因為發布在 127.0.0.1 上的連接埠只能由 VPS 本身存取,VPN 對等端無法連線。請改為在伺服器的通道路由位址上發布,例如 "10.8.0.1:8096:8096",使用你自己的 WireGuard 伺服器 IP;或者維持 localhost 綁定,並在前方設定一個監聽通道路由位址的代理伺服器,再透過 VPN 連線。通道本身請參閱 為私有 VPS 設定 WireGuard VPN。

儲存空間規劃與備份

應依畫質而非檔案數量編列容量。壓縮後的 1080p 電影每部約 4-15 GB;1080p remux 約 20-40 GB;一季 1080p 影集約 15-40 GB;4K 電影每部約 40-100 GB。數百部電影加上部分影集的媒體庫需要 2-4 TB 的磁碟區。一次預留較充足的 block volume,通常比日後搬遷更便宜。

/config 是整台伺服器的狀態,因此這是唯一必須備份的項目。建立 snapshot,或停止服務後將其打包成 tar,並把副本保存在伺服器之外:

docker compose down
sudo tar czf jellyfin-config-$(date +%F).tgz -C ~/jellyfin config
docker compose up -d

/cache 與轉碼資料夾都可捨棄。/mnt/media 上的媒體可另行備份,或接受日後重新擷取。考量容量,大多數人會選擇後者。升級使用 docker compose pull && docker compose up -d;上方的 :12 標籤仍在 12.x 系列內,因此移至下一個主要版本時,必須刻意修改標籤。修改前先閱讀 Jellyfin 的 release notes,因為主要版本會進行媒體庫結構描述遷移。Jellyfin 在 12.0(2026 年 9 月)取消版本號前導的「10.」:12.0 對應原本的 10.12,不存在 11.x,而 10.11.x 是舊版編號方式的最後一個系列。如果你的舊 compose 檔案仍寫著 jellyfin/jellyfin:10,它會固定在 10.11(該標籤最後於 2026-06-06 移至 10.11.11),永遠不會拉取 12.x。改成 :12 不只是修改標籤:12.0 會變更資料庫結構描述,並在首次啟動時重寫資料。因此,請先停止伺服器並建立上述備份,因為該備份是唯一的復原方式。12.0 可直接從 10.10.7 或任何 10.11.x 版本升級,之後還需要完整掃描媒體庫,所需時間會明顯長於平常。固定映像標籤,再搭配一個已備份的狀態目錄,就是所有長時間運作容器的完整做法;讓自架 agent 的記憶與排程在重新開機後持續保留也是基於相同模式。

失敗情況與畫面中會出現的字串

掃描後媒體庫是空的。 Dashboard → Logs(或 ~/jellyfin/config/log/log_*.log)中的日誌會顯示:

System.UnauthorizedAccessException: Access to the path '/media/Movies' is denied.

容器的 uid 無法讀取該路徑。原因可能是媒體檔案由 root 或不同於 user: 值的 uid 所有、目錄缺少執行權限,或父層掛載點本身無法由該 uid traversable。修正方式:chown -R 1000:1000 /mnt/media,將目錄設為 755,檔案設為 644,然後重新掃描。

播放時 CPU 使用率飆高並持續緩衝。 docker stats jellyfin 顯示 CPU 使用率接近核心數乘以 100%,而 Dashboard → Playback 將工作階段列為 Transcode,速度低於 1.0x。用戶端未採用 direct play,因此 VPS 正在進行 CPU 轉碼,速度低於即時播放速度,導致播放落後。原因可能是不支援的編解碼器或容器格式、字幕燒錄,或 HDR 色調映射。修正方式:改用支援 direct play 的用戶端,來源維持 H.264/AAC,使用文字字幕(SRT),不要使用影像字幕(PGS/VOBSUB)。多數 Jellyfin 用戶端無法自行繪製影像字幕,因此會強制進行燒錄;此外,CPU-only 主機應完全避免處理 4K HDR。

「沒有相容的串流可用。」 完整訊息通常是 「此用戶端與媒體不相容,且伺服器未傳送相容的媒體格式。」 用戶端拒絕了來源,而後備轉碼也未能啟動。原因可能是 ffmpeg 指令錯誤、檔案無法讀取,或使用者設定檔禁止影片轉換。修正方式:在 Dashboard → Logs 讀取 ffmpeg 指令列,確認檔案本身可以播放;若依賴轉碼,請檢查使用者的播放權限;另外也可嘗試第二個用戶端,以排除瀏覽器編解碼器相容性問題。

電影沒有海報或顯示錯誤的海報。 中繼資料比對失敗。原因可能是資料夾或檔名與中繼資料提供者列出的片名不一致、重拍作品或常見片名缺少年份而無法區分版本、季資料夾命名為 S01 而非 Season 01,或集數未採用 S01E01 格式。修正方式:依照上述結構重新命名,然後選取 Refresh metadata → Replace all;也可以對單一項目使用 Identify,指定正確的 TMDB/TVDB 項目。

FAQ

VPS 可以在沒有 GPU 的情況下轉碼影片嗎?

可以,但只能使用 CPU,而且成本很高。單一 1080p 軟體轉碼就可能耗盡數個 vCPU;4K 或 HEVC 通常無法跟上即時播放速度,因此播放會緩衝。最有效的方法是避免轉碼:將媒體庫維持為 H.264/AAC,並使用支援 direct-play 的用戶端應用程式,讓 VPS 只傳輸位元組。只有在確實需要即時轉碼時,才租用 GPU instance。

為什麼 Jellyfin 掃描後媒體庫是空的?

幾乎都是權限問題。官方 jellyfin/jellyfin image 會以你設定的 user:(或 root)執行;如果該 uid 無法讀取檔案,掃描日誌會記錄 Access to the path ... is denied 並略過這些檔案。使用 chown -R 1000:1000 /mnt/media 修正擁有者,為目錄加入執行權限位元(755),然後重新掃描。同時檢查上層目錄,因為如果容器的 uid 無法遍歷 /mnt/media 本身,就無法到達媒體庫目錄,結果會完全顯示為空。第二常見的原因是目錄結構不符合 Jellyfin 的預期。

如何安全地從遠端存取 Jellyfin?

有兩個可行方法。將它放在子網域上的 TLS reverse proxy 後方,讓登入資料與串流內容都經過加密,並加入 fail2ban。絕對不要公開 plain port 8096,因為這會以明文傳送密碼。另一種方法是完全維持私有,只透過 VPN 存取;對家庭使用情境而言,這是最簡單且安全的選擇。請直接將公開位址提供給應用程式,因為 autodiscovery 是區域網路廣播,無法到達從網際網路連入的用戶端。

Jellyfin VPS 需要多少磁碟空間與頻寬?

磁碟需求取決於畫質:每部壓縮的 1080p 電影預留 4-15 GB,每部 remux 預留 20-40 GB,4K 則預留 40-100 GB。因此,多數媒體庫需要 2-4 TB 的 block volume。頻寬取決於 direct-play bitrate;每個 1080p 串流約需 8-12 Mbps,4K 需要更多。請確認連接埠速度足以應付同時觀看的人數,並留意每月傳輸量上限。若計畫轉碼,請預留 CPU 效能;若計畫使用 direct-play,應優先配置頻寬,而不是增加核心數。

在 VPS 上執行 Jellyfin 合法嗎?

Jellyfin 本身是免費的 open-source software,執行它完全合法。關鍵在於內容:只能串流你擁有或取得授權持有的媒體,例如自己的光碟轉檔、錄製內容,或你有權使用的檔案。Jellyfin 不提供任何媒體,也不提供取得媒體的方式;它只是播放你已擁有之媒體庫的播放器。