SSD Nodes Learn 🎉 VPS $5.50/月〜
ガイド Matt Connor著者 Matt Connor

VPSでrootless Podman版Ollamaを運用する方法

VPSでOllamaをrootless Podmanコンテナとして安全に運用します。専用ユーザー、lingering、Quadlet、SELinuxラベル、再起動後の自動起動、port 11434を閉じたSSHトンネル接続を解説します。

rootless Podman で VPS 上で Ollama を実行する

サーバー上の rootless Podman で Ollama を実行するには、デスクトップ向けの手順では省略できる 5 つの条件を満たす必要があります。専用の非特権ユーザーがコンテナを所有していることが必要です。そのユーザーで lingering を有効にし、ログアウト後もコンテナが実行され続けるようにします。Quadlet ファイルでコンテナを systemd に引き渡し、再起動後も起動するようにします。SELinux を適用するディストリビューションでは、モデルディレクトリに SELinux ラベルを付けます。API は loopback でのみ待ち受け、SSH (secure shell) トンネル経由でアクセスします。

Ollama は大規模言語モデル (LLM) 用のサーバーです。モデルの重みをディスクに保存し、メモリに読み込み、port 11434 で HTTP リクエストに応答します。ログイン機能、API key、ユーザーアカウントがないため、利用できるアクセス制御はネットワークだけです。Podman は daemon なし、root なしでコンテナを実行するため、コンテナから脱出したプロセスも、最初は通常の非特権ユーザーとして動作します。ランタイムの比較を先に確認する場合は、VPS 上での Podman と Docker の違いを参照してください。コンテナを完全に省略する場合は、VPS に Ollama を直接インストールする方法のほうが短い手順です。

SSD Nodes はイメージとして Fedora を提供しており、Fedora では Podman と SELinux (security-enhanced Linux) の両方がデフォルトで提供されます。以下のすべてのコマンドは、Podman 5 以降を搭載する任意のディストリビューションで実行できます。

サーバーではノート PC 向けの手順を変更する必要がある理由

Fedora Magazine は 2026 年 8 月 5 日に、この構成を明確に説明する記事 Fedora Linux で Podman を使用して Ollama をローカル実行する を Yazan Monshed 名義で公開しました。ツールを試す最初の 1 時間に適した内容です。ただし、対象はノート PC です。そこで選ばれている 4 つの方法は、パブリック IP アドレスを持つマシンでは動作が異なります。

  • コンテナを単純な podman run -d で起動します。手動で起動したコンテナは、再起動後に戻ってきません。起動するように設定されていないためです。
  • 変更され続けるタグ ollama/ollama を使用します。ノート PC なら、動作が変わった日に気付けます。サーバーでは、最初の兆候が、夜間に動作しなくなったスクリプトとして現れます。
  • -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/subgid

grep の出力には、各ファイルから 1 行ずつ、65536 個の ID の範囲を示す 2 行が表示されます。

/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 インスタンスは通常、ログイン時に起動し、ログアウト時に停止します。/run/user/<uid> も同時に削除されます。そのため、そのユーザーが所有する rootless コンテナはすべて同じタイミングで停止します。lingering を有効にすると、セッションが接続されていなくてもユーザーインスタンスが稼働し続けます。

sudo loginctl enable-linger ollama
loginctl show-user ollama --property=Linger

Linger=yes と表示されます。unit を作成する前に有効にしてください。unit が必要とする /run/user/<uid> ディレクトリは、lingering が有効になって初めて存在するためです。

もう 1 つ、見落としやすい手順があります。sudo -iu ollama はシェルを提供しますが、セッションバスは提供しません。そのため、systemctl --user は直ちに失敗します。

Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined

systemd は $XDG_RUNTIME_DIR/bus でユーザーバスを探しますが、sudo -i はその変数を設定しません。このサービスを管理するすべての管理用シェルで、手動で設定してください。

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 に保存されます。Fedora Magazine の記事のように名前付きボリュームを使用する場合、同じディレクトリツリーは /home/ollama/.local/share/containers/storage/volumes/<volume>/_data 配下に配置されます。

何かを pull する前に、ディスク容量を確保してください。公開されているダウンロードサイズを最低限必要な容量の目安にします。

ChartPublished download size per Ollama model tag, ollama.com/library, checked 13 August 2026
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 dfdf -h /home で両方の容量を確認してください。モデルのロード中は、通常、ファイルサイズと同程度の RAM に加えてコンテキストウィンドウ用の容量も必要です。そのため、16 GB の VPS では 19 GB のモデルは実行できません。

