VPS 上以 rootless Podman 執行 Ollama
學會在 VPS 上安全執行 Ollama:建立專用使用者、啟用 lingering,使用 Quadlet 跨重開機恢復,設定 SELinux 標籤,並讓 API 僅監聽 loopback。
在 VPS 上以 rootless Podman 執行 Ollama
要在伺服器上以 rootless Podman 執行 Ollama,必須滿足桌面環境教學可以略過的 5 項條件。由專用的非特權使用者擁有容器。為該使用者啟用 lingering,讓容器在登出後仍持續執行。使用 Quadlet 檔案將容器交由 systemd 管理,使其在重新開機後自動恢復。模型目錄在強制執行 SELinux 的發行版上必須具有適當的 SELinux 標籤。API 僅監聽 loopback,並透過 SSH(secure shell)tunnel 存取。
Ollama 是大型語言模型(LLM)伺服器。它會將模型權重儲存在磁碟上、載入記憶體,並在 port 11434 上回應 HTTP 請求。它沒有登入機制、API key 或使用者帳號,因此網路是唯一可用的存取控制。Podman 不需要 daemon,也不需要 root 即可執行容器,因此任何逃逸容器的程序,起初都只是一般非特權使用者。若要先了解執行環境的差異,請閱讀 Podman 與 Docker 在 VPS 上的差異。若想完全略過容器,直接在 VPS 上安裝 Ollama 會是較短的路徑。
SSD Nodes 的映像檔包含 Fedora,而 Fedora 預設同時提供 Podman 與 SELinux(security-enhanced Linux)。以下每個命令都能在使用 Podman 5 或更新版本的任何發行版上執行。
伺服器上需要調整筆記型電腦版本的原因
Fedora Magazine 在 2026 年 8 月 5 日發布了這套技術堆疊的清楚操作指南:使用 Podman 在 Fedora Linux 上本機執行 Ollama,作者為 Yazan Monshed。這篇文章很適合用來熟悉這些工具。它的目標環境是筆記型電腦,其中 4 個選擇在具備公開 IP 位址的主機上會有不同的結果。
- 它使用一般的
podman run -d啟動容器。手動啟動的容器不會在重新開機後自動恢復,因為從未設定任何機制要求它啟動。 - 它使用會持續變動的標籤
ollama/ollama。在筆記型電腦上,你會在行為改變的當天察覺。在伺服器上,第一個跡象可能是某個 script 一夜之間停止運作。 - 它使用
-p 11434:11434發布連接埠,會繫結所有網路介面。在家用路由器後方時,這通常無法從網際網路連線。在 VPS 上,這會變成沒有密碼保護的公開推論 API。 - 它以你自己的登入使用者身分執行。在伺服器上,擁有容器的帳號不應擁有其他資源;如此一來,即使發生容器逃逸,也只會進入空的家目錄。
對於原本的目標主機而言,這些做法都沒有錯。只是當主機可從任何地方連線,且沒有人坐在主機前方時,就應重新檢視每一項決策。
建立非特權使用者並檢查 subuid
Rootless Podman 會將容器內部的使用者 ID(UID)映射到主機上一段未使用的 ID 範圍。這段範圍定義在 /etc/subuid 和 /etc/subgid 中。若缺少這項設定,rootless 容器完全無法啟動。
sudo dnf install -y podman # or: sudo apt install -y podman
sudo useradd --create-home --shell /bin/bash --comment "Ollama container owner" ollama
sudo passwd --lock ollama
grep ollama /etc/subuid /etc/subgidgrep 應輸出 2 行,分別來自其中一個檔案,且每行都會指定一段包含 65536 個 ID 的範圍:
/etc/subuid:ollama:100000:65536
/etc/subgid:ollama:100000:65536起始數字會不同,這是正常的。如果 grep 沒有輸出內容,表示 useradd 沒有配置 ID 範圍,因此該使用者執行第一個 podman 命令時會出現以下錯誤:
Error: cannot find UID/GID for user ollama: no subuid ranges found for user "ollama" in /etc/subuid指派一段其他使用者未持有的範圍,然後告知 Podman 其舊的映射已失效:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 ollama
sudo -iu ollama podman system migrate鎖定密碼表示任何人都不能直接以 ollama 登入。管理員使用者可透過 sudo -iu ollama 切換至該帳戶。
啟用 lingering,讓服務在登出後繼續執行
使用者的 systemd instance 通常會在登入時啟動,並在登出時停止;/run/user/<uid> 也會隨之移除。該使用者擁有的每個 rootless container 都會在同一時間停止。啟用 lingering 後,即使沒有附加工作階段,使用者 instance 仍會繼續執行。
sudo loginctl enable-linger ollama
loginctl show-user ollama --property=Linger此命令應輸出 Linger=yes。請在建立 unit 前啟用 lingering,因為 unit 所需的目錄 /run/user/<uid> 只有在啟用 lingering 後才會存在。
還有一個容易被忽略的步驟。sudo -iu ollama 會提供 shell,但不會提供 session bus,因此 systemctl --user 會立即失敗:
Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not definedsystemd 會在 $XDG_RUNTIME_DIR/bus 尋找 user bus,而 sudo -i 不會設定該變數。請在每個管理此服務的管理 shell 中手動設定:
sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
systemctl --user status模型檔案的存放位置,以及應預留多少磁碟空間
Ollama 會將權重寫入容器內的 /root/.ollama/models。將使用者家目錄中的某個目錄繫結掛載至該路徑,檔案就會存放在可測量的位置:/home/ollama/ollama-data/models。Blob 會以內容定址檔案的形式存放於 models/blobs,而 models/manifests 則存放用來命名這些檔案的小型索引。若改用具名 volume,如 Fedora Magazine 文章所示,相同的目錄樹會位於 /home/ollama/.local/share/containers/storage/volumes/<volume>/_data 底下。
在下載任何內容前,先規劃磁碟空間。公開的下載大小可作為最低需求。
The data behind this chart
[
{
"label": "gemma3:4b",
"download_gb": 3.3
},
{
"label": "mistral:7b",
"download_gb": 4.4
},
{
"label": "qwen3:8b",
"download_gb": 5.2
},
{
"label": "gemma3:12b",
"download_gb": 8.1
},
{
"label": "qwen3:14b",
"download_gb": 9.3
},
{
"label": "gemma3:27b",
"download_gb": 17
},
{
"label": "qwen3:30b",
"download_gb": 19
}
]7 個列出的數值,都是 ollama.com/library 公布的資料,不是實際在磁碟上測得的大小。此處最小的標籤 gemma3:4b 需要下載 3.3 GB。最大的標籤 qwen3:30b 需要下載 19 GB。容器映像檔還會使用 Podman 自身的儲存空間,因此請搭配 podman system df 與 df -h /home 一起確認這兩項數值。模型載入時通常還需要約等同於檔案大小的 RAM,並且要為 context window 預留空間,因此 19 GB 的模型無法在 16 GB 的 VPS 上執行。
固定映像標籤,並使用完整的 registry 名稱
sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
mkdir -p ~/ollama-data ~/.config/containers/systemd
podman pull docker.io/ollama/ollama:0.32.9使用已發布的版本標籤;截至 August 2026,應使用 0.32.9,而不是 latest。固定標籤可確保 04:00 重新啟動時取得與測試時相同的 binary,因此行為出現任何變更,都代表是你所做的變更。Docker Hub 也會為相同版本發布 -rc 和 -rocm 標籤;除非你使用 AMD GPU,否則請選擇不含額外後綴的標籤。
同時寫出 registry host。在 Fedora 上,systemd unit 中的簡短名稱沒有終端機可供提示輸入,因此 unit 會因以下錯誤而失敗:
Error: short-name "ollama/ollama" did not resolve to an alias and no unqualified-search registries are defined先手動 pull 並非必要,但很有幫助,因為這會將數 GB 的下載作業移出 unit 的啟動逾時範圍。
重新開機後仍會啟動的 Quadlet unit
Quadlet 是 Podman 的 systemd generator。您只需撰寫 .container 檔案,systemd 就會在開機時將其轉換為服務,不再需要 podman generate systemd。將以下內容儲存為 /home/ollama/.config/containers/systemd/ollama.container,並將擁有者設為 ollama 使用者。
[Unit]
Description=Ollama API (rootless)
After=network-online.target
Wants=network-online.target
[Container]
Image=docker.io/ollama/ollama:0.32.9
ContainerName=ollama
PublishPort=127.0.0.1:11434:11434
Volume=/home/ollama/ollama-data:/root/.ollama:Z
Environment=OLLAMA_KEEP_ALIVE=30m
Environment=OLLAMA_MAX_LOADED_MODELS=1
[Service]
Restart=always
TimeoutStartSec=900
[Install]
WantedBy=default.target檔名會決定服務名稱,因此 ollama.container 會變成 ollama.service。
systemctl --user daemon-reload
systemctl --user start ollama.service
systemctl --user status ollama.servicestatus 應顯示 active (running)。不要執行 systemctl --user enable ollama.service。該 unit 並不是磁碟上的檔案,因此 systemd 會拒絕:
Failed to enable unit: Unit file /run/user/1001/systemd/generator/ollama.service is transient or generated.[Install] 區段已經負責這項工作。Quadlet 會在 daemon-reload 期間自行建立開機啟動連結,因此該指令不能省略。TimeoutStartSec=900 用於處理第一次啟動時仍需拉取 image 的情況,因為預設的 90 秒不足以完成 2 GB 的下載,systemd 會將該啟動程序判定為失敗並終止。OLLAMA_KEEP_ALIVE=30m 會在請求之間將 model 保留在記憶體中,而不是在 5 分鐘後將其卸載;相關取捨請參閱讓 Ollama model 保留在記憶體中。如果這裡使用的 systemd 詞彙對您而言不熟悉,請參閱VPS 上的 systemd 服務與 timer 如何運作,其中會介紹這些 unit。
SELinux 下模型目錄出現 permission denied 的原因
在 Fedora、RHEL、Rocky 和 AlmaLinux 上,SELinux 預設會以 enforcing 模式啟用。容器程序會在 container_t 網域中執行,而使用者家目錄中的目錄則標記為 user_home_t。政策不允許兩者互相存取,因此 Ollama 無法建立模型目錄樹,容器也會結束。getenforce 在這些系統上會輸出 Enforcing,而拒絕事件會記錄如下:
sudo ausearch -m avc -ts recent您會看到列出網域和目標標籤的行:
avc: denied { write } for pid=1842 comm="ollama" name="models" dev="vda1" ino=131077 scontext=system_u:system_r:container_t:s0:c214,c827 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir permlisted=0Volume= 行末的 :Z 就是修正方式。它會將主機目錄重新標記為 container_file_t,並套用只有此容器使用的私有 MCS(多類別安全性)類別。小寫的 :z 會改用共用標籤;當兩個容器需要讀取同一個目錄時,應使用這種方式。
請注意 :Z,因為它會安靜地進行破壞性操作。重新標記會遞迴處理。若將它指向 /home/ollama,該家目錄中的每個檔案都會被重新標記,導致該使用者無法存取 SSH 金鑰。務必讓 :Z 指向專用子目錄,且該目錄中不得存放其他內容。具名 volume 不需要這項設定,因為 Podman 建立這類 volume 時會正確套用標籤。如果需要了解完整背景,請參閱 伺服器的 SELinux 基礎,其中說明內容與 boolean。在 Ubuntu 和 Debian 上改用 AppArmor,:Z 在這些系統上不會執行任何操作,保留在 unit 中也沒有影響。
關閉連接埠 11434,透過 SSH 存取 API
PublishPort=127.0.0.1:11434:11434會將主機端繫結至 loopback。請確認:
ss -ltnp | grep 11434
curl http://127.0.0.1:11434ss的輸出必須顯示127.0.0.1:11434。0.0.0.0:11434或*:11434表示連接埠已對網際網路開放,而curl必須回應Ollama is running。
請準確區分繫結的是哪一端。PublishPort中的位址是主機位址。在容器內,Ollama 必須繼續監聽所有介面,這是映像檔的預設設定。設定Environment=OLLAMA_HOST=127.0.0.1會將 Ollama 繫結至容器自己的 loopback,但 Podman 會將發布的流量轉送至容器的網路位址,因此即使從主機發出的請求也會全部遭到拒絕。
開放 11434 會造成兩項風險。Ollama 沒有驗證機制,因此任何能連線至該連接埠的人,都能透過/api/tags列出你的模型,透過/api/generate使用你的 CPU 與頻寬配額執行推論,將新模型下載至你的磁碟,並刪除現有模型。其次,對遠端連接埠使用純 HTTP 時,提示與完成內容會以明文傳送,路徑上的每台機器都能讀取。只要連接埠不離開本機,這兩項問題就能同時消除。
在工作站上,透過 SSH 轉送連接埠:
ssh -N -L 11434:127.0.0.1:11434 you@vps.example.com現在,筆記型電腦上的http://127.0.0.1:11434就是伺服器的 Ollama,且位於 SSH 工作階段的加密通道內。如果筆記型電腦已執行 Ollama,本機繫結會因bind [127.0.0.1]:11434: Address already in use而失敗;請使用-L 11435:127.0.0.1:11434,並將用戶端指向 11435。
如果瀏覽器用戶端需要存取,請改在前方設定帶有密碼的反向代理。Caddy site block 只需 4 行,而caddy hash-password會輸出它所需的 bcrypt 雜湊:
ollama.example.com {
basic_auth {
you $2a$14$replace_with_the_generated_hash
}
reverse_proxy 127.0.0.1:11434
}Caddy 會自行透過 TLS(transport layer security)取得憑證,因此流量會加密。請先測試用戶端:許多與 Ollama 通訊的工具沒有設定Authorization標頭的欄位,因此使用單獨的401 Unauthorized基本驗證時會失敗。SSH 通道沒有這項問題,因此本節預設建議使用 SSH 通道。
拉取模型並檢查完整路徑
podman exec -it ollama ollama pull gemma3:4b
curl -s http://127.0.0.1:11434/api/tags
curl -s http://127.0.0.1:11434/api/generate -d '{"model":"gemma3:4b","prompt":"Reply with the single word: ready","stream":false}'
du -sh ~/ollama-data/models/api/tags 會傳回列出 gemma3:4b 的 JSON。等待權重從磁碟載入後,/api/generate 會傳回包含 response 欄位的 JSON 物件。du 應回報接近已公布下載大小的數值。接著驗證本指南的核心部分:
sudo reboot
# reconnect, then:
sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
systemctl --user is-active ollama.serviceactive 表示持續存在,代表 [Install] 區段與 daemon-reload 都已正常運作。inactive 表示三者其中之一缺失。
失敗情況與會看到的訊息
重新開機後容器消失。 先檢查 loginctl show-user ollama --property=Linger,因為未設定 Linger=yes 時,使用者的 systemd instance 不會在開機時啟動。若已啟用 lingering,可能是 .container 檔案缺少 [Install] 區段,或是編輯檔案後未執行 systemctl --user daemon-reload。
Error: statfs /home/ollama/ollama-data: no such file or directory。 bind mount 的來源必須在容器啟動前存在。Podman 不會替您建立主機目錄。請以 ollama 使用者身分執行 mkdir -p ~/ollama-data。
啟動在 90 秒時失敗。 journalctl --user -u ollama.service 會顯示 Start operation timed out. Terminating.,因為當時仍在執行 image pull。請手動 pull,或保留 TimeoutStartSec=900。
容器啟動後立即結束。 podman logs ollama 與 sudo ausearch -m avc -ts recent 的內容可共同判斷問題是否出在 SELinux label。若 AVC 訊息同時指出 container_t 與 user_home_t,表示缺少 :Z。
主機拒絕請求。 對服務 active 執行 curl: (7) Failed to connect to 127.0.0.1 port 11434: Connection refused 時,通常表示容器內將 OLLAMA_HOST 設為 loopback 位址。請移除該行。
生成速度非常慢,或容器遭到終止。 沒有 GPU 時,推論會在 CPU 上執行,大型模型本來就較慢。若容器在處理請求期間結束,且日誌包含 signal: killed,表示這是核心的 out-of-memory killer 所致;請從上方圖表選擇較小的 tag。
更新固定映像
固定版本表示更新由你主動執行,而不是任由系統自動發生。在 ollama.container 中編輯 Image=,然後重新載入並重新啟動:
systemctl --user daemon-reload
systemctl --user restart ollama.service
podman exec ollama ollama --version模型位於 bind mount 中,因此映像變更不會影響模型。[Container] 區段中的 AutoUpdate=registry 是供使用浮動標籤的使用者使用;搭配固定版本標籤時沒有實際作用,因為該標籤所對應的內容不會變更。請備份 /home/ollama/ollama-data/models/manifests 與 .container 檔案,並略過 blobs:這些檔案很大,而且 ollama pull 會在新主機上重新下載。
FAQ
為什麼 rootless Podman 容器會在我登出時停止?
使用者最後一個工作階段結束時,該使用者的 systemd 執行個體與 /run/user/<uid> 目錄會一併被拆除,所有 rootless 容器也會隨之停止。執行 sudo loginctl enable-linger ollama,確認 loginctl show-user ollama --property=Linger 輸出 Linger=yes。建立 Quadlet unit 前先啟用 lingering,因為該 unit 所需的 runtime 目錄只有在啟用 lingering 後才會存在。
Ollama 模型目錄需要 SELinux 標籤嗎?
在 Fedora、RHEL、Rocky 和 AlmaLinux 上,如果使用 bind mount 掛載主機目錄,就需要。容器會在 container_t 網域中執行,而 home 資料夾中的目錄標籤是 user_home_t,因此寫入會被拒絕,Ollama 也會結束。將 :Z 附加至 Volume= 行,並為它指定專用子目錄,因為重新標籤會遞迴處理;若將 :Z 指向整個 home 目錄,會導致該使用者無法存取 SSH key。Named volume 會由 Podman 套用正確標籤,不需要額外設定。
Ollama 模型需要多少磁碟空間?
先以 ollama.com/library 公布的下載大小為基準,從 3.3 GB 的 gemma3:4b 到 19 GB 的 qwen3:30b 不等。再加上 Podman image 所需的空間,並預留餘裕,因為第二個模型不會取代磁碟上的第一個模型。拉取前檢查 df -h /home,完成後檢查 du -sh ~/ollama-data/models。RAM 也依相同方式規劃:模型載入時大約需要相當於檔案大小的記憶體,另外還要加上 context window 所需的空間。
在 VPS 上公開 11434 埠安全嗎?
不安全。Ollama 完全沒有內建驗證機制,因此任何能連線至該埠的使用者都能列出你的模型、刪除模型、將新模型拉取到磁碟,並使用你的 CPU 與頻寬配額執行推論。透過網際網路使用純 HTTP,也會以明文傳送所有 prompt 與 completion。使用 PublishPort=127.0.0.1:11434:11434 將主機端繫結至 127.0.0.1,再以 ss -ltnp | grep 11434 確認,並透過 SSH tunnel 或要求密碼的反向代理存取。