์ฝ˜ํ…์ธ ๋กœ ์ด๋™
OmniRoute source

๐ŸŒ OmniRoute Proxy Guide (ํ•œ๊ตญ์–ด)


๋งŽ์€ AI ์ œ๊ณต์—…์ฒด๋Š” ์ง€๋ฆฌ์  ์ง€์—ญ์— ๋”ฐ๋ผ ์•ก์„ธ์Šค๋ฅผ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ๋Ÿฌ์‹œ์•„, ์ค‘๊ตญ, ์ด๋ž€, ์ฟ ๋ฐ”, ํŠ€๋ฅดํ‚ค์˜ˆ ๋ฐ ๊ธฐํƒ€ ๊ตญ๊ฐ€์˜ ๊ฐœ๋ฐœ์ž๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๋ฅผ ๊ฒช์Šต๋‹ˆ๋‹ค.

unsupported_country_region_territory

์ฐจ๋‹จ๋œ ์ง€์—ญ์ด ์•„๋‹ˆ๋”๋ผ๋„ ํ”„๋ก์‹œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์šฉ๋„๋กœ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์‚ฌ๋ก€ ์„ค๋ช…
์ง€๋ฆฌ์  ์ฐจ๋‹จ ์šฐํšŒ ์ฐจ๋‹จ๋œ ๊ตญ๊ฐ€์—์„œ OpenAI, Anthropic, Codex, Copilot์— ์•ก์„ธ์Šค
IP ์ˆœํ™˜ ์†๋„ ์ œํ•œ์„ ๋ฐฉ์ง€ํ•˜๋„๋ก ์—ฌ๋Ÿฌ IP์— ์š”์ฒญ์„ ๋ถ„์‚ฐ
๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ ์—…์ŠคํŠธ๋ฆผ ์ œ๊ณต์—…์ฒด๋กœ๋ถ€ํ„ฐ ์‹ค์ œ IP๋ฅผ ์ˆจ๊น€
๊ทœ์ • ์ค€์ˆ˜ ํŠน์ • ๊ด€ํ• ๊ถŒ์„ ํ†ตํ•ด ํŠธ๋ž˜ํ”ฝ์„ ๋ผ์šฐํŒ…
ํ…Œ์ŠคํŠธ ์„œ๋กœ ๋‹ค๋ฅธ ์ง€์—ญ์—์„œ ๋ฐœ์ƒํ•œ ์š”์ฒญ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ OmniRoute ์„œ๋ฒ„ โ”‚
โ”‚ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ ํ”„๋ก์‹œ โ”‚ โ”‚ ํ”„๋ก์‹œ โ”‚ โ”‚ ํ”„๋ก์‹œ โ”‚ โ”‚
โ”‚ โ”‚ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ โ”‚โ”€โ”€โ”€โ–ถโ”‚ ๋””์ŠคํŒจ์ฒ˜ โ”‚โ”€โ”€โ”€โ–ถโ”‚ Fetch (undici) โ”‚ โ”‚
โ”‚ โ”‚ (SQLite) โ”‚ โ”‚ (์บ์‹œ๋จ) โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ–ฒ โ”‚ โ”‚
โ”‚ โ”‚ โ–ผ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ 1proxy ๋™๊ธฐํ™”โ”‚ โ”‚ ์—…์ŠคํŠธ๋ฆผ โ”‚ โ”‚
โ”‚ โ”‚ (๋ฌด๋ฃŒ ํ’€) โ”‚ โ”‚ ์ œ๊ณต์—…์ฒด API โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
๊ตฌ์„ฑ ์š”์†Œ ํŒŒ์ผ ์—ญํ• 
ํ”„๋ก์‹œ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ src/lib/db/proxies.ts ํ”„๋ก์‹œ ํ•ญ๋ชฉ ๋ฐ ๋ฒ”์œ„ ํ• ๋‹น์„ ์œ„ํ•œ CRUD
ํ”„๋ก์‹œ ๋””์ŠคํŒจ์ฒ˜ open-sse/utils/proxyDispatcher.ts ์บ์‹ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ undici ProxyAgent/SOCKS ๋””์ŠคํŒจ์ฒ˜ ์ƒ์„ฑ
ํ”„๋ก์‹œ Fetch open-sse/utils/proxyFetch.ts ํ”„๋ก์‹œ ๋””์ŠคํŒจ์ฒ˜๋ฅผ ์ฃผ์ž…ํ•˜์—ฌ fetch() ๋ž˜ํ•‘
์„ค์ • ๋ผ์šฐํŠธ src/app/api/settings/proxy/route.ts ๋ ˆ๊ฑฐ์‹œ ํ”„๋ก์‹œ ๊ตฌ์„ฑ API(GET/PUT/DELETE)
๊ด€๋ฆฌ ๋ผ์šฐํŠธ src/app/api/v1/management/proxies/route.ts ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ CRUD API(GET/POST/PATCH/DELETE)
1proxy DB src/lib/db/oneproxy.ts ๋ฌด๋ฃŒ ํ”„๋ก์‹œ ๋งˆ์ผ“ํ”Œ๋ ˆ์ด์Šค ์˜์†์„ฑ

OmniRoute๋Š” ์„œ๋กœ ๋…๋ฆฝ์ ์ธ ๋„ค ๊ฐ€์ง€ ๋ฒ”์œ„์—์„œ ํ”„๋ก์‹œ ๊ตฌ์„ฑ์„ ์ง€์›ํ•˜๋ฉฐ, ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค.

์šฐ์„ ์ˆœ์œ„ ๊ฒฐ์ • ์ˆœ์„œ(๋†’์Œ โ†’ ๋‚ฎ์Œ):
1. ๐Ÿ”ต ๊ณ„์ •/์—ฐ๊ฒฐ ํ”„๋ก์‹œ โ†’ API ํ‚ค/OAuth ์—ฐ๊ฒฐ๋ณ„
2. ๐ŸŸก ์ œ๊ณต์ž ํ”„๋ก์‹œ โ†’ ์ œ๊ณต์ž๋ณ„(์˜ˆ: ๋ชจ๋“  OpenAI ํŠธ๋ž˜ํ”ฝ)
3. ๐ŸŸ  ์ฝค๋ณด ํ”„๋ก์‹œ โ†’ ์ฝค๋ณด/๋ผ์šฐํŒ… ๊ตฌ์„ฑ๋ณ„
4. ๐ŸŸข ์ „์—ญ ํ”„๋ก์‹œ โ†’ ๋ชจ๋“  ํŠธ๋ž˜ํ”ฝ, ๋ชจ๋“  ์ œ๊ณต์ž

OmniRoute๊ฐ€ ์—…์ŠคํŠธ๋ฆผ ์ œ๊ณต์ž์— ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ resolveProxyForConnectionFromRegistry()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฐ ๋‹จ๊ณ„๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

  1. ๊ณ„์ • ์ˆ˜์ค€ โ€” ์ด ํŠน์ • ์—ฐ๊ฒฐ ID์— ํ• ๋‹น๋œ ํ”„๋ก์‹œ๊ฐ€ ์žˆ๋Š”๊ฐ€?
  2. ์ œ๊ณต์ž ์ˆ˜์ค€ โ€” ์ด ์ œ๊ณต์ž(์˜ˆ: openai)์— ํ• ๋‹น๋œ ํ”„๋ก์‹œ๊ฐ€ ์žˆ๋Š”๊ฐ€?
  3. ์ „์—ญ ์ˆ˜์ค€ โ€” ๊ตฌ์„ฑ๋œ ์ „์—ญ ํ”„๋ก์‹œ๊ฐ€ ์žˆ๋Š”๊ฐ€?
  4. ํ”„๋ก์‹œ ์—†์Œ โ€” ์ œ๊ณต์ž์— ์ง์ ‘ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€์žฅ ๋จผ์ € ์ผ์น˜ํ•˜๋Š” ํ•ญ๋ชฉ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ „์—ญ ํ”„๋ก์‹œ๋ฅผ ๋Œ€์ฒด ์ˆ˜๋‹จ์œผ๋กœ ์„ค์ •ํ•˜๋ฉด์„œ ํŠน์ • ์ œ๊ณต์ž๋‚˜ ์—ฐ๊ฒฐ์— ๋Œ€ํ•ด ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠธ๋ž˜ํ”ฝ ์œ ํ˜• ํ”„๋ก์‹œ ์‚ฌ์šฉ ์—ฌ๋ถ€ ์ฐธ๊ณ 
