From 5dcf3b75f1691296d937b804a6f29319ad35f668 Mon Sep 17 00:00:00 2001 From: Carlos Tello Date: Fri, 4 Sep 2026 20:56:50 -0300 Subject: [PATCH] Se crear el archivo install.sh para realizar el deploy de la app --- install.sh | 263 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 install.sh diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..cc0df53 --- /dev/null +++ b/install.sh @@ -0,0 +1,263 @@ +#!/usr/bin/env bash +# ============================================================================== +# install.sh — Instalador automático de Admin Edu-Space +# Sistema operativo: Debian 12 (Bookworm) — LXC / Bare Metal +# Uso: sudo bash install.sh +# Debe ejecutarse desde el directorio raíz del proyecto (donde está app.py) +# ============================================================================== +set -euo pipefail + +# ── Colores ───────────────────────────────────────────────────────────────── +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' + +step() { echo -e "\n${CYAN}${BOLD}▶ $*${NC}"; } +ok() { echo -e "${GREEN} ✔ $*${NC}"; } +warn() { echo -e "${YELLOW} ⚠ $*${NC}"; } +die() { echo -e "${RED} ✘ $*${NC}" >&2; exit 1; } + +# ── Verificaciones previas ─────────────────────────────────────────────────── +[[ $EUID -ne 0 ]] && die "Este script debe ejecutarse como root. Usá: sudo bash install.sh" +[[ ! -f "app.py" ]] && die "No se encontró app.py. Ejecutá el script desde el directorio raíz del proyecto." + +APP_DIR="$(pwd)" +APP_USER="eduspace" +SERVICE_NAME="admin-edu-space" +VENV_DIR="$APP_DIR/venv" +PYTHON_BIN="python3" + +# ── Banner ─────────────────────────────────────────────────────────────────── +echo -e "${BOLD}" +echo "╔══════════════════════════════════════════════════════════════╗" +echo "║ Admin Edu-Space — Instalador para Debian 12 ║" +echo "╚══════════════════════════════════════════════════════════════╝" +echo -e "${NC}" +echo " Directorio de instalación: ${CYAN}$APP_DIR${NC}" + +# ── 1. Locale UTF-8 ───────────────────────────────────────────────────────── +step "Configurando locale UTF-8..." +export DEBIAN_FRONTEND=noninteractive +apt-get install -y locales > /dev/null 2>&1 +sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen +sed -i 's/# es_AR.UTF-8 UTF-8/es_AR.UTF-8 UTF-8/' /etc/locale.gen +locale-gen en_US.UTF-8 es_AR.UTF-8 > /dev/null 2>&1 +update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 > /dev/null 2>&1 +export LANG=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 +export PYTHONUTF8=1 +export PYTHONIOENCODING=utf-8 +ok "Locale configurado: en_US.UTF-8" + +# ── 2. Dependencias del sistema ────────────────────────────────────────────── +step "Actualizando repositorios e instalando dependencias del sistema..." +apt-get update -qq +apt-get install -y \ + python3 \ + python3-venv \ + python3-pip \ + python3-dev \ + build-essential \ + libpq-dev \ + postgresql \ + postgresql-client \ + curl \ + git \ + > /dev/null 2>&1 +ok "Dependencias instaladas (Python3 + PostgreSQL + build tools)" + +# ── 3. Iniciar PostgreSQL ──────────────────────────────────────────────────── +step "Iniciando servicio PostgreSQL..." +# Intentar iniciar por distintos métodos (LXC puede no tener systemd activo aún) +pg_ctlcluster 15 main start 2>/dev/null \ + || service postgresql start 2>/dev/null \ + || systemctl start postgresql 2>/dev/null \ + || true +sleep 2 +# Habilitar para inicio automático (ignorar error si ya está habilitado) +systemctl enable postgresql > /dev/null 2>&1 || true +ok "PostgreSQL activo" + +# ── 4. Configurar variables de entorno (.env) ──────────────────────────────── +step "Configurando variables de entorno..." + +SECRET_KEY=$(python3 -c 'import secrets; print(secrets.token_hex(32))') + +echo "" +echo -e " ${BOLD}Configuración de la base de datos PostgreSQL${NC}" +read -rp " Contraseña para el usuario de BD [default: eduspace2024]: " DB_PASS_INPUT +DB_PASSWORD="${DB_PASS_INPUT:-eduspace2024}" +DB_NAME="classrooms_db" +DB_USER="eduspace_user" + +if [[ -f "$APP_DIR/.env" ]]; then + warn ".env ya existe — se conserva sin modificar" + # Leer variables del .env existente + source <(grep -v '^#' "$APP_DIR/.env" | grep '=' | sed 's/ *= */=/;s/^/export /') + # Reasignar desde el .env leído + DB_USER="${DB_USERNAME:-$DB_USER}" + DB_PASSWORD="${DB_PASSWORD:-eduspace2024}" + DB_NAME=$(echo "${DATABASE_URL:-}" | sed 's|.*\/||') + DB_NAME="${DB_NAME:-classrooms_db}" +else + cat > "$APP_DIR/.env" </dev/null \ + || warn "El usuario '${DB_USER}' ya existe — se omite creación" + +sudo -u postgres psql -c "CREATE DATABASE ${DB_NAME} OWNER ${DB_USER};" 2>/dev/null \ + || warn "La base de datos '${DB_NAME}' ya existe — se omite creación" + +sudo -u postgres psql -d "${DB_NAME}" -c "GRANT ALL PRIVILEGES ON DATABASE ${DB_NAME} TO ${DB_USER};" > /dev/null 2>&1 || true +sudo -u postgres psql -d "${DB_NAME}" -c "GRANT ALL ON SCHEMA public TO ${DB_USER};" > /dev/null 2>&1 || true +sudo -u postgres psql -d "${DB_NAME}" -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO ${DB_USER};" > /dev/null 2>&1 || true +ok "Base de datos '${DB_NAME}' lista con usuario '${DB_USER}'" + +# ── 6. Entorno virtual Python + dependencias ───────────────────────────────── +step "Creando entorno virtual Python e instalando dependencias..." +$PYTHON_BIN -m venv "$VENV_DIR" > /dev/null 2>&1 +"$VENV_DIR/bin/pip" install --upgrade pip --quiet +"$VENV_DIR/bin/pip" install gunicorn --quiet +"$VENV_DIR/bin/pip" install -r "$APP_DIR/requirements.txt" --quiet +ok "Virtualenv listo con todas las dependencias + Gunicorn" + +# ── 7. Inicializar base de datos ────────────────────────────────────────────── +step "Inicializando esquema y datos iniciales (init_db.py)..." +cd "$APP_DIR" + +# Exportar variables del .env para que Flask/SQLAlchemy las use +set -a +source "$APP_DIR/.env" +set +a + +LANG=en_US.UTF-8 \ +LC_ALL=en_US.UTF-8 \ +PYTHONUTF8=1 \ +PYTHONIOENCODING=utf-8 \ +FLASK_APP=app.py \ +"$VENV_DIR/bin/python" -X utf8 init_db.py + +ok "Esquema y datos iniciales cargados correctamente" +cd - > /dev/null + +# ── 8. Usuario del sistema ──────────────────────────────────────────────────── +step "Creando usuario del sistema '${APP_USER}'..." +if id "$APP_USER" &>/dev/null; then + warn "El usuario '${APP_USER}' ya existe — se omite" +else + useradd --system --no-create-home --shell /usr/sbin/nologin "$APP_USER" + ok "Usuario '${APP_USER}' creado" +fi + +chown -R "$APP_USER":"$APP_USER" "$APP_DIR" +chmod -R 755 "$APP_DIR" +# El .env debe ser legible sólo por el owner +chmod 640 "$APP_DIR/.env" +ok "Permisos aplicados en $APP_DIR" + +# ── 9. Servicio systemd ─────────────────────────────────────────────────────── +step "Registrando servicio systemd '${SERVICE_NAME}'..." + +mkdir -p "/var/log/${SERVICE_NAME}" +chown -R "$APP_USER":"$APP_USER" "/var/log/${SERVICE_NAME}" + +cat > "/etc/systemd/system/${SERVICE_NAME}.service" < /dev/null 2>&1 +systemctl start "$SERVICE_NAME" +sleep 3 + +if systemctl is-active --quiet "$SERVICE_NAME"; then + ok "Servicio '${SERVICE_NAME}' corriendo y habilitado para el arranque automático" +else + warn "El servicio no inició correctamente. Revisá con:" + warn " journalctl -u ${SERVICE_NAME} -n 60 --no-pager" +fi + +# ── 10. Resumen final ───────────────────────────────────────────────────────── +IP=$(hostname -I | awk '{print $1}') +echo "" +echo -e "${BOLD}${GREEN}" +echo "╔══════════════════════════════════════════════════════════════╗" +echo "║ ✔ Instalación completada con éxito ║" +echo "╚══════════════════════════════════════════════════════════════╝" +echo -e "${NC}" +echo -e " ${BOLD}URL de la aplicación:${NC} http://${IP}:5000" +echo "" +echo -e " ${BOLD}Credenciales por defecto:${NC}" +echo -e " Email: admin@edu-space.com" +echo -e " Password: admin123" +echo "" +echo -e " ${BOLD}Base de datos:${NC}" +echo -e " Host: localhost:5432" +echo -e " Base: ${DB_NAME}" +echo -e " Usuario: ${DB_USER}" +echo "" +echo -e " ${BOLD}Comandos de gestión:${NC}" +echo -e " Ver estado: ${CYAN}systemctl status ${SERVICE_NAME}${NC}" +echo -e " Ver logs: ${CYAN}journalctl -u ${SERVICE_NAME} -f${NC}" +echo -e " Reiniciar: ${CYAN}systemctl restart ${SERVICE_NAME}${NC}" +echo -e " Detener: ${CYAN}systemctl stop ${SERVICE_NAME}${NC}" +echo "" +echo -e " ${YELLOW}⚠ Cambiá la contraseña del admin desde la interfaz web${NC}" +echo ""