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

Immich 影片播放很慢?VPS 轉碼設定與排查

iPhone 的 HEVC 影片在 Immich 上要等很久才播得動,原因通常不是網路,而是 VPS 正在用 CPU 軟體轉碼。五種轉碼政策各自的代價、第一次匯入為什麼最慢,以及怎麼分辨線路與反向代理的問題。

Immich 影片播放很慢,問題多半不在網路

Immich 影片播放很慢,最常見的原因是伺服器還沒把那支影片轉碼完,播放器只好直接拉原始檔。iPhone 在「高效率」模式錄的 HEVC(H.265,高效率視訊編碼)位元率很高,瀏覽器又不一定解得開,於是你看到的就是一直轉圈圈。轉碼這件事發生在你租的 VPS 上,吃的是 CPU。

以下以 Immich v3.2.2(2026 年 9 月)的介面與官方預設值為準。轉碼的所有設定都在網頁管理介面裡(Administration → Settings → Video Transcoding Settings),不是設定檔,所以下面出現的 shell 指令都是你自己在 VPS 上跑來診斷用的,不是安裝步驟。

轉碼在哪裡發生,是誰在做

Immich 不會在你按下播放的那一刻才即時轉碼。轉碼是背景工作。影片上傳完成後,Immich 會排一個 Transcode Videos 工作,由 microservices worker 呼叫 ffmpeg 把它轉成一份相容格式,存進 encoded-video/ 資料夾。播放時如果那份轉碼檔已經存在,就送轉碼檔;還不存在,就送原始檔。

官方文件說明 immich-server 這個容器裡同時跑兩個 worker:API worker 負責回應網頁與手機 App 的請求,microservices worker 負責縮圖、機器學習與影片編碼。兩者共用同一台機器的 CPU 額度。所以轉碼佇列塞滿的時候,連相簿列表都會變鈍,因為 API worker 搶不到 CPU。這一點很重要:你看到的「播放慢」,有時候其實是「整個服務都慢」。

原始檔永遠不會被刪掉。官方 FAQ 的說法是 Immich always keeps your original files,轉碼檔是額外產生的。encoded-video/ 與 thumbs/ 都屬於可以重新產生的資料,官方估計縮圖加轉碼檔平均會讓相片庫多佔 10% 到 20% 的空間。這個數字在買磁碟的時候要算進去,細節可以看Immich 的記憶體與儲存空間需求。

為什麼 iPhone 的影片幾乎一定會被轉碼

Immich 預設的轉碼政策是 required,而預設「可接受的影片編碼」清單裡只有一種:h264。iPhone 的「高效率」錄影輸出的是 HEVC,不在清單裡,所以每一支都會被排進轉碼佇列。

required 還有另外兩個觸發條件:影片是 HDR(高動態範圍),或者像素格式不被接受。iPhone 開了 HDR 錄影之後拍出來就是 HDR 影片,把它轉成 SDR 需要做 tone mapping(色調對應),Immich 預設用 hable 演算法。這一步一樣是 CPU 在算。

所以一支 iPhone 4K HDR 影片,在預設設定下會同時踩到兩個條件。它不是偶爾被轉碼,是一定被轉碼。想確認手上的檔案到底是什麼編碼,在自己的電腦上對原始檔跑 ffprobe:

ffprobe -v error -select_streams v:0 \
  -show_entries stream=codec_name,pix_fmt,width,height,bit_rate \
  -of default=noprint_wrappers=1 IMG_1234.MOV

codec_name=hevc 就是 HEVC。pix_fmt=yuv420p10le 代表 10-bit,通常伴隨 HDR。看到這兩個,你就知道這支片在預設政策下必定會被轉。

五種轉碼政策,各自要付什麼代價

