Files
ATLAS/deploy/scripts/install.sh
2026-01-21 08:26:01 +00:00

1081 lines
30 KiB
Bash

#!/bin/bash
# ============================================
# Sistema de ADAN - Script de Instalacion
# ============================================
# Este script instala y configura todo el sistema
# Ejecutar como root en Ubuntu 22.04 LTS
#
# Uso: sudo ./install.sh [--skip-db] [--skip-traccar] [--dev]
#
# Opciones:
# --skip-db No instalar PostgreSQL (usar DB externa)
# --skip-traccar No instalar Traccar
# --dev Modo desarrollo (sin optimizaciones)
# ============================================
set -e # Salir en caso de error
set -o pipefail # Capturar errores en pipes
# ---------------------------------------------
# Colores para output
# ---------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# ---------------------------------------------
# Variables de Configuracion
# ---------------------------------------------
INSTALL_DIR="${INSTALL_DIR:-/opt/adan}"
REPO_URL="${REPO_URL:-https://github.com/tuorganizacion/adan.git}"
REPO_BRANCH="${REPO_BRANCH:-main}"
BACKUP_DIR="${BACKUP_DIR:-/var/backups/adan}"
# Versiones
POSTGRES_VERSION="15"
NODE_VERSION="20"
PYTHON_VERSION="3.11"
TRACCAR_VERSION="5.12"
MEDIAMTX_VERSION="1.5.1"
# Puertos
API_PORT="${API_PORT:-8000}"
FRONTEND_PORT="${FRONTEND_PORT:-3000}"
TRACCAR_PORT="${TRACCAR_PORT:-5055}"
# Flags
SKIP_DB=false
SKIP_TRACCAR=false
DEV_MODE=false
# Archivo de credenciales generadas
CREDENTIALS_FILE="/root/adan-credentials.txt"
# ---------------------------------------------
# Funciones de utilidad
# ---------------------------------------------
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[OK]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_section() {
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} $1${NC}"
echo -e "${GREEN}========================================${NC}"
echo ""
}
# Generar password aleatorio
generate_password() {
openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c "${1:-24}"
}
# Generar secret key
generate_secret_key() {
openssl rand -hex 32
}
# Verificar si comando existe
command_exists() {
command -v "$1" &> /dev/null
}
# Verificar si servicio esta activo
service_active() {
systemctl is-active --quiet "$1" 2>/dev/null
}
# ---------------------------------------------
# Parsear argumentos
# ---------------------------------------------
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
--skip-db)
SKIP_DB=true
shift
;;
--skip-traccar)
SKIP_TRACCAR=true
shift
;;
--dev)
DEV_MODE=true
shift
;;
--help|-h)
echo "Uso: $0 [--skip-db] [--skip-traccar] [--dev]"
echo ""
echo "Opciones:"
echo " --skip-db No instalar PostgreSQL (usar DB externa)"
echo " --skip-traccar No instalar Traccar"
echo " --dev Modo desarrollo"
exit 0
;;
*)
log_error "Opcion desconocida: $1"
exit 1
;;
esac
done
}
# ---------------------------------------------
# Verificar requisitos
# ---------------------------------------------
check_requirements() {
log_section "Verificando Requisitos"
# Verificar root
if [[ $EUID -ne 0 ]]; then
log_error "Este script debe ejecutarse como root"
exit 1
fi
# Verificar Ubuntu 22.04
if [[ -f /etc/os-release ]]; then
. /etc/os-release
if [[ "$ID" != "ubuntu" ]] || [[ ! "$VERSION_ID" =~ ^22 ]]; then
log_warn "Este script esta optimizado para Ubuntu 22.04"
log_warn "Sistema detectado: $ID $VERSION_ID"
read -p "Continuar de todos modos? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
fi
# Verificar memoria minima (2GB)
TOTAL_MEM=$(free -m | awk '/^Mem:/{print $2}')
if [[ $TOTAL_MEM -lt 2048 ]]; then
log_warn "Memoria RAM: ${TOTAL_MEM}MB (recomendado: 4GB+)"
else
log_success "Memoria RAM: ${TOTAL_MEM}MB"
fi
# Verificar espacio en disco (10GB minimo)
FREE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | tr -d 'G')
if [[ $FREE_SPACE -lt 10 ]]; then
log_error "Espacio insuficiente: ${FREE_SPACE}GB (minimo: 10GB)"
exit 1
else
log_success "Espacio en disco: ${FREE_SPACE}GB"
fi
# Verificar conexion a internet
if ! ping -c 1 google.com &> /dev/null; then
log_error "Sin conexion a internet"
exit 1
fi
log_success "Conexion a internet OK"
}
# ---------------------------------------------
# Actualizar sistema
# ---------------------------------------------
update_system() {
log_section "Actualizando Sistema"
export DEBIAN_FRONTEND=noninteractive
log_info "Actualizando lista de paquetes..."
apt-get update -qq
log_info "Actualizando paquetes instalados..."
apt-get upgrade -y -qq
log_info "Instalando paquetes base..."
apt-get install -y -qq \
curl \
wget \
gnupg \
lsb-release \
ca-certificates \
apt-transport-https \
software-properties-common \
build-essential \
git \
unzip \
jq \
htop \
net-tools \
ufw \
fail2ban \
logrotate \
cron
log_success "Sistema actualizado"
}
# ---------------------------------------------
# Instalar PostgreSQL + TimescaleDB + PostGIS
# ---------------------------------------------
install_postgresql() {
if [[ "$SKIP_DB" == "true" ]]; then
log_warn "Saltando instalacion de PostgreSQL (--skip-db)"
return
fi
log_section "Instalando PostgreSQL ${POSTGRES_VERSION} + TimescaleDB + PostGIS"
# Verificar si ya esta instalado
if command_exists psql && service_active postgresql; then
log_warn "PostgreSQL ya esta instalado"
POSTGRES_EXISTING=true
else
POSTGRES_EXISTING=false
# Agregar repositorio PostgreSQL
log_info "Agregando repositorio PostgreSQL..."
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgresql-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/postgresql-keyring.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list
# Agregar repositorio TimescaleDB
log_info "Agregando repositorio TimescaleDB..."
curl -fsSL https://packagecloud.io/timescale/timescaledb/gpgkey | gpg --dearmor -o /usr/share/keyrings/timescaledb-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/timescaledb-keyring.gpg] https://packagecloud.io/timescale/timescaledb/ubuntu/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/timescaledb.list
apt-get update -qq
# Instalar PostgreSQL
log_info "Instalando PostgreSQL ${POSTGRES_VERSION}..."
apt-get install -y -qq postgresql-${POSTGRES_VERSION} postgresql-contrib-${POSTGRES_VERSION}
# Instalar PostGIS
log_info "Instalando PostGIS..."
apt-get install -y -qq postgresql-${POSTGRES_VERSION}-postgis-3
# Instalar TimescaleDB
log_info "Instalando TimescaleDB..."
apt-get install -y -qq timescaledb-2-postgresql-${POSTGRES_VERSION}
# Configurar TimescaleDB
log_info "Configurando TimescaleDB..."
timescaledb-tune -yes -quiet
fi
# Iniciar PostgreSQL
systemctl enable postgresql
systemctl start postgresql
log_success "PostgreSQL instalado y configurado"
}
# ---------------------------------------------
# Instalar Redis
# ---------------------------------------------
install_redis() {
log_section "Instalando Redis"
if command_exists redis-server && service_active redis-server; then
log_warn "Redis ya esta instalado"
else
log_info "Instalando Redis..."
apt-get install -y -qq redis-server
# Configurar Redis para produccion
log_info "Configurando Redis..."
# Backup de config original
cp /etc/redis/redis.conf /etc/redis/redis.conf.bak
# Configuraciones de seguridad y rendimiento
sed -i 's/^bind 127.0.0.1 ::1/bind 127.0.0.1/' /etc/redis/redis.conf
sed -i 's/^# maxmemory <bytes>/maxmemory 256mb/' /etc/redis/redis.conf
sed -i 's/^# maxmemory-policy noeviction/maxmemory-policy allkeys-lru/' /etc/redis/redis.conf
fi
systemctl enable redis-server
systemctl restart redis-server
log_success "Redis instalado y configurado"
}
# ---------------------------------------------
# Instalar Python 3.11
# ---------------------------------------------
install_python() {
log_section "Instalando Python ${PYTHON_VERSION}"
if python3.11 --version &> /dev/null; then
log_warn "Python 3.11 ya esta instalado"
else
log_info "Agregando repositorio deadsnakes..."
add-apt-repository -y ppa:deadsnakes/ppa
apt-get update -qq
log_info "Instalando Python ${PYTHON_VERSION}..."
apt-get install -y -qq \
python${PYTHON_VERSION} \
python${PYTHON_VERSION}-venv \
python${PYTHON_VERSION}-dev \
python${PYTHON_VERSION}-distutils
fi
# Instalar pip
if ! python3.11 -m pip --version &> /dev/null; then
log_info "Instalando pip..."
curl -sS https://bootstrap.pypa.io/get-pip.py | python3.11
fi
# Actualizar pip
python3.11 -m pip install --upgrade pip setuptools wheel -q
log_success "Python ${PYTHON_VERSION} instalado"
}
# ---------------------------------------------
# Instalar Node.js 20
# ---------------------------------------------
install_nodejs() {
log_section "Instalando Node.js ${NODE_VERSION}"
if node --version 2>/dev/null | grep -q "v${NODE_VERSION}"; then
log_warn "Node.js ${NODE_VERSION} ya esta instalado"
else
log_info "Instalando Node.js ${NODE_VERSION}..."
curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash -
apt-get install -y -qq nodejs
fi
# Instalar pnpm (mas rapido que npm)
if ! command_exists pnpm; then
log_info "Instalando pnpm..."
npm install -g pnpm -q
fi
# Instalar serve para frontend
if ! command_exists serve; then
log_info "Instalando serve..."
npm install -g serve -q
fi
log_success "Node.js ${NODE_VERSION} instalado"
}
# ---------------------------------------------
# Instalar Traccar
# ---------------------------------------------
install_traccar() {
if [[ "$SKIP_TRACCAR" == "true" ]]; then
log_warn "Saltando instalacion de Traccar (--skip-traccar)"
return
fi
log_section "Instalando Traccar ${TRACCAR_VERSION}"
TRACCAR_DIR="/opt/traccar"
if [[ -d "$TRACCAR_DIR" ]] && service_active traccar; then
log_warn "Traccar ya esta instalado"
else
# Instalar Java (requerido por Traccar)
log_info "Instalando OpenJDK 17..."
apt-get install -y -qq openjdk-17-jre-headless
# Descargar Traccar
log_info "Descargando Traccar ${TRACCAR_VERSION}..."
TRACCAR_URL="https://github.com/traccar/traccar/releases/download/v${TRACCAR_VERSION}/traccar-linux-64-${TRACCAR_VERSION}.zip"
cd /tmp
wget -q "$TRACCAR_URL" -O traccar.zip
# Instalar Traccar
log_info "Instalando Traccar..."
unzip -q -o traccar.zip
./traccar.run
rm -f traccar.zip traccar.run
fi
log_success "Traccar instalado"
}
# ---------------------------------------------
# Instalar MediaMTX
# ---------------------------------------------
install_mediamtx() {
log_section "Instalando MediaMTX ${MEDIAMTX_VERSION}"
MEDIAMTX_DIR="/opt/mediamtx"
if [[ -d "$MEDIAMTX_DIR" ]] && [[ -f "$MEDIAMTX_DIR/mediamtx" ]]; then
log_warn "MediaMTX ya esta instalado"
else
log_info "Descargando MediaMTX ${MEDIAMTX_VERSION}..."
mkdir -p "$MEDIAMTX_DIR"
cd "$MEDIAMTX_DIR"
ARCH=$(uname -m)
case $ARCH in
x86_64) ARCH="amd64" ;;
aarch64) ARCH="arm64v8" ;;
armv7l) ARCH="armv7" ;;
esac
MEDIAMTX_URL="https://github.com/bluenviron/mediamtx/releases/download/v${MEDIAMTX_VERSION}/mediamtx_v${MEDIAMTX_VERSION}_linux_${ARCH}.tar.gz"
wget -q "$MEDIAMTX_URL" -O mediamtx.tar.gz
tar -xzf mediamtx.tar.gz
rm -f mediamtx.tar.gz
chmod +x mediamtx
fi
log_success "MediaMTX instalado"
}
# ---------------------------------------------
# Instalar Mosquitto MQTT
# ---------------------------------------------
install_mosquitto() {
log_section "Instalando Mosquitto MQTT"
if command_exists mosquitto && service_active mosquitto; then
log_warn "Mosquitto ya esta instalado"
else
log_info "Instalando Mosquitto..."
apt-get install -y -qq mosquitto mosquitto-clients
# Configuracion basica se hara despues con las credenciales
fi
systemctl enable mosquitto
log_success "Mosquitto instalado"
}
# ---------------------------------------------
# Configurar base de datos
# ---------------------------------------------
configure_database() {
if [[ "$SKIP_DB" == "true" ]]; then
log_warn "Saltando configuracion de base de datos"
return
fi
log_section "Configurando Base de Datos"
# Generar credenciales si no existen
if [[ -z "$DB_PASSWORD" ]]; then
DB_PASSWORD=$(generate_password 24)
fi
DB_NAME="${POSTGRES_DB:-adan}"
DB_USER="${POSTGRES_USER:-adan}"
log_info "Creando usuario y base de datos..."
# Crear usuario y base de datos
sudo -u postgres psql -v ON_ERROR_STOP=1 <<EOF
-- Crear usuario si no existe
DO \$\$
BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '${DB_USER}') THEN
CREATE ROLE ${DB_USER} WITH LOGIN PASSWORD '${DB_PASSWORD}';
ELSE
ALTER ROLE ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';
END IF;
END
\$\$;
-- Crear base de datos si no existe
SELECT 'CREATE DATABASE ${DB_NAME} OWNER ${DB_USER}'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${DB_NAME}')\gexec
-- Conectar a la base de datos y crear extensiones
\c ${DB_NAME}
-- Crear extensiones
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Permisos
GRANT ALL PRIVILEGES ON DATABASE ${DB_NAME} TO ${DB_USER};
GRANT ALL ON SCHEMA public TO ${DB_USER};
EOF
# Crear base de datos para Traccar si no se salto
if [[ "$SKIP_TRACCAR" != "true" ]]; then
TRACCAR_DB_NAME="${TRACCAR_DB_NAME:-traccar}"
sudo -u postgres psql -v ON_ERROR_STOP=1 <<EOF
SELECT 'CREATE DATABASE ${TRACCAR_DB_NAME} OWNER ${DB_USER}'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${TRACCAR_DB_NAME}')\gexec
GRANT ALL PRIVILEGES ON DATABASE ${TRACCAR_DB_NAME} TO ${DB_USER};
EOF
fi
log_success "Base de datos configurada"
}
# ---------------------------------------------
# Clonar y configurar aplicacion
# ---------------------------------------------
setup_application() {
log_section "Configurando Aplicacion"
# Crear directorio de instalacion
mkdir -p "$INSTALL_DIR"
mkdir -p "$BACKUP_DIR"
# Clonar repositorio si no existe
if [[ -d "$INSTALL_DIR/.git" ]]; then
log_info "Repositorio existente, actualizando..."
cd "$INSTALL_DIR"
git fetch origin
git reset --hard origin/${REPO_BRANCH}
else
log_info "Clonando repositorio..."
# Si el directorio actual contiene el codigo, copiarlo
if [[ -f "/root/Adan/backend/app/main.py" ]] 2>/dev/null; then
log_info "Copiando desde directorio local..."
cp -r /root/Adan/* "$INSTALL_DIR/"
else
git clone --branch "$REPO_BRANCH" "$REPO_URL" "$INSTALL_DIR"
fi
fi
cd "$INSTALL_DIR"
# Configurar backend
log_info "Configurando backend..."
cd "$INSTALL_DIR/backend"
# Crear entorno virtual
python3.11 -m venv venv
source venv/bin/activate
# Instalar dependencias
if [[ -f "requirements.txt" ]]; then
pip install -r requirements.txt -q
elif [[ -f "pyproject.toml" ]]; then
pip install -e . -q
fi
# Instalar dependencias adicionales
pip install uvicorn[standard] gunicorn -q
deactivate
# Configurar frontend
log_info "Configurando frontend..."
cd "$INSTALL_DIR/frontend"
if [[ -f "package.json" ]]; then
pnpm install --frozen-lockfile 2>/dev/null || npm install
# Build para produccion
if [[ "$DEV_MODE" != "true" ]]; then
pnpm build 2>/dev/null || npm run build
fi
fi
log_success "Aplicacion configurada"
}
# ---------------------------------------------
# Generar credenciales
# ---------------------------------------------
generate_credentials() {
log_section "Generando Credenciales"
# Generar todas las credenciales
[[ -z "$DB_PASSWORD" ]] && DB_PASSWORD=$(generate_password 24)
REDIS_PASSWORD=$(generate_password 24)
SECRET_KEY=$(generate_secret_key)
MQTT_PASSWORD=$(generate_password 16)
ADMIN_PASSWORD=$(generate_password 16)
# Guardar en archivo seguro
cat > "$CREDENTIALS_FILE" <<EOF
# ============================================
# Credenciales del Sistema de ADAN
# Generadas: $(date)
# IMPORTANTE: Guardar en lugar seguro y eliminar este archivo
# ============================================
# PostgreSQL
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=adan
POSTGRES_USER=adan
POSTGRES_PASSWORD=${DB_PASSWORD}
DATABASE_URL=postgresql://adan:${DB_PASSWORD}@localhost:5432/adan
# Redis
REDIS_PASSWORD=${REDIS_PASSWORD}
REDIS_URL=redis://:${REDIS_PASSWORD}@localhost:6379/0
# API
SECRET_KEY=${SECRET_KEY}
API_PORT=${API_PORT}
# MQTT
MQTT_USER=adan
MQTT_PASSWORD=${MQTT_PASSWORD}
# Admin inicial
ADMIN_EMAIL=admin@adan.local
ADMIN_PASSWORD=${ADMIN_PASSWORD}
# Puertos
API_PORT=${API_PORT}
FRONTEND_PORT=${FRONTEND_PORT}
TRACCAR_PORT=${TRACCAR_PORT}
EOF
chmod 600 "$CREDENTIALS_FILE"
log_success "Credenciales generadas en: $CREDENTIALS_FILE"
}
# ---------------------------------------------
# Crear archivo .env
# ---------------------------------------------
create_env_file() {
log_section "Creando archivo .env"
ENV_FILE="$INSTALL_DIR/.env"
cat > "$ENV_FILE" <<EOF
# Generado automaticamente por install.sh - $(date)
# Base de Datos
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=adan
POSTGRES_USER=adan
POSTGRES_PASSWORD=${DB_PASSWORD}
DATABASE_URL=postgresql://adan:${DB_PASSWORD}@localhost:5432/adan
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=${REDIS_PASSWORD}
REDIS_URL=redis://:${REDIS_PASSWORD}@localhost:6379/0
# API
API_HOST=0.0.0.0
API_PORT=${API_PORT}
API_WORKERS=4
SECRET_KEY=${SECRET_KEY}
JWT_ALGORITHM=HS256
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30
# Frontend
FRONTEND_PORT=${FRONTEND_PORT}
VITE_API_URL=http://localhost:${API_PORT}
VITE_WS_URL=ws://localhost:${API_PORT}/ws
# Traccar
TRACCAR_HOST=localhost
TRACCAR_PORT=${TRACCAR_PORT}
TRACCAR_FORWARD_URL=http://localhost:${API_PORT}/api/v1/traccar/position
# MQTT
MQTT_HOST=localhost
MQTT_PORT=1883
MQTT_USER=adan
MQTT_PASSWORD=${MQTT_PASSWORD}
# MediaMTX
MEDIAMTX_RTSP_PORT=8554
MEDIAMTX_WEBRTC_PORT=8889
MEDIAMTX_HLS_PORT=8888
MEDIAMTX_API_PORT=9997
# General
DEBUG=false
LOG_LEVEL=INFO
TIMEZONE=America/Mexico_City
BACKUP_DIR=${BACKUP_DIR}
EOF
chmod 600 "$ENV_FILE"
# Copiar a backend
cp "$ENV_FILE" "$INSTALL_DIR/backend/.env"
log_success "Archivo .env creado"
}
# ---------------------------------------------
# Configurar Traccar
# ---------------------------------------------
configure_traccar() {
if [[ "$SKIP_TRACCAR" == "true" ]]; then
return
fi
log_section "Configurando Traccar"
TRACCAR_CONFIG="/opt/traccar/conf/traccar.xml"
# Copiar configuracion personalizada
if [[ -f "$INSTALL_DIR/deploy/traccar/traccar.xml" ]]; then
cp "$INSTALL_DIR/deploy/traccar/traccar.xml" "$TRACCAR_CONFIG"
fi
# Actualizar credenciales de BD en config
sed -i "s/POSTGRES_PASSWORD/${DB_PASSWORD}/g" "$TRACCAR_CONFIG" 2>/dev/null || true
# Reiniciar Traccar
systemctl restart traccar 2>/dev/null || true
log_success "Traccar configurado"
}
# ---------------------------------------------
# Configurar MediaMTX
# ---------------------------------------------
configure_mediamtx() {
log_section "Configurando MediaMTX"
MEDIAMTX_CONFIG="/opt/mediamtx/mediamtx.yml"
# Copiar configuracion personalizada
if [[ -f "$INSTALL_DIR/deploy/mediamtx/mediamtx.yml" ]]; then
cp "$INSTALL_DIR/deploy/mediamtx/mediamtx.yml" "$MEDIAMTX_CONFIG"
fi
log_success "MediaMTX configurado"
}
# ---------------------------------------------
# Configurar Mosquitto
# ---------------------------------------------
configure_mosquitto() {
log_section "Configurando Mosquitto"
# Crear archivo de passwords
touch /etc/mosquitto/passwd
mosquitto_passwd -b /etc/mosquitto/passwd adan "${MQTT_PASSWORD}"
# Configuracion
cat > /etc/mosquitto/conf.d/adan.conf <<EOF
# Configuracion para Sistema de ADAN
listener 1883 localhost
listener 9001
protocol websockets
allow_anonymous false
password_file /etc/mosquitto/passwd
# Logging
log_dest file /var/log/mosquitto/mosquitto.log
log_type error
log_type warning
log_type notice
EOF
systemctl restart mosquitto
log_success "Mosquitto configurado"
}
# ---------------------------------------------
# Configurar Redis con password
# ---------------------------------------------
configure_redis() {
log_section "Configurando Redis con autenticacion"
# Establecer password
sed -i "s/^# requirepass foobared/requirepass ${REDIS_PASSWORD}/" /etc/redis/redis.conf
systemctl restart redis-server
log_success "Redis configurado con password"
}
# ---------------------------------------------
# Instalar servicios systemd
# ---------------------------------------------
install_services() {
log_section "Instalando Servicios Systemd"
SERVICES_DIR="$INSTALL_DIR/deploy/services"
# Copiar servicios
for service in adan-api adan-web mediamtx cloudflared; do
if [[ -f "$SERVICES_DIR/${service}.service" ]]; then
log_info "Instalando servicio: ${service}"
cp "$SERVICES_DIR/${service}.service" /etc/systemd/system/
fi
done
# Recargar systemd
systemctl daemon-reload
# Habilitar servicios
systemctl enable adan-api 2>/dev/null || true
systemctl enable adan-web 2>/dev/null || true
systemctl enable mediamtx 2>/dev/null || true
# Iniciar servicios
log_info "Iniciando servicios..."
systemctl start adan-api 2>/dev/null || log_warn "adan-api no pudo iniciar (puede requerir configuracion adicional)"
systemctl start adan-web 2>/dev/null || log_warn "adan-web no pudo iniciar"
systemctl start mediamtx 2>/dev/null || log_warn "mediamtx no pudo iniciar"
log_success "Servicios instalados"
}
# ---------------------------------------------
# Ejecutar migraciones de BD
# ---------------------------------------------
run_migrations() {
log_section "Ejecutando Migraciones"
cd "$INSTALL_DIR/backend"
source venv/bin/activate
# Cargar variables de entorno
export $(grep -v '^#' "$INSTALL_DIR/.env" | xargs)
# Ejecutar migraciones con Alembic si existe
if [[ -d "alembic" ]]; then
log_info "Ejecutando migraciones Alembic..."
alembic upgrade head 2>/dev/null || log_warn "Migraciones fallaron o no hay migraciones pendientes"
fi
# Ejecutar init.sql si existe y no hay migraciones
if [[ ! -d "alembic" ]] && [[ -f "$INSTALL_DIR/deploy/postgres/init.sql" ]]; then
log_info "Ejecutando script init.sql..."
PGPASSWORD="${DB_PASSWORD}" psql -h localhost -U adan -d adan -f "$INSTALL_DIR/deploy/postgres/init.sql" || true
fi
deactivate
log_success "Migraciones completadas"
}
# ---------------------------------------------
# Configurar firewall
# ---------------------------------------------
configure_firewall() {
log_section "Configurando Firewall"
# Resetear UFW
ufw --force reset
# Politica por defecto
ufw default deny incoming
ufw default allow outgoing
# SSH (siempre permitir)
ufw allow ssh
# Puerto GPS (Traccar) - UNICO PUERTO PUBLICO
ufw allow ${TRACCAR_PORT}/tcp comment 'Traccar GPS'
# Puertos internos (solo localhost para desarrollo)
# En produccion, todo va por Cloudflare Tunnel
if [[ "$DEV_MODE" == "true" ]]; then
ufw allow ${API_PORT}/tcp comment 'API (dev)'
ufw allow ${FRONTEND_PORT}/tcp comment 'Frontend (dev)'
fi
# Habilitar firewall
ufw --force enable
log_success "Firewall configurado - Solo puerto ${TRACCAR_PORT} publico"
}
# ---------------------------------------------
# Configurar fail2ban
# ---------------------------------------------
configure_fail2ban() {
log_section "Configurando Fail2ban"
cat > /etc/fail2ban/jail.local <<EOF
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
EOF
systemctl enable fail2ban
systemctl restart fail2ban
log_success "Fail2ban configurado"
}
# ---------------------------------------------
# Configurar logrotate
# ---------------------------------------------
configure_logrotate() {
log_section "Configurando Logrotate"
cat > /etc/logrotate.d/adan <<EOF
/var/log/adan/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 root root
sharedscripts
postrotate
systemctl reload adan-api > /dev/null 2>&1 || true
endscript
}
EOF
mkdir -p /var/log/adan
log_success "Logrotate configurado"
}
# ---------------------------------------------
# Configurar cron para backups
# ---------------------------------------------
configure_cron() {
log_section "Configurando Backups Automaticos"
# Crear cron para backup diario a las 3 AM
CRON_JOB="0 3 * * * $INSTALL_DIR/deploy/scripts/backup.sh >> /var/log/adan/backup.log 2>&1"
# Agregar si no existe
(crontab -l 2>/dev/null | grep -v "backup.sh"; echo "$CRON_JOB") | crontab -
log_success "Backup diario configurado (3 AM)"
}
# ---------------------------------------------
# Mostrar resumen final
# ---------------------------------------------
show_summary() {
log_section "Instalacion Completada"
echo ""
echo -e "${GREEN}============================================${NC}"
echo -e "${GREEN} SISTEMA DE ADAN INSTALADO ${NC}"
echo -e "${GREEN}============================================${NC}"
echo ""
echo -e "${BLUE}Servicios:${NC}"
echo " - API Backend: http://localhost:${API_PORT}"
echo " - Frontend: http://localhost:${FRONTEND_PORT}"
echo " - Traccar GPS: puerto ${TRACCAR_PORT}"
echo " - MediaMTX RTSP: rtsp://localhost:8554"
echo " - MediaMTX WebRTC: http://localhost:8889"
echo ""
echo -e "${BLUE}Base de Datos:${NC}"
echo " - PostgreSQL: localhost:5432"
echo " - Database: adan"
echo " - Usuario: adan"
echo ""
echo -e "${BLUE}Credenciales:${NC}"
echo " - Guardadas en: ${CREDENTIALS_FILE}"
echo ""
echo -e "${YELLOW}IMPORTANTE:${NC}"
echo " 1. Guarda las credenciales en un lugar seguro"
echo " 2. Configura Cloudflare Tunnel para acceso externo"
echo " 3. El unico puerto publico es ${TRACCAR_PORT} (GPS)"
echo ""
echo -e "${BLUE}Comandos utiles:${NC}"
echo " - Ver logs API: journalctl -u adan-api -f"
echo " - Reiniciar API: systemctl restart adan-api"
echo " - Backup manual: ${INSTALL_DIR}/deploy/scripts/backup.sh"
echo " - Actualizar: ${INSTALL_DIR}/deploy/scripts/update.sh"
echo ""
echo -e "${GREEN}============================================${NC}"
# Mostrar credenciales en pantalla
echo ""
echo -e "${YELLOW}=== CREDENCIALES (guardar y eliminar archivo) ===${NC}"
cat "$CREDENTIALS_FILE"
echo ""
}
# ---------------------------------------------
# Main
# ---------------------------------------------
main() {
parse_args "$@"
echo ""
echo -e "${GREEN}============================================${NC}"
echo -e "${GREEN} INSTALADOR SISTEMA DE ADAN ${NC}"
echo -e "${GREEN}============================================${NC}"
echo ""
echo "Directorio instalacion: $INSTALL_DIR"
echo "Modo desarrollo: $DEV_MODE"
echo "Saltar DB: $SKIP_DB"
echo "Saltar Traccar: $SKIP_TRACCAR"
echo ""
# Confirmar instalacion
read -p "Continuar con la instalacion? (Y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Nn]$ ]]; then
echo "Instalacion cancelada"
exit 0
fi
# Ejecutar pasos de instalacion
check_requirements
update_system
install_postgresql
install_redis
install_python
install_nodejs
install_traccar
install_mediamtx
install_mosquitto
generate_credentials
configure_database
setup_application
create_env_file
configure_traccar
configure_mediamtx
configure_mosquitto
configure_redis
run_migrations
install_services
configure_firewall
configure_fail2ban
configure_logrotate
configure_cron
show_summary
}
# Ejecutar
main "$@"