Files
office_translator/DEPLOYMENT_HOMELAB.md
sepehr ce8e150a61 feat: homelab deployment - NPM + IONOS DNS + monitoring + NAS backup
- Restructured docker-compose for Nginx Proxy Manager (no custom nginx)
- Added domain wordly.art configuration
- Added Prometheus + Grafana monitoring stack with pre-configured dashboards
- Added PostgreSQL backup script to NAS (daily/weekly/monthly rotation)
- Added alert rules for backend, system, and Docker metrics
- Updated deployment guide for NPM + IONOS DNS homelab setup
- Added marketing plan document
- PDF translator and watermark support
- Enhanced middleware, routes, and translator modules

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-10 11:43:28 +02:00

15 KiB

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

# 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 :

# 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.

# 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 <NPM_CONTAINER> | 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 <NPM_CONTAINER>

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 :

# 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 :

    # 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 :

    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

# 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

# Cloner le repo
git clone <ton-repo-git> /opt/wordly
cd /opt/wordly
git checkout production-deployment

3.3 Configurer les secrets

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.

# 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

# Build et demarrage
docker compose up -d --build

# Suivre les logs pendant le premier demarrage
docker compose logs -f

3.5 Verifier

# 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

# 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)

sudo apt install cifs-utils
sudo mkdir -p /mnt/nas-backups/wordly

# Fichier credentials
sudo tee /etc/nas-credentials <<EOF
username=wordly-backup
password=MOT_DE_PASSE_NAS
domain=WORKGROUP
EOF
sudo chmod 600 /etc/nas-credentials

# Montage auto au demarrage
echo "//IP_DU_NAS/wordly-backups /mnt/nas-backups/wordly cifs credentials=/etc/nas-credentials,uid=$(id -u),gid=$(id -g),iocharset=utf8,vers=3.0,noperm 0 0" | sudo tee -a /etc/fstab

sudo mount /mnt/nas-backups/wordly

Option B : NFS

sudo apt install nfs-common
sudo mkdir -p /mnt/nas-backups/wordly
echo "IP_DU_NAS:/volume1/wordly-backups /mnt/nas-backups/wordly nfs rw,hard,intr 0 0" | sudo tee -a /etc/fstab
sudo mount /mnt/nas-backups/wordly

5.2 Tester le backup

chmod +x /opt/wordly/scripts/backup-to-nas.sh
/opt/wordly/scripts/backup-to-nas.sh --full

# Verifier
ls -lh /mnt/nas-backups/wordly/daily/

5.3 Programmer le cron

crontab -e

# Backup quotidien a 3h du matin
0 3 * * * /opt/wordly/scripts/backup-to-nas.sh >> /var/log/wordly-backup.log 2>&1

Etape 6 : Monitoring (Prometheus + Grafana)

6.1 Lancer le stack monitoring

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

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

docker compose restart backend
docker compose restart frontend

Mettre a jour

cd /opt/wordly
git pull origin production-deployment
docker compose up -d --build

Restaurer un backup

/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

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