Accès refusé : l'interface dit pourquoi et comment le lever

Depuis la protection anti-site-tiers (0.14.0), un accès par nom de domaine
derrière un reverse proxy, sans clé de pilotage, reçoit un 403 sur toute
l'API. L'interface restait vide : chaque appel échouait en silence dans la
console.

- Au premier 403, un bandeau fixe affiche la raison donnée par le serveur
  et le correctif : LOKI_TRUSTED_HOSTS=<le nom affiché> dans les variables
  du conteneur, ou une clé de pilotage.
- docker-compose.yml et docker-compose.unraid.yml exposent la variable
  LOKI_TRUSTED_HOSTS, commentée.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 5.5 committed 2026-10-03 22:11:19 +02:00
1 parent cf8d1cfaaa
commit aebecd75bd
4 files changed
+54

No files matched your search

+23
View File
@@ -33,8 +33,31 @@ async function jfetch(u, opts){
const k = await askKeyOnce();
if(k){ opts.headers = authHeaders(opts.headers); r = await fetch(u, opts); }
}
// 403 de la garde anti-site-tiers (web_auth.go, crossSiteReject) : sans ce
// bandeau, l'interface restait vide sans dire pourquoi — chaque appel échouait
// en silence dans la console.
if(r.status === 403 && !accessBlockedShown){
r.clone().json().then(j=>{ if(j && j.error) showAccessBlocked(j.error); }).catch(()=>{});
}
return r;
}
// showAccessBlocked : bandeau fixe expliquant le refus d'accès et comment le
// lever (nom de domaine derrière un reverse proxy, sans clé de pilotage).
let accessBlockedShown = false;
function showAccessBlocked(msg){
if(accessBlockedShown) return;
accessBlockedShown = true;
const d = document.createElement('div');
d.id = 'access-blocked';
d.setAttribute('role', 'alert');
d.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:9999;padding:12px 16px;background:var(--err,#b3564d);color:#fff;font-size:13px;line-height:1.5';
const host = location.hostname;
d.innerHTML = '<b>Accès refusé par Loki</b> — ' + escHtml(msg) +
'<br>Derrière un reverse proxy : ajoute <code>LOKI_TRUSTED_HOSTS=' + escHtml(host) +
'</code> aux variables du conteneur puis recrée-le, ou définis une clé de pilotage (<code>docker exec -it loki loki set-web-key</code>).';
document.body.appendChild(d);
}
// askKeyOnce : UNE seule demande de clé à la fois, partagée par tous les appels.
//
// Le chargement de l'UI lance une dizaine d'appels /api/* en parallèle, et le