SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor

Claude APIをUbuntu VPSで始める方法

Ubuntu 24.04 VPSでClaude API keyを安全に設定し、Pythonでログ説明ツールを作ります。streaming、型付きエラー処理、systemd、実際のコスト制御まで解説します。

構築するもの

新しい Ubuntu 24.04 VPS 上で動作するコマンドラインツールを構築します。エラーメッセージまたはログの一部をパイプで渡すと、平易な英語による診断結果が返ります: journalctl -u nginx -n 50 | explain。Python のコードはおそらく約60行です。実際の Claude API アプリケーションに必要な要素をすべて扱います。適切に保存した key、virtualenv、SDK の response shapes、streaming、typed exception chain、さらに手動操作なしで実行する systemd unit です。

このプロジェクトを選んだのには理由があります。多くの「初めての API アプリケーション」チュートリアルでは、二度と開かない chatbot を作ります。ログ説明ツールは初日からサーバー上で役立ちます。また、初心者が実際によく間違える2つの点にも取り組めます。response object を正しく読み取ることと、支出を制御することです。API は token 単位で課金され、上限は自分で設定したものだけです。そのため、ここではコスト制御を後付けではなく設計要件として扱います。これは、同じ VPS 上で tmux を使って Claude Code を実行する段階に進んだときにも重要な考え方です。

Console から API key を取得する

API access は platform.claude.com の Anthropic Console で管理します。アカウントを作成し、Settings → API Keys で key を作成します(ドキュメントからは platform.claude.com/settings/keys に直接移動できます)。Console では、key の名前、expiration、紐付け先として自分自身または service account を指定します。Anthropic は、本番サービスや共有用途では service account key を推奨しています。key は一度だけ表示され、sk-ant- で始まります。後から再取得できないため、すぐにコピーしてください。紛失した場合は、削除して再発行します。

料金について説明します。2026 年 10 月時点で、API に継続的な free tier はありません。Anthropic の pricing docs によると、新規ユーザーにはテスト用として少額の free credit が付与されます。正確な金額は signup 時に Console に表示される値です。credit を使い切ると、リクエストを成功させる前にアカウントへ入金する必要があります。これは claude.ai subscription とは別です。API key で chat app を利用することはできません。Pro plan に API credit は含まれませんが、Max plan と Team plan には含まれます。2026 年 10 月時点では、Max 5x は月額 $100、Max 20x は月額 $200 です。Team は Standard seat 1 つあたり $20、Premium seat 1 つあたり $100 で、上限は $500 です。claude.ai の billing settings から Console organization を紐付けることで利用できます。未使用の credit は各 billing cycle の終了時に失効し、Claude Code には使用できません。詳細は Max と Team の月間 API credit の仕組み を参照してください。subscription と API のどちらを選ぶか検討している場合、その比較は別の論点です。実際に必要な Claude plan の選び方 を参照してください。

key は 1 つの project または server に限定して作成してください。key が漏えいした場合、十分に長い期間で見れば、いずれその事態は起こります。他の所有リソースに影響を与えずに、その key だけを revoke できるようにしておきます。

鍵を .bashrc に保存しない

よくある対応は export ANTHROPIC_API_KEY=sk-ant-... を ~/.bashrc に追加することです。これは避けてください。問題は3つあります。

  • すべてのプロセスが継承します。 ログインシェルでエクスポートした環境変数は、起動するすべてのプロセスに伝播します。Webアプリ、環境変数をバグレポートに出力してしまうクラッシュレポーター、誰かが有効にしたままの phpinfo() ページも対象です。鍵の露出範囲が「このユーザーが実行するすべてのもの」になります。
  • 入力内容が ~/.bash_history に保存されます。 export を手動で一度実行すると、鍵が平文ファイルに永続的に残り、ホームディレクトリのすべてのバックアップにも同期されます。
  • systemd が必要とするときに存在しません。 サービスは .bashrc を読み込まないため、スクリプトを unit に移行したときにこの方法は機能しません。通常は、午前6時に原因不明の 401 として発生します。

サーバーでは、必要なプロセスだけが読み込む、専用の環境ファイルを 600 の権限で用意する方法が適切です。

sudo mkdir -p /opt/explain
sudo install -m 600 -o root -g root /dev/null /etc/claude-explain.env
printf 'ANTHROPIC_API_KEY=sk-ant-YOUR-KEY-HERE\n' | sudo tee /etc/claude-explain.env >/dev/null

