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

Ollama APIにパスワードはない?対策3つ

Ollamaサーバーには認証がなく、11434番ポートに接続できる相手はモデルの実行、追加、削除まで可能です。安全にする3つの対策を順番に解説します。

Ollama API にはパスワードがありません

Ollama API には認証がありません。実行しているサーバー内には、ユーザー、パスワード、鍵の確認、許可リストのいずれもありません。TCP 接続でポート 11434 に接続できるものは、モデルの一覧表示、実行、新しいモデルのダウンロード、既存モデルの削除を実行できます。

公式ドキュメントにも明記されています。「http://localhost:11434 を介して Ollama API にローカルでアクセスする場合、認証は必要ありません」。セキュリティモデル全体を担っているのが、この「ローカル」という条件です。Ollama はデフォルトで 127.0.0.1 にバインドするため、ラップトップではループバックインターフェースがアクセス制御になります。このリスナーをパブリックアドレスに移すと、それを置き換えるものがないため、アクセス制御はなくなります。

VPS(仮想プライベートサーバー)でこの点が重要になるのは、そのためです。デフォルト設定は安全です。多くの人が最初に行う変更は、2 台目のマシンからモデルを使用できるようリスナーを開くことです。しかし、この変更によってすべての保護が一度に失われます。

開放された 11434 番ポートから分かること

すべてのエンドポイントにアクセスできます。読み取り専用モードも、管理用の別ポートもありません。以下は、localhost ではなくサーバーのアドレスを指定した実際のリクエストです。

# List every model on the box
curl http://SERVER_IP:11434/api/tags

# See what is loaded into memory right now
curl http://SERVER_IP:11434/api/ps

# Run a prompt on your hardware
curl http://SERVER_IP:11434/api/generate -d '{"model":"llama3.2","prompt":"Why is the sky blue?"}'

# Write several gigabytes to your disk
curl http://SERVER_IP:11434/api/pull -d '{"model":"llama3.2"}'

# Remove a model
curl -X DELETE http://SERVER_IP:11434/api/delete -d '{"model":"llama3.2"}'

運用上、4 つの問題が発生します。

  • 他人のために CPU または GPU で推論を実行することになります。CPU の公正利用枠があるプランでは、継続的な負荷によって、見知らぬ相手に利用枠を消費されます。また、自分だけが呼び出す構成でなくなると、VPS で AI ワークロードのコストを抑えることが難しくなります。
  • /api/pull によってディスクへ書き込まれます。モデルは 1 つあたり 2 から 40 ギガバイトあります。pull のループによってボリュームが満杯になり、Ollama だけでなく、サーバー上の他のすべてのサービスも停止します。
  • リクエストはプロセス内に到達し、ログに記録されます。デフォルトのログレベルでは、Ollama はメタデータのみを記録します。そのため、プロンプト本文ではなく、エンドポイント、ステータス、レイテンシ、クライアントのアドレスが記録されます。それでも、誰がサーバーを何のために使用したかの記録が journal に残ります。これは、意図して収集した情報ではありません。
  • /api/delete によってモデルが削除されます。復元するには、自分の帯域幅を使って再度ダウンロードする必要があります。

このいずれにも、エクスプロイトは必要ありません。文書化された API が、設計どおりに動作しているだけです。

Ed25519 鍵はアクセス制御ではありません

「Ollama API key」を検索すると、2 つの異なるものが見つかります。どちらもサーバーのパスワードではありません。この 2 つを区別すれば、混乱の大半を解消できます。

1 つ目は、識別用の鍵ペアです。 Ollama は初回起動時に Ed25519 鍵ペアを生成します。Linux では、インストールスクリプトが ollama という system user を作成し、その home directory を /usr/share/ollama に設定します。そのため、鍵ペアは次の場所に保存されます。

/usr/share/ollama/.ollama/id_ed25519
/usr/share/ollama/.ollama/id_ed25519.pub

この鍵は外向きに使用されます。ollama signin は公開鍵を ollama.com アカウントに登録します。この鍵により、registry へのモデルの push や、private モデルの pull が認証されます。これは ollama.com に対してマシンを証明するものです。マシンに接続するクライアントには、何も要求しません。これを削除、ローテーション、または作成しなくても、API を呼び出せるユーザーには何も影響しません。

2 つ目は OLLAMA_API_KEY です。 この変数には https://ollama.com/settings/keys で作成した鍵が格納されます。クライアントは、https://ollama.com/api でホストされた API を呼び出す際に、Authorization: Bearer $OLLAMA_API_KEY としてこの鍵を送信します。これは相手のサービス用の認証情報であり、クライアントであるあなたが使用します。あなたの ollama serve がこの値を読み取ることはありません。VPS で OLLAMA_API_KEY を設定しても、VPS にパスワードが設定されるわけではありません。

