add github
This commit is contained in:
93
workers/ollama-proxy.js
Normal file
93
workers/ollama-proxy.js
Normal file
@ -0,0 +1,93 @@
|
||||
// Cloudflare Worker for secure Ollama proxy
|
||||
export default {
|
||||
async fetch(request, env, ctx) {
|
||||
// CORS preflight
|
||||
if (request.method === 'OPTIONS') {
|
||||
return new Response(null, {
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': 'https://log.syui.ai',
|
||||
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, X-User-Token',
|
||||
'Access-Control-Max-Age': '86400',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Verify origin
|
||||
const origin = request.headers.get('Origin');
|
||||
const referer = request.headers.get('Referer');
|
||||
|
||||
// 許可されたオリジンのみ
|
||||
const allowedOrigins = [
|
||||
'https://log.syui.ai',
|
||||
'https://log.pages.dev' // Cloudflare Pages preview
|
||||
];
|
||||
|
||||
if (!origin || !allowedOrigins.some(allowed => origin.startsWith(allowed))) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
// ユーザー認証トークン検証(オプション)
|
||||
const userToken = request.headers.get('X-User-Token');
|
||||
if (env.REQUIRE_AUTH && !userToken) {
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
}
|
||||
|
||||
// リクエストボディを取得
|
||||
const body = await request.json();
|
||||
|
||||
// プロンプトサイズ制限
|
||||
if (body.prompt && body.prompt.length > 1000) {
|
||||
return new Response(JSON.stringify({
|
||||
error: 'Prompt too long. Maximum 1000 characters.'
|
||||
}), {
|
||||
status: 400,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
|
||||
// レート制限(CF Workers KV使用)
|
||||
if (env.RATE_LIMITER) {
|
||||
const clientIP = request.headers.get('CF-Connecting-IP');
|
||||
const rateLimitKey = `rate:${clientIP}`;
|
||||
const currentCount = await env.RATE_LIMITER.get(rateLimitKey) || 0;
|
||||
|
||||
if (currentCount >= 20) {
|
||||
return new Response(JSON.stringify({
|
||||
error: 'Rate limit exceeded. Try again later.'
|
||||
}), {
|
||||
status: 429,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
|
||||
// カウント増加(1時間TTL)
|
||||
await env.RATE_LIMITER.put(rateLimitKey, currentCount + 1, {
|
||||
expirationTtl: 3600
|
||||
});
|
||||
}
|
||||
|
||||
// Ollamaへプロキシ
|
||||
const ollamaResponse = await fetch(env.OLLAMA_API_URL || 'https://ollama.syui.ai/api/generate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
// 内部認証ヘッダー(必要に応じて)
|
||||
'X-Internal-Token': env.OLLAMA_INTERNAL_TOKEN || ''
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
||||
// レスポンスを返す
|
||||
const responseData = await ollamaResponse.text();
|
||||
|
||||
return new Response(responseData, {
|
||||
status: ollamaResponse.status,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Access-Control-Allow-Origin': origin,
|
||||
'Cache-Control': 'no-store'
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
20
workers/wrangler.toml
Normal file
20
workers/wrangler.toml
Normal file
@ -0,0 +1,20 @@
|
||||
name = "ollama-proxy"
|
||||
main = "ollama-proxy.js"
|
||||
compatibility_date = "2024-01-01"
|
||||
|
||||
# 環境変数
|
||||
[vars]
|
||||
REQUIRE_AUTH = false
|
||||
|
||||
# 本番環境
|
||||
[env.production.vars]
|
||||
OLLAMA_API_URL = "https://ollama.syui.ai/api/generate"
|
||||
REQUIRE_AUTH = true
|
||||
|
||||
# KVネームスペース(レート制限用)
|
||||
[[kv_namespaces]]
|
||||
binding = "RATE_LIMITER"
|
||||
id = "your-kv-namespace-id"
|
||||
|
||||
# シークレット(wrangler secret putで設定)
|
||||
# OLLAMA_INTERNAL_TOKEN = "your-internal-token"
|
Reference in New Issue
Block a user