From 9c15109f26238ea94a1b2b55d5f0f7a20ac0648d Mon Sep 17 00:00:00 2001 From: infosave2007 Date: Fri, 21 Aug 2026 13:21:24 +0300 Subject: [PATCH] chore(router): address the hosted router by hostname, TLS verification on router.allaigate.com now resolves and serves a valid certificate, so the hosted routing API no longer has to be reached by bare IP with certificate verification switched off. Make https://router.allaigate.com the default [router].url with verify_tls = true. Existing configs still pointing at 138.226.222.209 (with or without a scheme or a trailing slash) are moved to the hostname on load and have verification restored, then saved: it is the same machine, and this is the difference between a verified connection and a blind one. A self-hosted router URL is left untouched. README, docs/ROUTER.md (both languages), config/gateway.example.toml and bench/accuracy.py follow. Verified live: the migration rewrites a legacy config on startup, admin health reports the hostname reachable over verified TLS (389 ms), and real requests route through it - "math"/medium 0.416 and "translation"/low 0.268 with route_source=router. --- CHANGELOG.md | 16 ++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 6 +-- README.ru.md | 6 +-- bench/accuracy.py | 4 +- config/gateway.example.toml | 4 +- docs/ROUTER.md | 8 ++-- docs/ROUTER.ru.md | 8 ++-- src/config.rs | 74 +++++++++++++++++++++++++++++++++++-- 10 files changed, 107 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c33f43c..9f7f410 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/). +## [0.2.47] - 2026-08-21 + +### Changed +- **The hosted allaigate router is addressed by hostname: + `https://router.allaigate.com`** is now the default `[router].url`, and + `verify_tls` defaults to `true`. The endpoint used to be reachable only by bare IP, + whose certificate is issued for the hostname — so every hosted setup had to run with + certificate verification switched off. It no longer does. +- **Existing configs are migrated on load.** A `[router].url` still pointing at the old + `138.226.222.209` (with or without a scheme or trailing slash) is rewritten to the + hostname, `verify_tls` is turned back on, and the file is saved — the endpoint is the + same machine, and this is the difference between a verified connection and a blind one. + A self-hosted router URL is never touched. +- README, `docs/ROUTER.md` (both languages), `config/gateway.example.toml` and + `bench/accuracy.py` updated to the hostname. + ## [0.2.46] - 2026-08-21 Verified end to end against a real Open WebUI container talking to the gateway. diff --git a/Cargo.lock b/Cargo.lock index 45a5bd7..0916880 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,7 +285,7 @@ checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "cortiq-gateway" -version = "0.2.46" +version = "0.2.47" dependencies = [ "anyhow", "arc-swap", diff --git a/Cargo.toml b/Cargo.toml index 3c6ca09..3d5d9a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cortiq-gateway" -version = "0.2.46" +version = "0.2.47" edition = "2021" rust-version = "1.75" license = "Apache-2.0" diff --git a/README.md b/README.md index 1422adf..8a890da 100644 --- a/README.md +++ b/README.md @@ -175,9 +175,9 @@ print(resp.choices[0].message.content) `model: "cortiq-auto"` enables routing. Any **real** model name from the config (`"gpt-4o-mini"`, `"local-qwen"`) is a direct passthrough, without routing. -> **Using the hosted allaigate router?** Set `url = "https://138.226.222.209"`, -> `verify_tls = false`, `taxonomy_id = "data-assistant"`, and a `cortiq_…` key in -> `CORTIQ_ROUTER_KEY`. On hard prompts the router escalates to an oracle (~10 s), so +> **Using the hosted allaigate router?** It is the default: `url = +> "https://router.allaigate.com"` with `verify_tls = true`. Set `taxonomy_id = +> "data-assistant"` and a `cortiq_…` key in `CORTIQ_ROUTER_KEY`. On hard prompts the router escalates to an oracle (~10 s), so > set `timeout_ms = 12000+` — otherwise the gateway gracefully degrades to the default model. --- diff --git a/README.ru.md b/README.ru.md index 03527a2..8c5f9a6 100644 --- a/README.ru.md +++ b/README.ru.md @@ -167,9 +167,9 @@ print(resp.choices[0].message.content) `model: "cortiq-auto"` включает роутинг. Любое **реальное** имя модели из конфига (`"gpt-4o-mini"`, `"local-qwen"`) — это passthrough напрямую, без роутинга. -> **Используете хостовый allaigate-роутер?** Укажите `url = "https://138.226.222.209"`, -> `verify_tls = false`, `taxonomy_id = "data-assistant"` и ключ `cortiq_…` в -> `CORTIQ_ROUTER_KEY`. На сложных запросах роутер эскалирует к oracle (~10 с), поэтому +> **Используете хостовый allaigate-роутер?** Он стоит по умолчанию: `url = +> "https://router.allaigate.com"`, `verify_tls = true`. Задайте `taxonomy_id = +> "data-assistant"` и ключ `cortiq_…` в `CORTIQ_ROUTER_KEY`. На сложных запросах роутер эскалирует к oracle (~10 с), поэтому > ставьте `timeout_ms = 12000+` — иначе шлюз мягко деградирует на default-модель. --- diff --git a/bench/accuracy.py b/bench/accuracy.py index 072c65e..3a96ce1 100644 --- a/bench/accuracy.py +++ b/bench/accuracy.py @@ -4,12 +4,12 @@ heuristic (what you get without a semantic classifier, e.g. with LiteLLM/Portkey CORTIQ_ROUTER_KEY=cortiq_... python3 bench/accuracy.py -Env: CORTIQ_ROUTER_KEY (required), ROUTER_URL (default https://138.226.222.209), +Env: CORTIQ_ROUTER_KEY (required), ROUTER_URL (default https://router.allaigate.com), TAXONOMY (default data-assistant). """ import json, os, ssl, sys, urllib.request -ROUTER_URL = os.environ.get("ROUTER_URL", "https://138.226.222.209").rstrip("/") +ROUTER_URL = os.environ.get("ROUTER_URL", "https://router.allaigate.com").rstrip("/") TAXONOMY = os.environ.get("TAXONOMY", "data-assistant") KEY = os.environ.get("CORTIQ_ROUTER_KEY", "") CTX = ssl._create_unverified_context() diff --git a/config/gateway.example.toml b/config/gateway.example.toml index 127d0de..a2141e7 100644 --- a/config/gateway.example.toml +++ b/config/gateway.example.toml @@ -8,13 +8,13 @@ listen = "0.0.0.0:9000" # --- connection to cortiq-router (decides task type / complexity) ----------- -# Hosted allaigate router: url = "https://138.226.222.209", verify_tls = false +# Hosted allaigate router: url = "https://router.allaigate.com" (the default) # (cert is bound to an IP), taxonomy_id = "data-assistant", a cortiq_… key in # CORTIQ_ROUTER_KEY. # NOTE: on hard prompts the router escalates to an oracle LLM (~10 s) — for the # hosted router set timeout_ms = 12000+, otherwise the gateway degrades to default. [router] -url = "https://138.226.222.209" # hosted allaigate router (or your own cortiq-router URL) +url = "https://router.allaigate.com" # hosted allaigate router (or your own cortiq-router URL) api_key_env = "CORTIQ_ROUTER_KEY" # name of the env var holding the router key timeout_ms = 12000 # hard prompts escalate to an oracle (~10 s) taxonomy_id = "data-assistant" # the hosted router's task taxonomy diff --git a/docs/ROUTER.md b/docs/ROUTER.md index 2e41929..17ea8e9 100644 --- a/docs/ROUTER.md +++ b/docs/ROUTER.md @@ -41,11 +41,11 @@ minted and shown to you. ```toml [router] -url = "https://138.226.222.209" # allaigate routing API -verify_tls = false # cert is bound to an IP +url = "https://router.allaigate.com" # allaigate routing API (the default) +verify_tls = true # valid certificate — keep verification on taxonomy_id = "data-assistant" -api_key_env = "CORTIQ_ROUTER_KEY" # your cortiq_… key -timeout_ms = 15000 # allow for oracle escalation on hard prompts +api_key_env = "CORTIQ_ROUTER_KEY" # your cortiq_… key +timeout_ms = 15000 # allow for oracle escalation on hard prompts ``` ```bash diff --git a/docs/ROUTER.ru.md b/docs/ROUTER.ru.md index d1c8e87..f26fabe 100644 --- a/docs/ROUTER.ru.md +++ b/docs/ROUTER.ru.md @@ -40,11 +40,11 @@ Cortiq Gateway — тонкий и быстрый прокси; **интелле ```toml [router] -url = "https://138.226.222.209" # routing API allaigate -verify_tls = false # серт привязан к IP +url = "https://router.allaigate.com" # routing API allaigate (значение по умолчанию) +verify_tls = true # валидный сертификат — проверку не выключаем taxonomy_id = "data-assistant" -api_key_env = "CORTIQ_ROUTER_KEY" # ваш ключ cortiq_… -timeout_ms = 15000 # запас под oracle-эскалацию на сложных запросах +api_key_env = "CORTIQ_ROUTER_KEY" # ваш ключ cortiq_… +timeout_ms = 15000 # запас под oracle-эскалацию на сложных запросах ``` ```bash diff --git a/src/config.rs b/src/config.rs index 6293ec8..f356e20 100644 --- a/src/config.rs +++ b/src/config.rs @@ -318,6 +318,34 @@ fn default_verify_tls() -> bool { true } +/// The hosted allaigate routing API. +pub const DEFAULT_ROUTER_URL: &str = "https://router.allaigate.com"; + +/// The bare IP the hosted router used to be addressed by. It served a +/// certificate for `router.allaigate.com`, so every config pointing at it had to +/// turn TLS verification off. The hostname now resolves, so configs written +/// before it existed are moved over on load — the endpoint is the same machine, +/// and this is the difference between a verified connection and a blind one. +const LEGACY_ROUTER_HOSTS: &[&str] = &[ + "https://138.226.222.209", + "http://138.226.222.209", + "138.226.222.209", +]; + +impl RouterCfg { + /// Point a legacy IP-addressed router config at the hostname and restore TLS + /// verification. Returns true when something changed. + fn migrate_hosted_endpoint(&mut self) -> bool { + let url = self.url.trim().trim_end_matches('/'); + if !LEGACY_ROUTER_HOSTS.contains(&url) { + return false; + } + self.url = DEFAULT_ROUTER_URL.to_string(); + self.verify_tls = true; + true + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct RouteCfg { #[serde(default = "default_text_strategy")] @@ -882,9 +910,9 @@ impl Default for Config { // models and the console asks for one; nothing breaks. router: RouterCfg { enabled: true, - url: "https://138.226.222.209".to_string(), + url: DEFAULT_ROUTER_URL.to_string(), timeout_ms: 15_000, // hard prompts escalate to an oracle (~10 s) - verify_tls: false, // the hosted endpoint is IP-bound + verify_tls: true, api_key_env: Some("CORTIQ_ROUTER_KEY".to_string()), taxonomy_id: Some("data-assistant".to_string()), }, @@ -954,7 +982,14 @@ impl Config { pub fn load(path: &str) -> anyhow::Result { let raw = std::fs::read_to_string(path) .map_err(|e| anyhow::anyhow!("cannot read config {path}: {e}"))?; - let cfg: Config = toml::from_str(&raw)?; + let mut cfg: Config = toml::from_str(&raw)?; + if cfg.router.migrate_hosted_endpoint() { + tracing::info!( + url = DEFAULT_ROUTER_URL, + "router endpoint moved from the bare IP to the hostname; TLS verification is on" + ); + let _ = cfg.save(path); + } cfg.validate()?; Ok(cfg) } @@ -1091,6 +1126,39 @@ impl Config { mod tests { use super::*; + #[test] + fn the_hosted_router_defaults_to_the_hostname_with_tls_on() { + let cfg = Config::default(); + assert_eq!(cfg.router.url, "https://router.allaigate.com"); + assert!(cfg.router.verify_tls); + } + + #[test] + fn a_legacy_ip_router_config_moves_to_the_hostname() { + for legacy in [ + "https://138.226.222.209", + "https://138.226.222.209/", + "138.226.222.209", + ] { + let mut r = Config::default().router; + r.url = legacy.to_string(); + r.verify_tls = false; + assert!(r.migrate_hosted_endpoint(), "{legacy} must migrate"); + assert_eq!(r.url, DEFAULT_ROUTER_URL); + assert!(r.verify_tls, "TLS verification must be restored"); + } + } + + #[test] + fn a_self_hosted_router_url_is_left_alone() { + let mut r = Config::default().router; + r.url = "http://127.0.0.1:8081".to_string(); + r.verify_tls = false; + assert!(!r.migrate_hosted_endpoint()); + assert_eq!(r.url, "http://127.0.0.1:8081"); + assert!(!r.verify_tls); + } + const SAMPLE: &str = r#" listen = "0.0.0.0:9000"