L'endpoint compatible OpenAI n'était pas servi par Loki : le panneau annonçait
l'adresse de llama-server lui-même, http://<ip>:8080/v1. Dans le déploiement de
référence de ce fork, cette adresse ne peut joindre personne — le port 8080
n'est pas publié par le conteneur, l'entrypoint sème HOST=127.0.0.1, et l'IP
annoncée est celle du bridge Docker. L'autre voie proposée, « exposer en public
(ajean.link) », exigeait un jeton de relais que ce fork ne permet plus
d'obtenir : l'interrupteur ne pouvait que renvoyer vers un panneau supprimé.
Désormais, Loki sert /v1/* SUR SON PROPRE PORT et relaie vers le moteur. L'API
est donc joignable partout où l'interface l'est — IP du réseau local, nom de
domaine, reverse proxy — sans publier de second port ni ouvrir le moteur.
Serveur
- mountOAI (llm_oai.go) monte /v1/ sur le mux, et RIEN d'autre : ni /metrics,
ni /props, ni /slots, qui divulgueraient le modèle chargé et l'état des slots.
Le filtre interne d'oaiHandler reste en seconde barrière.
- requireCompletionKey (web_auth.go) garde cette surface avec la clé des
COMPLÉTIONS, pas celle de pilotage : un client OpenAI n'a qu'un en-tête
Authorization, et on veut pouvoir lui donner l'accès au modèle sans le droit
de redémarrer la machine. Erreurs au format d'OpenAI (body.error.message), que
les SDK savent présenter. Le préflight CORS passe sans clé — il n'en porte
jamais, et le refuser casserait tout client tiers de navigateur.
- effectiveAPIKeyErr (backend_config.go) devient la source unique de la clé
exigée : base d'abord, config.env en repli, exactement comme le moteur. Sans
ce miroir, un API_KEY résiduel donnait un endpoint « ouvert » côté Loki et un
401 côté moteur, sans rien pour l'expliquer. Lecture ratée = refus, jamais
ouverture (même raisonnement que readWebKeyErr).
- oaiHandler passe à ReverseProxy.Rewrite : le port du moteur est relu à chaque
requête au lieu d'être figé à la construction — il visait l'ancien port dès
qu'on changeait PORT, jusqu'au redémarrage de Loki.
- withLocalAuth (relay_link.go) n'injecte plus la clé de pilotage sur /v1 : elle
aurait été refusée par la garde, et surtout relayée au moteur. Le trafic du
tunnel est marqué (en-tête effacé avant d'être posé, sinon un client le forge)
et la surface y reste fermée tant que oai_public est faux — la promesse du
tunnel est tenue.
Adresse affichée
- web_public_url.go : normalisation d'une adresse publique saisie à la main
(schéma ajouté, /v1 recopié toléré, chemin refusé), origine de la requête via
Host + X-Forwarded-Proto, et la règle de priorité entre les deux.
- Le calcul quitte le navigateur pour le serveur : c'est la concaténation côté
client qui produisait l'adresse fantôme.
Interface
- Le panneau perd l'interrupteur ajean.link et l'interrupteur d'écoute LAN — ce
dernier n'a plus d'objet, et deux interrupteurs pour « rendre l'IA joignable »
était la confusion à lever. La route /api/network et `loki network` restent
pour qui veut exposer le moteur en direct.
- Il gagne un champ « adresse publique » (facultatif, pour le reverse proxy) et
un avertissement rouge tant qu'aucune clé n'est définie — l'endpoint est
maintenant ouvert PARTOUT où l'interface l'est, ça ne se dit pas à voix basse.
Le démarrage de `loki web` le crie aussi.
Vérifié bout en bout sur le serveur réel : liste des modèles à travers Loki avec
la clé (200), sans la clé (401), et complétion en streaming dont les tokens
arrivent espacés de 120 ms — le flux traverse bien le double proxy.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LPyFxVHNAN9u5pVzSYMwjd
- module github.com/R0m1k3/Loki, cmd/loki, internal/loki (package loki)
- LOKI_HOME, LOKI_MODEL_DIRS, LOKI_SERVICE, LOKI_DL_CONNS ; /etc/loki ;
units loki-engine / loki-ui ; binaire et aide CLI
- updateRepo pointe sur R0m1k3/Loki (l'auto-update ne tirera plus les
binaires AJEAN amont)
Conservé à l'identique : le domaine ajean.link (service de tunnel amont),
les littéraux de migration 0.7.x (migrate_07.go), RELEASE_NOTES.md et
LICENSE (historique et licence de l'amont).
go build/vet/test : verts.