# Guide de déploiement — Ionos VPS ## Résumé de l'architecture en production ``` Internet ↓ HTTPS :443 [Nginx] ──→ /api/* → [Backend FastAPI :8000] ──→ /* → [Frontend Next.js :3000] ↓ [PostgreSQL :5432] [Redis :6379] ``` --- ## Étape 1 — Choisir et commander le VPS Ionos Sur **ionos.fr → Cloud → VPS** : | Critère | Recommandation | |---|---| | **Offre** | VPS RAM 4 Go (ou Cloud M1) | | **RAM** | 4 Go minimum (8 Go recommandé) | | **CPU** | 2 vCores | | **Stockage** | 80 Go SSD | | **OS** | Ubuntu 22.04 LTS | | **Prix** | ~8–12 €/mois | > **Pourquoi Ubuntu 22.04 ?** LTS jusqu'en 2027, Docker officiel disponible, apt bien documenté. --- ## Étape 2 — Premier accès SSH et sécurisation ```bash # Depuis votre Mac — connexion initiale (Ionos vous donne root + IP) ssh root@VOTRE_IP_IONOS # Créer un utilisateur non-root adduser deploy usermod -aG sudo docker deploy # Copier votre clé SSH publique (depuis votre Mac dans un autre terminal) ssh-copy-id deploy@VOTRE_IP_IONOS # Désactiver l'auth par mot de passe SSH nano /etc/ssh/sshd_config # → PasswordAuthentication no # → PermitRootLogin no systemctl restart sshd # Pare-feu UFW ufw allow OpenSSH ufw allow 80/tcp ufw allow 443/tcp ufw enable ``` --- ## Étape 3 — Installer Docker ```bash # Se connecter en tant que deploy ssh deploy@VOTRE_IP_IONOS # Installer Docker (méthode officielle) curl -fsSL https://get.docker.com | sudo bash # Ajouter deploy au groupe docker (sans sudo) sudo usermod -aG docker $USER newgrp docker # Vérifier docker --version docker compose version ``` --- ## Étape 4 — Configurer le domaine Ionos Dans votre espace client **Ionos → Domaines & SSL** : 1. Allez dans **DNS** de votre domaine 2. Ajoutez un enregistrement **A** : - Nom : `translate` (ou `@` pour la racine) - Valeur : `VOTRE_IP_IONOS` - TTL : 3600 3. Attendez 5–15 minutes la propagation DNS Testez : ```bash # Depuis votre Mac dig wordly.art # → doit retourner votre IP ``` --- ## Étape 5 — Déployer l'application ```bash # Sur le serveur Ionos cd /home/deploy # Cloner le dépôt git clone https://github.com/VOTRE_USER/office-translator.git cd office-translator # Créer le fichier .env depuis le template Ionos cp .env.ionos .env nano .env # Remplissez TOUTES les valeurs (voir ci-dessous) ``` ### Valeurs à générer pour le .env ```bash # Clé JWT (obligatoire) python3 -c "import secrets; print(secrets.token_urlsafe(64))" # Mot de passe PostgreSQL python3 -c "import secrets; print(secrets.token_urlsafe(32))" # Hash mot de passe admin python3 -c "from passlib.context import CryptContext; print(CryptContext(schemes=['bcrypt']).hash('VotreMotDePasse'))" ``` --- ## Étape 6 — Obtenir le certificat SSL (Let's Encrypt) ```bash # 1. Démarrer Nginx en mode HTTP seulement d'abord # Créer conf HTTP temporaire pour la vérification ACME cat > docker/nginx/conf.d/app.conf << 'EOF' server { listen 80; server_name wordly.art; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { proxy_pass http://frontend:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /api/ { proxy_pass http://backend:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } EOF # 2. Démarrer les services docker compose -f docker-compose.ionos.yml up -d postgres redis backend frontend nginx # 3. Obtenir le certificat docker compose -f docker-compose.ionos.yml run --rm certbot certonly \ --webroot \ --webroot-path=/var/www/certbot \ --email votre-email@wordly.art \ --agree-tos \ --no-eff-email \ -d wordly.art # 4. Activer la conf HTTPS complète (modifier app.conf pour ajouter SSL) # Voir section "Configuration Nginx HTTPS" ci-dessous ``` ### Configuration Nginx HTTPS complète ```bash cat > docker/nginx/conf.d/app.conf << 'EOF' server { listen 80; server_name wordly.art; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://$host$request_uri; } } server { listen 443 ssl http2; server_name wordly.art; ssl_certificate /etc/letsencrypt/live/wordly.art/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/wordly.art/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options DENY always; add_header X-Content-Type-Options nosniff always; client_max_body_size 60M; location /api/ { proxy_pass http://backend:8000; 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_read_timeout 300s; proxy_send_timeout 300s; } location / { proxy_pass http://frontend:3000; 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; } } EOF # Redémarrer Nginx docker compose -f docker-compose.ionos.yml restart nginx ``` --- ## Étape 7 — Migrations base de données ```bash # Exécuter les migrations Alembic docker compose -f docker-compose.ionos.yml exec backend alembic upgrade head # Vérifier les tables docker compose -f docker-compose.ionos.yml exec postgres \ psql -U translate -d translate_db -c "\dt" ``` --- ## Étape 8 — Vérifications finales ```bash # Tous les services actifs ? docker compose -f docker-compose.ionos.yml ps # Logs backend docker compose -f docker-compose.ionos.yml logs backend --tail=50 # Test santé API curl https://wordly.art/health # Test frontend curl -I https://wordly.art ``` --- ## Mises à jour (déploiement continu) ```bash # Sur le serveur Ionos cd /home/deploy/office-translator # Récupérer les modifications git pull origin main # Reconstruire et redémarrer (zéro downtime possible avec --no-deps) docker compose -f docker-compose.ionos.yml build backend frontend docker compose -f docker-compose.ionos.yml up -d --no-deps backend frontend # Migrations si besoin docker compose -f docker-compose.ionos.yml exec backend alembic upgrade head ``` --- ## Checklist de sécurité avant mise en ligne - [ ] `JWT_SECRET_KEY` généré aléatoirement (64+ chars) - [ ] `POSTGRES_PASSWORD` fort et unique (32+ chars) - [ ] `ADMIN_PASSWORD_HASH` est un vrai hash bcrypt (pas un mot de passe en clair) - [ ] `CORS_ORIGINS` pointe sur votre domaine HTTPS uniquement - [ ] `DEBUG=false` et `ENV=production` - [ ] Clés Stripe en mode **live** (pas test) - [ ] Clé Google Cloud régénérée (ancienne révoquée) - [ ] Clé OpenRouter régénérée (ancienne révoquée) - [ ] UFW activé avec seulement 22/80/443 ouverts - [ ] Connexion SSH par clé uniquement (mot de passe désactivé) - [ ] `.env` absent du dépôt git (`git status` ne le montre pas) --- ## Surveillance & Logs ```bash # Voir les logs en temps réel docker compose -f docker-compose.ionos.yml logs -f # Espace disque df -h # RAM/CPU docker stats # Renouvellement SSL (automatique, mais vérification manuelle) docker compose -f docker-compose.ionos.yml exec certbot certbot certificates ``` --- ## Sauvegarde PostgreSQL ```bash # Créer un backup docker compose -f docker-compose.ionos.yml exec postgres \ pg_dump -U translate translate_db | gzip > backup_$(date +%Y%m%d).sql.gz # Restaurer un backup gunzip -c backup_20260418.sql.gz | \ docker compose -f docker-compose.ionos.yml exec -T postgres \ psql -U translate translate_db ``` Idéalement, configurez une **tâche cron** pour sauvegarder automatiquement : ```bash # Sur le serveur, en tant que deploy crontab -e # Ajouter : 0 3 * * * cd /home/deploy/office-translator && docker compose -f docker-compose.ionos.yml exec -T postgres pg_dump -U translate translate_db | gzip > /home/deploy/backups/db_$(date +\%Y\%m\%d).sql.gz ```