イメージタグを固定し、完全なレジストリ名を使用する

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 を使用していない場合は、プレーンなタグを選択してください。

レジストリホストも記述します。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.containerollama.service になります。

systemctl --user daemon-reload
systemctl --user start ollama.service
systemctl --user status ollama.service

status では 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 は、最初の起動時にイメージの pull が必要になる場合に備えた設定です。2 GB のダウンロードにはデフォルトの 90 秒では足りず、systemd が起動を失敗として終了させるためです。OLLAMA_KEEP_ALIVE=30m は、5 分後にモデルをアンロードせず、リクエスト間でメモリに保持します。トレードオフについては、Ollama モデルをメモリに保持するで説明しています。ここで使用する systemd の用語に不明なものがある場合は、VPS で systemd のサービスとタイマーが動作する仕組みを参照してください。

SELinux でモデルディレクトリが permission denied になる理由

Fedora、RHEL、Rocky、AlmaLinux では、SELinux がデフォルトで enforcing になっています。コンテナプロセスは container_t ドメインで実行され、ユーザーのホームディレクトリ内のディレクトリには user_home_t のラベルが付いています。ポリシーにより両者のアクセスが許可されないため、Ollama はモデル用のディレクトリツリーを作成できず、コンテナが終了します。これらのシステムでは getenforceEnforcing を出力し、拒否の記録が残ります。

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=0

Volume= 行の末尾にある :Z が対処方法です。ホストのディレクトリを container_file_t に再ラベル付けし、このコンテナだけが持つプライベートな MCS(multi-category security)カテゴリを付与します。小文字の :z は共有ラベルを使用します。2 つのコンテナで同じディレクトリを読み取る場合はこちらを使用します。

:Z には注意が必要です。この操作は破壊的で、確認なしに実行されます。ラベルの再付与は再帰的に行われます。/home/ollama を指定すると、そのホームディレクトリ内のすべてのファイルが再ラベル付けされ、ユーザーが SSH 鍵にアクセスできなくなります。:Z には、他のファイルを置かない専用のサブディレクトリを必ず指定してください。Named volume にはこの操作は不要です。Podman が作成時に正しいラベルを付けるためです。詳細については、サーバー向け 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:11434

ss の出力に 127.0.0.1:11434 と表示される必要があります。0.0.0.0:11434 または *:11434 は、ポートがインターネットに公開されていることを示します。また、curlOllama is running に応答する必要があります。

どちら側をバインドしているかを正確に確認してください。PublishPort のアドレスはホストのアドレスです。コンテナ内では、Ollama がすべてのインターフェースで待ち受ける必要があります。これはイメージのデフォルト設定です。Environment=OLLAMA_HOST=127.0.0.1 を設定すると、Ollama はコンテナ自身の loopback にバインドします。その場合、Podman は公開ポートからのトラフィックをコンテナのネットワークアドレスへ転送するため、ホストからのリクエストを含め、すべてのリクエストが拒否されます。

11434 を公開すると、2 つの問題が発生します。Ollama には認証がないため、ポートに到達できる誰もが /api/tags を通じてモデル一覧を取得できます。また、/api/generate を通じて CPU と帯域幅を使って推論を実行したり、ディスクに新しいモデルを取得したり、既存のモデルを削除したりできます。2 つ目は、リモートポートへの平文 HTTP では、プロンプトと生成結果が暗号化されずに送信されることです。そのため、経路上のすべてのマシンが内容を読み取れます。ポートがホストの外部に公開されなければ、両方の問題を解消できます。

ワークステーションから、SSH 経由でポートを転送します。

ssh -N -L 11434:127.0.0.1:11434 you@vps.example.com

これで、ノート PC 上の http://127.0.0.1:11434 は、SSH セッションの暗号化された接続内にあるサーバーの Ollama になります。ノート PC ですでに Ollama が動作している場合、ローカルバインドは bind [127.0.0.1]:11434: Address already in use で失敗します。その場合は -L 11435:127.0.0.1:11434 を使用し、クライアントの接続先を 11435 に設定します。

ブラウザクライアントで利用する場合は、代わりにパスワード付きのリバースプロキシを前段に配置します。Caddy のサイトブロックは 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 認証には対応できません。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/tagsgemma3: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.service

active は lingering を示します。これは、[Install] セクションと daemon-reload がすべて正常に機能したことを意味します。inactive は、3 つのうちいずれかが欠けていることを意味します。

