* docs: move superpowers/research artifacts to isolated _tasks repo + docs tree cleanup
- Move docs/superpowers/{plans,specs} and docs/research/* into the gitignored,
separately-versioned _tasks/ repo; untrack the two tracked research design docs.
- Add CLAUDE.md "Planning & Research Artifacts" section overriding the superpowers
default save paths (docs/... -> _tasks/...); align REPOSITORY_MAP and
DOCUMENTATION_OVERHAUL_PLAN with the new convention.
- Drop 4 now-obsolete /api/discovery/* entries from check-docs-symbols allowlist
(stale-enforcement) and refresh code/spec path comments to _tasks/...
- Sweeps in concurrent docs-tree restructuring (root-level provider/guide docs,
compression spec cleanup, .mcp.json.example removal).
* docs: reorganize docs/ tree + fix stale facts across ~26 docs
Phase A — reorganization:
- Move 7 orphan root docs into subfolders (providers/ created; TIERS+USAGE_QUOTA→guides/;
plugins+PLUGIN_SDK→frameworks/); delete 8 obsolete/redundant docs (SUBMIT_PR superseded
by CONTRIBUTING; DOCUMENTATION_OVERHAUL_PLAN; INCIDENT_RESPONSE/PERF_BUDGETS/THREAT_MODEL;
3 ops snapshots). Rebuild README index (was missing ~40 files) + per-folder meta.json nav.
- Clean 14 dangling doc-path references in bin/ ops scripts, scripts/, workflow, tests;
fix the dockerignore-docs-coverage required-docs path (PROVIDERS→providers/CLAUDE_WEB).
Phase B — content accuracy (verified against code, not the audit summary):
- Functional: ENVIRONMENT flag defaults (INPUT_SANITIZER/MCP_ENFORCE_SCOPES=true,
COMPRESS_DESCRIPTIONS=false, dynamic heap); MCP-SERVER notion tool names (omniroute_*→
notion_*) + counts 87→94; coverage gate 75/70→60/60/60/60 (RELEASE_CHECKLIST, COVERAGE_PLAN,
ERROR_SANITIZATION, CONTRIBUTING); pre-push hook description; regenerate PROVIDER_REFERENCE (237).
- Count drift: providers 237, executors 70, migrations 106, db modules 94, oauth 19,
strategies 17, MCP 94, flags 38, TS 6.0, open-sse ~900/services 294 across architecture/
frameworks/ops docs; AUTO-COMBO 9→12 factors w/ correct DEFAULT_WEIGHTS; REASONING +2
patterns; STEALTH UA defaults; AGENT_PROTOCOLS +cursor-cloud/list-capabilities;
LANGUAGE_PACKS +id pack.
- Kept Node 20 (runtime guard accepts 20.20.2+; only engines is stricter) and MCP scopes=13
(mcpScopes.ts) — both were correct in the docs; corrected only the attribution.
* docs: finish content refresh — compression engines, CLI_TOKEN merge, metadata sweep
- Compression: document the additional built-in engines (CCR, headroom, ionizer,
session-dedup) in COMPRESSION_ENGINES; clarify LLMLingua-2 is the ultra-mode SLM
backend + cross-ref the extra engines in EXTENDING_COMPRESSION; add the id
(Indonesian) language pack to LANGUAGE_PACKS.
- AUTO-COMBO: replace the orphan 'How tiers fit' weight table (stale weights) with a
pointer to the canonical 12-factor DEFAULT_WEIGHTS table.
- Security: merge CLI_TOKEN_AUTH.md (legacy 32-char SHA-256 format) into CLI_TOKEN.md
as a 'Legacy format — still accepted' section (server accepts both HMAC + legacy),
delete CLI_TOKEN_AUTH.md, drop it from the index + security nav.
- Metadata: bump stale frontmatter (version/lastUpdated) to 3.8.40/2026-06-28 across the
doc set audited this pass, and normalize the in-body 'Last updated' header lines to match.
* fix(runtime): drop Node 20 from supported range + align all docs/diagrams/counts
- Node minimum is now 22 (aligned with package.json engines). SUPPORTED_NODE_RANGE in
src/shared/utils/nodeRuntimeSupport.ts (and the bin/ mirror) drops the 20.x line →
'>=22.22.2 <23 || >=24.0.0 <27'; getNodeRuntimeSupport now rejects Node 20 as
unsupported-major. Test updated (TDD): node-runtime-support.test.ts asserts Node 20
rejected. Docs aligned (TROUBLESHOOTING ×2, TERMUX, RELEASE_CHECKLIST, CODEBASE,
CLI-TOOLS, README, llm.txt + 42 i18n llm.txt mirrors, skills/cli-serve).
- Diagrams regenerated: mcp-tools-87 -> mcp-tools-94 (34 base + pool 6 = 94) and
auto-combo-9factor -> auto-combo-12factor (correct DEFAULT_WEIGHTS); SVGs re-rendered
via mermaid-cli; doc refs + diagrams/README updated; fixed a pre-existing broken
resilience-3layers image path.
- CLAUDE.md + AGENTS.md aligned to real counts (237 providers, 94 MCP tools / 34 base,
106 migrations, 94 db modules, 12-factor auto-combo, 17 strategies); README provider
count 231 -> 237; executor count corrected to 68 (provider executors, excl base/index)
and OAuth to 18 across architecture docs. check:docs-all now passes (0 strict drift,
0 broken links); removed dead .mcp.json.example doc link.
* fix(services): update installer Node hint to >=22.22.2 (aligned with dropped Node 20)
* docs: realign counts to current release tip after rebase
The release tip advanced while this work was in flight (Gemini CLI provider/executor
removed by #5246, plus other PRs). Re-counted against the current code and updated:
providers 237->236, executors 68->67, OAuth modules 18->17, open-sse services 294->298;
regenerated PROVIDER_REFERENCE.md (236). check:docs-all passes (0 strict drift).
* docs(changelog) + i18n: record Node 20 drop + fix nodeIncompatibleHint
- CHANGELOG: add [3.8.40] entries for the Node 20.x removal (runtime) and the docs
reorganization/accuracy audit.
- i18n: nodeIncompatibleHint across all 42 locales no longer lists Node 20.x as
supported (ASCII + CJK full-width variants), aligned with the dropped Node 20.
* fix(docs): repair CI breakages from the doc moves
- test: cli-plugin-system asserted docs/dev/plugins.md exists; the file moved to
docs/frameworks/PLUGINS.md — point the test at the new path (Unit fast-path 2/2 fix).
- frontmatter: PLUGINS.md and PLUGIN_SDK.md moved into the fumadocs-indexed
docs/frameworks/ which requires a 'title' frontmatter; the missing frontmatter
failed the Next.js MDX build (dast-smoke 'invalid frontmatter'). Added frontmatter
to both, plus the providers/ docs (consistency; that folder is not indexed).
33 KiB
title, version, lastUpdated
| title | version | lastUpdated |
|---|---|---|
| 🌐 OmniRoute Proxy Guide | 3.8.40 | 2026-06-28 |
🌐 OmniRoute Proxy Guide
Bypass geographic blocks, protect your identity, and route AI traffic through any proxy — with zero configuration complexity.
OmniRoute includes a full-featured proxy management system that lets you route upstream AI provider traffic through HTTP, HTTPS, or SOCKS5 proxies. Whether you're in a blocked region, need IP rotation, or want stealth fingerprinting — this guide covers everything.
Table of Contents
- Why Use Proxies?
- Architecture Overview
- 4-Level Proxy System
- Proxy Registry (CRUD)
- 1proxy Free Marketplace
- Proxy Rotation
- Anti-Detection & Stealth
- Upstream Proxy Modes
- Dashboard UI
- API Reference
- Environment Variables
- Troubleshooting
Why Use Proxies?
Many AI providers restrict access by geographic region. Developers in Russia, China, Iran, Cuba, Turkey, and other countries encounter errors like:
unsupported_country_region_territory
Even outside blocked regions, proxies are useful for:
| Use Case | Description |
|---|---|
| Geographic bypass | Access OpenAI, Anthropic, Codex, Copilot from blocked countries |
| IP rotation | Distribute requests across multiple IPs to avoid rate limiting |
| Privacy | Hide your real IP from upstream providers |
| Compliance | Route traffic through specific jurisdictions |
| Testing | Simulate requests from different regions |
Architecture Overview
┌───────────────────────────────────────────────────────────────┐
│ OmniRoute Server │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Proxy │ │ Proxy │ │ Proxy │ │
│ │ Registry │───▶│ Dispatcher │───▶│ Fetch (undici) │ │
│ │ (SQLite) │ │ (cached) │ │ │ │
│ └─────────────┘ └──────────────┘ └────────┬─────────┘ │
│ ▲ │ │
│ │ ▼ │
│ ┌──────┴──────┐ ┌──────────────────┐ │
│ │ 1proxy Sync │ │ Upstream │ │
│ │ (free pool) │ │ Provider API │ │
│ └─────────────┘ └──────────────────┘ │
└───────────────────────────────────────────────────────────────┘
Key Components
| Component | File | Role |
|---|---|---|
| Proxy Registry | src/lib/db/proxies.ts |
CRUD for proxy entries + scope assignments |
| Proxy Dispatcher | open-sse/utils/proxyDispatcher.ts |
Creates undici ProxyAgent/SOCKS dispatchers with caching |
| Proxy Fetch | open-sse/utils/proxyFetch.ts |
Wraps fetch() with proxy dispatcher injection |
| Settings Route | src/app/api/settings/proxy/route.ts |
Legacy proxy config API (GET/PUT/DELETE) |
| Management Route | src/app/api/v1/management/proxies/route.ts |
Registry CRUD API (GET/POST/PATCH/DELETE) |
| 1proxy DB | src/lib/db/oneproxy.ts |
Free proxy marketplace persistence |
| 1proxy Sync | src/lib/oneproxySync.ts |
Fetches proxies from 1proxy API |
| 1proxy Rotator | src/lib/oneproxyRotator.ts |
Rotation strategies (quality/random/sequential) |
4-Level Proxy System
OmniRoute supports proxy configuration at four independent scopes, resolved in priority order:
Priority Resolution Order (highest → lowest):
1. 🔵 Account/Connection Proxy → per API key / OAuth connection
2. 🟡 Provider Proxy → per provider (e.g., all OpenAI traffic)
3. 🟠 Combo Proxy → per combo/routing configuration
4. 🟢 Global Proxy → all traffic, all providers
How Resolution Works
When OmniRoute sends a request to an upstream provider, it calls resolveProxyForConnectionFromRegistry() which checks each level in order:
- Account-level — Is there a proxy assigned to this specific connection ID?
- Provider-level — Is there a proxy assigned to this provider (e.g.,
openai)? - Global-level — Is there a global proxy configured?
- No proxy — Direct connection to the provider.
The first match wins. This means you can set a global proxy as a fallback but override it for specific providers or connections.
What Gets Proxied
| Traffic Type | Proxied? | Notes |
|---|---|---|
| Chat completions | ✅ | All /v1/chat/completions requests |
| Embeddings | ✅ | /v1/embeddings |
| Image generation | ✅ | /v1/images/generations |
| Audio (TTS/STT) | ✅ | /v1/audio/* |
| OAuth token exchange | ✅ | Solves unsupported_country_region_territory |
| Connection tests | ✅ | "Test Connection" button uses proxy |
| Token refresh | ✅ | Background OAuth renewal |
| Model sync | ✅ | Model listing and discovery |
Proxy Registry (CRUD)
The proxy registry is a SQLite table (proxy_registry) that stores all your proxies. Each proxy has:
| Field | Type | Description |
|---|---|---|
id |
UUID | Unique identifier |
name |
String | Human-readable label |
type |
String | Protocol: http, https, socks5 |
host |
String | Proxy hostname or IP |
port |
Integer | Port number |
username |
String | Auth username (encrypted at rest) |
password |
String | Auth password (encrypted at rest) |
region |
String | Geographic region label |
notes |
String | Free-text notes |
status |
String | active or inactive |
source |
String | manual or oneproxy |
Creating a Proxy
Via Dashboard:
- Go to Settings → Proxy
- Click Add Proxy
- Fill in the type, host, port, and optional auth credentials
- Save
Via 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"
}'
Updating a Proxy
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
}'
Note: Credentials are preserved unless you explicitly send non-empty replacements. Sending empty strings for
username/passwordwill keep the stored values.
Deleting a Proxy
# Fails if proxy is assigned to any scope
curl -X DELETE "http://localhost:20128/api/v1/management/proxies?id=proxy-uuid"
# Force delete (removes assignments too)
curl -X DELETE "http://localhost:20128/api/v1/management/proxies?id=proxy-uuid&force=1"
Listing Proxies
curl "http://localhost:20128/api/v1/management/proxies?limit=50&offset=0"
Assigning Proxies to Scopes
# Assign to global scope
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}}'
# Assign to a specific provider
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}}'
# Assign to a specific connection/key
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}}'
Resolving Effective Proxy
Check which proxy would be used for a given connection:
curl "http://localhost:20128/api/settings/proxy?resolve=connection-uuid"
Returns the resolved proxy with its level (account, provider, or global) and source.
Bulk Assignment
Assign one proxy to multiple providers or connections at once:
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"
}'
Import/Export
Proxies are included in the Backup/Restore system. When you export your OmniRoute configuration:
- Go to Dashboard → Settings → Backup
- Click Export — proxy registry and assignments are included
- To restore, click Import and upload the backup file
The proxy registry also supports upsert by host+port — if you import a proxy that already exists (same host and port), it updates instead of creating a duplicate.
Legacy Migration
If you configured proxies in an older version (pre-registry), OmniRoute automatically migrates them:
Legacy key_value store → proxy_registry + proxy_assignments
This happens once on first startup after upgrade. Use migrateLegacyProxyConfigToRegistry({ force: true }) to re-run.
1proxy Free Proxy Marketplace
OmniRoute integrates with the 1proxy community platform to provide access to hundreds of free, validated proxies from around the world. This is perfect for users who don't have their own proxy infrastructure.
How It Works
┌─────────────┐ Sync ┌─────────────────┐ Rotate ┌──────────┐
│ 1proxy API │ ────────────▶ │ proxy_registry │ ────────────▶ │ Provider │
│ (external) │ up to 500 │ source=oneproxy │ by quality │ API │
└─────────────┘ proxies └─────────────────┘ └──────────┘
- Sync — OmniRoute fetches validated proxies from the 1proxy API
- Store — Proxies are saved in the same
proxy_registrytable withsource = 'oneproxy' - Filter — Filter by protocol, country, quality score
- Rotate — Pick the best proxy using quality, random, or sequential strategies
- Auto-degrade — Failed proxies get their quality score reduced; below threshold → marked inactive
Syncing Proxies
Via Dashboard:
- Go to Settings → 1proxy tab
- Click "Sync Now"
- View stats: total proxies, active count, average quality, by-country breakdown
Via API:
# Trigger sync
curl -X POST http://localhost:20128/api/settings/oneproxy \
-H "Content-Type: application/json" \
-d '{}'
# Response:
# { "success": true, "added": 127, "updated": 45, "failed": 2, "total": 172 }
Filtering Proxies
# Filter by protocol
curl "http://localhost:20128/api/settings/oneproxy?protocol=socks5"
# Filter by country
curl "http://localhost:20128/api/settings/oneproxy?countryCode=US"
# Filter by minimum quality score
curl "http://localhost:20128/api/settings/oneproxy?minQuality=80"
# Combine filters
curl "http://localhost:20128/api/settings/oneproxy?protocol=http&countryCode=DE&minQuality=70"
Proxy Quality Scores
Each 1proxy proxy comes with metadata:
| Field | Description |
|---|---|
qualityScore |
0-100 rating from 1proxy validation |
latencyMs |
Measured network latency |
anonymity |
transparent, anonymous, or elite |
googleAccess |
Whether the proxy can access Google services |
countryCode |
Two-letter ISO country code |
lastValidated |
Timestamp of last validation |
Quality scores are dynamically adjusted:
- Failed requests reduce the score by 10 points
- Score drops to ≤10 → proxy is marked
inactive - Inactive proxies are excluded from rotation
Rotation Strategies
# Rotate by quality (best proxy first) — default
curl -X POST http://localhost:20128/api/settings/oneproxy/rotate \
-H "Content-Type: application/json" \
-d '{"strategy": "quality"}'
# Random rotation
curl -X POST http://localhost:20128/api/settings/oneproxy/rotate \
-d '{"strategy": "random"}'
# Sequential (least recently validated first)
curl -X POST http://localhost:20128/api/settings/oneproxy/rotate \
-d '{"strategy": "sequential"}'
Circuit Breaker
The 1proxy sync has a built-in circuit breaker:
- After 5 consecutive sync failures, further sync attempts are blocked
- Reset with:
resetOneproxyCircuitBreaker()or restart the server - Sync status is available at
GET /api/settings/oneproxy?action=status
Clearing 1proxy Proxies
# Delete a single 1proxy proxy
curl -X DELETE "http://localhost:20128/api/settings/oneproxy?id=proxy-uuid"
# Clear ALL 1proxy proxies (manual proxies are untouched)
curl -X DELETE "http://localhost:20128/api/settings/oneproxy?clearAll=1"
Anti-Detection & Stealth
OmniRoute doesn't just route traffic through a proxy — it makes the traffic look legitimate:
TLS Fingerprint Spoofing
Uses wreq-js to generate browser-like TLS fingerprints, bypassing bot detection systems that flag non-browser TLS handshakes.
CLI Fingerprint Matching
The CLI Fingerprint Toggle (Settings → Security) reorders HTTP headers and JSON body fields to match the exact signature of native CLI binaries (Claude Code, Codex, etc.). This works on top of the proxy:
Your IP (blocked) → Proxy IP (US) → Provider API
+ TLS spoof
+ CLI fingerprint
You get both IP masking and request authenticity simultaneously.
Proxy IP Preservation
Color-coded badges in the dashboard show which proxy level is active:
| Badge | Level | Meaning |
|---|---|---|
| 🟢 | Global | All traffic goes through this proxy |
| 🟡 | Provider | Only this provider's traffic is proxied |
| 🔵 | Connection | This specific key/account uses this proxy |
The badge also shows the resolved proxy IP for verification.
Upstream Proxy Modes
For providers that use the CLIProxyAPI pattern, OmniRoute supports three upstream proxy modes:
| Mode | Description |
|---|---|
native |
OmniRoute handles proxy routing directly (default) |
cliproxyapi |
Delegates to an external CLIProxyAPI instance |
fallback |
Tries native first, falls back to CLIProxyAPI |
Configure per-provider:
curl -X PUT "http://localhost:20128/api/upstream-proxy/openai" \
-H "Content-Type: application/json" \
-d '{"mode": "native", "enabled": true}'
Dashboard UI
Settings → Proxy Tab
- Global proxy configuration (set once for all traffic)
- Per-provider proxy overrides
- Per-connection proxy assignments
- Connection test through configured proxy
- Color-coded badges showing active proxy level
Settings → 1proxy Tab
- Sync Now button to fetch free proxies
- Stats cards: Total, Active, Avg Quality, Last Sync
- Filters: Protocol, Country Code, Min Quality
- Proxy table with host, protocol, country, quality score, latency, anonymity, Google access
- Sync status panel with success/failure tracking and consecutive failure count
- Clear All to remove all 1proxy entries
API Reference
Proxy Settings API
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/settings/proxy |
Get full proxy config |
GET |
/api/settings/proxy?level=global |
Get global proxy |
GET |
/api/settings/proxy?level=provider&id=openai |
Get provider proxy |
GET |
/api/settings/proxy?resolve=connectionId |
Resolve effective proxy |
PUT |
/api/settings/proxy |
Update proxy config |
DELETE |
/api/settings/proxy?level=provider&id=openai |
Remove proxy at level |
Proxy Registry API
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/management/proxies |
List all proxies |
GET |
/api/v1/management/proxies?id=uuid |
Get proxy by ID |
GET |
/api/v1/management/proxies?id=uuid&where_used=1 |
Get proxy assignments |
POST |
/api/v1/management/proxies |
Create proxy |
PATCH |
/api/v1/management/proxies |
Update proxy |
DELETE |
/api/v1/management/proxies?id=uuid |
Delete proxy |
DELETE |
/api/v1/management/proxies?id=uuid&force=1 |
Force delete |
POST |
/api/v1/management/proxies/bulk-assign |
Bulk assign |
GET |
/api/v1/management/proxies/assignments |
List assignments |
GET |
/api/v1/management/proxies/health |
Proxy health stats |
Tunnels API
For exposing your OmniRoute instance to the public internet (Cloudflare/ngrok/Tailscale) instead of routing outbound through a proxy, see TUNNELS_GUIDE.md. The tunnel REST API lives under /api/tunnels/{cloudflared,ngrok,tailscale}/* and is orthogonal to the outbound proxy chain documented above.
1proxy API
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/settings/oneproxy |
List 1proxy proxies |
GET |
/api/settings/oneproxy?action=stats |
Get stats + sync status |
GET |
/api/settings/oneproxy?action=status |
Get sync status only |
POST |
/api/settings/oneproxy |
Trigger sync |
POST |
/api/settings/oneproxy/rotate |
Rotate to next proxy |
DELETE |
/api/settings/oneproxy?id=uuid |
Delete one |
DELETE |
/api/settings/oneproxy?clearAll=1 |
Clear all |
Upstream Proxy API
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/upstream-proxy/:providerId |
Get upstream proxy config |
PUT |
/api/upstream-proxy/:providerId |
Set upstream proxy mode |
DELETE |
/api/upstream-proxy/:providerId |
Remove upstream proxy config |
Environment Variables
| Variable | Default | Description |
|---|---|---|
ENABLE_SOCKS5_PROXY |
true |
Enable SOCKS5 proxy support (default true in .env.example) |
ONEPROXY_ENABLED |
true |
Enable 1proxy integration |
ONEPROXY_API_URL |
https://1proxy-api.aitradepulse.com |
1proxy API endpoint |
ONEPROXY_MAX_PROXIES |
500 |
Maximum proxies to sync |
ONEPROXY_MIN_QUALITY_THRESHOLD |
50 |
Minimum quality score to import |
Troubleshooting
"SOCKS5 proxy is disabled"
Set ENABLE_SOCKS5_PROXY=true in your .env file and restart.
"socket hang up" errors through proxy
This is normal with cheap proxies that drop idle connections. OmniRoute already handles this by:
- Disabling keep-alive on proxy connections (
keepAliveTimeout: 1) - Disabling pipelining (
pipelining: 0) - Caching dispatchers to avoid repeated handshakes
If it persists, try a different proxy or use the 1proxy rotation feature.
"unsupported_country_region_territory" during OAuth
Make sure the proxy is configured before starting the OAuth flow. OmniRoute routes OAuth token exchange through the configured proxy. Set a global or provider-level proxy first, then connect.
Proxy not being used
Check the resolution order:
- Verify with
GET /api/settings/proxy?resolve=your-connection-id - Check if the proxy
statusisactive(notinactive) - Ensure the proxy assignment scope matches your connection
1proxy sync failing
Check the sync status:
curl "http://localhost:20128/api/settings/oneproxy?action=status"
If consecutiveFailures >= 5, the circuit breaker has tripped. Restart the server to reset, or wait for manual reset.
Database Schema
proxy_registry Table
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' or 'oneproxy'
quality_score INTEGER, -- 0-100 (1proxy only)
latency_ms INTEGER, -- milliseconds (1proxy only)
anonymity TEXT, -- transparent/anonymous/elite
google_access INTEGER DEFAULT 0, -- can access Google? (1proxy)
last_validated TEXT, -- ISO timestamp (1proxy)
country_code TEXT, -- ISO 2-letter code (1proxy)
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
proxy_assignments Table
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, -- provider ID, connection ID, or combo ID
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
UNIQUE(scope, scope_id)
);
Proxy Health Checking (v3.8.16+)
OmniRoute's proxy fast-fail mechanism (src/lib/proxyHealth.ts) detects dead proxies in <2s via a quick TCP connection check, then caches the result to avoid per-request overhead.
How It Works
Request ──▶ ProxyHealthCache.get(url)
│
├─ Cache hit + fresh? ──▶ return cached status
│
└─ Cache miss / stale? ──▶ TCP connect to host:port
(timeout: FAST_FAIL_TIMEOUT_MS)
──▶ cache for HEALTH_CACHE_TTL_MS
──▶ return result
Without this, a dead proxy would block every request for the full PROXY_TIMEOUT_MS (default 30s) before failing.
Tunable Environment Variables
| Variable | Default | Purpose |
|---|---|---|
PROXY_FAST_FAIL_TIMEOUT_MS |
2000 |
TCP connection timeout per health check |
PROXY_HEALTH_CACHE_TTL_MS |
30000 |
How long a health result is cached |
Recommended values:
| Scenario | Fast-fail timeout | Cache TTL | Reasoning |
|---|---|---|---|
| High-throughput API gateway | 1500ms | 60000ms | Aggressive fail-fast, longer cache to reduce checks |
| Geo-distributed nodes | 3000ms | 15000ms | Slower networks need more time; shorter cache for fast failover |
| Dev / testing | 1000ms | 10000ms | Quick iteration on local proxies |
| Stealth / anti-detection | 2500ms | 45000ms | Avoid rapid probing that could trigger rate limits |
Inspecting Proxy Health
import { getAllProxyHealthStatuses, invalidateProxyHealth } from "omniroute/proxyHealth";
const statuses = getAllProxyHealthStatuses();
for (const s of statuses) {
console.log(`${s.proxyUrl} → healthy=${s.healthy}, stale=${s.stale}`);
}
// Force re-check a specific proxy
invalidateProxyHealth("http://user:pass@1.2.3.4:8080");
The stale flag is true when the cache entry has exceeded HEALTH_CACHE_TTL_MS and the next request will trigger a fresh check.
Per-Proxy Type Defaults
The health check uses sensible defaults based on the URL scheme:
| Scheme | Default port |
|---|---|
http:// |
8080 |
https:// |
443 |
socks5:// / socks5h:// |
1080 |
Custom ports in the URL (http://host:9999) always take precedence over the scheme default.
Proxy Analytics & Observability
OmniRoute tracks per-proxy usage to help operators diagnose routing patterns, latency spikes, and recurring failures.
What's Tracked
For every request through a configured proxy, OmniRoute records:
| Metric | Description |
|---|---|
proxy_url |
Full proxy URL (with auth credentials masked) |
provider |
Upstream provider ID (openai, anthropic, etc.) |
latency_ms |
Total round-trip time including proxy handshake |
connect_ms |
TCP connect time only |
status |
HTTP status code from upstream |
error |
Error class if request failed |
timestamp |
ISO 8601 UTC |
Accessing the Data
# Recent proxy events
curl -H "Authorization: Bearer $OMNIROUTE_KEY" \
"http://localhost:20128/api/usage/proxy-logs?limit=100"
The real endpoint is /api/usage/proxy-logs (see src/app/api/usage/proxy-logs/route.ts). This endpoint supports:
GET /api/usage/proxy-logs— retrieve proxy logsDELETE /api/usage/proxy-logs— clear all proxy logs
Aggregate stats can be queried directly from the proxy_logs table via SQL if needed. The dashboard UI may offer aggregate views.
Common Patterns
Detect a flapping proxy (alternates between success/failure):
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;
Find slow proxies (p95 latency > 2s):
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;
Rotation Strategy Decision Tree
When multiple proxies are assigned to a scope, OmniRoute uses a rotation strategy to pick which one to use for each request. The strategy is configured at the scope level (global, per-provider, per-account, per-combo).
Available Strategies
| Strategy | When to use | Trade-off |
|---|---|---|
quality (default) |
Production with mixed-quality proxies | Favors high-rated proxies; may starve low-rated ones |
random |
Load distribution, privacy | Even distribution; ignores quality signals |
sequential |
Debugging, deterministic testing | Cycles through proxies in order; easy to reason about |
Decision Tree
Do you have quality scores for your proxies?
│
┌───────────┴───────────┐
│ │
YES NO
│ │
Are all proxies │
roughly equal │
in quality? │
│ │
┌────┴────┐ │
│ │ │
YES NO Use
│ │ `random`
│ │ (even spread
│ │ builds quality
│ │ data over time)
│ │
│ Use `quality`
│ (best for
│ mixed quality)
│
Use `random`
(spread load
evenly)
Configuring Rotation Strategy
import { rotateOneproxyProxy } from "omniroute/oneproxyRotator";
// In a one-off script
const proxy = await rotateOneproxyProxy({ strategy: "quality" });
if (proxy) {
console.log(`Selected: ${proxy.host}:${proxy.port}, quality=${proxy.qualityScore}`);
}
Resetting Sequential Index
When using sequential strategy, the internal index accumulates. To reset:
import { resetSequentialIndex } from "omniroute/oneproxyRotator";
resetSequentialIndex();
Useful when:
- Restarting a load test
- Recovering from a proxy outage (so you don't cycle through dead ones first)
- Manually rebalancing after adding new proxies
Marking a Proxy as Failed
When a proxy consistently fails, mark it manually so the rotator will skip it:
import { failOneproxyProxy } from "omniroute/oneproxyRotator";
const removed = await failOneproxyProxy("1.2.3.4", 8080);
if (removed) {
console.log("Proxy marked as failed; rotator will skip it");
}
The proxy is not deleted — it's marked unhealthy and won't be selected until the next successful health check (via proxyHealth.ts) or manual reset.
📖 Related documentation:
- User Guide — General setup and configuration
- API Reference — Full API documentation
- Environment Config — All environment variables