fix(rvs-clients): RVS_SNI via getaddrinfo-Override statt host=/port= (HTTP-200-Fix)
Symptom mit RVS_SNI: 'server rejected WebSocket connection: HTTP 200'. Ursache: die IP stand in der URI -> HTTP-Host-Header = IP -> Caddy findet keinen RVS-Site- Block (routet nach Host) und liefert eine Default-200-Seite statt WS-Upgrade. Der vorige Fix korrigierte nur SNI/Cert (server_hostname), nicht den Host-Header. Zudem: host=/port= als websockets.connect-kwargs kollidieren in der Legacy-API mit dem aus der URI abgeleiteten Host (TypeError). Loesung (host-agent, satellite, f5tts/whisper/voxtral/llm-adapter): die URI nutzt den HOSTNAMEN (RVS_SNI) -> Host-Header + SNI + Cert stimmen; ein In-Process- getaddrinfo-Override mappt RVS_SNI -> RVS_HOST (IP) fuer den TCP-Connect. Versionsunabhaengig, nicht-blockierend, nur aktiv wenn RVS_SNI gesetzt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+21
-10
@@ -105,6 +105,18 @@ RVS_TOKEN = os.environ.get("RVS_TOKEN", "")
|
||||
# RVS_SNI=<zert-name>. Leer = SNI = RVS_HOST (Normalfall).
|
||||
RVS_SNI = os.environ.get("RVS_SNI", "").strip()
|
||||
|
||||
# In-Process-DNS-Override: wenn RVS_SNI gesetzt ist, verbindet die URI ueber den
|
||||
# HOSTNAMEN (Host-Header + SNI + Cert stimmen), waehrend getaddrinfo den Namen auf
|
||||
# die echte IP in RVS_HOST aufloest. Versionsunabhaengig — host=/port= kollidiert
|
||||
# in der Legacy-websockets-API mit dem aus der URI abgeleiteten Host.
|
||||
if RVS_TLS and RVS_SNI:
|
||||
import socket as _socket
|
||||
_orig_getaddrinfo = _socket.getaddrinfo
|
||||
def _sni_getaddrinfo(host, *a, **k):
|
||||
return _orig_getaddrinfo(RVS_HOST if host == RVS_SNI else host, *a, **k)
|
||||
_socket.getaddrinfo = _sni_getaddrinfo
|
||||
|
||||
|
||||
HOST_ID = (os.environ.get("HOST_ID") or _default_id()).strip()
|
||||
HOST_NAME = (os.environ.get("HOST_NAME") or HOST_ID).strip()
|
||||
|
||||
@@ -405,20 +417,19 @@ class HostAgent:
|
||||
logger.error("RVS_HOST und RVS_TOKEN sind Pflicht (siehe .env.example).")
|
||||
return
|
||||
backoff = 1
|
||||
# SNI-/Cert-Override: auf eine IP verbinden, aber den Namen im TLS-
|
||||
# Handshake praesentieren (Caddy-Cert gilt fuer den Namen).
|
||||
# RVS_SNI gesetzt (Verbindung auf eine interne IP): die URI nutzt den
|
||||
# HOSTNAMEN, damit Host-Header + SNI + Cert-Pruefung stimmen (sonst weist
|
||||
# Caddy die Verbindung ab -> HTTP 200 statt WS-Upgrade). Der TCP-Connect
|
||||
# wird per host=/port= auf die IP in RVS_HOST umgebogen.
|
||||
proto = "wss" if RVS_TLS else "ws"
|
||||
uri_host = RVS_SNI if (RVS_TLS and RVS_SNI) else RVS_HOST
|
||||
url = f"{proto}://{uri_host}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
connect_kwargs = {"max_size": 16 * 1024 * 1024,
|
||||
"ping_interval": 20, "ping_timeout": 20}
|
||||
if RVS_TLS and RVS_SNI:
|
||||
import ssl
|
||||
connect_kwargs["ssl"] = ssl.create_default_context()
|
||||
connect_kwargs["server_hostname"] = RVS_SNI
|
||||
while True:
|
||||
proto = "wss" if RVS_TLS else "ws"
|
||||
url = f"{proto}://{RVS_HOST}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
try:
|
||||
logger.info("Verbinde mit RVS %s://%s:%s%s …", proto, RVS_HOST, RVS_PORT,
|
||||
f" (SNI {RVS_SNI})" if RVS_SNI else "")
|
||||
logger.info("Verbinde mit RVS %s://%s:%s%s …", proto, uri_host, RVS_PORT,
|
||||
f" (TCP {RVS_HOST})" if (RVS_TLS and RVS_SNI) else "")
|
||||
async with websockets.connect(url, **connect_kwargs) as ws:
|
||||
self.ws = ws
|
||||
backoff = 1
|
||||
|
||||
+21
-10
@@ -112,6 +112,18 @@ RVS_TOKEN = os.environ.get("RVS_TOKEN", "")
|
||||
# (das Caddy-Zertifikat gilt aber fuer den Namen). Leer = SNI = RVS_HOST.
|
||||
RVS_SNI = os.environ.get("RVS_SNI", "").strip()
|
||||
|
||||
# In-Process-DNS-Override: wenn RVS_SNI gesetzt ist, verbindet die URI ueber den
|
||||
# HOSTNAMEN (Host-Header + SNI + Cert stimmen), waehrend getaddrinfo den Namen auf
|
||||
# die echte IP in RVS_HOST aufloest. Versionsunabhaengig — host=/port= kollidiert
|
||||
# in der Legacy-websockets-API mit dem aus der URI abgeleiteten Host.
|
||||
if RVS_TLS and RVS_SNI:
|
||||
import socket as _socket
|
||||
_orig_getaddrinfo = _socket.getaddrinfo
|
||||
def _sni_getaddrinfo(host, *a, **k):
|
||||
return _orig_getaddrinfo(RVS_HOST if host == RVS_SNI else host, *a, **k)
|
||||
_socket.getaddrinfo = _sni_getaddrinfo
|
||||
|
||||
|
||||
SATELLITE_ID = (os.environ.get("SATELLITE_ID") or _default_id()).strip()
|
||||
SATELLITE_LOCATION = (os.environ.get("SATELLITE_LOCATION") or SATELLITE_ID).strip()
|
||||
|
||||
@@ -1320,20 +1332,19 @@ class Satellite:
|
||||
_creds_load()
|
||||
asyncio.create_task(self._periodic_scan())
|
||||
backoff = 1
|
||||
# SNI-/Cert-Override: auf eine IP verbinden, aber den Namen im TLS-
|
||||
# Handshake praesentieren (Caddy-Cert gilt fuer den Namen).
|
||||
# RVS_SNI gesetzt (Verbindung auf eine interne IP): die URI nutzt den
|
||||
# HOSTNAMEN, damit Host-Header + SNI + Cert-Pruefung stimmen (sonst weist
|
||||
# Caddy die Verbindung ab -> HTTP 200 statt WS-Upgrade). Der TCP-Connect
|
||||
# wird per host=/port= auf die IP in RVS_HOST umgebogen.
|
||||
proto = "wss" if RVS_TLS else "ws"
|
||||
uri_host = RVS_SNI if (RVS_TLS and RVS_SNI) else RVS_HOST
|
||||
url = f"{proto}://{uri_host}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
connect_kwargs = {"max_size": 8 * 1024 * 1024,
|
||||
"ping_interval": 20, "ping_timeout": 20}
|
||||
if RVS_TLS and RVS_SNI:
|
||||
import ssl
|
||||
connect_kwargs["ssl"] = ssl.create_default_context()
|
||||
connect_kwargs["server_hostname"] = RVS_SNI
|
||||
while True:
|
||||
proto = "wss" if RVS_TLS else "ws"
|
||||
url = f"{proto}://{RVS_HOST}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
try:
|
||||
logger.info("Verbinde mit RVS %s://%s:%s%s …", proto, RVS_HOST, RVS_PORT,
|
||||
f" (SNI {RVS_SNI})" if RVS_SNI else "")
|
||||
logger.info("Verbinde mit RVS %s://%s:%s%s …", proto, uri_host, RVS_PORT,
|
||||
f" (TCP {RVS_HOST})" if (RVS_TLS and RVS_SNI) else "")
|
||||
async with websockets.connect(url, **connect_kwargs) as ws:
|
||||
self.ws = ws
|
||||
backoff = 1
|
||||
|
||||
+15
-6
@@ -55,6 +55,18 @@ RVS_TOKEN = os.getenv("RVS_TOKEN", "").strip()
|
||||
# der RVS, direkt auf die interne IP). Leer = SNI = RVS_HOST.
|
||||
RVS_SNI = os.getenv("RVS_SNI", "").strip()
|
||||
|
||||
# In-Process-DNS-Override: wenn RVS_SNI gesetzt ist, verbindet die URI ueber den
|
||||
# HOSTNAMEN (Host-Header + SNI + Cert stimmen), waehrend getaddrinfo den Namen auf
|
||||
# die echte IP in RVS_HOST aufloest. Versionsunabhaengig — host=/port= kollidiert
|
||||
# in der Legacy-websockets-API mit dem aus der URI abgeleiteten Host.
|
||||
if RVS_TLS and RVS_SNI:
|
||||
import socket as _socket
|
||||
_orig_getaddrinfo = _socket.getaddrinfo
|
||||
def _sni_getaddrinfo(host, *a, **k):
|
||||
return _orig_getaddrinfo(RVS_HOST if host == RVS_SNI else host, *a, **k)
|
||||
_socket.getaddrinfo = _sni_getaddrinfo
|
||||
|
||||
|
||||
# F5-TTS Konfiguration
|
||||
# ─────────────────────────────────────────────────────────────────
|
||||
# Defaults sind hard-coded — bewusst KEINE ENV-Vars (ausser F5TTS_DEVICE,
|
||||
@@ -880,16 +892,13 @@ async def run_loop(runner: F5Runner) -> None:
|
||||
|
||||
while True:
|
||||
scheme = "wss" if use_tls else "ws"
|
||||
url = f"{scheme}://{RVS_HOST}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
uri_host = RVS_SNI if (use_tls and RVS_SNI) else RVS_HOST
|
||||
url = f"{scheme}://{uri_host}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
masked = url.replace(RVS_TOKEN, "***") if RVS_TOKEN else url
|
||||
|
||||
connect_kwargs = {"ping_interval": 20, "ping_timeout": 10, "max_size": 50 * 1024 * 1024}
|
||||
if use_tls and RVS_SNI:
|
||||
import ssl
|
||||
connect_kwargs["ssl"] = ssl.create_default_context()
|
||||
connect_kwargs["server_hostname"] = RVS_SNI
|
||||
try:
|
||||
logger.info("Verbinde zu RVS: %s%s", masked, f" (SNI {RVS_SNI})" if (use_tls and RVS_SNI) else "")
|
||||
logger.info("Verbinde zu RVS: %s%s", masked, f" (TCP {RVS_HOST})" if (use_tls and RVS_SNI) else "")
|
||||
async with websockets.connect(url, **connect_kwargs) as ws:
|
||||
logger.info("RVS verbunden")
|
||||
retry_s = 2
|
||||
|
||||
@@ -47,6 +47,18 @@ RVS_TOKEN = os.getenv("RVS_TOKEN", "").strip()
|
||||
# der RVS, direkt auf die interne IP). Leer = SNI = RVS_HOST.
|
||||
RVS_SNI = os.getenv("RVS_SNI", "").strip()
|
||||
|
||||
# In-Process-DNS-Override: wenn RVS_SNI gesetzt ist, verbindet die URI ueber den
|
||||
# HOSTNAMEN (Host-Header + SNI + Cert stimmen), waehrend getaddrinfo den Namen auf
|
||||
# die echte IP in RVS_HOST aufloest. Versionsunabhaengig — host=/port= kollidiert
|
||||
# in der Legacy-websockets-API mit dem aus der URI abgeleiteten Host.
|
||||
if RVS_TLS and RVS_SNI:
|
||||
import socket as _socket
|
||||
_orig_getaddrinfo = _socket.getaddrinfo
|
||||
def _sni_getaddrinfo(host, *a, **k):
|
||||
return _orig_getaddrinfo(RVS_HOST if host == RVS_SNI else host, *a, **k)
|
||||
_socket.getaddrinfo = _sni_getaddrinfo
|
||||
|
||||
|
||||
LLAMA_URL = os.getenv("LLAMA_URL", "http://llama:8081").rstrip("/")
|
||||
LLM_MODEL = os.getenv("LLM_MODEL", "qwen3-8b")
|
||||
LLM_TIMEOUT_SEC = float(os.getenv("LLM_TIMEOUT_SEC", "60"))
|
||||
@@ -420,16 +432,13 @@ async def _run() -> None:
|
||||
|
||||
while True:
|
||||
scheme = "wss" if use_tls else "ws"
|
||||
url = f"{scheme}://{RVS_HOST}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
uri_host = RVS_SNI if (use_tls and RVS_SNI) else RVS_HOST
|
||||
url = f"{scheme}://{uri_host}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
masked = url.replace(RVS_TOKEN, "***") if RVS_TOKEN else url
|
||||
connect_kwargs = {"ping_interval": 20, "ping_timeout": 10, "max_size": 16 * 1024 * 1024}
|
||||
if use_tls and RVS_SNI:
|
||||
import ssl
|
||||
connect_kwargs["ssl"] = ssl.create_default_context()
|
||||
connect_kwargs["server_hostname"] = RVS_SNI
|
||||
try:
|
||||
logger.info("Verbinde zu RVS: %s%s (llama=%s)", masked,
|
||||
f" (SNI {RVS_SNI})" if (use_tls and RVS_SNI) else "", LLAMA_URL)
|
||||
f" (TCP {RVS_HOST})" if (use_tls and RVS_SNI) else "", LLAMA_URL)
|
||||
async with websockets.connect(url, **connect_kwargs) as ws:
|
||||
logger.info("RVS verbunden — llm-adapter online")
|
||||
retry_s = 2
|
||||
|
||||
+15
-6
@@ -57,6 +57,18 @@ RVS_TOKEN = os.getenv("RVS_TOKEN", "").strip()
|
||||
# der RVS, direkt auf die interne IP). Leer = SNI = RVS_HOST.
|
||||
RVS_SNI = os.getenv("RVS_SNI", "").strip()
|
||||
|
||||
# In-Process-DNS-Override: wenn RVS_SNI gesetzt ist, verbindet die URI ueber den
|
||||
# HOSTNAMEN (Host-Header + SNI + Cert stimmen), waehrend getaddrinfo den Namen auf
|
||||
# die echte IP in RVS_HOST aufloest. Versionsunabhaengig — host=/port= kollidiert
|
||||
# in der Legacy-websockets-API mit dem aus der URI abgeleiteten Host.
|
||||
if RVS_TLS and RVS_SNI:
|
||||
import socket as _socket
|
||||
_orig_getaddrinfo = _socket.getaddrinfo
|
||||
def _sni_getaddrinfo(host, *a, **k):
|
||||
return _orig_getaddrinfo(RVS_HOST if host == RVS_SNI else host, *a, **k)
|
||||
_socket.getaddrinfo = _sni_getaddrinfo
|
||||
|
||||
|
||||
VOXTRAL_MODEL = os.getenv("VOXTRAL_MODEL", "mistralai/Voxtral-Mini-3B-2507")
|
||||
VOXTRAL_LANGUAGE = os.getenv("VOXTRAL_LANGUAGE", "de")
|
||||
VOXTRAL_DEVICE = os.getenv("VOXTRAL_DEVICE", "cuda")
|
||||
@@ -745,15 +757,12 @@ async def run_loop(sessions: SessionManager) -> None:
|
||||
tls_fallback_tried = False
|
||||
while True:
|
||||
scheme = "wss" if use_tls else "ws"
|
||||
url = f"{scheme}://{RVS_HOST}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
uri_host = RVS_SNI if (use_tls and RVS_SNI) else RVS_HOST
|
||||
url = f"{scheme}://{uri_host}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
masked = url.replace(RVS_TOKEN, "***") if RVS_TOKEN else url
|
||||
connect_kwargs = {"ping_interval": 20, "ping_timeout": 10, "max_size": 50 * 1024 * 1024}
|
||||
if use_tls and RVS_SNI:
|
||||
import ssl
|
||||
connect_kwargs["ssl"] = ssl.create_default_context()
|
||||
connect_kwargs["server_hostname"] = RVS_SNI
|
||||
try:
|
||||
logger.info("Verbinde zu RVS: %s%s", masked, f" (SNI {RVS_SNI})" if (use_tls and RVS_SNI) else "")
|
||||
logger.info("Verbinde zu RVS: %s%s", masked, f" (TCP {RVS_HOST})" if (use_tls and RVS_SNI) else "")
|
||||
async with websockets.connect(url, **connect_kwargs) as ws:
|
||||
logger.info("RVS verbunden")
|
||||
retry_s = 2
|
||||
|
||||
+15
-6
@@ -57,6 +57,18 @@ RVS_TOKEN = os.getenv("RVS_TOKEN", "").strip()
|
||||
# der RVS, direkt auf die interne IP). Leer = SNI = RVS_HOST.
|
||||
RVS_SNI = os.getenv("RVS_SNI", "").strip()
|
||||
|
||||
# In-Process-DNS-Override: wenn RVS_SNI gesetzt ist, verbindet die URI ueber den
|
||||
# HOSTNAMEN (Host-Header + SNI + Cert stimmen), waehrend getaddrinfo den Namen auf
|
||||
# die echte IP in RVS_HOST aufloest. Versionsunabhaengig — host=/port= kollidiert
|
||||
# in der Legacy-websockets-API mit dem aus der URI abgeleiteten Host.
|
||||
if RVS_TLS and RVS_SNI:
|
||||
import socket as _socket
|
||||
_orig_getaddrinfo = _socket.getaddrinfo
|
||||
def _sni_getaddrinfo(host, *a, **k):
|
||||
return _orig_getaddrinfo(RVS_HOST if host == RVS_SNI else host, *a, **k)
|
||||
_socket.getaddrinfo = _sni_getaddrinfo
|
||||
|
||||
|
||||
WHISPER_MODEL = os.getenv("WHISPER_MODEL", "small")
|
||||
WHISPER_DEVICE = os.getenv("WHISPER_DEVICE", "cuda")
|
||||
WHISPER_COMPUTE_TYPE = os.getenv("WHISPER_COMPUTE_TYPE", "float16")
|
||||
@@ -877,15 +889,12 @@ async def run_loop(runner: WhisperRunner, sessions: SessionManager) -> None:
|
||||
|
||||
while True:
|
||||
scheme = "wss" if use_tls else "ws"
|
||||
url = f"{scheme}://{RVS_HOST}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
uri_host = RVS_SNI if (use_tls and RVS_SNI) else RVS_HOST
|
||||
url = f"{scheme}://{uri_host}:{RVS_PORT}?token={RVS_TOKEN}"
|
||||
masked = url.replace(RVS_TOKEN, "***") if RVS_TOKEN else url
|
||||
connect_kwargs = {"ping_interval": 20, "ping_timeout": 10, "max_size": 50 * 1024 * 1024}
|
||||
if use_tls and RVS_SNI:
|
||||
import ssl
|
||||
connect_kwargs["ssl"] = ssl.create_default_context()
|
||||
connect_kwargs["server_hostname"] = RVS_SNI
|
||||
try:
|
||||
logger.info("Verbinde zu RVS: %s%s", masked, f" (SNI {RVS_SNI})" if (use_tls and RVS_SNI) else "")
|
||||
logger.info("Verbinde zu RVS: %s%s", masked, f" (TCP {RVS_HOST})" if (use_tls and RVS_SNI) else "")
|
||||
async with websockets.connect(url, **connect_kwargs) as ws:
|
||||
logger.info("RVS verbunden")
|
||||
retry_s = 2
|
||||
|
||||
Reference in New Issue
Block a user