**Motivations:** - Simplify Cursor/custom clients; Bearer caused confusion with Cursor user API key. **Root causes:** - N/A. **Correctifs:** - Drop if map check and Authorization stripping on /ollama/; deploy script no longer emits Bearer map. **Evolutions:** - Optional Bearer documented in http-maps example; README/services/feature/infrastructure updated; proxy redeployed. **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
158 lines
8.3 KiB
Markdown
158 lines
8.3 KiB
Markdown
# ia.enso.4nkweb.com — Nginx sur le proxy (192.168.1.100)
|
||
|
||
Reverse TLS vers l’hô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` |
|
||
|
||
**Sécurité :** `/ollama/` n’a **pas** de garde Bearer nginx par défaut : toute personne qui peut joindre l’URL peut utiliser l’API Ollama. Restreindre par **pare-feu** (IP du proxy uniquement vers `.164`) ou réintroduire un `map` Bearer (voir `http-maps/ia-enso-ollama-bearer.map.conf.example`). AnythingLLM sous `/anythingllm/` reste derrière son **login applicatif**.
|
||
|
||
| Chemin (relatif) | Backend | Port LAN | Protection |
|
||
|------------------|---------|----------|------------|
|
||
| `/ollama/` | Ollama | `11434` | Aucune auth nginx (Ollama sans clé par défaut) |
|
||
| `/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 n’est 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 d’architecture : [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
|
||
# accès LAN direct au proxy (.100), sans bastion (variable vide = pas de ProxyJump) :
|
||
# export DEPLOY_SSH_PROXY_HOST=
|
||
./deploy/nginx/deploy-ia-enso-to-proxy.sh
|
||
```
|
||
|
||
### 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** Let’s 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 l’entré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` WebSocket `$connection_upgrade` (ou fichier stub si doublon ailleurs) |
|
||
| `/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 d’un **doublon** `map $http_upgrade $connection_upgrade`, le script retente avec un **stub** commenté à la place du `map`.
|
||
|
||
### Variables d’environnement du script
|
||
|
||
| Variable | Défaut | Rôle |
|
||
|----------|--------|------|
|
||
| `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 l’entré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 (WebSocket ; Bearer optionnel)
|
||
|
||
**WebSocket (AnythingLLM)** : si `$connection_upgrade` n’existe pas déjà dans l’instance, inclure `http-maps/websocket-connection.map.conf.example` dans `http { }` ou utiliser le fichier `ia-enso-http-maps.conf` déployé par le script.
|
||
|
||
**Bearer sur `/ollama/` (optionnel)** : pour réactiver une garde nginx, ajouter le `map` de `http-maps/ia-enso-ollama-bearer.map.conf.example` et dans `location /ollama/` un `if ($ia_enso_ollama_authorized = 0) { return 401; }` (+ `map_hash_bucket_size 256` si secret long). Ne pas commiter le secret.
|
||
|
||
### 3. Fichier `server`
|
||
|
||
Le fichier dans le dépôt contient le marqueur `__IA_ENSO_BACKEND_IP__`. Remplacer par l’IPv4 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 l’IPv4 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" https://ia.enso.4nkweb.com/ollama/v1/models
|
||
curl -sS -o /dev/null -w "%{http_code}\n" https://ia.enso.4nkweb.com/ollama/api/tags
|
||
```
|
||
|
||
Attendu : **200** sans en-tête `Authorization` (config par défaut sans Bearer nginx).
|
||
|
||
### 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 : laisser vide ou valeur factice si Cursor l’exige (plus de Bearer nginx sur `/ollama/` par défaut).
|
||
|
||
Si **`curl`** vers `/ollama/v1/models` renvoie **200** mais Cursor affiche **`ERROR_BAD_USER_API_KEY`**, l’échec vient **du client Cursor** (validation / infra Cursor), pas du proxy : [forum](https://forum.cursor.com/t/unauthorized-user-api-key-with-custom-openai-api-key-url/132572).
|
||
|
||
---
|
||
|
||
## Pare-feu backend
|
||
|
||
Sur **`192.168.1.164`**, n’autoriser **11434** et **3001** TCP que depuis **192.168.1.100** (proxy) si un pare-feu hôte est actif.
|
||
|
||
---
|
||
|
||
## Dépannage
|
||
|
||
| Symptôme | Piste |
|
||
|----------|--------|
|
||
| `nginx -t` erreur sur `connection_upgrade` | Doublon de `map $http_upgrade $connection_upgrade` : retirer l’un des blocs ou laisser le stub du script. |
|
||
| `could not build map_hash` / `map_hash_bucket_size` | Uniquement si tu réactives un `map` Bearer avec un secret très long ; ajouter `map_hash_bucket_size 256;` dans `http { }`. |
|
||
| `401` sur `/ollama/` | Bearer nginx réactivé manuellement : aligner client et `map`, ou désactiver la garde. |
|
||
| `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` | L’hôte utilisé résout encore vers une IP privée côté infrastructure Cursor ; vérifier DNS public / NAT. |
|