エディターのスワップファイルに鍵を残したくない場合は、エディターではなく printf から tee を使用してください。どちらの方法でも、ls -l /etc/claude-explain.env で -rw------- を読み取り、root が所有していることを確認します。対話型シェルにはラッパー(下記)を使用して呼び出しごとに鍵を渡し、systemd には EnvironmentFile= を使用します。root が権限を下げる前にファイルを読み込むため、サービスユーザーにそのファイルの読み取り権限は必要ありません。鍵がコード、git、ps の出力、シェル履歴に現れることはありません。

venv に SDK をインストールする

Ubuntu 24.04 には PEP 668 の適用された Python 3.12 が含まれています。そのため、システムインタープリターに対して bare pip install anthropic を実行すると、error: externally-managed-environment で失敗します。このエラーは OS が意図どおりに動作していることを示します。virtualenv を使用してください。

sudo apt update && sudo apt install -y python3-venv
sudo python3 -m venv /opt/explain/venv
sudo /opt/explain/venv/bin/pip install anthropic

サーバーではアクティベーション操作は必要ありません。/opt/explain/venv/bin/python を直接呼び出すと、常に venv のパッケージが使用されます。

初回の呼び出しとレスポンスの正しい読み取り

import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1000,
    messages=[{"role": "user", "content": "Explain what a systemd unit file is in three sentences."}],
)

for block in response.content:
    if block.type == "text":
        print(block.text)

この12行には、APIの基本的な考え方に関わる重要な点が2つあります。1つ目は、引数なしの anthropic.Anthropic() が環境変数からキーを読み取ることです。キーを文字列リテラルとして渡してはいけません。2つ目は、response.content が文字列ではなく、コンテンツブロックのリストであることです。これをそのまま出力すると、初回によくある次のような結果になります。

[TextBlock(citations=None, text='A systemd unit file is...', type='text')]

これはバグではありません。オブジェクトの repr です。レスポンスには、テキスト、ツール呼び出し、thinking など、複数のブロックタイプを含めることができます。そのため、反復処理を行い、.text にアクセスする前に block.type == "text" を確認します。Opus 5.5 では、初回の呼び出しからこの処理が重要です。thinking は常に有効であるため、単純なリクエストでモデルが thinking を省略しない限り、リストの先頭には thinking ブロックが入ります。このブロックの text はデフォルトで空であり、response.content[0].text は回答ではありません。このループを初日から組み込めば、「出力が不正なデータになる」という混乱の多くを防げます。

モデル ID には claude-opus-5-5 をそのまま使用します。4.6 世代以降、モデル ID に日付は含まれません。この日付なしの ID が固定されたスナップショットです。そのため、現在のモデルに日付のサフィックスを追加するよう促す古い習慣や古いブログ記事に従わないでください。そうすると 404 になります。詳細は後述します。旧モデルでは逆の方式です。Haiku 4.5 の正式な ID は、日付付きの claude-haiku-4-5-20251001 です。

実際のツール: 解説

以下が完全なプログラムです。標準入力を受け取り、診断結果をストリーム出力し、エラーを処理します。

#!/usr/bin/env python3
"""explain: pipe an error or log excerpt in, get a diagnosis out."""
import sys
import anthropic

MODEL = "claude-opus-5-5"

def main() -> int:
    text = sys.stdin.read().strip()
    if not text:
        print("usage: journalctl -u nginx -n 50 | explain", file=sys.stderr)
        return 1

    client = anthropic.Anthropic()
    try:
        with client.messages.stream(
            model=MODEL,
            max_tokens=4096,
            system=(
                "You are a senior Linux sysadmin. The user pipes you server "
                "logs or error output. Name the most likely cause outright, "
                "then give the commands to confirm and fix it. Be terse."
            ),
            messages=[{"role": "user", "content": text}],
        ) as stream:
            for chunk in stream.text_stream:
                print(chunk, end="", flush=True)
        print()
    except anthropic.RateLimitError as e:
        retry_after = e.response.headers.get("retry-after", "60")
        print(f"rate limited; retry in {retry_after}s", file=sys.stderr)
        return 2
    except anthropic.APIStatusError as e:
        print(f"API error {e.status_code}: {e.message}", file=sys.stderr)
        return 2
    except anthropic.APIConnectionError:
        print("network error reaching the API", file=sys.stderr)
        return 2
    return 0

if __name__ == "__main__":
    sys.exit(main())

これを /opt/explain/explain.py として保存し、対話的に使用できるよう、keyを読み込むwrapperを追加します。

