VPS 上以 rootless Podman 執行 Ollama
了解如何在 VPS 以專用使用者執行 Ollama,設定 lingering 與 Quadlet,確保重開機後恢復,處理 SELinux 標籤,並關閉 11434 公開連接埠。
在 VPS 上以 rootless Podman 執行 Ollama
若要在伺服器上以 rootless Podman 執行 Ollama,必須滿足 5 項條件,而桌面環境的操作教學可能會略過這些條件。由專用的非特權使用者擁有容器。為該使用者啟用 lingering,讓您登出後容器仍持續執行。由 Quadlet 檔案將容器交給 systemd 管理,使其在重新開機後恢復執行。在採用 SELinux 的發行版上,模型目錄必須具有正確的 SELinux 標籤。API 僅監聽 loopback,並透過 SSH(secure shell)通道存取。
Ollama 是大型語言模型(LLM)伺服器。它會將模型權重儲存在磁碟上、載入記憶體,並在 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 日發表了這套軟體堆疊的清楚操作指南:在 Fedora Linux 上使用 Podman 本機執行 Ollama,作者是 Yazan Monshed。這是熟悉這些工具的良好起點。不過,該指南的目標環境是筆記型電腦,其中 4 個選擇在具備公開 IP 位址的機器上會有不同的行為。
- 它使用純粹的
podman run -d啟動容器。手動啟動的容器不會在重新開機後自動恢復,因為從未設定任何機制要求它重新啟動。 - 它使用會持續變動的標籤
ollama/ollama。在筆記型電腦上,你會在行為改變當天察覺。在伺服器上,第一個跡象可能是某個腳本在一夜之間停止運作。 - 它使用
-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 行,分別來自 2 個檔案,且每行都會指定包含 65536 個 ID 的範圍:
/etc/subuid:ollama:100000:65536
/etc/subgid:ollama:100000:65536起始編號會有所不同,這是正常的。如果 grep 沒有輸出內容,表示 useradd 沒有配置範圍,該使用者執行的第一個 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 尋找使用者 bus,而 sudo -i 不會設定該變數。請在每個管理此服務的 admin 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 會保存用於命名這些檔案的小型索引。若改用 named volume,如 Fedora Magazine 文章所示,同一個目錄樹會位於 /home/ollama/.local/share/containers/storage/volumes/<volume>/_data 下。無論採用哪種方式,ollama pull 與 ollama run 都會將權重寫入同一個目錄樹;區分這兩個指令的差異,只有下載完成後是否開啟一次聊天工作階段。
在下載任何內容前先規劃磁碟空間。已發布的下載大小可作為最低需求。
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請使用已發布的版本標籤;截至 2026 年 8 月,使用 0.32.9,不要使用 latest。固定標籤可確保 04:00 重新啟動時取得與測試時相同的二進位檔,因此行為變更必定來自你的修改。Docker Hub 也會為相同版本發布 -rc 與 -rocm 標籤;除非你使用 AMD GPU,否則請選擇不含額外後綴的標籤。
同時寫出 registry 主機名稱。在 Fedora 上,systemd unit 中的簡短名稱沒有終端機可供提示,因此該 unit 會失敗,並顯示:
Error: short-name "ollama/ollama" did not resolve to an alias and no unqualified-search registries are defined先手動拉取映像檔不是必要步驟,但很實用,因為可將數 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 會在請求之間將模型保留在記憶體中,而不是在 5 分鐘後卸載模型;相關取捨請參閱 讓 Ollama 模型保留在記憶體中。如果這裡使用的 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 指定專用子目錄,且其中不得存放其他內容。Named volumes 不需要這項設定,因為 Podman 建立它們時會正確套用標籤。若需要更完整的說明,伺服器的 SELinux 基礎 介紹 context 與 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 時,會無法通過 basic auth。SSH tunnel 沒有這項問題,因此這裡預設建議使用 SSH tunnel。
下載模型並檢查完整流程
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 執行個體不會在開機時啟動。如果已啟用 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.,因為映像檔仍在下載。請手動執行 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。
更新固定映像
固定版本表示更新由你主動執行,而不是被動接受。編輯 Image= 中的 ollama.container,然後重新載入並重新啟動:
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 instance 及其 /run/user/<uid> 目錄,會在該使用者的最後一個 session 結束時一併拆除,所有 rootless 容器也會隨之停止。執行 sudo loginctl enable-linger ollama,確認 loginctl show-user ollama --property=Linger 輸出 Linger=yes。建立 Quadlet unit 前先啟用 lingering,因為該 unit 所需的 runtime directory 只有在啟用 lingering 後才會存在。
Ollama model directory 需要 SELinux labels 嗎?
在 Fedora、RHEL、Rocky 和 AlmaLinux 上,如果 bind mount 主機目錄,就需要。容器會在 container_t domain 中執行,而 home folder 中的目錄標記為 user_home_t,因此寫入會被拒絕,Ollama 也會結束。將 :Z 附加到 Volume= 行,並為它指定專用子目錄,因為重新標記會遞迴處理;若將 :Z 指向整個 home directory,會導致該使用者無法存取 SSH key。Named volumes 會由 Podman 正確標記,不需要額外設定。
Ollama model 需要多少磁碟空間?
先參考 ollama.com/library 公布的 download size,從 3.3 GB(gemma3:4b)到 19 GB(qwen3:30b)不等。另加上 Podman image 所需的空間,並預留餘裕,因為第二個 model 不會取代磁碟上的第一個 model。pull 前檢查 df -h /home,完成後檢查 du -sh ~/ollama-data/models。RAM 也應採用相同估算方式:model 載入時大約需要相當於其檔案大小的記憶體,另加 context window 所需的空間。
在 VPS 上公開 port 11434 安全嗎?
不安全。Ollama 完全沒有內建 authentication,因此任何能連到該 port 的人,都能列出你的 model、刪除 model、將新的 model pull 到你的磁碟,並使用你的 CPU 和頻寬額度執行 inference。透過網際網路使用 plain HTTP,也會以明文傳送所有 prompt 和 completion。使用 PublishPort=127.0.0.1:11434:11434 將主機端繫結至 127.0.0.1,以 ss -ltnp | grep 11434 確認,並透過 SSH tunnel 或要求密碼的 reverse proxy 存取。