AIコーディング 2026.04.20
Claude API月2ドルで使う方法|自作プロキシサーバーとcurlコマンドのセットアップ
なぜプロキシサーバーを挟むのか
❌ 直接APIを呼ぶ場合:
クライアント → Anthropic API
問題: APIキーがフロントに露出・レート制限の制御が難しい
✅ プロキシを挟む場合:
クライアント → 自作プロキシ($2/月) → Anthropic API
メリット:
- APIキーをサーバーに隠せる(クライアントには渡さない)
- 自前のレート制限・ログ・コスト追跡ができる
- 将来的にモデルを切り替えてもクライアント変更不要
Step 1:FastAPIでプロキシサーバーを実装
# proxy_server.py
# pip install fastapi uvicorn anthropic python-dotenv
import os
import time
from collections import defaultdict
from fastapi import FastAPI, HTTPException, Header
from fastapi.middleware.cors import CORSMiddleware
import anthropic
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
# CORS設定(フロントエンドからのアクセスを許可)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"], # 本番では自分のドメインに変更
allow_methods=["POST"],
allow_headers=["*"],
)
# Anthropicクライアント(環境変数からAPIキーを取得)
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
# 簡易レート制限(本番ではRedisを使う)
request_counts: dict[str, list[float]] = defaultdict(list)
RATE_LIMIT = 10 # 1分間に最大10リクエスト
class ChatRequest(BaseModel):
messages: list[dict]
model: str = "claude-haiku-4-5-20251001"
max_tokens: int = 1024
system: Optional[str] = None
def check_rate_limit(client_ip: str) -> None:
now = time.time()
# 1分以内のリクエストだけ残す
request_counts[client_ip] = [
t for t in request_counts[client_ip] if now - t < 60
]
if len(request_counts[client_ip]) >= RATE_LIMIT:
raise HTTPException(
status_code=429,
detail=f"レート制限: 1分間に{RATE_LIMIT}回まで"
)
request_counts[client_ip].append(now)
@app.post("/v1/messages")
async def proxy_messages(
request: ChatRequest,
x_forwarded_for: str = Header(default="unknown")
):
check_rate_limit(x_forwarded_for)
try:
kwargs = {
"model": request.model,
"max_tokens": request.max_tokens,
"messages": request.messages,
}
if request.system:
kwargs["system"] = request.system
response = client.messages.create(**kwargs)
return {
"content": [{"type": "text", "text": response.content[0].text}],
"usage": {
"input_tokens": response.usage.input_tokens,
"output_tokens": response.usage.output_tokens,
}
}
except anthropic.RateLimitError:
raise HTTPException(status_code=429, detail="Anthropic レート制限超過")
except anthropic.AuthenticationError:
raise HTTPException(status_code=401, detail="APIキーエラー")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Step 2:Fly.ioにデプロイ
# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY proxy_server.py .
CMD ["uvicorn", "proxy_server:app", "--host", "0.0.0.0", "--port", "8080"]
# requirements.txt
fastapi==0.115.0
uvicorn==0.30.0
anthropic==0.98.1
python-dotenv==1.0.0
# Fly.ioにデプロイ(初回のみ fly auth login が必要)
fly launch --name my-claude-proxy
# APIキーをシークレットとして設定(コードには書かない)
fly secrets set ANTHROPIC_API_KEY=sk-ant-api03-xxxxx
# デプロイ
fly deploy
デプロイ後のURL: https://my-claude-proxy.fly.dev
最小インスタンス(shared-cpu-1x, 256MB)で月$2〜$3程度。
Step 3:curlでテスト
# 基本リクエスト
curl -X POST https://my-claude-proxy.fly.dev/v1/messages \
-H "Content-Type: application/json" \
-d '{
"model": "claude-haiku-4-5-20251001",
"max_tokens": 256,
"messages": [{"role": "user", "content": "こんにちは"}]
}'
# システムプロンプト付き
curl -X POST https://my-claude-proxy.fly.dev/v1/messages \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"system": "あなたは日本語のコードレビュアーです。",
"messages": [{"role": "user", "content": "このコードをレビューして: def f(x): return x*x"}]
}'
Pythonからプロキシ経由で呼ぶ
# call_proxy.py
import requests
import os
PROXY_URL = os.environ.get("CLAUDE_PROXY_URL", "http://localhost:8000")
def chat_via_proxy(user_message: str, system: str = "") -> str:
payload = {
"model": "claude-haiku-4-5-20251001",
"max_tokens": 1024,
"messages": [{"role": "user", "content": user_message}],
}
if system:
payload["system"] = system
response = requests.post(
f"{PROXY_URL}/v1/messages",
json=payload,
timeout=30,
)
response.raise_for_status()
data = response.json()
return data["content"][0]["text"]
# 使用例
result = chat_via_proxy(
user_message="Pythonのdataclassを説明して",
system="簡潔に3行以内で答えてください"
)
print(result)
コスト追跡を追加する
# proxy_server.pyに追加: コスト追跡ミドルウェア
from datetime import datetime
import json
COST_LOG_FILE = "/tmp/api_costs.jsonl"
# Haiku料金
HAIKU_INPUT_COST = 0.80 / 1_000_000
HAIKU_OUTPUT_COST = 4.00 / 1_000_000
def log_usage(input_tokens: int, output_tokens: int, model: str) -> float:
cost = input_tokens * HAIKU_INPUT_COST + output_tokens * HAIKU_OUTPUT_COST
with open(COST_LOG_FILE, "a") as f:
f.write(json.dumps({
"ts": datetime.now().isoformat(),
"model": model,
"input": input_tokens,
"output": output_tokens,
"cost_usd": cost,
}) + "\n")
return cost
# エンドポイント内で呼ぶ
# cost = log_usage(response.usage.input_tokens, response.usage.output_tokens, request.model)
あわせて読みたい
- 【2026年版】GoModelとLiteLLM比較|LLMプロキシ設定コードと使い分けガイド
- Claude APIアカウント停止時の対応|影響確認コードと復旧手順
- 【2026年版】Claude料金プラン完全比較表|API・Pro・Teamの月額コスト計算式