sudo tee /usr/local/bin/explain >/dev/null <<'EOF'
#!/bin/sh
set -a; . /etc/claude-explain.env; set +a
exec /opt/explain/venv/bin/python /opt/explain/explain.py "$@"
EOF
sudo chmod 755 /usr/local/bin/explain

(wrapperは sudo 経由で実行する必要があります。または、env fileにadmin userが所属するgroupを設定します。ファイルの権限を644に緩めるのではなく、どちらを採用するか意図的に決めてください。)

ストリーミングを使う理由。 client.messages.stream は生成結果全体を待たず、tokenが到着するたびに出力します。長い出力でのHTTP timeoutも回避できます。SDKはまさにこの理由から、non-streaming callで非常に大きな max_tokens 値を実際に拒否します。text_stream は回答テキストだけを返します。また、Opus 5.5ではデフォルトでthinking表示が有効でも、thinking textはまったくstreamされないため、出力をクリーンに保てます。後で組み立て済みのobjectが必要な場合は、with block内で stream.get_final_message() を呼び出します。

例外の順序をこのようにする理由。 SDKは、より具体的な型から順にtyped exceptionを送出します。RateLimitError は429で、待機時間を示す retry-after headerを含みます。APIStatusError はその他のnon-2xx responseを処理します(server-sideの問題は e.status_code >= 500 を確認してください)。APIConnectionError はrequestに対するresponseがまったく返らなかったことを示します。retry loopを実装する前に、次の点にも注意してください。SDKは429 errorと5xx errorをすでに自動でretryします。デフォルトではexponential backoffを使用し、2回実行します(client側の max_retries による設定)。except が実行される時点ではretryを使い切っています。そのため、CLIでは待機して繰り返し送信するのではなく、エラーを報告して終了するのが適切です。

コスト管理

ここは独立したセクションにする価値があります。API には、設定した上限を超える月間上限が組み込まれていないためです。ここでのミスは、気付かないまま積み重なります。

max_tokens は、1 回の呼び出しに許容する支出の上限です。 Opus 5.5 では、出力トークンの単価は入力の 5 倍です。max_tokens は、モデルが生成できる出力トークン数のハード上限です。暴走したプロンプトでも、許可した上限を超える出力コストは発生しません。5.5 モデルでは、この上限に thinking も含まれます。thinking tokens は max_tokens に加算され、出力として課金されます。ただし、thinking のテキストは返されません。上限はタスクに合わせて設定します。4,096 なら、短いログ診断で、その前段の thinking にも余裕があります。分類タスクでは、これよりはるかに少なくて済みます。stop_reason: "max_tokens" で応答が途中で止まるなら、上限が低すぎます。むやみに大きな値を使うのではなく、意識的に引き上げるか、effort 設定を下げてモデルに考えさせる量を減らしてください。

送信前に数えてください。 入力にも料金がかかり、ログは容量が大きくなりがちです。API には無料で使えるカウント用エンドポイントがあります。独自のレート制限があり、メッセージ作成とは別に管理されます。

count = client.messages.count_tokens(
    model="claude-opus-5-5",
    messages=[{"role": "user", "content": big_log_text}],
)
print(count.input_tokens)

これを使うと、誤って 2 GB のログをツールに渡す事故を防げます。実際に呼び出すモデルを指定してください。Claude 4.7 以降のモデルは新しい tokenizer を使用するため、同じテキストでも以前の Claude モデルより約 30% 多くのトークンになります。tiktoken は使わないでください。これは OpenAI の tokenizer であり、Claude 用ではありません。そのため、カウント結果が実際の請求額と一致しません。

モデルは忠誠心ではなく、タスクごとに選んでください。 2026 年 10 月時点で、Opus 5.5(claude-opus-5-5)は入力トークン 100 万個あたり $4、出力トークン 100 万個あたり $20 です。Haiku 5.5(claude-haiku-5-5)は、最大 100,000 トークンのプロンプトでは $0.10/$0.50、それを超える場合は $0.50/$2.50 です。コンテキスト長は 1M です。Sonnet 5.5(claude-sonnet-5-5)はその中間で、$2/$10 です。具体的には、2,000 トークンのログ抜粋と 500 トークンの回答の場合、Opus では約 $0.018、Haiku では約 $0.00045 です。これに、モデルが行う thinking の料金が加わります。thinking は出力として課金されます。出力品質を評価している段階では Opus から始めてください。その後、同じプロンプトを Haiku で試します。大量処理する単純な変換では、トークン単価が 40 分の 1 でも、結果にほとんど違いがないことがよくあります。予算にこれらの数値を固定的に組み込む前に、pricing page で最新の料金を確認してください。