์ฑ„ํŒ… ์™„์„ฑ โœ… ๋ชจ๋“  /v1/chat/completions ์š”์ฒญ
์ž„๋ฒ ๋”ฉ โœ… /v1/embeddings
์ด๋ฏธ์ง€ ์ƒ์„ฑ โœ… /v1/images/generations
์˜ค๋””์˜ค(TTS/STT) โœ… /v1/audio/*
OAuth ํ† ํฐ ๊ตํ™˜ โœ… unsupported_country_region_territory ํ•ด๊ฒฐ
์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ โœ… โ€œ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธโ€ ๋ฒ„ํŠผ์—์„œ ํ”„๋ก์‹œ ์‚ฌ์šฉ
ํ† ํฐ ๊ฐฑ์‹  โœ… ๋ฐฑ๊ทธ๋ผ์šด๋“œ OAuth ๊ฐฑ์‹ 
๋ชจ๋ธ ๋™๊ธฐํ™” โœ… ๋ชจ๋ธ ๋ชฉ๋ก ์กฐํšŒ ๋ฐ ๊ฒ€์ƒ‰

ํ”„๋ก์‹œ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋Š” ๋ชจ๋“  ํ”„๋ก์‹œ๋ฅผ ์ €์žฅํ•˜๋Š” SQLite ํ…Œ์ด๋ธ”(proxy_registry)์ž…๋‹ˆ๋‹ค. ๊ฐ ํ”„๋ก์‹œ์—๋Š” ๋‹ค์Œ ํ•„๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•„๋“œ ์œ ํ˜• ์„ค๋ช…
id UUID ๊ณ ์œ  ์‹๋ณ„์ž
name ๋ฌธ์ž์—ด ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๋ ˆ์ด๋ธ”
type ๋ฌธ์ž์—ด ํ”„๋กœํ† ์ฝœ: http, https, socks5
host ๋ฌธ์ž์—ด ํ”„๋ก์‹œ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„ ๋˜๋Š” IP
port ์ •์ˆ˜ ํฌํŠธ ๋ฒˆํ˜ธ
username ๋ฌธ์ž์—ด ์ธ์ฆ ์‚ฌ์šฉ์ž ์ด๋ฆ„(์ €์žฅ ์‹œ ์•”ํ˜ธํ™”)
password ๋ฌธ์ž์—ด ์ธ์ฆ ๋น„๋ฐ€๋ฒˆํ˜ธ(์ €์žฅ ์‹œ ์•”ํ˜ธํ™”)
region ๋ฌธ์ž์—ด ์ง€๋ฆฌ์  ์ง€์—ญ ๋ ˆ์ด๋ธ”
notes ๋ฌธ์ž์—ด ์ž์œ  ํ˜•์‹ ๋ฉ”๋ชจ
status ๋ฌธ์ž์—ด active ๋˜๋Š” inactive
source ๋ฌธ์ž์—ด manual ๋˜๋Š” oneproxy

๋Œ€์‹œ๋ณด๋“œ์—์„œ:

  1. ์„ค์ • โ†’ ํ”„๋ก์‹œ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  2. ํ”„๋ก์‹œ ์ถ”๊ฐ€๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  3. ์œ ํ˜•, ํ˜ธ์ŠคํŠธ, ํฌํŠธ ๋ฐ ์„ ํƒ์  ์ธ์ฆ ์ž๊ฒฉ ์ฆ๋ช…์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.
  4. ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

API์—์„œ:

ํ„ฐ๋ฏธ๋„ ์ฐฝ
curl -X POST http://localhost:20128/api/v1/management/proxies \
-H "Content-Type: application/json" \
-d '{
"name": "US Proxy",
"type": "http",
"host": "proxy.example.com",
"port": 8080,
"username": "user",
"password": "pass",
"region": "US"
}'
ํ„ฐ๋ฏธ๋„ ์ฐฝ
curl -X PATCH http://localhost:20128/api/v1/management/proxies \
-H "Content-Type: application/json" \
-d '{
"id": "proxy-uuid-here",
"host": "new-proxy.example.com",
"port": 9090
}'

์ฐธ๊ณ : ๋น„์–ด ์žˆ์ง€ ์•Š์€ ๋Œ€์ฒด ๊ฐ’์„ ๋ช…์‹œ์ ์œผ๋กœ ๋ณด๋‚ด์ง€ ์•Š๋Š” ํ•œ ์ž๊ฒฉ ์ฆ๋ช…์€ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. username/password์— ๋นˆ ๋ฌธ์ž์—ด์„ ๋ณด๋‚ด๋ฉด ์ €์žฅ๋œ ๊ฐ’์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

ํ„ฐ๋ฏธ๋„ ์ฐฝ
# ํ”„๋ก์‹œ๊ฐ€ ์–ด๋–ค ๋ฒ”์œ„์—๋“  ํ• ๋‹น๋˜์–ด ์žˆ์œผ๋ฉด ์‹คํŒจ
curl -X DELETE "http://localhost:20128/api/v1/management/proxies?id=proxy-uuid"
# ๊ฐ•์ œ ์‚ญ์ œ(ํ• ๋‹น๋„ ํ•จ๊ป˜ ์ œ๊ฑฐ)
curl -X DELETE "http://localhost:20128/api/v1/management/proxies?id=proxy-uuid&force=1"
ํ„ฐ๋ฏธ๋„ ์ฐฝ
curl "http://localhost:20128/api/v1/management/proxies?limit=50&offset=0"
ํ„ฐ๋ฏธ๋„ ์ฐฝ
# ์ „์—ญ ๋ฒ”์œ„์— ํ• ๋‹น
curl -X PUT http://localhost:20128/api/settings/proxy \
-H "Content-Type: application/json" \
-d '{"level": "global", "proxy": {"type":"http","host":"proxy.example.com","port":8080}}'
# ํŠน์ • ์ œ๊ณต์ž์— ํ• ๋‹น
curl -X PUT http://localhost:20128/api/settings/proxy \
-H "Content-Type: application/json" \
-d '{"level": "provider", "id": "openai", "proxy": {"type":"socks5","host":"socks.example.com","port":1080}}'
# ํŠน์ • ์—ฐ๊ฒฐ/ํ‚ค์— ํ• ๋‹น
curl -X PUT http://localhost:20128/api/settings/proxy \
-H "Content-Type: application/json" \
-d '{"level": "key", "id": "connection-uuid", "proxy": {"type":"http","host":"key-proxy.com","port":3128}}'

์ฃผ์–ด์ง„ ์—ฐ๊ฒฐ์— ์–ด๋–ค ํ”„๋ก์‹œ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

ํ„ฐ๋ฏธ๋„ ์ฐฝ
curl "http://localhost:20128/api/settings/proxy?resolve=connection-uuid"

๊ฒฐ์ •๋œ ํ”„๋ก์‹œ๋ฅผ ํ•ด๋‹น ์ˆ˜์ค€(account, provider ๋˜๋Š” global) ๋ฐ ์†Œ์Šค์™€ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜๋‚˜์˜ ํ”„๋ก์‹œ๋ฅผ ์—ฌ๋Ÿฌ ์ œ๊ณต์ž ๋˜๋Š” ์—ฐ๊ฒฐ์— ํ•œ ๋ฒˆ์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

ํ„ฐ๋ฏธ๋„ ์ฐฝ
curl -X POST http://localhost:20128/api/v1/management/proxies/bulk-assign \
-H "Content-Type: application/json" \
-d '{
"scope": "provider",
"scopeIds": ["openai", "anthropic", "codex"],
"proxyId": "proxy-uuid"
}'

ํ”„๋ก์‹œ๋Š” ๋ฐฑ์—…/๋ณต์› ์‹œ์Šคํ…œ์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. OmniRoute ๊ตฌ์„ฑ์„ ๋‚ด๋ณด๋‚ผ ๋•Œ๋Š” ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

  1. ๋Œ€์‹œ๋ณด๋“œ โ†’ ์„ค์ • โ†’ ๋ฐฑ์—…์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋‚ด๋ณด๋‚ด๊ธฐ๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ก์‹œ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์™€ ํ• ๋‹น์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
  3. ๋ณต์›ํ•˜๋ ค๋ฉด ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ํด๋ฆญํ•˜๊ณ  ๋ฐฑ์—… ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋ก์‹œ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋Š” host+port ๊ธฐ์ค€ upsert๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํ”„๋ก์‹œ(ํ˜ธ์ŠคํŠธ์™€ ํฌํŠธ๊ฐ€ ๋™์ผํ•จ)๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด ์ค‘๋ณต ํ•ญ๋ชฉ์„ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹  ๊ธฐ์กด ํ•ญ๋ชฉ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

์ด์ „ ๋ฒ„์ „(๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋„์ž… ์ „)์—์„œ ํ”„๋ก์‹œ๋ฅผ ๊ตฌ์„ฑํ•œ ๊ฒฝ์šฐ OmniRoute๊ฐ€ ํ•ด๋‹น ํ”„๋ก์‹œ๋ฅผ ์ž๋™์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•ฉ๋‹ˆ๋‹ค.

๋ ˆ๊ฑฐ์‹œ key_value ์ €์žฅ์†Œ โ†’ proxy_registry + proxy_assignments

์—…๊ทธ๋ ˆ์ด๋“œ ํ›„ ์ฒ˜์Œ ์‹œ์ž‘ํ•  ๋•Œ ํ•œ ๋ฒˆ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ ค๋ฉด migrateLegacyProxyConfigToRegistry({ force: true })๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.


๐Ÿ†• @oyi77 ๊ธฐ์—ฌ โ€” PR #1847 (์ด์Šˆ #1788)

OmniRoute๋Š” 1proxy ์ปค๋ฎค๋‹ˆํ‹ฐ ํ”Œ๋žซํผ๊ณผ ํ†ตํ•ฉ๋˜์–ด ์ „ ์„ธ๊ณ„์˜ ๊ฒ€์ฆ๋œ ๋ฌด๋ฃŒ ํ”„๋ก์‹œ ์ˆ˜๋ฐฑ ๊ฐœ์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ž์ฒด ํ”„๋ก์‹œ ์ธํ”„๋ผ๊ฐ€ ์—†๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” ๋™๊ธฐํ™” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” ์ˆœํ™˜ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 1proxy API โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ โ”‚ proxy_registry โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ โ”‚ ์ œ๊ณต์ž โ”‚
โ”‚ (์™ธ๋ถ€) โ”‚ ์ตœ๋Œ€ 500๊ฐœ โ”‚ source=oneproxy โ”‚ ํ’ˆ์งˆ ๊ธฐ์ค€ โ”‚ API โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ํ”„๋ก์‹œ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  1. ๋™๊ธฐํ™” โ€” OmniRoute๊ฐ€ 1proxy API์—์„œ ๊ฒ€์ฆ๋œ ํ”„๋ก์‹œ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
  2. ์ €์žฅ โ€” ํ”„๋ก์‹œ๋Š” ๋™์ผํ•œ proxy_registry ํ…Œ์ด๋ธ”์— source = 'oneproxy'๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค
  3. ํ•„ํ„ฐ๋ง โ€” ํ”„๋กœํ† ์ฝœ, ๊ตญ๊ฐ€, ํ’ˆ์งˆ ์ ์ˆ˜๋ณ„๋กœ ํ•„ํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค
  4. ์ˆœํ™˜ โ€” ํ’ˆ์งˆ, ๋ฌด์ž‘์œ„ ๋˜๋Š” ์ˆœ์ฐจ ์ „๋žต์„ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์ ์˜ ํ”„๋ก์‹œ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค
  5. ์ž๋™ ์„ฑ๋Šฅ ์ €ํ•˜ ์ฒ˜๋ฆฌ โ€” ์‹คํŒจํ•œ ํ”„๋ก์‹œ๋Š” ํ’ˆ์งˆ ์ ์ˆ˜๊ฐ€ ๊ฐ์†Œํ•˜๋ฉฐ, ์ž„๊ณ„๊ฐ’ ๋ฏธ๋งŒ์ด ๋˜๋ฉด โ†’ ๋น„ํ™œ์„ฑ ์ƒํƒœ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค

๋Œ€์‹œ๋ณด๋“œ์—์„œ:

  1. Settings โ†’ 1proxy ํƒญ์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค
  2. **โ€œSync Nowโ€**๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค
  3. ์ „์ฒด ํ”„๋ก์‹œ ์ˆ˜, ํ™œ์„ฑ ํ”„๋ก์‹œ ์ˆ˜, ํ‰๊ท  ํ’ˆ์งˆ, ๊ตญ๊ฐ€๋ณ„ ๋ถ„์„ ๋“ฑ ํ†ต๊ณ„๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค

API๋ฅผ ํ†ตํ•ด:

ํ„ฐ๋ฏธ๋„ ์ฐฝ
# ๋™๊ธฐํ™” ์‹คํ–‰
curl -X POST http://localhost:20128/api/settings/oneproxy \
-H "Content-Type: application/json" \
-d '{}'
# ์‘๋‹ต:
# { "success": true, "added": 127, "updated": 45, "failed": 2, "total": 172 }
ํ„ฐ๋ฏธ๋„ ์ฐฝ
# ํ”„๋กœํ† ์ฝœ๋ณ„ ํ•„ํ„ฐ๋ง
curl "http://localhost:20128/api/settings/oneproxy?protocol=socks5"
# ๊ตญ๊ฐ€๋ณ„ ํ•„ํ„ฐ๋ง
curl "http://localhost:20128/api/settings/oneproxy?countryCode=US"
# ์ตœ์†Œ ํ’ˆ์งˆ ์ ์ˆ˜๋ณ„ ํ•„ํ„ฐ๋ง
curl "http://localhost:20128/api/settings/oneproxy?minQuality=80"
# ํ•„ํ„ฐ ์กฐํ•ฉ
curl "http://localhost:20128/api/settings/oneproxy?protocol=http&countryCode=DE&minQuality=70"

๊ฐ 1proxy ํ”„๋ก์‹œ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค:

ํ•„๋“œ ์„ค๋ช…
qualityScore 1proxy ๊ฒ€์ฆ์—์„œ ๋ถ€์—ฌ๋œ 0-100์  ํ‰์ 
latencyMs ์ธก์ •๋œ ๋„คํŠธ์›Œํฌ ์ง€์—ฐ ์‹œ๊ฐ„
anonymity transparent, anonymous ๋˜๋Š” elite
googleAccess ํ”„๋ก์‹œ์˜ Google ์„œ๋น„์Šค ์•ก์„ธ์Šค ๊ฐ€๋Šฅ ์—ฌ๋ถ€
countryCode ๋‘ ๊ธ€์ž๋กœ ๋œ ISO ๊ตญ๊ฐ€ ์ฝ”๋“œ
lastValidated ๋งˆ์ง€๋ง‰ ๊ฒ€์ฆ ํƒ€์ž„์Šคํƒฌํ”„

ํ’ˆ์งˆ ์ ์ˆ˜๋Š” ๋™์ ์œผ๋กœ ์กฐ์ •๋ฉ๋‹ˆ๋‹ค:

  • ์‹คํŒจํ•œ ์š”์ฒญ์€ ์ ์ˆ˜๋ฅผ 10์  ๊ฐ์†Œ์‹œํ‚ต๋‹ˆ๋‹ค
  • ์ ์ˆ˜๊ฐ€ โ‰ค10์œผ๋กœ ๊ฐ์†Œ โ†’ ํ”„๋ก์‹œ๊ฐ€ inactive๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค
  • ๋น„ํ™œ์„ฑ ํ”„๋ก์‹œ๋Š” ์ˆœํ™˜ ๋Œ€์ƒ์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค
ํ„ฐ๋ฏธ๋„ ์ฐฝ
# ํ’ˆ์งˆ๋ณ„ ์ˆœํ™˜(์ตœ์ƒ์˜ ํ”„๋ก์‹œ ์šฐ์„ ) โ€” ๊ธฐ๋ณธ๊ฐ’
curl -X POST http://localhost:20128/api/settings/oneproxy/rotate \
-H "Content-Type: application/json" \
-d '{"strategy": "quality"}'
# ๋ฌด์ž‘์œ„ ์ˆœํ™˜
curl -X POST http://localhost:20128/api/settings/oneproxy/rotate \
-d '{"strategy": "random"}'
# ์ˆœ์ฐจ ์ˆœํ™˜(๊ฐ€์žฅ ์˜ค๋ž˜์ „์— ๊ฒ€์ฆ๋œ ํ”„๋ก์‹œ ์šฐ์„ )
curl -X POST http://localhost:20128/api/settings/oneproxy/rotate \
-d '{"strategy": "sequential"}'

1proxy ๋™๊ธฐํ™”์—๋Š” ์„œํ‚ท ๋ธŒ๋ ˆ์ด์ปค๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค:

  • ๋™๊ธฐํ™”๊ฐ€ 5ํšŒ ์—ฐ์† ์‹คํŒจํ•˜๋ฉด ์ดํ›„์˜ ๋™๊ธฐํ™” ์‹œ๋„๊ฐ€ ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค
  • resetOneproxyCircuitBreaker()๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์„œ๋ฒ„๋ฅผ ์žฌ์‹œ์ž‘ํ•˜์—ฌ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค
  • ๋™๊ธฐํ™” ์ƒํƒœ๋Š” GET /api/settings/oneproxy?action=status์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
ํ„ฐ๋ฏธ๋„ ์ฐฝ
# ๋‹จ์ผ 1proxy ํ”„๋ก์‹œ ์‚ญ์ œ
curl -X DELETE "http://localhost:20128/api/settings/oneproxy?id=proxy-uuid"
# ๋ชจ๋“  1proxy ํ”„๋ก์‹œ ์‚ญ์ œ(์ˆ˜๋™ ํ”„๋ก์‹œ๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€๋จ)
curl -X DELETE "http://localhost:20128/api/settings/oneproxy?clearAll=1"

OmniRoute๋Š” ๋‹จ์ˆœํžˆ ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ํŠธ๋ž˜ํ”ฝ์„ ๋ผ์šฐํŒ…ํ•˜๋Š” ๋ฐ ๊ทธ์น˜์ง€ ์•Š๊ณ , ํŠธ๋ž˜ํ”ฝ์ด ์ •์ƒ์ ์ธ ์š”์ฒญ์ฒ˜๋Ÿผ ๋ณด์ด๋„๋ก ๋งŒ๋“ญ๋‹ˆ๋‹ค.

wreq-js๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €์™€ ์œ ์‚ฌํ•œ TLS ํ•‘๊ฑฐํ”„๋ฆฐํŠธ๋ฅผ ์ƒ์„ฑํ•จ์œผ๋กœ์จ, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์•„๋‹Œ TLS ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ํƒ์ง€ํ•˜๋Š” ๋ด‡ ๊ฐ์ง€ ์‹œ์Šคํ…œ์„ ์šฐํšŒํ•ฉ๋‹ˆ๋‹ค.

CLI ํ•‘๊ฑฐํ”„๋ฆฐํŠธ ํ† ๊ธ€(์„ค์ • โ†’ ๋ณด์•ˆ)์€ ๋„ค์ดํ‹ฐ๋ธŒ CLI ๋ฐ”์ด๋„ˆ๋ฆฌ(Claude Code, Codex ๋“ฑ)์˜ ์ •ํ™•ํ•œ ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ์ผ์น˜ํ•˜๋„๋ก HTTP ํ—ค๋”์™€ JSON ๋ณธ๋ฌธ ํ•„๋“œ์˜ ์ˆœ์„œ๋ฅผ ์žฌ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ ํ”„๋ก์‹œ์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž IP(์ฐจ๋‹จ๋จ) โ†’ ํ”„๋ก์‹œ IP(๋ฏธ๊ตญ) โ†’ ์ œ๊ณต์ž API
+ TLS ์Šคํ‘ธํ•‘
+ CLI ํ•‘๊ฑฐํ”„๋ฆฐํŠธ

๋”ฐ๋ผ์„œ IP ๋งˆ์Šคํ‚น๊ณผ ์š”์ฒญ ์‹ ๋ขฐ์„ฑ์„ ๋™์‹œ์— ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€์‹œ๋ณด๋“œ์˜ ์ƒ‰์ƒ ๊ตฌ๋ถ„ ๋ฐฐ์ง€๋Š” ํ˜„์žฌ ํ™œ์„ฑํ™”๋œ ํ”„๋ก์‹œ ์ˆ˜์ค€์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

๋ฐฐ์ง€ ์ˆ˜์ค€ ์˜๋ฏธ
๐ŸŸข ์ „์—ญ ๋ชจ๋“  ํŠธ๋ž˜ํ”ฝ์ด ์ด ํ”„๋ก์‹œ๋ฅผ ํ†ต๊ณผํ•จ
๐ŸŸก ์ œ๊ณต์ž ์ด ์ œ๊ณต์ž์˜ ํŠธ๋ž˜ํ”ฝ๋งŒ ํ”„๋ก์‹œ๋ฅผ ํ†ต๊ณผํ•จ
๐Ÿ”ต ์—ฐ๊ฒฐ ์ด ํŠน์ • ํ‚ค/๊ณ„์ •์ด ์ด ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•จ

๋ฐฐ์ง€์—๋Š” ๊ฒ€์ฆ์„ ์œ„ํ•ด ํ™•์ธ๋œ ํ”„๋ก์‹œ IP๋„ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.


CLIProxyAPI ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ์ œ๊ณต์ž์— ๋Œ€ํ•ด OmniRoute๋Š” ์„ธ ๊ฐ€์ง€ ์—…์ŠคํŠธ๋ฆผ ํ”„๋ก์‹œ ๋ชจ๋“œ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“œ ์„ค๋ช…
native OmniRoute๊ฐ€ ํ”„๋ก์‹œ ๋ผ์šฐํŒ…์„ ์ง์ ‘ ์ฒ˜๋ฆฌํ•จ(๊ธฐ๋ณธ๊ฐ’)
cliproxyapi ์™ธ๋ถ€ CLIProxyAPI ์ธ์Šคํ„ด์Šค์— ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„ํ•จ
fallback ๋จผ์ € ๋„ค์ดํ‹ฐ๋ธŒ ๋ฐฉ์‹์„ ์‹œ๋„ํ•œ ํ›„ CLIProxyAPI๋กœ ๋Œ€์ฒดํ•จ

์ œ๊ณต์ž๋ณ„๋กœ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

ํ„ฐ๋ฏธ๋„ ์ฐฝ
curl -X PUT "http://localhost:20128/api/upstream-proxy/openai" \
-H "Content-Type: application/json" \
-d '{"mode": "native", "enabled": true}'

  • ์ „์—ญ ํ”„๋ก์‹œ ๊ตฌ์„ฑ(๋ชจ๋“  ํŠธ๋ž˜ํ”ฝ์— ๋Œ€ํ•ด ํ•œ ๋ฒˆ๋งŒ ์„ค์ •)
  • ์ œ๊ณต์ž๋ณ„ ํ”„๋ก์‹œ ์žฌ์ •์˜
  • ์—ฐ๊ฒฐ๋ณ„ ํ”„๋ก์‹œ ํ• ๋‹น
  • ๊ตฌ์„ฑ๋œ ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•œ ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ
  • ํ™œ์„ฑ ํ”„๋ก์‹œ ์ˆ˜์ค€์„ ๋ณด์—ฌ์ฃผ๋Š” ์ƒ‰์ƒ ๊ตฌ๋ถ„ ๋ฐฐ์ง€
  • ๋ฌด๋ฃŒ ํ”„๋ก์‹œ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ง€๊ธˆ ๋™๊ธฐํ™” ๋ฒ„ํŠผ
  • ํ†ต๊ณ„ ์นด๋“œ: ์ „์ฒด, ํ™œ์„ฑ, ํ‰๊ท  ํ’ˆ์งˆ, ๋งˆ์ง€๋ง‰ ๋™๊ธฐํ™”
  • ํ•„ํ„ฐ: ํ”„๋กœํ† ์ฝœ, ๊ตญ๊ฐ€ ์ฝ”๋“œ, ์ตœ์†Œ ํ’ˆ์งˆ
  • ํ˜ธ์ŠคํŠธ, ํ”„๋กœํ† ์ฝœ, ๊ตญ๊ฐ€, ํ’ˆ์งˆ ์ ์ˆ˜, ์ง€์—ฐ ์‹œ๊ฐ„, ์ต๋ช…์„ฑ, Google ์ ‘๊ทผ ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ํ‘œ์‹œํ•˜๋Š” ํ”„๋ก์‹œ ํ…Œ์ด๋ธ”
  • ์„ฑ๊ณต/์‹คํŒจ ์ถ”์  ๋ฐ ์—ฐ์† ์‹คํŒจ ํšŸ์ˆ˜๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๋™๊ธฐํ™” ์ƒํƒœ ํŒจ๋„
  • ๋ชจ๋“  1proxy ํ•ญ๋ชฉ์„ ์ œ๊ฑฐํ•˜๋Š” ๋ชจ๋‘ ์ง€์šฐ๊ธฐ

๋ฉ”์„œ๋“œ ์—”๋“œํฌ์ธํŠธ ์„ค๋ช…
GET /api/settings/proxy ์ „์ฒด ํ”„๋ก์‹œ ๊ตฌ์„ฑ ๊ฐ€์ ธ์˜ค๊ธฐ
GET /api/settings/proxy?level=global ์ „์—ญ ํ”„๋ก์‹œ ๊ฐ€์ ธ์˜ค๊ธฐ
GET /api/settings/proxy?level=provider&id=openai ์ œ๊ณต์ž ํ”„๋ก์‹œ ๊ฐ€์ ธ์˜ค๊ธฐ
GET /api/settings/proxy?resolve=connectionId ์œ ํšจ ํ”„๋ก์‹œ ํ™•์ธํ•˜๊ธฐ
PUT /api/settings/proxy ํ”„๋ก์‹œ ๊ตฌ์„ฑ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ
DELETE /api/settings/proxy?level=provider&id=openai ํ•ด๋‹น ์ˆ˜์ค€์˜ ํ”„๋ก์‹œ ์ œ๊ฑฐํ•˜๊ธฐ
๋ฉ”์„œ๋“œ ์—”๋“œํฌ์ธํŠธ ์„ค๋ช…
GET /api/v1/management/proxies ๋ชจ๋“  ํ”„๋ก์‹œ ๋‚˜์—ดํ•˜๊ธฐ
GET /api/v1/management/proxies?id=uuid ID๋กœ ํ”„๋ก์‹œ ๊ฐ€์ ธ์˜ค๊ธฐ
GET /api/v1/management/proxies?id=uuid&where_used=1 ํ”„๋ก์‹œ ํ• ๋‹น ๊ฐ€์ ธ์˜ค๊ธฐ
POST /api/v1/management/proxies ํ”„๋ก์‹œ ์ƒ์„ฑํ•˜๊ธฐ
PATCH /api/v1/management/proxies ํ”„๋ก์‹œ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ
DELETE /api/v1/management/proxies?id=uuid ํ”„๋ก์‹œ ์‚ญ์ œํ•˜๊ธฐ
DELETE /api/v1/management/proxies?id=uuid&force=1 ๊ฐ•์ œ๋กœ ์‚ญ์ œํ•˜๊ธฐ
POST /api/v1/management/proxies/bulk-assign ์ผ๊ด„ ํ• ๋‹นํ•˜๊ธฐ
GET /api/v1/management/proxies/assignments ํ• ๋‹น ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ
GET /api/v1/management/proxies/health ํ”„๋ก์‹œ ์ƒํƒœ ํ†ต๊ณ„ ๊ฐ€์ ธ์˜ค๊ธฐ

ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ์•„์›ƒ๋ฐ”์šด๋“œ ํŠธ๋ž˜ํ”ฝ์„ ๋ผ์šฐํŒ…ํ•˜๋Š” ๋Œ€์‹  OmniRoute ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์šฉ ์ธํ„ฐ๋„ท์— ๋…ธ์ถœํ•˜๋ ค๋ฉด(Cloudflare/ngrok/Tailscale) TUNNELS_GUIDE.md๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. ํ„ฐ๋„ REST API๋Š” /api/tunnels/{cloudflared,ngrok,tailscale}/* ์•„๋ž˜์— ์žˆ์œผ๋ฉฐ, ์œ„์—์„œ ์„ค๋ช…ํ•œ ์•„์›ƒ๋ฐ”์šด๋“œ ํ”„๋ก์‹œ ์ฒด์ธ๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค.

๋ฉ”์„œ๋“œ ์—”๋“œํฌ์ธํŠธ ์„ค๋ช…
GET /api/settings/oneproxy 1proxy ํ”„๋ก์‹œ ๋‚˜์—ดํ•˜๊ธฐ
GET /api/settings/oneproxy?action=stats ํ†ต๊ณ„ ๋ฐ ๋™๊ธฐํ™” ์ƒํƒœ ๊ฐ€์ ธ์˜ค๊ธฐ
GET /api/settings/oneproxy?action=status ๋™๊ธฐํ™” ์ƒํƒœ๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ
POST /api/settings/oneproxy ๋™๊ธฐํ™” ์‹คํ–‰ํ•˜๊ธฐ
POST /api/settings/oneproxy/rotate ๋‹ค์Œ ํ”„๋ก์‹œ๋กœ ์ „ํ™˜ํ•˜๊ธฐ
DELETE /api/settings/oneproxy?id=uuid ํ•˜๋‚˜ ์‚ญ์ œํ•˜๊ธฐ
DELETE /api/settings/oneproxy?clearAll=1 ๋ชจ๋‘ ์ง€์šฐ๊ธฐ
๋ฉ”์„œ๋“œ ์—”๋“œํฌ์ธํŠธ ์„ค๋ช…
GET /api/upstream-proxy/:providerId ์—…์ŠคํŠธ๋ฆผ ํ”„๋ก์‹œ ๊ตฌ์„ฑ ๊ฐ€์ ธ์˜ค๊ธฐ
PUT /api/upstream-proxy/:providerId ์—…์ŠคํŠธ๋ฆผ ํ”„๋ก์‹œ ๋ชจ๋“œ ์„ค์ •ํ•˜๊ธฐ
DELETE /api/upstream-proxy/:providerId ์—…์ŠคํŠธ๋ฆผ ํ”„๋ก์‹œ ๊ตฌ์„ฑ ์ œ๊ฑฐํ•˜๊ธฐ

๋ณ€์ˆ˜ ๊ธฐ๋ณธ๊ฐ’ ์„ค๋ช…
ENABLE_SOCKS5_PROXY true SOCKS5 ํ”„๋ก์‹œ ์ง€์› ํ™œ์„ฑํ™”(.env.example์˜ ๊ธฐ๋ณธ๊ฐ’์€ true)

.env ํŒŒ์ผ์—์„œ ENABLE_SOCKS5_PROXY=true๋กœ ์„ค์ •ํ•˜๊ณ  ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์„ธ์š”.

์œ ํœด ์—ฐ๊ฒฐ์„ ๋Š๋Š” ์ €๊ฐ€ํ˜• ํ”„๋ก์‹œ์—์„œ๋Š” ์ •์ƒ์ ์œผ๋กœ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. OmniRoute๋Š” ์ด๋ฏธ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ด๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • ํ”„๋ก์‹œ ์—ฐ๊ฒฐ์—์„œ keep-alive ๋น„ํ™œ์„ฑํ™”(keepAliveTimeout: 1)
  • ํŒŒ์ดํ”„๋ผ์ด๋‹ ๋น„ํ™œ์„ฑํ™”(pipelining: 0)
  • ๋ฐ˜๋ณต์ ์ธ ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋””์ŠคํŒจ์ฒ˜ ์บ์‹ฑ

๋ฌธ์ œ๊ฐ€ ๊ณ„์†๋˜๋ฉด ๋‹ค๋ฅธ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ 1proxy ๋กœํ…Œ์ด์…˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.

OAuth ํ๋ฆ„์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ํ”„๋ก์‹œ๊ฐ€ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. OmniRoute๋Š” ๊ตฌ์„ฑ๋œ ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด OAuth ํ† ํฐ ๊ตํ™˜์„ ๋ผ์šฐํŒ…ํ•ฉ๋‹ˆ๋‹ค. ๋จผ์ € ์ „์—ญ ๋˜๋Š” ๊ณต๊ธ‰์ž ์ˆ˜์ค€ ํ”„๋ก์‹œ๋ฅผ ์„ค์ •ํ•œ ๋‹ค์Œ ์—ฐ๊ฒฐํ•˜์„ธ์š”.

ํ™•์ธ ์ˆœ์„œ๋ฅผ ์ ๊ฒ€ํ•˜์„ธ์š”.

  1. GET /api/settings/proxy?resolve=your-connection-id๋กœ ํ™•์ธ
  2. ํ”„๋ก์‹œ status๊ฐ€ active์ธ์ง€ ํ™•์ธ(inactive๊ฐ€ ์•„๋‹ˆ์–ด์•ผ ํ•จ)
  3. ํ”„๋ก์‹œ ํ• ๋‹น ๋ฒ”์œ„๊ฐ€ ์—ฐ๊ฒฐ๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ

๋™๊ธฐํ™” ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

ํ„ฐ๋ฏธ๋„ ์ฐฝ
curl "http://localhost:20128/api/settings/oneproxy?action=status"

consecutiveFailures >= 5์ด๋ฉด ํšŒ๋กœ ์ฐจ๋‹จ๊ธฐ๊ฐ€ ์ž‘๋™ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์„œ๋ฒ„๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์—ฌ ์ดˆ๊ธฐํ™”ํ•˜๊ฑฐ๋‚˜ ์ˆ˜๋™์œผ๋กœ ์ดˆ๊ธฐํ™”๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์„ธ์š”.


CREATE TABLE proxy_registry (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
type TEXT NOT NULL DEFAULT 'http',
host TEXT NOT NULL,
port INTEGER NOT NULL,
username TEXT DEFAULT '',
password TEXT DEFAULT '',
region TEXT,
notes TEXT,
status TEXT DEFAULT 'active',
source TEXT NOT NULL DEFAULT 'manual', -- 'manual' ๋˜๋Š” 'oneproxy'
quality_score INTEGER, -- 0-100(1proxy ์ „์šฉ)
latency_ms INTEGER, -- ๋ฐ€๋ฆฌ์ดˆ(1proxy ์ „์šฉ)
anonymity TEXT, -- ํˆฌ๋ช…/์ต๋ช…/์—˜๋ฆฌํŠธ
google_access INTEGER DEFAULT 0, -- Google์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€? (1proxy)
last_validated TEXT, -- ISO ํƒ€์ž„์Šคํƒฌํ”„(1proxy)
country_code TEXT, -- ISO 2์ž๋ฆฌ ์ฝ”๋“œ(1proxy)
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE proxy_assignments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
proxy_id TEXT NOT NULL REFERENCES proxy_registry(id),
scope TEXT NOT NULL, -- 'global', 'provider', 'account', 'combo'
scope_id TEXT, -- ๊ณต๊ธ‰์ž ID, ์—ฐ๊ฒฐ ID ๋˜๋Š” ์กฐํ•ฉ ID
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
UNIQUE(scope, scope_id)
);

OmniRoute์˜ ํ”„๋ก์‹œ ๋น ๋ฅธ ์‹คํŒจ ๋ฉ”์ปค๋‹ˆ์ฆ˜(src/lib/proxyHealth.ts)์€ ๋น ๋ฅธ TCP ์—ฐ๊ฒฐ ๊ฒ€์‚ฌ๋ฅผ ํ†ตํ•ด 2์ดˆ ์ด๋‚ด์— ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ํ”„๋ก์‹œ๋ฅผ ๊ฐ์ง€ํ•œ ๋‹ค์Œ, ์š”์ฒญ๋ณ„ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑํ•ฉ๋‹ˆ๋‹ค.

์š”์ฒญ โ”€โ”€โ–ถ ProxyHealthCache.get(url)
โ”‚
โ”œโ”€ ์บ์‹œ ์ ์ค‘ + ์ตœ์‹  ์ƒํƒœ? โ”€โ”€โ–ถ ์บ์‹œ๋œ ์ƒํƒœ ๋ฐ˜ํ™˜
โ”‚
โ””โ”€ ์บ์‹œ ๋ˆ„๋ฝ / ์˜ค๋ž˜๋œ ์ƒํƒœ? โ”€โ”€โ–ถ host:port์— TCP ์—ฐ๊ฒฐ
(์ œํ•œ ์‹œ๊ฐ„: FAST_FAIL_TIMEOUT_MS)
โ”€โ”€โ–ถ HEALTH_CACHE_TTL_MS ๋™์•ˆ ์บ์‹ฑ
โ”€โ”€โ–ถ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜

์ด ๊ธฐ๋Šฅ์ด ์—†์œผ๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ํ”„๋ก์‹œ๋กœ ์ธํ•ด ๋ชจ๋“  ์š”์ฒญ์ด ์‹คํŒจํ•˜๊ธฐ ์ „๊นŒ์ง€ ์ „์ฒด PROXY_TIMEOUT_MS(๊ธฐ๋ณธ๊ฐ’ 30์ดˆ) ๋™์•ˆ ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค.

๋ณ€์ˆ˜ ๊ธฐ๋ณธ๊ฐ’ ์šฉ๋„
PROXY_FAST_FAIL_TIMEOUT_MS 2000 ์ƒํƒœ ํ™•์ธ๋‹น TCP ์—ฐ๊ฒฐ ์ œํ•œ ์‹œ๊ฐ„
PROXY_HEALTH_CACHE_TTL_MS 30000 ์ƒํƒœ ๊ฒฐ๊ณผ๊ฐ€ ์บ์‹ฑ๋˜๋Š” ๊ธฐ๊ฐ„

๊ถŒ์žฅ ๊ฐ’:

์‹œ๋‚˜๋ฆฌ์˜ค ๋น ๋ฅธ ์‹คํŒจ ์ œํ•œ ์‹œ๊ฐ„ ์บ์‹œ TTL ๊ทผ๊ฑฐ
์ฒ˜๋ฆฌ๋Ÿ‰์ด ๋†’์€ API ๊ฒŒ์ดํŠธ์›จ์ด 1500ms 60000ms ์ ๊ทน์ ์ธ ๋น ๋ฅธ ์‹คํŒจ, ๊ฒ€์‚ฌ ํšŸ์ˆ˜๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•œ ๋” ๊ธด ์บ์‹œ
์ง€๋ฆฌ์ ์œผ๋กœ ๋ถ„์‚ฐ๋œ ๋…ธ๋“œ 3000ms 15000ms ๋А๋ฆฐ ๋„คํŠธ์›Œํฌ์—๋Š” ๋” ๋งŽ์€ ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๋ฉฐ, ๋น ๋ฅธ ์žฅ์•  ์กฐ์น˜๋ฅผ ์œ„ํ•ด ๋” ์งง์€ ์บ์‹œ ์‚ฌ์šฉ
๊ฐœ๋ฐœ / ํ…Œ์ŠคํŠธ 1000ms 10000ms ๋กœ์ปฌ ํ”„๋ก์‹œ์—์„œ ๋น ๋ฅด๊ฒŒ ๋ฐ˜๋ณต ์ž‘์—…
์Šคํ…”์Šค / ํƒ์ง€ ๋ฐฉ์ง€ 2500ms 45000ms ์†๋„ ์ œํ•œ์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” ๋น ๋ฅธ ํƒ์ƒ‰ ๋ฐฉ์ง€
import { getAllProxyHealthStatuses, invalidateProxyHealth } from "omniroute/proxyHealth";
const statuses = getAllProxyHealthStatuses();
for (const s of statuses) {
console.log(`${s.proxyUrl} โ†’ healthy=${s.healthy}, stale=${s.stale}`);
}
// ํŠน์ • ํ”„๋ก์‹œ ๊ฐ•์ œ ์žฌ๊ฒ€์‚ฌ
invalidateProxyHealth("http://user:pass@203.0.113.7:8080");

์บ์‹œ ํ•ญ๋ชฉ์ด HEALTH_CACHE_TTL_MS๋ฅผ ์ดˆ๊ณผํ•˜์—ฌ ๋‹ค์Œ ์š”์ฒญ์—์„œ ์ƒˆ๋กœ์šด ๊ฒ€์‚ฌ๊ฐ€ ์‹คํ–‰๋  ๊ฒฝ์šฐ stale ํ”Œ๋ž˜๊ทธ๋Š” true์ž…๋‹ˆ๋‹ค.

์ƒํƒœ ํ™•์ธ์€ URL ์Šคํ‚ด์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์Šคํ‚ด ๊ธฐ๋ณธ ํฌํŠธ
http:// 8080
https:// 443
socks5:// / socks5h:// 1080

URL์˜ ์‚ฌ์šฉ์ž ์ง€์ • ํฌํŠธ(http://host:9999)๋Š” ํ•ญ์ƒ ์Šคํ‚ด ๊ธฐ๋ณธ๊ฐ’๋ณด๋‹ค ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค.


OmniRoute๋Š” ์šด์˜์ž๊ฐ€ ๋ผ์šฐํŒ… ํŒจํ„ด, ์ง€์—ฐ ์‹œ๊ฐ„ ๊ธ‰์ฆ ๋ฐ ๋ฐ˜๋ณต๋˜๋Š” ์žฅ์• ๋ฅผ ์ง„๋‹จํ•  ์ˆ˜ ์žˆ๋„๋ก ํ”„๋ก์‹œ๋ณ„ ์‚ฌ์šฉ๋Ÿ‰์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.

์„ค์ •๋œ ํ”„๋ก์‹œ๋ฅผ ํ†ต๊ณผํ•˜๋Š” ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•ด OmniRoute๋Š” ๋‹ค์Œ์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

๋ฉ”ํŠธ๋ฆญ ์„ค๋ช…
proxy_url ์ „์ฒด ํ”„๋ก์‹œ URL(์ธ์ฆ ์ž๊ฒฉ ์ฆ๋ช…์€ ๋งˆ์Šคํ‚น๋จ)
provider ์—…์ŠคํŠธ๋ฆผ ์ œ๊ณต์ž ID(openai, anthropic ๋“ฑ)
latency_ms ํ”„๋ก์‹œ ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ํฌํ•จํ•œ ์ „์ฒด ์™•๋ณต ์‹œ๊ฐ„
connect_ms TCP ์—ฐ๊ฒฐ ์‹œ๊ฐ„๋งŒ
status ์—…์ŠคํŠธ๋ฆผ์—์„œ ๋ฐ˜ํ™˜๋œ HTTP ์ƒํƒœ ์ฝ”๋“œ
error ์š”์ฒญ์ด ์‹คํŒจํ•œ ๊ฒฝ์šฐ ์˜ค๋ฅ˜ ํด๋ž˜์Šค
timestamp ISO 8601 UTC
ํ„ฐ๋ฏธ๋„ ์ฐฝ
# ์ตœ๊ทผ ํ”„๋ก์‹œ ์ด๋ฒคํŠธ
curl -H "Authorization: Bearer $OMNIROUTE_KEY" \
"http://localhost:20128/api/usage/proxy-logs?limit=100"

์‹ค์ œ ์—”๋“œํฌ์ธํŠธ๋Š” /api/usage/proxy-logs์ž…๋‹ˆ๋‹ค(src/app/api/usage/proxy-logs/route.ts ์ฐธ์กฐ). ์ด ์—”๋“œํฌ์ธํŠธ๋Š” ๋‹ค์Œ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

  • GET /api/usage/proxy-logs โ€” ํ”„๋ก์‹œ ๋กœ๊ทธ ์กฐํšŒ
  • DELETE /api/usage/proxy-logs โ€” ๋ชจ๋“  ํ”„๋ก์‹œ ๋กœ๊ทธ ์‚ญ์ œ

ํ•„์š”ํ•œ ๊ฒฝ์šฐ SQL์„ ํ†ตํ•ด proxy_logs ํ…Œ์ด๋ธ”์—์„œ ์ง‘๊ณ„ ํ†ต๊ณ„๋ฅผ ์ง์ ‘ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€์‹œ๋ณด๋“œ UI์—์„œ๋„ ์ง‘๊ณ„ ๋ณด๊ธฐ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ถˆ์•ˆ์ •ํ•œ ํ”„๋ก์‹œ ๊ฐ์ง€(์„ฑ๊ณต๊ณผ ์‹คํŒจ๊ฐ€ ๋ฒˆ๊ฐˆ์•„ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ):

SELECT proxy_url,
COUNT(*) AS total,
SUM(CASE WHEN status >= 500 THEN 1 ELSE 0 END) AS errors,
ROUND(100.0 * SUM(CASE WHEN status >= 500 THEN 1 ELSE 0 END) / COUNT(*), 1) AS error_pct
FROM proxy_logs
WHERE timestamp > datetime('now', '-1 hour')
GROUP BY proxy_url
HAVING error_pct > 5
ORDER BY error_pct DESC;

๋А๋ฆฐ ํ”„๋ก์‹œ ์ฐพ๊ธฐ(p95 ์ง€์—ฐ ์‹œ๊ฐ„ > 2์ดˆ):

WITH ranked AS (
SELECT proxy_url, latency_ms,
PERCENT_RANK() OVER (PARTITION BY proxy_url ORDER BY latency_ms) AS pct
FROM proxy_logs
WHERE timestamp > datetime('now', '-24 hour')
)
SELECT proxy_url, latency_ms
FROM ranked
WHERE pct >= 0.95
ORDER BY latency_ms DESC;

๋กœํ…Œ์ด์…˜ ์ „๋žต ์˜์‚ฌ ๊ฒฐ์ • ํŠธ๋ฆฌ

์„น์…˜ ์ œ๋ชฉ: โ€œ๋กœํ…Œ์ด์…˜ ์ „๋žต ์˜์‚ฌ ๊ฒฐ์ • ํŠธ๋ฆฌโ€

์—ฌ๋Ÿฌ ํ”„๋ก์‹œ๊ฐ€ ํ•˜๋‚˜์˜ ๋ฒ”์œ„์— ํ• ๋‹น๋˜๋ฉด OmniRoute๋Š” ๊ฐ ์š”์ฒญ์— ์‚ฌ์šฉํ•  ํ”„๋ก์‹œ๋ฅผ ์„ ํƒํ•˜๊ธฐ ์œ„ํ•ด ๋กœํ…Œ์ด์…˜ ์ „๋žต์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ „๋žต์€ ๋ฒ”์œ„ ์ˆ˜์ค€(์ „์—ญ, ์ œ๊ณต์ž๋ณ„, ๊ณ„์ •๋ณ„, ์กฐํ•ฉ๋ณ„)์—์„œ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

์ „๋žต ์‚ฌ์šฉ ์‹œ์  ์žฅ๋‹จ์ 
quality (๊ธฐ๋ณธ๊ฐ’) ํ’ˆ์งˆ์ด ์„œ๋กœ ๋‹ค๋ฅธ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ๋•์…˜ ํ‰์ ์ด ๋†’์€ ํ”„๋ก์‹œ๋ฅผ ์„ ํ˜ธํ•˜๋ฉฐ, ๋‚ฎ์€ ํ”„๋ก์‹œ๋Š” ๋ฐฐ์ œ๋  ์ˆ˜ ์žˆ์Œ
random ๋ถ€ํ•˜ ๋ถ„์‚ฐ, ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ ๊ณ ๋ฅด๊ฒŒ ๋ถ„์‚ฐ๋˜์ง€๋งŒ ํ’ˆ์งˆ ์‹ ํ˜ธ๋ฅผ ๋ฌด์‹œํ•จ
sequential ๋””๋ฒ„๊น…, ๊ฒฐ์ •๋ก ์  ํ…Œ์ŠคํŠธ ํ”„๋ก์‹œ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์ˆœํ™˜ํ•˜๋ฏ€๋กœ ๋™์ž‘์„ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์›€
ํ”„๋ก์‹œ์˜ ํ’ˆ์งˆ ์ ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?
โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ โ”‚
์˜ˆ ์•„๋‹ˆ์š”
โ”‚ โ”‚
๋ชจ๋“  ํ”„๋ก์‹œ์˜ โ”‚
ํ’ˆ์งˆ์ด ๋Œ€์ฒด๋กœ โ”‚
๋™์ผํ•ฉ๋‹ˆ๊นŒ? โ”‚
โ”‚ โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ โ”‚
์˜ˆ ์•„๋‹ˆ์š” ์‚ฌ์šฉ
โ”‚ โ”‚ `random`
โ”‚ โ”‚ (๊ณ ๋ฅด๊ฒŒ ๋ถ„์‚ฐํ•˜์—ฌ
โ”‚ โ”‚ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ํ’ˆ์งˆ
โ”‚ โ”‚ ๋ฐ์ดํ„ฐ ์ถ•์ )
โ”‚ โ”‚
โ”‚ `quality` ์‚ฌ์šฉ
โ”‚ (์„œ๋กœ ๋‹ค๋ฅธ ํ’ˆ์งˆ์—
โ”‚ ๊ฐ€์žฅ ์ ํ•ฉ)
โ”‚
`random` ์‚ฌ์šฉ
(๋ถ€ํ•˜๋ฅผ ๊ณ ๋ฅด๊ฒŒ
๋ถ„์‚ฐ)

1proxy ๋งˆ์ผ“ํ”Œ๋ ˆ์ด์Šค ํ’€์€ ์ด๋ฏธ ์‹คํŒจํ•œ ํ”„๋ก์‹œ์˜ ๋“ฑ๊ธ‰์„ ์ž์ฒด์ ์œผ๋กœ ์ž๋™ ํ•˜ํ–ฅ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค(ํ”„๋ก์‹œ ํ’ˆ์งˆ ์ ์ˆ˜ ์ฐธ์กฐ). ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์ง์ ‘ ์ถ”๊ฐ€ํ•œ ํ”„๋ก์‹œ์˜ ๊ฒฝ์šฐ, ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ƒํƒœ ์Šค์ผ€์ค„๋Ÿฌ(src/lib/proxyHealth/scheduler.ts)๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ์‚ญ์ œํ•˜์ง€ ์•Š์œผ๋ฉด์„œ ๋™์ผํ•œ โ€œ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ตฌ์„ฑ์›์„ ์ฒด์ธ์—์„œ ์ž๋™ ์ œ์™ธโ€ํ•˜๋Š” ๋™์ž‘์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

ํ„ฐ๋ฏธ๋„ ์ฐฝ
# .env โ€” ์—ฐ์†๋œ ํ”„๋กœ๋ธŒ๊ฐ€ 3๋ฒˆ ์‹คํŒจํ•˜๋ฉด ํ”„๋ก์‹œ๋ฅผ ์ผ์‹œ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”ํ•˜๊ณ ,
# ํ”„๋กœ๋ธŒ์— ๋‹ค์‹œ ์‘๋‹ตํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด ์ž๋™์œผ๋กœ ๋‹ค์‹œ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.
PROXY_AUTO_DISABLE=true
PROXY_AUTO_REMOVE_AFTER=3

๋‹ค์ค‘ ํ”„๋ก์‹œ ์ฒด์ธ์—์„œ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ์Šค์ผ€์ค„๋Ÿฌ๋Š” ๋“ฑ๋ก๋œ ๋ชจ๋“  ํ”„๋ก์‹œ๋ฅผ PROXY_HEALTH_INTERVAL_MS ๊ฐ„๊ฒฉ์œผ๋กœ ํ”„๋กœ๋ธŒํ•ฉ๋‹ˆ๋‹ค (๊ธฐ๋ณธ๊ฐ’ 10๋ถ„, ์ตœ์†Ÿ๊ฐ’ 1๋ถ„).
  2. ์—ฐ์†์œผ๋กœ PROXY_AUTO_REMOVE_AFTER๋ฒˆ์˜ ํ™•์ •์  ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด(์‹ค์ œ ์—ฐ๊ฒฐ ์žฅ์• ๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ, ์‹œ๊ฐ„ ์ดˆ๊ณผ ๋˜๋Š” ํ”„๋กœ๋ธŒ ๋Œ€์ƒ ์ž์ฒด์˜ 5xx ์‘๋‹ต์€ ์ ˆ๋Œ€ ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ”„๋ก์‹œ ์ƒํƒœ ํ™•์ธ ์ฐธ์กฐ), ํ”„๋ก์‹œ์˜ status๊ฐ€ dead๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
  3. dead๋Š” ํ’€/๋กœํ…Œ์ด์…˜ ํ•ด์„์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํ™œ์„ฑ ์ƒํƒœ ํ•„ํ„ฐ๊ฐ€ ์ œ์™ธํ•˜๋Š” ์ƒํƒœ ์ค‘ ํ•˜๋‚˜์ด๋ฏ€๋กœ, ํ•ด๋‹น ๋ฒ”์œ„์˜ ๋กœํ…Œ์ด์…˜(๋ผ์šด๋“œ ๋กœ๋นˆ / ๋ฌด์ž‘์œ„ / ๊ณ ์ • / ์ง€์—ฐ ์‹œ๊ฐ„ โ€” ๋กœํ…Œ์ด์…˜ ์ „๋žต ๊ฒฐ์ • ํŠธ๋ฆฌ ์ฐธ์กฐ)์€ ์ƒˆ ์š”์ฒญ์— ํ•ด๋‹น ํ”„๋ก์‹œ๋ฅผ ์ฆ‰์‹œ ํ• ๋‹นํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ’€์˜ ๋‹ค๋ฅธ ํ”„๋ก์‹œ๋Š” ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š์œผ๋ฉฐ, ์ „์ฒด ํ’€์ด ์ธ์ง€๋˜์ง€ ์•Š์€ ์ฑ„ ์ง์ ‘ ์—ฐ๊ฒฐ๋กœ ๋Œ€์ฒด๋˜๋Š” ์ผ๋„ ์—†์Šต๋‹ˆ๋‹ค. ํŽ˜์ผ ํด๋กœ์ฆˆ ๋ณดํ˜ธ ๊ธฐ๋Šฅ์€ 4๋‹จ๊ณ„ ํ”„๋ก์‹œ ์‹œ์Šคํ…œ์„ ์ฐธ์กฐํ•˜์„ธ์š”.
  4. ์Šค์ผ€์ค„๋Ÿฌ๋Š” ๋™์ผํ•œ ๊ฐ„๊ฒฉ์œผ๋กœ dead ํ”„๋ก์‹œ๋ฅผ ๊ณ„์† ํ”„๋กœ๋ธŒํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ํ”„๋กœ๋ธŒ๊ฐ€ ์„ฑ๊ณตํ•˜๋ฉด status๊ฐ€ ๋‹ค์‹œ active๋กœ ์ „ํ™˜๋˜๊ณ  ํ”„๋ก์‹œ๋Š” ๋กœํ…Œ์ด์…˜์— ์žฌ์ง„์ž…ํ•ฉ๋‹ˆ๋‹ค. ์ˆ˜๋™์œผ๋กœ ๋‹ค์‹œ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์€ ์˜๋„์ ์œผ๋กœ ์˜ตํŠธ์ธ ๋ฐฉ์‹์ด๋ฉฐ ๋น„ํŒŒ๊ดด์ ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์Šค์ผ€์ค„๋Ÿฌ๋Š” ์‹คํŒจ ํšŸ์ˆ˜๋ฅผ ์ง‘๊ณ„ํ•˜๊ณ  ๋กœ๊ทธ๋งŒ ๊ธฐ๋กํ•˜๋ฉฐ(decision.ts์˜ ์ •์ฑ… C ์ฐธ์กฐ), PROXY_AUTO_DISABLE์€ ํ–‰์„ ์‚ญ์ œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ–‰ ์‚ญ์ œ๋Š” ๋ณ„๋„์˜ ๋” ๊ฐ•๋ ฅํ•œ PROXY_AUTO_REMOVE ํ”Œ๋ž˜๊ทธ๊ฐ€ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค true๋กœ ์„ค์ •๋œ ๊ฒฝ์šฐ PROXY_AUTO_REMOVE๊ฐ€ ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค(๊ณง ์‚ญ์ œ๋  ํ”„๋ก์‹œ๋ฅผ ์ค‘๊ฐ„์— ์ผ์‹œ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”ํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค). ์ „์ฒด ๋ณ€์ˆ˜ ๋ชฉ๋ก์€ ํ™˜๊ฒฝ ๊ตฌ์„ฑ ์ฐธ์กฐ ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.


๐Ÿ“– ๊ด€๋ จ ๋ฌธ์„œ:


OmniRoute ์†Œ์Šค ์ฝ”๋“œ (a58000c7685f)

HagiCode

HagiCode๋Š” ๊ตฌ์กฐํ™”๋œ ์›Œํฌํ”Œ๋กœ, ๋‹ค์ค‘ ์—์ด์ „ํŠธ ์‹คํ–‰, Hero Dungeon ๋ทฐ๋ฅผ ๊ฐ–์ถ˜ ์—์ด์ „ํŠธ ์ฝ”๋”ฉ ์ž‘์—… ๊ณต๊ฐ„์ž…๋‹ˆ๋‹ค.

๋” ์Šค๋งˆํŠธํ•˜๊ณ  ๋น ๋ฅด๋ฉฐ ์ฆ๊ฑฐ์šด ์—์ด์ „ํŠธ ์›Œํฌํ”Œ๋กœ๋กœ ์œ ์šฉํ•œ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ๋งŒ๋“œ์„ธ์š”.

HagiCode ๋ผ์ดํŠธ ํ…Œ๋งˆ ๋ฉ”์ธ ํ™”๋ฉด
  • Smart๊ตฌ์กฐํ™”๋œ ์›Œํฌํ”Œ๋กœ๋Š” ์˜๋„๋ฅผ ์•„์ด๋””์–ด๋ถ€ํ„ฐ ๋ฐฐํฌ๊นŒ์ง€ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ๊ฒฝ๋กœ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
  • Efficient๋‹ค์ค‘ ์—์ด์ „ํŠธ ์›Œํฌํ”Œ๋กœ๋กœ ์กฐ์‚ฌ, ๊ตฌํ˜„, ๊ฒ€ํ† ๋ฅผ ๋ณ‘๋ ฌ๋กœ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • FunHero Dungeon์€ ๊ธด ์ฝ”๋”ฉ ์„ธ์…˜์„ ์‹œ๊ฐ์ ์ด๊ณ  ํ˜‘์—…์ ์ธ ๊ฒฝํ—˜์œผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
HagiCode ๋ฐฉ๋ฌธ