したがって、有効化すべき設定はありません。以下の 3 つの防御策は、すべて同じ仕組みで機能します。ポートに到達できない状態を保ち、その前段に認証を実行するものを配置します。

現在サーバーが待ち受けているポートを確認します

sudo ss -tlnp | grep 11434

安全な結果では、loopback アドレスが表示されます。

LISTEN 0  4096  127.0.0.1:11434  0.0.0.0:*  users:(("ollama",pid=812,fd=3))

公開されている結果では、すべてのインターフェースが表示されます。

LISTEN 0  4096  0.0.0.0:11434  0.0.0.0:*  users:(("ollama",pid=812,fd=3))

0.0.0.0 は、このサーバー上のすべての IPv4 アドレスを意味します。公開アドレスも含まれます。*:11434[::]:11434 は、IPv6 を含めた場合に同じ意味になります。

次に、外部から確認します。サーバーではなく、ラップトップで実行してください。

curl -m 5 http://YOUR_SERVER_IP:11434/api/version

curl: (28) Connection timed out after 5001 milliseconds であれば問題ありません。curl: (7) Failed to connect ... Connection refused も同様です。version フィールドを含む JSON オブジェクトが返る場合、API 全体に誰でもアクセスできます。サーバー上で curl を実行しても確認にはなりません。loopback は常に応答するためです。

公開状態になる経路は、通常 2 つあります。1 つ目は、別のマシンからモデルへ接続する必要があり、意図的に設定を変更する場合です。

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"

この 1 行だけで、すべてのインターフェースへの公開が発生します。2 つ目は Docker を使う場合です。この場合、設定ファイルを編集する必要はありません。Docker については、以下のセクションで説明します。

防御策 1: localhost でのみ待ち受け、トンネル経由で接続する

まずこの方法を選択してください。追加のソフトウェアは不要で、漏えいする可能性のある認証情報も作成しません。ポートはパブリックインターフェース上に存在しないため、スキャンで検出されることもありません。

デフォルト設定に依存せず、bind address を明示的に設定します。

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_HOST=127.0.0.1:11434"

これにより /etc/systemd/system/ollama.service.d/override.conf が書き込まれます。適用して確認します。

sudo systemctl daemon-reload
sudo systemctl restart ollama
sudo ss -tlnp | grep 11434

ss には 127.0.0.1:11434 と表示されるはずです。それでも 0.0.0.0 と表示される場合は、別の drop-in ファイルが優先されています。systemctl cat ollama.service を実行して、unit とすべての drop-in、およびそれぞれのパスを一覧表示し、古いファイルを削除します。

ノートパソコンからモデルを使用するには、SSH 経由でポートを転送します。

ssh -N -L 11434:127.0.0.1:11434 you@your-server

-L 11434:127.0.0.1:11434 により、ノートパソコンのポート 11434 が開き、そこに到着した通信が、サーバーから見た 127.0.0.1:11434 へ送信されます。-N は SSH にリモートコマンドを実行させない指定です。そのため、プロセスはトンネルを開いたまま保持します。トンネルの実行中は、ノートパソコンで次のように使用できます。

curl -s http://localhost:11434/api/tags

遭遇しやすい失敗が 2 つあります。bind [127.0.0.1]:11434: Address already in use は、ノートパソコン上で Ollama がそのポートを使用していることを示します。その場合は -L 11500:127.0.0.1:11434 で別のローカルポートを選び、クライアントの接続先を 11500 にします。トンネル接続が正常に確立したのに応答が空の場合、SSH は機能しており、サーバー側で Ollama が待ち受けていません。SSH コマンドを変更する前に、サーバー上で ss を確認してください。

複数のクライアントマシンから接続する場合は、ユーザーごとに 1 本のトンネルを作るより、プライベートネットワークの方が適しています。マシンを WireGuard または Tailscale に接続し、Ollama を 0.0.0.0 ではなく、そのネットワーク上のアドレスで待ち受けるようにします。

[Service]
Environment="OLLAMA_HOST=10.8.0.1:11434"

この場合、ポートは、鍵を使って参加する必要があるインターフェース上にのみ存在します。これはファイアウォール設定を誤った場合にも有効です。ルールが誤って全世界からの通信を許可しても、パブリックインターフェースが待ち受けていないポートを公開することはできません。

