Use stty -echo instead of read -s for password input, compatible with dash/sh shells found on Ubuntu/Debian servers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
377 lines
11 KiB
Bash
377 lines
11 KiB
Bash
#!/bin/bash
|
|
# ============================================
|
|
# Wordly.art - Configuration Wizard
|
|
# ============================================
|
|
# Script interactif pour configurer le .env
|
|
# Lancer sur le serveur: bash scripts/setup-env.sh
|
|
# ============================================
|
|
|
|
set -e
|
|
|
|
# Couleurs
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
BOLD='\033[1m'
|
|
NC='\033[0m'
|
|
|
|
ENV_FILE=".env"
|
|
|
|
echo ""
|
|
echo -e "${CYAN}${BOLD}=========================================${NC}"
|
|
echo -e "${CYAN}${BOLD} Wordly.art - Configuration Wizard${NC}"
|
|
echo -e "${CYAN}${BOLD}=========================================${NC}"
|
|
echo ""
|
|
|
|
# Verifier qu'on est dans le bon dossier
|
|
if [ ! -f "docker-compose.yml" ]; then
|
|
echo -e "${RED}Erreur: lance ce script depuis la racine du projet (cd /opt/wordly)${NC}"
|
|
echo "Usage: bash scripts/setup-env.sh"
|
|
exit 1
|
|
fi
|
|
|
|
# Fonction pour demander une valeur avec defaut
|
|
ask() {
|
|
local prompt="$1"
|
|
local default="$2"
|
|
local varname="$3"
|
|
local required="$4"
|
|
|
|
if [ -n "$default" ]; then
|
|
echo -ne "${YELLOW}${prompt}${NC} [${default}]: "
|
|
else
|
|
echo -ne "${YELLOW}${prompt}${NC}: "
|
|
fi
|
|
|
|
read -r answer
|
|
answer="${answer:-$default}"
|
|
|
|
if [ "$required" = "true" ] && [ -z "$answer" ]; then
|
|
echo -e "${RED}Cette valeur est obligatoire!${NC}"
|
|
ask "$prompt" "$default" "$varname" "$required"
|
|
return
|
|
fi
|
|
|
|
eval "$varname=\"\$answer\""
|
|
}
|
|
|
|
# Fonction pour demander un mot de passe cache
|
|
ask_password() {
|
|
local prompt="$1"
|
|
local varname="$2"
|
|
|
|
echo -ne "${YELLOW}${prompt}${NC}: "
|
|
stty -echo 2>/dev/null || true
|
|
read -r answer
|
|
stty echo 2>/dev/null || true
|
|
echo ""
|
|
eval "$varname=\"\$answer\""
|
|
}
|
|
|
|
# Fonction pour generer un secret
|
|
generate_secret() {
|
|
python3 -c "import secrets; print(secrets.token_urlsafe(64))" 2>/dev/null || \
|
|
openssl rand -base64 48 | tr -d '\n'
|
|
}
|
|
|
|
generate_hex() {
|
|
python3 -c "import secrets; print(secrets.token_hex(32))" 2>/dev/null || \
|
|
openssl rand -hex 32
|
|
}
|
|
|
|
generate_password() {
|
|
python3 -c "import secrets; print(secrets.token_urlsafe(32))" 2>/dev/null || \
|
|
openssl rand -base64 24 | tr -d '\n'
|
|
}
|
|
|
|
# ===========================================
|
|
# ETAPE 1 : Domaine
|
|
# ===========================================
|
|
echo -e "${BOLD}--- Domaine & DNS ---${NC}"
|
|
echo ""
|
|
ask "Nom de domaine" "wordly.art" DOMAIN true
|
|
|
|
# ===========================================
|
|
# ETAPE 2 : Base de donnees
|
|
# ===========================================
|
|
echo ""
|
|
echo -e "${BOLD}--- Base de donnees PostgreSQL ---${NC}"
|
|
echo ""
|
|
ask "Utilisateur PostgreSQL" "translate" POSTGRES_USER true
|
|
POSTGRES_PASSWORD=$(generate_password)
|
|
echo -e " ${GREEN}Mot de passe genere automatiquement${NC}"
|
|
|
|
# ===========================================
|
|
# ETAPE 3 : Admin
|
|
# ===========================================
|
|
echo ""
|
|
echo -e "${BOLD}--- Compte Administrateur ---${NC}"
|
|
echo ""
|
|
ask "Nom d'utilisateur admin" "admin" ADMIN_USERNAME true
|
|
ask_password "Mot de passe admin (cache)" ADMIN_PASSWORD
|
|
if [ -z "$ADMIN_PASSWORD" ]; then
|
|
echo -e "${RED}Le mot de passe admin est obligatoire!${NC}"
|
|
ask_password "Mot de passe admin (cache)" ADMIN_PASSWORD
|
|
fi
|
|
echo ""
|
|
ask_password "Confirmer le mot de passe" ADMIN_PASSWORD_CONFIRM
|
|
if [ "$ADMIN_PASSWORD" != "$ADMIN_PASSWORD_CONFIRM" ]; then
|
|
echo -e "${RED}Les mots de passe ne correspondent pas!${NC}"
|
|
exit 1
|
|
fi
|
|
echo -e " ${GREEN}Mot de passe confirme${NC}"
|
|
|
|
# Generer le hash bcrypt
|
|
echo -e " ${CYAN}Generation du hash bcrypt...${NC}"
|
|
if command -v docker &> /dev/null; then
|
|
ADMIN_PASSWORD_HASH=$(docker run --rm python:3.12-slim bash -c \
|
|
"pip install 'passlib[bcrypt]' bcrypt > /dev/null 2>&1 && \
|
|
python3 -c \"from passlib.context import CryptContext; \
|
|
print(CryptContext(schemes=['bcrypt']).hash('${ADMIN_PASSWORD}'))\"" 2>/dev/null)
|
|
fi
|
|
|
|
if [ -z "$ADMIN_PASSWORD_HASH" ]; then
|
|
echo -e " ${YELLOW}Impossible de generer le hash bcrypt automatiquement.${NC}"
|
|
echo -e " ${YELLOW}Tu devras le generer manuellement plus tard.${NC}"
|
|
ADMIN_PASSWORD_HASH="CHANGE_WITH_BCRYPT_HASH"
|
|
else
|
|
echo -e " ${GREEN}Hash bcrypt genere${NC}"
|
|
fi
|
|
|
|
# ===========================================
|
|
# ETAPE 4 : Secrets
|
|
# ===========================================
|
|
echo ""
|
|
echo -e "${BOLD}--- Secrets de securite ---${NC}"
|
|
echo -e " ${CYAN}Generation automatique des secrets...${NC}"
|
|
JWT_SECRET_KEY=$(generate_secret)
|
|
ADMIN_TOKEN_SECRET=$(generate_hex)
|
|
echo -e " ${GREEN}JWT_SECRET_KEY genere${NC}"
|
|
echo -e " ${GREEN}ADMIN_TOKEN_SECRET genere${NC}"
|
|
|
|
# ===========================================
|
|
# ETAPE 5 : Services de traduction
|
|
# ===========================================
|
|
echo ""
|
|
echo -e "${BOLD}--- Services de traduction ---${NC}"
|
|
echo ""
|
|
echo "Quel service de traduction par defaut ?"
|
|
echo " 1) ollama (local, gratuit)"
|
|
echo " 2) google (API payante)"
|
|
echo " 3) deepl (API payante, haute qualite)"
|
|
echo " 4) openai (GPT, payant)"
|
|
echo " 5) openrouter (multi-modeles, payant)"
|
|
ask "Choix (1-5)" "1" TRANSLATION_CHOICE
|
|
|
|
case "$TRANSLATION_CHOICE" in
|
|
1) TRANSLATION_SERVICE="ollama" ;;
|
|
2) TRANSLATION_SERVICE="google" ;;
|
|
3) TRANSLATION_SERVICE="deepl" ;;
|
|
4) TRANSLATION_SERVICE="openai" ;;
|
|
5) TRANSLATION_SERVICE="openrouter" ;;
|
|
*) TRANSLATION_SERVICE="ollama" ;;
|
|
esac
|
|
|
|
DEEPL_API_KEY=""
|
|
OPENAI_API_KEY=""
|
|
OPENROUTER_API_KEY=""
|
|
|
|
if [ "$TRANSLATION_SERVICE" = "ollama" ]; then
|
|
ask "URL Ollama" "http://ollama:11434" OLLAMA_BASE_URL
|
|
ask "Modele Ollama" "llama3" OLLAMA_MODEL
|
|
fi
|
|
|
|
if [ "$TRANSLATION_SERVICE" = "deepl" ] || [ "$TRANSLATION_SERVICE" = "all" ]; then
|
|
ask "Cle API DeepL (laisser vide si pas maintenant)" "" DEEPL_API_KEY
|
|
fi
|
|
|
|
if [ "$TRANSLATION_SERVICE" = "openai" ] || [ "$TRANSLATION_SERVICE" = "all" ]; then
|
|
ask "Cle API OpenAI (laisser vide si pas maintenant)" "" OPENAI_API_KEY
|
|
fi
|
|
|
|
if [ "$TRANSLATION_SERVICE" = "openrouter" ] || [ "$TRANSLATION_SERVICE" = "all" ]; then
|
|
ask "Cle API OpenRouter (laisser vide si pas maintenant)" "" OPENROUTER_API_KEY
|
|
fi
|
|
|
|
# ===========================================
|
|
# ETAPE 6 : Monitoring
|
|
# ===========================================
|
|
echo ""
|
|
echo -e "${BOLD}--- Monitoring Grafana ---${NC}"
|
|
echo ""
|
|
ask "Utilisateur Grafana" "admin" GRAFANA_USER true
|
|
GRAFANA_PASSWORD=$(generate_password)
|
|
echo -e " ${GREEN}Mot de passe Grafana genere: ${GRAFANA_PASSWORD}${NC}"
|
|
|
|
# ===========================================
|
|
# ETAPE 7 : Stripe (optionnel)
|
|
# ===========================================
|
|
echo ""
|
|
echo -e "${BOLD}--- Paiements Stripe (optionnel) ---${NC}"
|
|
echo ""
|
|
ask "Configurer Stripe maintenant ? (oui/non)" "non" SETUP_STRIPE
|
|
STRIPE_SECRET_KEY=""
|
|
STRIPE_WEBHOOK_SECRET=""
|
|
STRIPE_STARTER_PRICE_ID=""
|
|
STRIPE_PRO_PRICE_ID=""
|
|
STRIPE_BUSINESS_PRICE_ID=""
|
|
|
|
if [ "$SETUP_STRIPE" = "oui" ]; then
|
|
ask "Cle secrete Stripe (sk_live_...)" "" STRIPE_SECRET_KEY
|
|
ask "Webhook secret (whsec_...)" "" STRIPE_WEBHOOK_SECRET
|
|
ask "Price ID Starter" "" STRIPE_STARTER_PRICE_ID
|
|
ask "Price ID Pro" "" STRIPE_PRO_PRICE_ID
|
|
ask "Price ID Business" "" STRIPE_BUSINESS_PRICE_ID
|
|
fi
|
|
|
|
# ===========================================
|
|
# RESUME
|
|
# ===========================================
|
|
echo ""
|
|
echo -e "${CYAN}${BOLD}=========================================${NC}"
|
|
echo -e "${CYAN}${BOLD} Resume de la configuration${NC}"
|
|
echo -e "${CYAN}${BOLD}=========================================${NC}"
|
|
echo ""
|
|
echo -e " Domaine: ${BOLD}${DOMAIN}${NC}"
|
|
echo -e " Traduction: ${BOLD}${TRANSLATION_SERVICE}${NC}"
|
|
echo -e " DB User: ${BOLD}${POSTGRES_USER}${NC}"
|
|
echo -e " Admin: ${BOLD}${ADMIN_USERNAME}${NC}"
|
|
echo -e " Admin hash: ${BOLD}${ADMIN_PASSWORD_HASH:0:20}...${NC}"
|
|
echo -e " JWT Secret: ${BOLD}${JWT_SECRET_KEY:0:20}...${NC}"
|
|
echo -e " Admin Token: ${BOLD}${ADMIN_TOKEN_SECRET:0:20}...${NC}"
|
|
echo -e " Grafana: ${BOLD}${GRAFANA_USER} / ${GRAFANA_PASSWORD}${NC}"
|
|
echo ""
|
|
if [ -n "$STRIPE_SECRET_KEY" ]; then
|
|
echo -e " Stripe: ${GREEN}Configure${NC}"
|
|
else
|
|
echo -e " Stripe: ${YELLOW}Non configure${NC}"
|
|
fi
|
|
echo ""
|
|
|
|
# Confirmation
|
|
ask "Cette configuration est correcte ? (oui/non)" "oui" CONFIRM
|
|
if [ "$CONFIRM" != "oui" ]; then
|
|
echo "Annule. Relance le script pour recommencer."
|
|
exit 0
|
|
fi
|
|
|
|
# ===========================================
|
|
# GENERATION DU FICHIER .env
|
|
# ===========================================
|
|
echo ""
|
|
echo -e "${CYAN}Generation du fichier .env...${NC}"
|
|
|
|
cat > "$ENV_FILE" <<ENVEOF
|
|
# ============================================
|
|
# Wordly.art - Environnement de production
|
|
# Genere automatiquement le $(date +"%Y-%m-%d a %H:%M")
|
|
# ============================================
|
|
|
|
# Application
|
|
APP_NAME=Wordly
|
|
APP_ENV=production
|
|
DEBUG=false
|
|
LOG_LEVEL=INFO
|
|
|
|
# Domaine
|
|
DOMAIN=${DOMAIN}
|
|
NEXT_PUBLIC_API_URL=https://${DOMAIN}
|
|
|
|
# Ports internes
|
|
BACKEND_PORT=8000
|
|
FRONTEND_PORT=3000
|
|
|
|
# Traduction
|
|
TRANSLATION_SERVICE=${TRANSLATION_SERVICE}
|
|
OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://ollama:11434}
|
|
OLLAMA_MODEL=${OLLAMA_MODEL:-llama3}
|
|
DEEPL_API_KEY=${DEEPL_API_KEY}
|
|
OPENAI_API_KEY=${OPENAI_API_KEY}
|
|
OPENAI_MODEL=gpt-4o-mini
|
|
OPENROUTER_API_KEY=${OPENROUTER_API_KEY}
|
|
|
|
# Upload
|
|
MAX_FILE_SIZE_MB=50
|
|
ALLOWED_EXTENSIONS=.docx,.xlsx,.pptx
|
|
|
|
# Rate Limiting
|
|
RATE_LIMIT_ENABLED=true
|
|
RATE_LIMIT_REQUESTS_PER_MINUTE=60
|
|
RATE_LIMIT_TRANSLATIONS_PER_MINUTE=10
|
|
RATE_LIMIT_TRANSLATIONS_PER_HOUR=100
|
|
RATE_LIMIT_TRANSLATIONS_PER_DAY=500
|
|
|
|
# Admin
|
|
ADMIN_USERNAME=${ADMIN_USERNAME}
|
|
ADMIN_PASSWORD_HASH=${ADMIN_PASSWORD_HASH}
|
|
JWT_SECRET_KEY=${JWT_SECRET_KEY}
|
|
ADMIN_TOKEN_SECRET=${ADMIN_TOKEN_SECRET}
|
|
CORS_ORIGINS=https://${DOMAIN}
|
|
|
|
# Database
|
|
POSTGRES_USER=${POSTGRES_USER}
|
|
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
|
POSTGRES_DB=translate_db
|
|
|
|
# Monitoring
|
|
GRAFANA_USER=${GRAFANA_USER}
|
|
GRAFANA_PASSWORD=${GRAFANA_PASSWORD}
|
|
|
|
# Stripe
|
|
STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
|
|
STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
|
|
STRIPE_STARTER_PRICE_ID=${STRIPE_STARTER_PRICE_ID}
|
|
STRIPE_PRO_PRICE_ID=${STRIPE_PRO_PRICE_ID}
|
|
STRIPE_BUSINESS_PRICE_ID=${STRIPE_BUSINESS_PRICE_ID}
|
|
ENVEOF
|
|
|
|
# Securiser le fichier
|
|
chmod 600 "$ENV_FILE"
|
|
|
|
echo -e "${GREEN}Fichier .env cree avec succes!${NC}"
|
|
echo ""
|
|
|
|
# ===========================================
|
|
# PROPOSITIONS FINALES
|
|
# ===========================================
|
|
echo -e "${BOLD}Prochaines etapes :${NC}"
|
|
echo ""
|
|
echo -e " 1. Verifier le fichier:"
|
|
echo -e " ${CYAN}cat .env${NC}"
|
|
echo ""
|
|
echo -e " 2. Lancer l'application:"
|
|
echo -e " ${CYAN}docker compose up -d --build${NC}"
|
|
echo ""
|
|
echo -e " 3. Verifier que tout tourne:"
|
|
echo -e " ${CYAN}docker compose ps${NC}"
|
|
echo -e " ${CYAN}curl http://localhost:8000/health${NC}"
|
|
echo ""
|
|
echo -e " 4. Lancer le monitoring:"
|
|
echo -e " ${CYAN}docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d${NC}"
|
|
echo ""
|
|
|
|
# Sauvegarder les infos importantes dans un fichier temp
|
|
INFO_FILE="/tmp/wordly-setup-info.txt"
|
|
cat > "$INFO_FILE" <<INFOEOF
|
|
========================================
|
|
Wordly.art - Infos de configuration
|
|
Genere le $(date)
|
|
========================================
|
|
|
|
Domaine: ${DOMAIN}
|
|
Admin: ${ADMIN_USERNAME}
|
|
Grafana: ${GRAFANA_USER} / ${GRAFANA_PASSWORD}
|
|
DB Password: ${POSTGRES_PASSWORD}
|
|
|
|
ATTENTION: Ce fichier contient des secrets!
|
|
Supprime-le apres avoir note les infos: rm ${INFO_FILE}
|
|
========================================
|
|
INFOEOF
|
|
chmod 600 "$INFO_FILE"
|
|
|
|
echo -e "${YELLOW}Infos sensibles sauvegardees dans ${INFO_FILE}${NC}"
|
|
echo -e "${YELLOW}Supprime ce fichier apres note: rm ${INFO_FILE}${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}${BOLD}Configuration terminee!${NC}"
|