Administration → Settings → Video Transcoding Settings 的政策下拉選單有五個選項,括號裡是設定檔中對應的值。

  • All videos(all):全部轉碼。播放體驗最一致,CPU 與磁碟代價最高。
  • Only videos not in an accepted format(required):預設值。只轉不合格的,iPhone 的片子全中。
  • Videos higher than max bitrate or not in an accepted format(bitrate):在 required 之上,再加上超過最大位元率的也轉。
  • Videos higher than target resolution or not in an accepted format(optimal):在 required 之上,再加上長寬都超過目標解析度的也轉。
  • Don't transcode any videos(disabled):完全不轉。省 CPU 也省磁碟。

很多人在小機器上撐不住,直接把政策改成 disabled,這不是純粹的勝利。不轉碼以後 CPU 立刻安靜下來,但播放時 Immich 只能把原始檔整個丟給你的瀏覽器。原始的 4K HEVC 檔案一分鐘就可能上看幾百 MB,從台灣或香港連到海外機房,這個位元率大概率拉不滿,結果是 CPU 閒著而畫面在卡。桌面版瀏覽器對 HEVC 的支援也不一致:Safari 可以播,Chrome 要看作業系統有沒有提供硬體解碼器,Firefox 通常直接放棄。你換到的是另一種失敗,不是沒有失敗。

改完政策之後要回 Administration → Jobs 重跑 Transcode Videos,舊的轉碼檔才會依新政策被刪除或重做。改設定本身不會動到已經存在的檔案。

一般 VPS 沒有 GPU,Quick Sync 與 NVENC 那幾個選項不要碰

Video Transcoding Settings 裡有一個硬體加速選項,可以選 NVENC(NVIDIA)、Quick Sync(Intel)、RKMPP(Rockchip)、VAAPI。這些選項會出現在介面上,不代表你的機器有對應的硬體。一台標準雲端 VPS 只有虛擬 CPU,沒有內顯,沒有 Quick Sync,也沒有 NVENC 編碼器。把加速從 disabled 改成別的值,結果是轉碼工作開始失敗,而不是變快。

開之前先在 VPS 上確認硬體到底存不存在:

ls /dev/dri
nvidia-smi

一般 VPS 的第一行會回 ls: cannot access '/dev/dri': No such file or directory,第二行會回 nvidia-smi: command not found。沒有 /dev/dri 就沒有可用的 VAAPI 或 Quick Sync 裝置節點,ffmpeg 打不開裝置,工作就會失敗。這兩個指令的輸出是你唯一需要的證據。

官方文件另外列了幾個限制:只支援 Linux 與透過 WSL2 的 Windows;WSL2 不支援 Quick Sync;Raspberry Pi 不支援;而且硬體編碼的畫質通常比軟體編碼差,檔案也比較大。換句話說,硬體加速買的是速度,不是品質。

真的想用硬體編碼,就要一台把 GPU 直通給你的方案,那是另一個價格帶,可以先看有 GPU 可用的 VPS 方案再決定值不值得。同一套道理在影音伺服器上也成立,Jellyfin 搭 NVIDIA 顯示卡做硬體轉碼的前提一樣是你手上真的有那張卡。

第一次匯入,是它這輩子最慢的一次

把幾年份的手機相簿一次倒進去,Immich 會同時排出大量工作:中繼資料萃取、縮圖、機器學習的 Smart Search 與人臉偵測,還有影片轉碼。官方 FAQ 直接點名轉碼與機器學習是最吃 CPU 的兩類工作。官方建議的最低規格是 2 核心、6GB 記憶體,推薦 4 核心、8GB。在 2 核心的機器上,這些工作會互相搶資源好幾天。

重點是:這是一次性的。每支影片只會被轉碼一次,轉完就躺在 encoded-video/ 裡。之後每天新增的幾支片子,同一台機器處理起來毫無壓力。第一週的體驗不能代表這台機器的常態。

官方 FAQ 給了兩個旋鈕,都在管理介面裡。第一個是 Job Settings,把 Video Transcoding 的併發數降到 1。第二個是 Video Transcoding Settings 裡的 Threads,設成 1 或 2。Threads 的預設值是 0,意思是交給 ffmpeg 自己決定,在 2 vCPU 的機器上它會把兩顆都吃滿,網頁介面因此完全沒有餘裕可用。