防御 2: bearer token を確認するリバースプロキシ

パブリックインターネット上のクライアントからモデルを呼び出す必要がある場合は、Ollama を loopback に限定し、その前段にプロキシを配置します。プロキシで TLS(transport layer security)を終端し、正しいヘッダーがないリクエストを拒否します。Ollama は 127.0.0.1 からの接続だけを受け付けるため、外部からはプロキシだけが入口になります。

まず、実際の token を生成します。手動で作成しないでください。

openssl rand -base64 36

token を確認する nginx のサイト設定は次のとおりです。

map $http_authorization $ollama_ok {
    default                                   0;
    "Bearer PASTE_YOUR_GENERATED_TOKEN_HERE"  1;
}

server {
    listen 443 ssl;
    server_name llm.example.com;

    ssl_certificate     /etc/letsencrypt/live/llm.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/llm.example.com/privkey.pem;

    location = /api/pull   { return 403; }
    location = /api/delete { return 403; }
    location = /api/push   { return 403; }

    location / {
        if ($ollama_ok = 0) { return 401; }

        proxy_pass http://127.0.0.1:11434;
        proxy_set_header Host 127.0.0.1:11434;
        proxy_buffering off;
        proxy_read_timeout 600s;
    }
}

この設定では 5 行が実際の役割を担っており、それぞれが、設定しなければ発生する障害を防ぎます。

location ブロック内の if は、通常 nginx では適切ではありません。ただし、本文が return ちょうどの場合は、期待どおりに動作する 2 つの形式の 1 つであるため、この用途では安全です。

location = /api/pull は完全一致です。nginx は完全一致を location / prefix より優先するため、この 3 つの endpoint は token を確認する前に拒否されます。有効な token があっても、利用できるのは推論だけであり、ディスクを埋めることはできません。

proxy_set_header Host 127.0.0.1:11434; が重要なのは、Ollama が受信した HostOrigin のヘッダーを検査するためです。プロキシの公開 hostname をそのまま転送すると、403 Forbidden が nginx ではなく Ollama から生成されたように見えることがあり、デバッグが難しくなります。ブラウザクライアントで特定の origin を許可する必要がある場合は、OLLAMA_ORIGINS がもう 1 つの制御手段になります。

proxy_buffering off; が重要なのは、Ollama が response を token 単位でストリーミングするためです。buffering が有効だと、nginx はストリームを保持し、生成が完了した最後にまとめて配信します。そのため、クライアントは生成中ずっと停止したように見えます。

proxy_read_timeout 600s; が重要なのは、nginx のデフォルト値が 60 秒だからです。CPU での長い生成ではこの時間を簡単に超え、クライアントには 504 Gateway Time-out が返り、/var/log/nginx/error.log には upstream timed out (110: Connection timed out) while reading response header from upstream が記録されます。リクエストは処理中でしたが、nginx が処理を打ち切っただけです。

両方の経路を reload してテストします。

sudo nginx -t && sudo systemctl reload nginx
curl -s -o /dev/null -w '%{http_code}\n' https://llm.example.com/api/tags
curl -s -H "Authorization: Bearer YOUR_TOKEN" https://llm.example.com/api/tags

1 つ目は 401 を出力するはずです。2 つ目は model list を出力するはずです。1 つ目も model list を返す場合は、map ブロックのスコープが間違っています。これは http レベルに置く必要があります。/etc/nginx/conf.d/ 配下のファイル、または server ブロックより上に配置し、server 内には置かないでください。

Caddy でも同じ役割を 4 行で実現できます。bearer token よりも、ブラウザクライアントに適しています。

llm.example.com {
	basic_auth {
		apiuser PASTE_BCRYPT_HASH_HERE
	}
	reverse_proxy 127.0.0.1:11434
}

caddy hash-password を実行すると、必要な bcrypt hash が生成されます。名前には注意点があります。Caddy v2.8 より前は directive が basicauth で、現在は basic_auth です。そのため、古いガイドからコピーした設定は読み込みに失敗し、Caddy は認識できなかった directive の名前を表示します。

どのプロキシを選んでも、これは全員で共有する 1 つの Secret です。これを持つすべてのクライアントは同じアクセス権を持ちます。無効化するには設定を編集し、すべての呼び出し元を同時に更新する必要があります。

防御 3: クライアントごとにキーを発行するゲートウェイ

