smart_ide/deploy/nginx/README-ia-enso.md
Nicolas Cantu c4215044f0 Re-enable nginx Bearer auth on ia.enso /ollama
**Motivations:**
- Restore gate on /ollama/; document Cursor streamFromAgentBackend note.

**Root causes:**
- N/A.

**Correctifs:**
- location /ollama/ if map + clear Authorization upstream; deploy script emits Bearer + websocket maps with retry bearer_only.

**Evolutions:**
- README Cursor subsection on streamFromAgentBackend (observed behavior); feature/services/infrastructure aligned.

**Pages affectées:**
- deploy/nginx/sites/ia.enso.4nkweb.com.conf
- deploy/nginx/deploy-ia-enso-to-proxy.sh
- deploy/nginx/README-ia-enso.md
- deploy/nginx/http-maps/ia-enso-ollama-bearer.map.conf.example
- docs/features/ia-enso-nginx-proxy-ollama-anythingllm.md
- docs/services.md
- docs/infrastructure.md
2026-03-23 07:49:06 +01:00

169 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ia.enso.4nkweb.com — Nginx sur le proxy (192.168.1.100)
Reverse TLS vers lhôte LAN **`192.168.1.164`** (Ollama + AnythingLLM ; IP substituée au déploiement via `__IA_ENSO_BACKEND_IP__` / `IA_ENSO_BACKEND_IP`).
## URLs publiques complètes (HTTPS)
| Service | URL |
|---------|-----|
| **AnythingLLM** (interface) | `https://ia.enso.4nkweb.com/anythingllm/` |
| **Ollama** API native (ex. liste des modèles) | `https://ia.enso.4nkweb.com/ollama/api/tags` |
| **Ollama** API compatible OpenAI (Cursor, etc.) | base URL `https://ia.enso.4nkweb.com/ollama/v1` — ex. `https://ia.enso.4nkweb.com/ollama/v1/models` |
**Bearer nginx :** tout `/ollama/` exige `Authorization: Bearer <secret>` (fichier `map` sur le proxy). La valeur nest **pas** transmise à Ollama (`Authorization` effacé en amont). AnythingLLM sous `/anythingllm/` : auth **applicative** uniquement.
| Chemin (relatif) | Backend | Port LAN | Protection |
|------------------|---------|----------|------------|
| `/ollama/` | Ollama | `11434` | **Bearer** nginx |
| `/anythingllm/` | AnythingLLM | `3001` | Login AnythingLLM |
**Contexte Cursor :** une URL en IP privée (ex. `http://192.168.1.164:11434`) peut être refusée par Cursor (`ssrf_blocked`). Un **nom public** HTTPS vers le proxy évite ce blocage si le DNS résolu depuis Internet nest pas une IP RFC1918.
**Fichiers dans le dépôt :** `sites/ia.enso.4nkweb.com.conf`, `http-maps/*.example`, `deploy-ia-enso-to-proxy.sh`. Détails darchitecture : [docs/features/ia-enso-nginx-proxy-ollama-anythingllm.md](../../docs/features/ia-enso-nginx-proxy-ollama-anythingllm.md).
---
## Déploiement recommandé : script SSH
Depuis la racine du dépôt **`smart_ide`**, sur une machine avec accès SSH au bastion puis au proxy :
```bash
export IA_ENSO_OLLAMA_BEARER_TOKEN='secret-ascii-sans-guillemets-ni-backslash'
# accès LAN direct au proxy (.100), sans bastion :
# export DEPLOY_SSH_PROXY_HOST=
./deploy/nginx/deploy-ia-enso-to-proxy.sh
```
Si `IA_ENSO_OLLAMA_BEARER_TOKEN` est absent, le script génère un token hex (affichage unique) à conserver pour Cursor.
### Prérequis sur le proxy
- `http { include /etc/nginx/conf.d/*.conf; ... }` dans `/etc/nginx/nginx.conf` (sinon le script échoue avec un message explicite).
- **Certificats** Lets Encrypt pour `ia.enso.4nkweb.com` aux chemins du fichier site (`/etc/letsencrypt/live/ia.enso.4nkweb.com/fullchain.pem` et `privkey.pem`). Sans eux, le bloc `listen 443` fait échouer `nginx -t` : voir **Bootstrap TLS** ci-dessous.
- **`sudo` non interactif** pour `nginx` et `systemctl reload nginx`.
### Bootstrap TLS (première fois, `nginx -t` impossible)
1. DNS : `ia.enso.4nkweb.com` doit résoudre vers lentrée publique qui atteint ce proxy (HTTP port 80).
2. Sur le proxy :
```bash
sudo install -d -m 0755 /var/www/certbot
# Remplacer temporairement le vhost par HTTP seul (fichier dans le dépôt : sites/ia.enso.4nkweb.com.http-only.conf)
sudo cp /chemin/smart_ide/deploy/nginx/sites/ia.enso.4nkweb.com.http-only.conf /etc/nginx/sites-available/ia.enso.4nkweb.com.conf
sudo nginx -t && sudo systemctl reload nginx
sudo certbot certonly --webroot -w /var/www/certbot -d ia.enso.4nkweb.com --non-interactive --agree-tos --register-unsafely-without-email
```
3. Déployer la config complète : `./deploy/nginx/deploy-ia-enso-to-proxy.sh` (rétablit HTTPS + upstreams).
### Fichiers installés par le script
| Chemin sur le proxy | Rôle |
|---------------------|------|
| `/etc/nginx/conf.d/ia-enso-http-maps.conf` | `map_hash_bucket_size`, `map` Bearer `$ia_enso_ollama_authorized`, et souvent `map` WebSocket |
| `/etc/nginx/sites-available/ia.enso.4nkweb.com.conf` | `server` HTTP→HTTPS + HTTPS |
| Lien `sites-enabled/ia.enso.4nkweb.com.conf` | Activation du vhost |
Si `nginx -t` échoue à cause dun **doublon** `map $http_upgrade $connection_upgrade`, le script retente avec **Bearer seul** (sans dupliquer le `map` WebSocket).
### Variables denvironnement du script
| Variable | Défaut | Rôle |
|----------|--------|------|
| `IA_ENSO_OLLAMA_BEARER_TOKEN` | généré (`openssl rand -hex 32`) | Secret pour `Authorization: Bearer …` |
| `IA_ENSO_SSH_KEY` | `~/.ssh/id_ed25519` | Clé privée SSH |
| `IA_ENSO_PROXY_USER` | `ncantu` | Utilisateur SSH sur le proxy |
| `IA_ENSO_PROXY_HOST` | `192.168.1.100` | Cible SSH (IP ou hostname LAN) |
| `DEPLOY_SSH_PROXY_HOST` | `4nk.myftp.biz` | Bastion ProxyJump ; vide = SSH direct |
| `DEPLOY_SSH_PROXY_USER` | idem proxy | Utilisateur sur le bastion |
| `IA_ENSO_BACKEND_IP` | `192.168.1.164` | Hôte Ollama + AnythingLLM (IPv4) |
Bibliothèque utilisée : `ia_dev/deploy/_lib/ssh.sh` (`BatchMode=yes`).
---
## Déploiement manuel (sans script)
### 1. DNS et TLS
Le DNS doit résoudre `ia.enso.4nkweb.com` vers lentrée publique qui atteint ce proxy.
```bash
sudo certbot certonly --webroot -w /var/www/certbot -d ia.enso.4nkweb.com
```
Adapter dans `sites/ia.enso.4nkweb.com.conf` les directives `ssl_certificate` / `ssl_certificate_key` si le répertoire `live/` diffère.
### 2. Maps HTTP (Bearer + WebSocket)
Le script déploie `ia-enso-http-maps.conf` avec `map_hash_bucket_size 256`, le `map` Bearer et le `map` WebSocket (ou Bearer seul si doublon WebSocket ailleurs). Installation manuelle : combiner `http-maps/ia-enso-ollama-bearer.map.conf.example` et `websocket-connection.map.conf.example` dans `http { }` si besoin.
### 3. Fichier `server`
Le fichier dans le dépôt contient le marqueur `__IA_ENSO_BACKEND_IP__`. Remplacer par lIPv4 du backend (ex. `192.168.1.164`) avant copie, ou utiliser :
```bash
sed "s/__IA_ENSO_BACKEND_IP__/192.168.1.164/g" deploy/nginx/sites/ia.enso.4nkweb.com.conf | sudo tee /etc/nginx/sites-available/ia.enso.4nkweb.com.conf >/dev/null
```
Sans `sed` : éditer le fichier sur le proxy pour remplacer `__IA_ENSO_BACKEND_IP__` par lIPv4 réelle, puis :
```bash
sudo ln -sf /etc/nginx/sites-available/ia.enso.4nkweb.com.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```
---
## Vérifications
### API Ollama via le proxy
```bash
curl -sS -o /dev/null -w "%{http_code}\n" \
-H "Authorization: Bearer <secret>" \
https://ia.enso.4nkweb.com/ollama/v1/models
```
Attendu : **200** avec le bon secret ; **401** sans `Authorization` ou secret incorrect.
### AnythingLLM
Navigateur : `https://ia.enso.4nkweb.com/anythingllm/` (redirection vers `/anythingllm/`). Connexion avec les identifiants **AnythingLLM**.
Si les assets statiques échouent, vérifier la doc upstream (sous-chemin, en-têtes `X-Forwarded-*`).
### Cursor
- URL de base OpenAI : `https://ia.enso.4nkweb.com/ollama/v1`
- Clé API : **identique** au secret du `map` nginx (sans préfixe `Bearer ` dans le champ).
**`streamFromAgentBackend` (comportement observé)** : dans lapplication Cursor (bundle Electron), le flux **Agent / chat** appelle une couche interne qui ouvre un stream vers **les serveurs Cursor** (`getAgentStreamResponse`, etc.), pas un `fetch` direct depuis ton poste vers ton URL OpenAI override. Cursor peut donc valider une **« User API key »** ou des droits **avant** ou **en parallèle** de lusage de loverride. Si **`curl`** avec le Bearer vers `/ollama/v1/models` renvoie **200** mais Cursor affiche **`ERROR_BAD_USER_API_KEY`**, léchec reste **côté client / infra Cursor** : [forum](https://forum.cursor.com/t/unauthorized-user-api-key-with-custom-openai-api-key-url/132572). Le code minifié du produit nest pas dans ce dépôt ; seuls les noms de fonctions dans la stack trace décrivent ce chemin dexécution.
---
## Pare-feu backend
Sur **`192.168.1.164`**, nautoriser **11434** et **3001** TCP que depuis **192.168.1.100** (proxy) si un pare-feu hôte est actif.
---
## Rotation du secret Bearer
1. Mettre à jour `"Bearer …"` dans `/etc/nginx/conf.d/ia-enso-http-maps.conf` (ou redéployer avec `IA_ENSO_OLLAMA_BEARER_TOKEN`).
2. `sudo nginx -t && sudo systemctl reload nginx`.
3. Mettre à jour la clé API dans Cursor (et tout autre client).
---
## Dépannage
| Symptôme | Piste |
|----------|--------|
| `nginx -t` erreur sur `connection_upgrade` | Doublon de `map $http_upgrade $connection_upgrade` : retirer lun des blocs ou laisser le déploiement « Bearer seul » du script. |
| `could not build map_hash` / `map_hash_bucket_size` | Secret Bearer long : le fichier généré par le script inclut `map_hash_bucket_size 256;`. |
| `401` sur `/ollama/` | Secret différent entre client et `map` ; en-tête `Authorization` absent ou mal formé. |
| `502` / timeout | Ollama ou AnythingLLM arrêtés sur le backend ; pare-feu ; mauvaise IP dans `upstream` (vérifier `grep server /etc/nginx/sites-available/ia.enso.4nkweb.com.conf` sur le proxy ; redéployer avec `IA_ENSO_BACKEND_IP=192.168.1.164`). |
| Erreur SSL / `cannot load certificate` | Certificat absent : exécuter certbot sur le proxy pour `ia.enso.4nkweb.com`, ou adapter les chemins `ssl_certificate` dans le fichier site. |
| Cursor `ssrf_blocked` | Lhôte utilisé résout encore vers une IP privée côté infrastructure Cursor ; vérifier DNS public / NAT. |