把這兩個值調低不會讓總轉碼時間變短,它讓機器在轉碼期間還能回應你。這是刻意的取捨,不是最佳化。

另外兩個預設值也值得知道。Preset 預設是 ultrafast:編碼速度最快,相對地檔案最大。CRF 預設 23,目標解析度預設 720。把 preset 調慢(例如 veryfast、medium)可以換到更小的檔案,代價是轉碼時間拉長,在第一次匯入期間不建議動它。

實務上最有效的做法是分批。先在手機 App 裡只備份最近一年,等佇列清空再開下一批。如果記憶體吃緊,匯入期間可以先把機器學習關掉,之後再開回來補跑。

怎麼分辨是轉碼、是線路,還是反向代理

這三件事的症狀很像,但檢查方法完全不同。依序做這四步。

  1. 看 CPU。在 VPS 上跑 docker stats --no-stream,如果 immich_server 的 CPU 長時間貼在 100% 以上,同時管理介面的 Jobs 頁面顯示 Transcode Videos 還有一大堆待處理,那就是轉碼在吃資源。
  2. 看那支影片有沒有轉碼檔。把路徑換成你 .env 裡 UPLOAD_LOCATION 指到的位置。
# 路徑請換成你自己的 UPLOAD_LOCATION
sudo du -sh /srv/immich/encoded-video
sudo find /srv/immich/encoded-video -type f | wc -l

檔案數遠少於你的影片總數,代表大部分影片目前還是用原始檔在播。這時候卡頓的原因是位元率,不是轉碼。

  1. 量線路。在 VPS 上裝 iperf3 並開成伺服端,再從自己的電腦連過去。
sudo apt install -y iperf3
iperf3 -s

自己電腦上跑 iperf3 -c <你的 VPS IP> -R,-R 是反向測試,量的是從 VPS 到你的下載方向。這個數字如果只有十幾 Mbps,那麼再怎麼調轉碼設定都救不了原始 4K 檔案。台灣與香港連東京、新加坡機房的來回延遲通常在 50 ms 以內,連到歐美節點會跳到 200 ms 以上,TCP 在高延遲下本來就拉不滿頻寬。機房位置對影片播放的影響,往往比 CPU 規格大。

  1. 量反向代理。在 VPS 上直接打容器,跳過 nginx 或 Caddy。
curl -s -o /dev/null -w 'code=%{http_code} total=%{time_total}s\n' \
  http://127.0.0.1:2283/api/server/ping

正常會回 code=200,時間在毫秒等級。接著把同一個請求換成你對外的網址再打一次。兩者差距很大,問題就在代理層,跟 Immich 無關。

官方建議的 nginx 設定如下,缺了會出事的主要是上傳與逾時。

client_max_body_size 50000M;
client_body_buffer_size 1024k;
proxy_request_buffering off;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
send_timeout 600s;

proxy_request_buffering off 是為了上傳:開著的時候 nginx 會先把整支影片寫進暫存檔,收完才轉給後端,上傳看起來就會卡很久而且吃光磁碟。逾時設 600 秒是因為大檔案的傳輸本來就慢。官方還明講 Immich 不能掛在子路徑下(例如 /immich),一定要放在網域或子網域的根目錄,否則很多請求會壞掉。

有一個症狀特別好認:從頭播沒問題,但拖動進度條就壞掉或整個重載。那是代理層沒有把 HTTP Range 請求(部分內容請求)原樣傳給後端,播放器沒辦法只要影片中間那一段。如果不想自己維護這層設定,用 Cloudflare Tunnel 不開任何連接埠把服務接出去是另一條路,但大檔案傳輸在那條路上也有自己的行為要測。

log 要看哪裡

在放 docker-compose.yml 的目錄底下跑:

docker compose logs -f immich-server
docker compose logs --since 30m immich-server | grep -i -e transcod -e ffmpeg

