Files
office_translator/DEPLOY_IONOS.md
Sepehr Ramezani 26bd096a06 feat: production deployment - full update with providers, admin, glossaries, pricing, tests
Major changes across backend, frontend, infrastructure:
- Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud)
- Admin panel: user management, pricing, settings
- Glossary system with CSV import/export
- Subscription and tier quota management
- Security hardening (rate limiting, API key auth, path traversal fixes)
- Docker compose for dev, prod, and IONOS deployment
- Alembic migrations for new tables
- Frontend: dashboard, pricing page, landing page, i18n (en/fr)
- Test suite and verification scripts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-25 15:01:47 +02:00

339 lines
8.1 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.
# 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** | ~812 €/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 515 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
```