複数のユーザーやアプリケーションがモデルを呼び出すようになると、共有トークンでは対応できなくなります。どのクライアントが負荷を発生させたのか判別できず、1 つだけ停止することもできません。ゲートウェイはプロキシがあった場所に配置し、同じ OpenAI互換 API で通信します。クライアントごとに個別のキーを発行し、各キーの利用状況を記録します。セルフホスト型の LiteLLM ゲートウェイが一般的な選択肢で、アクセス制御に加えて、キーごとの予算とリクエストログを利用できます。

防御 1 のルールは変わりません。Ollama は 127.0.0.1 に bind し、Ollama と通信するプロセスはゲートウェイだけにします。外部から listen するサービスもゲートウェイだけにします。port 11434 を外部に開放したままのホストにゲートウェイを置いても、形だけの対策です。呼び出し元はゲートウェイを迂回して直接接続できるためです。

ファイアウォールの落とし穴: 公開したコンテナポートは UFW を迂回します

これが、所有者が正しくファイアウォールを設定したサーバーでも、外部に公開されたインスタンスが存在する理由です。

UFW (uncomplicated firewall) は、カーネルの filter テーブルにある INPUT チェーンへルールを書き込みます。INPUT は、ホスト自体を宛先とするパケットを処理します。Docker の -p フラグは、nat テーブルの PREROUTING チェーンへ宛先 NAT (network address translation) ルールを書き込みます。カーネルは、パケットの転送先を決定する前にこのルールを評価します。ルーティングの判断が行われる時点では、宛先はすでにコンテナのアドレスへ書き換えられています。そのため、パケットはローカル配信ではなく転送され、INPUT ではなく FORWARD を通過します。UFW の INPUT ルールは参照されないため、パケットはファイアウォールを通過せずに迂回します。

そのため、次の手順ではポート 11434 がインターネットに公開されたままになります。

sudo ufw default deny incoming
sudo ufw enable
docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama

それでも sudo ufw status は、デフォルトポリシーが deny でファイアウォールが有効だと報告します。2 つの結果は同時に正しいため、誤った結果を信頼してしまいます。原因となったルールは次のコマンドで確認できます。

sudo iptables -t nat -L DOCKER -n

修正には、publish フラグにアドレスを 1 つ追加します。

docker rm -f ollama
docker run -d -v ollama:/root/.ollama -p 127.0.0.1:11434:11434 --name ollama ollama/ollama

-p 11434:11434-p 0.0.0.0:11434:11434 の短縮形です。127.0.0.1 を指定すると、ポートマッピングのホスト側が loopback にバインドされます。そのため、SSH トンネルとリバースプロキシからは引き続き到達できますが、インターネットからは到達できません。モデルはコンテナ内ではなく名前付きの ollama volume に保存されているため、ここではコンテナを作り直しても安全です。

2 つの見方が一致することを確認します。

docker port ollama
sudo ss -tlnp | grep 11434

docker port ollama の出力は 11434/tcp -> 127.0.0.1:11434 になるはずです。0.0.0.0:11434 と表示される場合は、まだ外部に公開されています。この仕組みを一度理解すれば、今後公開するすべてのコンテナに適用できます。Docker の公開ポートが UFW を迂回する理由では、DOCKER-USER チェーンと Docker の再起動後も残るルールについて説明しています。ホストのポリシー自体をこれから構築する場合は、新しい VPS に必要な UFW ルールで、その基盤を確認できます。

プロセスが実行されているアカウント

Linux のインストールスクリプトは専用アカウントを作成し、そのアカウントでサービスを実行します。

useradd -r -s /bin/false -U -m -d /usr/share/ollama ollama

/etc/systemd/system/ollama.service の unit は、User=ollamaGroup=ollama を設定します。これは変更しないでください。ターミナルで手動実行した簡易な ollama serve は、ログイン中のアカウントで実行されます。そのアカウントが root の場合、認証されていない API が root としてファイルを書き込みます。実行アカウントを確認します。

ps -o user= -C ollama

結果は ollama になるはずです。それ以外の場合は、unit と並行して手動起動したプロセスが実行されているか、unit の代わりに実行されています。後から追加するすべてのデーモンにも同じ考え方を適用します。最小権限のユーザーでサービスを実行することで、これを適切に実現できます。

Ollama API エンドポイントが安全か確認する方法

どの構成を選んだ場合でも、1 つのテストで確認できます。ただし、別のマシンから実行する必要があります。

curl -m 5 http://YOUR_SERVER_IP:11434/api/version
curl -m 5 http://YOUR_SERVER_IP:11434/api/tags

どちらもタイムアウトするか、接続を拒否する必要があります。プロキシを構築した場合は、プロキシのホスト名に対する同じ 2 つのパスが、認証情報なしでは 401 を返し、認証情報ありでは実際の JSON を返す必要があります。