預設 log 等級是 log,看不到 ffmpeg 的細節。在 .env 加一行 IMMICH_LOG_LEVEL=debug,然後 docker compose up -d 讓容器帶新設定重建,就能看到每一次轉碼的完整命令列與錯誤。可用的值是 verbose、debug、log、warn、error。查完記得改回 log,debug 會很快把磁碟寫滿。

如果 log 在轉碼途中毫無預警中斷,而 docker ps 顯示容器的重啟次數在增加,那是容器被系統的 OOM killer 砍掉了,記憶體不足。這種情況下降低併發數同時解決 CPU 與記憶體兩個問題。

小機器上的一組穩定設定

一台 2 到 4 核心的 VPS,下面這組值通常最省心。

  • 轉碼政策留在 required,不要改成 disabled。
  • Threads 設 2,Video Transcoding 的併發數設 1。
  • Preset 留 ultrafast,等佇列清空後再考慮換慢一點的。
  • 目標解析度看你主要在哪裡看:手機為主留 720,常用電腦看就設 1080。

轉碼檔可以重生,原始檔不行。備份的時候要保的是 upload/、library/ 與 profile/,thumbs/ 與 encoded-video/ 掉了重跑工作就好,這部分的完整流程在Immich 的備份與還原裡。如果你還在評估要不要留在 Immich,PhotoPrism 與 Immich 的取捨把兩邊對硬體的要求講得比較細;還沒裝起來的話,從在 VPS 上自架 Immich 取代 Google 相簿開始比較快。

FAQ

為什麼 iPhone 拍的影片在 Immich 上要等很久才播得動?

Immich 預設可接受的影片編碼只有 h264,而 iPhone 的「高效率」模式錄的是 HEVC(H.265)。預設政策 required 因此會把每一支都排進轉碼佇列,由 ffmpeg 在你的 VPS 上用 CPU 軟體編碼。在轉碼完成之前,播放器拿到的是原始檔,位元率高而且瀏覽器不一定解得開。等 Transcode Videos 工作跑完,同一支影片就會順很多。

把轉碼政策設成 Don't transcode 會變快嗎?

CPU 會立刻閒下來,磁碟也省了,但播放時 Immich 只能把原始檔整個送給瀏覽器。4K HEVC 的原始檔位元率很高,跨海線路通常拉不滿,畫面照樣會卡,而且桌面版 Chrome 與 Firefox 對 HEVC 的支援並不保證。改完政策要回 Administration → Jobs 重跑 Transcode Videos,既有的轉碼檔才會被清掉。

一般 VPS 可以開啟 Quick Sync 或 NVENC 嗎?

不行。介面上看得到 NVENC、Quick Sync、RKMPP、VAAPI 四個選項,但它們需要實際存在的硬體裝置。在 VPS 上跑 ls /dev/dri 會得到 No such file or directory,跑 nvidia-smi 會得到 command not found,代表沒有任何可用的編碼器。硬開只會讓轉碼工作失敗。要用硬體編碼就得找有 GPU 直通的方案。

怎麼知道慢的是轉碼還是我的網路?

先在 VPS 上跑 docker stats --no-stream。CPU 貼滿而且 Jobs 頁面有大量待處理的 Transcode Videos,就是轉碼。CPU 很閒但播放還是卡,就用 iperf3 -c <VPS IP> -R 量從 VPS 到你這端的實際頻寬與延遲。兩者都正常的話,用 curl http://127.0.0.1:2283/api/server/ping 在 VPS 本機打一次,再從外網打同一個服務,時間差很大就是反向代理的問題。

轉碼檔佔太多空間,可以刪掉嗎?

可以,原始檔不會受影響。官方估計縮圖加轉碼檔平均讓相片庫多佔 10% 到 20% 的空間,encoded-video/ 屬於可重新產生的資料。把轉碼政策改成 Don't transcode any videos,再對全部資產重跑一次轉碼工作,Immich 就會把不再需要的轉碼檔刪除。之後想要回來,把政策改回去再跑一次即可,代價是那段 CPU 時間要重付一次。