待てる処理には Batches を使います。 Batches API はリクエストを非同期で処理し、通常料金の 50% で利用できます。ほとんどのバッチは 1 時間以内に完了します。夜間ダイジェスト、バックフィル、大量分類など、人が待つ必要のない処理は Batches に適しています。

繰り返し送るコンテキストには prompt caching を使います。 大きな system prompt や runbook を毎回再送する場合は、cacheable として指定します。

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1000,
    system=[{
        "type": "text",
        "text": RUNBOOK_TEXT,  # the same 30K tokens on every call
        "cache_control": {"type": "ephemeral"},
    }],
    messages=[{"role": "user", "content": question}],
)
print(response.usage.cache_read_input_tokens)  # non-zero from the second call on

cache write は、5 分の TTL では入力単価の 1.25 倍です。cache read は、Opus 5.5 と Sonnet 5.5 では 0.05 倍、その他の多くのモデルでは 0.1 倍です。そのため、ウィンドウ内の 2 回目の呼び出しで、1 回目のコストを回収できます。注意点が 2 つあります。キャッシュ対象の prefix は、モデルごとの最小トークン数を満たす必要があります。Opus 5.5 では 512 トークンです。そのため、system prompt が非常に短い場合は、キャッシュされないままになることがあります。また、同じ呼び出しを繰り返しても cache_read_input_tokens が 0 のままなら、リクエストごとに prefix のどこかが変化しています。よくある原因は timestamp です。

何が入力として数えられるかを把握してください。 system prompt、tool definitions、そして multi-turn の会話で毎回再送する履歴全体は、すべて入力トークンとして課金されます。履歴を削除しない chat loop は、コストが二次関数的に増加します。会話機能を構築する前に、料金の全体像を理解しておく価値があります。Claude の token usage と billing の実際の計算方法

systemd で実行する

環境ファイルを適切に管理するメリットは、毎朝、前日のエラーを要約するタイマーを実行できることです。

# /etc/systemd/system/log-digest.service
[Unit]
Description=Daily error-log digest via the Claude API

[Service]
Type=oneshot
User=explain
Group=systemd-journal
EnvironmentFile=/etc/claude-explain.env
ExecStart=/bin/sh -c 'journalctl -p err --since yesterday | /opt/explain/venv/bin/python /opt/explain/explain.py >> /var/log/log-digest.txt'
# /etc/systemd/system/log-digest.timer
[Unit]
Description=Run the log digest every morning

[Timer]
OnCalendar=06:15
Persistent=true

[Install]
WantedBy=timers.target
sudo useradd -r -s /usr/sbin/nologin explain
sudo touch /var/log/log-digest.txt && sudo chown explain /var/log/log-digest.txt
sudo systemctl daemon-reload
sudo systemctl enable --now log-digest.timer
sudo systemctl start log-digest.service   # test it once, right now

EnvironmentFile= によって得られる利点に注目してください。systemd は、権限のない explain ユーザーに切り替える 前 に、root が所有する mode-600 のファイルを読み取ります。そのため、プロセスは変数を取得できますが、ユーザーはキーファイルを読み取れません。systemd-journal グループによってログへのアクセスが許可されます。手動で systemctl start を実行して journalctl -u log-digest.service を読み取り、06:15 まで待って入力ミスに気付くことのないようにしてください。この方法が単純なシェルパイプラインでは対応できなくなっても、同じキーを環境ファイルに保存する方法を、そのまま同じマシン上の Claude を使用する n8n ワークフロー に適用できます。

問題が発生した場合に表示される文字列

動作する key で 401 が返る場合。 例外には次のように表示されます。

anthropic.AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}, 'request_id': 'req_011CSHoEeqs5C35K2UUqR7Fy'}

shell では key が機能するのにサービスが 401 を返す場合、サービスに key が渡っていません。systemd は .bashrc を読み込まないため、EnvironmentFile= が正しいパスを指しているか確認してください。その他の原因として、env ファイルに引用符を貼り付けているケースがあります(ANTHROPIC_API_KEY="sk-ant-..." では systemd が引用符を値から除外しますが、shell wrapper の . file では引用符の付け方によって値に残ります)。末尾の空白、先週 Console で失効させた key、作成時に指定した有効期限に達した key も原因になります。

モデル名の誤記で 404 が返る場合。 最も多いのは、日付形式を持たないモデル ID に日付のサフィックスを付けるケースです。

