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>
This commit is contained in:
338
DEPLOY_IONOS.md
Normal file
338
DEPLOY_IONOS.md
Normal file
@@ -0,0 +1,338 @@
|
||||
# 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
|
||||
```
|
||||
Reference in New Issue
Block a user