次に、アクセスログを 1 回確認します。ポートが公開されていた間に、誰かがそのポートを見つけたかどうかを確認できるためです。

journalctl -u ollama --since "-30 days" | grep GIN | grep -v 127.0.0.1

Ollama はリクエストごとに 1 行を書き込み、クライアントアドレスを含めます。

[GIN] 2026/08/12 - 14:01:10 | 200 | 103.965898ms | 127.0.0.1 | POST "/api/generate"

Ollama が loopback にバインドされると、すべての行に 127.0.0.1 が 1 回表示されます。接続元になり得るアドレスがそれだけだからです。その列にパブリックアドレスが表示されている場合、外部からのリクエストです。タイムスタンプから発生時刻を確認できます。このコマンドが何も出力しない状態が、期待する結果です。モデル側の運用に慣れていない場合は、VPS で Ollama を実行する で、インストール、モデルサイズ、実際にロードできるモデルを決めるメモリ制限について説明しています。

FAQ

Ollama には API key やパスワードがありますか?

いいえ。実行しているサーバーには、どのような認証もありません。公式ドキュメントにも、API へのアクセスに認証は不要と記載されています。「Ollama API key」と呼ばれるものは、どちらも別の用途です。/usr/share/ollama/.ollama/ の Ed25519 ペアは、モデルの push や非公開モデルの pull を行うために、あなたのマシンを ollama.com に証明します。OLLAMA_API_KEY は、クライアントが https://ollama.com/api のホスト型 API に送信する認証情報です。あなた自身の ollama serve は、どちらも読み取りません。そのため、アクセス制御はネットワークまたは前段のプロキシで行う必要があります。

ファイアウォールがある場合、OLLAMA_HOST=0.0.0.0 は安全ですか?

そのマシン上で他のソフトウェアがファイアウォールルールを書き換えない間だけです。0.0.0.0 は、リスナーがパブリックインターフェース上に実際に存在し、到達不能に保つ処理をファイアウォールだけに任せていることを意味します。Docker がポートを公開すると、この信頼は崩れます。Docker が nat テーブルに追加する DNAT ルールは、パケットが UFW のある INPUT チェーンに到達する前に評価されるため、パケットは転送され、UFW はそのパケットを認識できません。127.0.0.1 またはプライベートトンネルのアドレスに bind すると、リスナーがパブリックインターフェースから外れます。そのため、ファイアウォールの設定ミスが公開できる対象は残りません。

Ollama のポートがインターネットに公開されているか確認するにはどうすればよいですか?

サーバー上で sudo ss -tlnp | grep 11434 を実行し、別のマシンから curl -m 5 http://YOUR_SERVER_IP:11434/api/version を実行します。ss127.0.0.1:11434 を表示し、リモートからの curl がタイムアウトする状態が、確認したい組み合わせです。ss0.0.0.0:11434 または *:11434 を表示し、リモートからの curl が JSON を返す場合は、API 全体に到達できます。サーバー自身で curl を使ってテストしてはいけません。bind アドレスに関係なく、loopback が応答するためです。

ポートを 11434 から適当な番号に変更するだけではいけませんか?

いけません。理由を明確にしておく必要があります。別のポートに変更しても、遅くできるのは 1 つのポートだけを調べるスキャンに限られます。スキャナーはポート範囲全体を調べます。また、/api/tags への 1 回のリクエストで、どのポートに到着したかに関係なくサービスを特定できます。ポートを変更すると、すべてのクライアントのデフォルト設定も壊れ、後で自分の構成を把握しにくくなります。ポートを移動するのではなく、loopback に bind してください。これにより、リスナー自体が外部から到達できなくなります。

誰かが公開された Ollama にアクセスしました。何を確認すべきですか?

まず 127.0.0.1 に bind してサービスを再起動し、調査を始める前に公開状態を止めます。次に journalctl -u ollama --since "-30 days" | grep GIN | grep -v 127.0.0.1 を実行し、どの外部アドレスが、いつ、どのエンドポイントを呼び出したかを確認します。ollama list を、意図して用意したモデルと比較してください。/api/pull は認証なしで利用できるため、pull していないモデルがあれば、ディスク使用量の増加であると同時に侵害の証拠でもあります。空き容量を df -h で確認します。Ollama はデフォルトのログレベルではプロンプト本文を記録しません。そのため、誰がどのモデルに対してリクエストしたかは分かりますが、何が生成されたかは分かりません。