anthropic.NotFoundError: Error code: 404 - {'type': 'error', 'error': {'type': 'not_found_error', 'message': 'model: claude-opus-5-5-20260922'}, 'request_id': 'req_011CSJqymAvNw4bT3qmDdMbA'}

現行世代の ID は、claude-opus-5-5、claude-sonnet-5-5、claude-haiku-5-5、claude-fable-5-1 のように記載どおり正確に指定します。4.6 世代より前のモデルは例外です。claude-haiku-4-5 は日付付き ID claude-haiku-4-5-20251001 の便利な alias であり、どちらの形式も使用できます。ID は記憶や古いチュートリアルからではなく、models のドキュメントからコピーしてください。

429 rate_limit_error。 エラー種別の文字列は rate_limit_error です。レスポンスには、待機すべき秒数を示す retry-after ヘッダーが含まれます。例外が表示されるまでに、SDK は backoff 付きで 2 回リトライしています。そのため、429 が継続する場合は、継続的なレートが実際に tier の上限を超えています。処理を batch 化するか分散させ、リトライループの間隔を短くしないでください。

テキストではなく object が出力される場合。 出力は [TextBlock(citations=None, text='...', type='text')] のようになります。blocks を反復処理して block.type == "text" のものから .text を読み取る代わりに、response.content を出力しています。上記の SDK 例では正しく処理しているため、その loop をコピーしてください。

error: externally-managed-environment。 Ubuntu 24.04 の system Python に対して pip install を実行しています。venv を使用し、管理対象のサーバーでは --break-system-packages を決して実行しないでください。

回答が途中で切れる場合。 response.stop_reason == "max_tokens" は、モデルが出力上限の途中で思考を停止したことを示します。これは仕様どおりの動作です。上限は意図的に引き上げてください。また、5.5 models では思考にも同じ上限が消費される点に注意してください。

最初のアプリが動作したら、Claude で AI agent を構築する に進むと、同じ API 呼び出しを tool を使う agent に発展させられます。

FAQ

Claude API の試用料金はいくらですか?

このようなツールとしては、実際にはわずかな費用です。2026 年 10 月時点で、Opus 5.5 は入力 100 万トークンあたり $4、出力 100 万トークンあたり $20 です。通常のログ診断では、入力が数千トークン、出力が数百トークンになるため、thinking tokens(出力として課金)を除けば約 2 セントです。Haiku 5.5($0.10/$0.50)なら、0.1 セントを大きく下回ります。毎日のダイジェストを 1 か月実行しても、コーヒー 1 杯未満です。リスクは 1 回あたりの料金ではなく、無制限のループと無制限の max_tokens です。そのため、このガイドでは両方を明示的に設定します。

Claude API に無料利用枠はありますか?

2026 年 10 月時点で、継続的な無料利用枠はありません。Anthropic の料金ドキュメントによると、新規ユーザーには API を試すための少額の無料クレジットが 1 回限りで付与されます。正確な金額は、登録時に Console に表示されます。その後はアカウントに入金します。例外は Max と Team のサブスクライバーです。これらのプランには、前述の月間 API クレジットが含まれます。最先端の品質ではなく、リクエストごとの限界費用をゼロにすることが目的なら、Ollama でオープンウェイトモデルをセルフホストする方法があります。トークンではなく RAM を使って支払う形です。

サーバー上で API key を安全に保管するにはどうすればよいですか?

コード内、git 内、.bashrc からのエクスポート、履歴が残るシェルへの入力は、いずれも避けてください。root が所有するファイルに 600 の権限で保存し、プロセス単位で読み込ませます。対話的な利用にはラッパースクリプトを使い、systemd には EnvironmentFile= を使います。漏えいした key をすぐに無効化できるよう、サーバーまたはプロジェクトごとに 1 つの key を割り当ててください。key が paste site や git commit に一度でも含まれた場合は、直ちに Console で無効化します。commit を削除しても、漏えいした key は無効になりません。

最初に使うべき Claude model はどれですか?

出力を基盤として十分に使えるか評価している段階では claude-opus-5-5 から始めてください。アイデアを最高品質で評価したい場合にも適しています。趣味の規模で使う限り、料金差は数セントです。prompt が固まったら、実際の入力を claude-haiku-5-5 でもう一度実行します。要約、分類、ログのトリアージでは、トークン単価が 40 分の 1 でも十分な品質になることが多くあります。Haiku や Sonnet への移行は、デフォルトで決めず、測定結果に基づいて判断してください。