Se crear el archivo install.sh para realizar el deploy de la app
This commit is contained in:
+263
@@ -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" <<ENVEOF
|
||||||
|
# Admin Edu-Space — Configuración de producción
|
||||||
|
# Generado automáticamente por install.sh el $(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
FLASK_APP=app.py
|
||||||
|
FLASK_ENV=production
|
||||||
|
|
||||||
|
SECRET_KEY=${SECRET_KEY}
|
||||||
|
|
||||||
|
DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@localhost:5432/${DB_NAME}
|
||||||
|
DB_USERNAME=${DB_USER}
|
||||||
|
DB_PASSWORD=${DB_PASSWORD}
|
||||||
|
|
||||||
|
API_BASE_URL=http://localhost:8080/api
|
||||||
|
|
||||||
|
BABEL_DEFAULT_LOCALE=es
|
||||||
|
BABEL_DEFAULT_TIMEZONE=America/Argentina/Buenos_Aires
|
||||||
|
ENVEOF
|
||||||
|
ok ".env creado con credenciales de producción"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 5. Crear usuario y base de datos PostgreSQL ──────────────────────────────
|
||||||
|
step "Configurando usuario y base de datos PostgreSQL..."
|
||||||
|
|
||||||
|
sudo -u postgres psql -c "CREATE USER ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';" 2>/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" <<SVCEOF
|
||||||
|
[Unit]
|
||||||
|
Description=Admin Edu-Space — Flask/Gunicorn Application
|
||||||
|
Documentation=https://github.com/carlostellocba/admin-edu-space
|
||||||
|
After=network.target postgresql.service
|
||||||
|
Wants=postgresql.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=${APP_USER}
|
||||||
|
Group=${APP_USER}
|
||||||
|
WorkingDirectory=${APP_DIR}
|
||||||
|
EnvironmentFile=${APP_DIR}/.env
|
||||||
|
Environment="LANG=en_US.UTF-8"
|
||||||
|
Environment="LC_ALL=en_US.UTF-8"
|
||||||
|
Environment="PYTHONUTF8=1"
|
||||||
|
Environment="PYTHONIOENCODING=utf-8"
|
||||||
|
Environment="FLASK_ENV=production"
|
||||||
|
ExecStart=${VENV_DIR}/bin/gunicorn \
|
||||||
|
--workers 3 \
|
||||||
|
--bind 0.0.0.0:5000 \
|
||||||
|
--timeout 120 \
|
||||||
|
--access-logfile /var/log/${SERVICE_NAME}/access.log \
|
||||||
|
--error-logfile /var/log/${SERVICE_NAME}/error.log \
|
||||||
|
--log-level info \
|
||||||
|
app:app
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
SyslogIdentifier=${SERVICE_NAME}
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
SVCEOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable "$SERVICE_NAME" > /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 ""
|
||||||
Reference in New Issue
Block a user