# Guide de Deploiement - Wordly.art (Homelab) > Nginx Proxy Manager + IONOS DNS + Docker + NAS Backup + Monitoring --- ## Architecture ``` Internet | | DNS IONOS: wordly.art -> ton IP fixe | [Routeur/Box] (port forwarding 80+443 -> machine NPM) | +-- Machine 1: Nginx Proxy Manager (NPM) | - SSL Let's Encrypt automatique | - Reverse proxy vers les services | +-- Machine 2 ou 3: Docker (Wordly app) | +-- wordly-backend (FastAPI :8000) +-- wordly-frontend (Next.js :3000) +-- wordly-postgres (PostgreSQL :5432) +-- wordly-redis (Redis :6379) +-- wordly-prometheus (interne :9090) +-- wordly-grafana (:3001) +-- wordly-node-exporter +-- wordly-cadvisor | +-- Backup quotidien -> NAS (SMB/NFS) ``` ### Routing NPM | Sous-domaine | Cible Docker | Port | |--------------|-------------|------| | `wordly.art` | `wordly-frontend` | 3000 | | `wordly.art/api/*` | `wordly-backend` | 8000 | | `wordly.art/translate` | `wordly-backend` | 8000 | | `monitoring.wordly.art` | `wordly-grafana` | 3000 | --- ## Etape 1 : Configuration DNS chez IONOS ### 1.1 Connexion a IONOS 1. Se connecter sur **ionos.fr** / **ionos.com** 2. Aller dans **Domaines & SSL** 3. Cliquer sur **wordly.art** ### 1.2 Creer les enregistrements DNS Cliquer sur **DNS** > **Gerer les enregistrements** et ajouter : | Type | Nom | Valeur | TTL | |------|-----|--------|-----| | **A** | `@` | `TON_IP_FIXE` | 3600 | | **A** | `www` | `TON_IP_FIXE` | 3600 | | **A** | `monitoring` | `TON_IP_FIXE` | 3600 | > Remplace `TON_IP_FIXE` par ton IP fixe publique. > Pour la trouver : https://whatismyip.com ### 1.3 Verifier la propagation DNS ```bash # Attendre 5-30 minutes puis verifier nslookup wordly.art nslookup monitoring.wordly.art ``` --- ## Etape 2 : Nginx Proxy Manager (NPM) ### 2.1 Verifier que NPM tourne NPM est deja installe sur une de tes machines. Verifier : ```bash # Sur la machine qui heberge NPM docker ps | grep npm # ou docker ps | grep nginx-proxy-manager ``` L'interface admin NPM est accessible sur **http://IP_NPM:81** ### 2.2 Connecter NPM au reseau Docker de Wordly Pour que NPM puisse atteindre les containers Wordly par leur nom, il doit etre sur le meme reseau Docker. ```bash # Sur la machine qui heberge NPM, trouver le nom du container NPM docker ps | grep -i npm # Trouver le reseau du container NPM docker inspect | grep -A5 Networks # Sur la machine Wordly, on va connecter NPM au reseau wordly-network # (uniquement si NPM et Wordly sont sur la MEME machine Docker) docker network connect wordly-network ``` **Si NPM et Wordly sont sur des machines differentes** (recommande avec 3 machines) : - Pas besoin de reseau Docker partage - NPM utilisera l'IP de la machine Wordly au lieu du nom de container - Voir section 2.4 pour la configuration ### 2.3 Creer les Proxy Hosts dans NPM Se connecter a **http://IP_NPM:81** puis : #### Proxy Host 1 : wordly.art (Frontend + Backend) Aller dans **Proxy Hosts** > **Add Proxy Host** : **Onglet Details :** - **Domain Names** : `wordly.art` - **Scheme** : `http` - **Forward Hostname/IP** : `wordly-frontend` *(si meme machine)* OU `IP_MACHINE_WORDLY` *(si machines differentes)* - **Forward Port** : `3000` - Cocher **Block Common Exploits** - Cocher **Websockets Support** **Onglet SSL :** - **SSL Certificate** : `Request a new SSL Certificate` - Cocher **Force SSL** - Cocher **HTTP/2 Support** - Cocher **HSTS Enabled** - **Email** : `admin@wordly.art` - Cocher **I Agree to the...** Cliquer **Save**. NPM va automatiquement obtenir le certificat Let's Encrypt. #### Proxy Host 2 : www.wordly.art -> redirect **Onglet Details :** - **Domain Names** : `www.wordly.art` - **Scheme** : `http` - **Forward Hostname/IP** : `wordly-frontend` - **Forward Port** : `3000` **Onglet SSL :** - Meme certificat que wordly.art (selectionner le certificat deja cree) **Onglet Advanced :** Ajouter dans le champ Custom Nginx Configuration : ```nginx # Rediriger toutes les requetes API et translate vers le backend location /api/ { proxy_pass http://wordly-backend:8000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Connection ""; proxy_connect_timeout 60s; proxy_send_timeout 300s; proxy_read_timeout 300s; proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; add_header Access-Control-Allow-Origin https://wordly.art always; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always; add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With, X-API-Key" always; add_header Access-Control-Allow-Credentials "true" always; if ($request_method = 'OPTIONS') { return 204; } } location /translate { proxy_pass http://wordly-backend:8000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 60s; proxy_send_timeout 600s; proxy_read_timeout 600s; client_max_body_size 100M; } location /health { proxy_pass http://wordly-backend:8000; proxy_http_version 1.1; proxy_set_header Connection ""; } location /docs { proxy_pass http://wordly-backend:8000; proxy_set_header Host $host; } location /redoc { proxy_pass http://wordly-backend:8000; proxy_set_header Host $host; } location /openapi.json { proxy_pass http://wordly-backend:8000; proxy_set_header Host $host; } location /admin { proxy_pass http://wordly-frontend:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /_next/static/ { proxy_pass http://wordly-frontend:3000; add_header Cache-Control "public, max-age=31536000, immutable"; } ``` > **IMPORTANT** : Si NPM et Wordly sont sur des machines differentes, remplacer > `wordly-backend:8000` par `IP_MACHINE_WORDLY:8000` et > `wordly-frontend:3000` par `IP_MACHINE_WORDLY:3000` #### Proxy Host 3 : monitoring.wordly.art (Grafana) **Onglet Details :** - **Domain Names** : `monitoring.wordly.art` - **Scheme** : `http` - **Forward Hostname/IP** : `wordly-grafana` *(si meme machine)* OU `IP_MACHINE_WORDLY` *(si machines differentes)* - **Forward Port** : `3000` - Cocher **Block Common Exploits** **Onglet SSL :** - **SSL Certificate** : `Request a new SSL Certificate` - Cocher **Force SSL** - Cocher **HSTS Enabled** - **Email** : `admin@wordly.art` ### 2.4 Cas : NPM et Wordly sur machines differentes Si NPM tourne sur Machine A et Wordly sur Machine B : 1. **Ouvrir les ports** sur la Machine B pour que NPM puisse atteindre les services : ```bash # Sur Machine B, ouvrir dans le pare-feu local sudo ufw allow from IP_MACHINE_A to any port 3000 # Frontend sudo ufw allow from IP_MACHINE_A to any port 8000 # Backend sudo ufw allow from IP_MACHINE_A to any port 3001 # Grafana ``` 2. **Exposer les ports** dans docker-compose.yml en ajoutant la section `ports` : ```yaml backend: # ... config existante ... ports: - "IP_MACHINE_B:8000:8000" # Bind sur IP locale seulement frontend: # ... config existante ... ports: - "IP_MACHINE_B:3000:3000" grafana: # ... config existante ... ports: - "IP_MACHINE_B:3000:3000" ``` 3. Dans NPM, utiliser `IP_MACHINE_B` comme Forward Hostname --- ## Etape 3 : Deploiement de l'application ### 3.1 Preparer le serveur ```bash # Installer Docker (si pas deja fait) curl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER newgrp docker # Verifier docker --version docker compose version ``` ### 3.2 Transferer le code ```bash # Cloner le repo git clone /opt/wordly cd /opt/wordly git checkout production-deployment ``` ### 3.3 Configurer les secrets ```bash cd /opt/wordly # Copier le fichier env cp .env.production .env # Generer le hash bcrypt du mot de passe admin docker run --rm python:3.12-slim bash -c " pip install 'passlib[bcrypt]' bcrypt > /dev/null 2>&1 && python -c \"from passlib.context import CryptContext; print(CryptContext(schemes=['bcrypt']).hash('TON_MOT_DE_PASSE_ADMIN'))\" " ``` Copier le hash affiche et le coller dans `.env` pour `ADMIN_PASSWORD_HASH`. ```bash # Editer le fichier .env et verifier tous les champs nano .env ``` Verifications cles dans `.env` : - `DOMAIN=wordly.art` - `NEXT_PUBLIC_API_URL=https://wordly.art` - `JWT_SECRET_KEY=` (deja rempli) - `ADMIN_TOKEN_SECRET=` (deja rempli) - `ADMIN_PASSWORD_HASH=` (coller le hash genere) - `CORS_ORIGINS=https://wordly.art` - `POSTGRES_PASSWORD=` (deja rempli) ### 3.4 Lancer l'application ```bash # Build et demarrage docker compose up -d --build # Suivre les logs pendant le premier demarrage docker compose logs -f ``` ### 3.5 Verifier ```bash # Sur le serveur, tester directement curl http://localhost:8000/health # Verifier tous les containers docker compose ps ``` Resultat attendu : ``` NAME STATUS PORTS wordly-postgres Up (healthy) wordly-redis Up (healthy) wordly-backend Up (healthy) wordly-frontend Up (healthy) ``` --- ## Etape 4 : Verification complete ### 4.1 Tester depuis l'exterieur ```bash # Depuis un autre ordinateur ou telephone curl -I https://wordly.art # Doit retourner: # HTTP/2 200 # server: nginx # strict-transport-security: ... ``` ### 4.2 Tester dans le navigateur 1. Ouvrir **https://wordly.art** -> doit afficher le frontend 2. Ouvrir **https://wordly.art/health** -> doit retourner `{"status": "ok"}` 3. Ouvrir **https://wordly.art/admin** -> doit afficher le login admin 4. Ouvrir **https://monitoring.wordly.art** -> doit afficher Grafana ### 4.3 Tester le SSL Le cadenas vert doit etre present sur wordly.art. NPM a automatiquement obtenu le certificat Let's Encrypt. --- ## Etape 5 : Backup automatique vers NAS ### 5.1 Monter le NAS #### Option A : SMB/CIFS (Synology / QNAP) ```bash sudo apt install cifs-utils sudo mkdir -p /mnt/nas-backups/wordly # Fichier credentials sudo tee /etc/nas-credentials <> /var/log/wordly-backup.log 2>&1 ``` --- ## Etape 6 : Monitoring (Prometheus + Grafana) ### 6.1 Lancer le stack monitoring ```bash cd /opt/wordly # Creer le reseau externe si necessaire docker network create wordly-network 2>/dev/null || true # Lancer application + monitoring docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d ``` ### 6.2 Acceder a Grafana - **URL** : `https://monitoring.wordly.art` (via NPM) - **Login** : `admin` - **Mot de passe** : `WordlyGrafana2026!` - Changer le mot de passe a la premiere connexion ### 6.3 Dashboards pre-configures | Dashboard | Contenu | |-----------|---------| | **Wordly - Application** | Traductions, latence, providers, taux d'erreur | | **Wordly - Infrastructure** | CPU, RAM, disque, reseau, status containers | Ils apparaissent automatiquement dans le dossier **Wordly** de Grafana. ### 6.4 Configurer les alertes (optionnel) Dans Grafana : **Alerting** > **Contact points** > **Add contact point** : - Type : **Email** ou **Discord webhook** - Ajouter ton email ou l'URL du webhook Les regles d'alerte suivantes sont pre-configures : - Backend down - Taux d'erreur > 10% - RAM > 90% - Disque < 15% --- ## Etape 7 : Operations courantes ### Logs ```bash docker compose logs -f --tail=100 # Tous les services docker compose logs -f backend # Backend seul docker compose logs -f frontend # Frontend seul docker compose logs -f postgres # Base de donnees ``` ### Redemarrer ```bash docker compose restart backend docker compose restart frontend ``` ### Mettre a jour ```bash cd /opt/wordly git pull origin production-deployment docker compose up -d --build ``` ### Restaurer un backup ```bash /opt/wordly/scripts/backup-to-nas.sh --restore # Liste les backups disponibles /opt/wordly/scripts/backup-to-nas.sh --restore wordly_db_20260510_030000.sql.gz ``` ### Verifier l'espace ```bash df -h # Disque systeme docker system df # Espace Docker ``` ### Renouveler le SSL NPM renouvelle les certificats Let's Encrypt automatiquement. Pas d'action requise. Verifier dans NPM > SSL Certificates que le statut est OK. --- ## Checklist de deploiement ### DNS IONOS - [ ] Enregistrement A : `@` -> IP fixe - [ ] Enregistrement A : `www` -> IP fixe - [ ] Enregistrement A : `monitoring` -> IP fixe - [ ] Propagation DNS verifiee (nslookup) ### Nginx Proxy Manager - [ ] Proxy Host cree pour `wordly.art` -> frontend:3000 - [ ] SSL Let's Encrypt obtenu pour `wordly.art` - [ ] Custom config nginx ajoutee (routing API/backend) - [ ] Proxy Host cree pour `monitoring.wordly.art` -> grafana:3000 - [ ] SSL Let's Encrypt obtenu pour `monitoring.wordly.art` ### Serveur Docker - [ ] Docker installe - [ ] Code clone dans /opt/wordly - [ ] Fichier .env rempli avec tous les secrets - [ ] Hash bcrypt genere et colle - [ ] `docker compose up -d --build` reussi - [ ] Tous les containers healthy ### NAS - [ ] Partage de backup cree sur le NAS - [ ] NAS monte sur /mnt/nas-backups/wordly - [ ] Backup manuel test OK - [ ] Cron programme a 3h ### Verification finale - [ ] https://wordly.art accessible depuis Internet - [ ] HTTPS OK (cadenas vert) - [ ] Upload fichier OK - [ ] Traduction test OK - [ ] https://monitoring.wordly.art accessible - [ ] Dashboards Grafana affichent des donnees - [ ] Page admin accessible (/admin)