エラーが発生する状況と表示される文字列

再起動後にコンテナが消える。 まず 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 秒後に起動に失敗する。 イメージの pull がまだ実行中だったため、journalctl --user -u ollama.service には Start operation timed out. Terminating. と表示されます。手動で pull するか、TimeoutStartSec=900 を保持してください。

コンテナが起動後すぐに終了する。 podman logs ollamasudo ausearch -m avc -ts recent を併せて確認すると、SELinux ラベルが原因かどうかを判断できます。container_tuser_home_t を示す AVC がある場合、:Z がありません。

ホストからのリクエストが拒否される。 サービス active に対する curl: (7) Failed to connect to 127.0.0.1 port 11434: Connection refused が通常、OLLAMA_HOST にコンテナ内の loopback アドレスが設定されていることを示します。その行を削除してください。

生成に非常に時間がかかる、またはコンテナが強制終了される。 GPU がない場合、推論は CPU で実行されるため、大きなモデルでは本質的に時間がかかります。ログに signal: killed があり、リクエストの途中でコンテナが終了する場合は、kernel の out-of-memory killer が原因です。上の表から、より小さい tag を選択してください。

固定したイメージの更新

Pinning を使うと、更新は意図せず発生するものではなく、手動で実施する作業になります。ollama.containerImage= を編集し、その後に reload と restart を実行します。

systemctl --user daemon-reload
systemctl --user restart ollama.service
podman exec ollama ollama --version

モデルは bind mount に保存されるため、イメージを変更してもそのまま保持されます。[Container]AutoUpdate=registry は moving tag を使用する場合の設定であり、固定バージョンの tag と併用しても、その tag の内容は変わらないため意味がありません。/home/ollama/ollama-data/models/manifests.container ファイルをバックアップし、blob は対象外にします。blob はサイズが大きく、新しいホストでは ollama pull が再取得するためです。

FAQ

rootless Podman コンテナは、ログアウトすると停止するのはなぜですか?

ユーザーの systemd インスタンスと /run/user/<uid> ディレクトリは、そのユーザーの最後のセッションが終了すると破棄されます。そのため、すべての rootless コンテナも停止します。sudo loginctl enable-linger ollama を実行し、loginctl show-user ollama --property=LingerLinger=yes を出力することを確認してください。Quadlet unit を作成する前に lingering を有効にしてください。unit が必要とするランタイムディレクトリは、lingering が有効になって初めて存在するためです。

Ollama のモデルディレクトリに SELinux ラベルは必要ですか?

Fedora、RHEL、Rocky、AlmaLinux でホストディレクトリを bind mount する場合は必要です。コンテナは container_t ドメインで実行されます。一方、home ディレクトリ内のディレクトリには user_home_t のラベルが付いているため、書き込みが拒否され、Ollama が終了します。Volume= 行に :Z を追加し、専用のサブディレクトリを指定してください。再ラベル付けはサブディレクトリ以下を再帰的に処理するため、:Z に home ディレクトリ全体を指定すると、そのユーザーの SSH key へのアクセスが壊れます。Named volume には Podman が正しいラベルを付けるため、追加設定は不要です。

Ollama のモデルには、どの程度のディスク容量が必要ですか?

ollama.com/library に公開されているダウンロードサイズを基準にしてください。サイズは 3.3 GB の gemma3:4b から、19 GB の qwen3:30b まであります。これに Podman image の容量を加え、さらに余裕を確保してください。2 つ目のモデルを取得しても、ディスク上の 1 つ目のモデルは置き換えられないためです。取得前に df -h /home を確認し、取得後に du -sh ~/ollama-data/models を確認してください。RAM も同様に計画します。モデルのロード中は、概ねファイルサイズ分のメモリに加えて context window 分のメモリが必要です。

VPS で port 11434 を公開しても安全ですか?

いいえ。Ollama には認証機能が一切ないため、その port に到達できるユーザーは、モデルの一覧表示、削除、ディスクへの新しいモデルの取得、CPU とネットワーク帯域の使用による推論の実行が可能です。インターネット上で平文の HTTP を使用すると、すべての prompt と completion も平文で送信されます。ホスト側を PublishPort=127.0.0.1:11434:11434127.0.0.1 に bind し、ss -ltnp | grep 11434 で確認してください。そのうえで、SSH tunnel または password を要求する reverse proxy 経由でアクセスします。

#ollama#podman#rootless#quadlet#selinux#systemd