Spaces:
Runtime error
Runtime error
| title: "π OmniRoute Proxy Guide" | |
| version: 3.8.2 | |
| lastUpdated: 2026-05-13 | |
| # π 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?](#why-use-proxies) | |
| - [Architecture Overview](#architecture-overview) | |
| - [4-Level Proxy System](#4-level-proxy-system) | |
| - [Proxy Registry (CRUD)](#proxy-registry-crud) | |
| - [1proxy Free Marketplace](#1proxy-free-proxy-marketplace) | |
| - [Proxy Rotation](#proxy-rotation) | |
| - [Anti-Detection & Stealth](#anti-detection--stealth) | |
| - [Upstream Proxy Modes](#upstream-proxy-modes) | |
| - [Dashboard UI](#dashboard-ui) | |
| - [API Reference](#api-reference) | |
| - [Environment Variables](#environment-variables) | |
| - [Troubleshooting](#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: | |
| 1. **Account-level** β Is there a proxy assigned to this specific connection ID? | |
| 2. **Provider-level** β Is there a proxy assigned to this provider (e.g., `openai`)? | |
| 3. **Global-level** β Is there a global proxy configured? | |
| 4. **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:** | |
| 1. Go to **Settings β Proxy** | |
| 2. Click **Add Proxy** | |
| 3. Fill in the type, host, port, and optional auth credentials | |
| 4. Save | |
| **Via API:** | |
| ```bash | |
| 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 | |
| ```bash | |
| 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`/`password` will keep the stored values. | |
| ### Deleting a Proxy | |
| ```bash | |
| # 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 | |
| ```bash | |
| curl "http://localhost:20128/api/v1/management/proxies?limit=50&offset=0" | |
| ``` | |
| ### Assigning Proxies to Scopes | |
| ```bash | |
| # 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: | |
| ```bash | |
| 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: | |
| ```bash | |
| 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: | |
| 1. Go to **Dashboard β Settings β Backup** | |
| 2. Click **Export** β proxy registry and assignments are included | |
| 3. 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 | |
| > π **Contributed by [@oyi77](https://github.com/oyi77)** β PR [#1847](https://github.com/diegosouzapw/OmniRoute/pull/1847) (Issue [#1788](https://github.com/diegosouzapw/OmniRoute/issues/1788)) | |
| OmniRoute integrates with the **[1proxy](https://1proxy-api.aitradepulse.com)** 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 βββββββββββββββββββ ββββββββββββ | |
| ``` | |
| 1. **Sync** β OmniRoute fetches validated proxies from the 1proxy API | |
| 2. **Store** β Proxies are saved in the same `proxy_registry` table with `source = 'oneproxy'` | |
| 3. **Filter** β Filter by protocol, country, quality score | |
| 4. **Rotate** β Pick the best proxy using quality, random, or sequential strategies | |
| 5. **Auto-degrade** β Failed proxies get their quality score reduced; below threshold β marked inactive | |
| ### Syncing Proxies | |
| **Via Dashboard:** | |
| 1. Go to **Settings β 1proxy** tab | |
| 2. Click **"Sync Now"** | |
| 3. View stats: total proxies, active count, average quality, by-country breakdown | |
| **Via API:** | |
| ```bash | |
| # 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 | |
| ```bash | |
| # 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 | |
| ```bash | |
| # 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 | |
| ```bash | |
| # 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: | |
| ```bash | |
| 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](./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: | |
| 1. Verify with `GET /api/settings/proxy?resolve=your-connection-id` | |
| 2. Check if the proxy `status` is `active` (not `inactive`) | |
| 3. Ensure the proxy assignment scope matches your connection | |
| ### 1proxy sync failing | |
| Check the sync status: | |
| ```bash | |
| 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 | |
| ```sql | |
| 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 | |
| ```sql | |
| 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 | |
| ```ts | |
| 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 | |
| ```bash | |
| # 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 logs | |
| - `DELETE /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): | |
| ```sql | |
| 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): | |
| ```sql | |
| 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 | |
| ```ts | |
| 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: | |
| ```ts | |
| 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: | |
| ```ts | |
| 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](../guides/USER_GUIDE.md) β General setup and configuration | |
| > - [API Reference](../reference/API_REFERENCE.md) β Full API documentation | |
| > - [Environment Config](../reference/ENVIRONMENT.md) β All environment variables | |