Sistema completo para monitoreo y gestion de flotas de vehiculos con: - Backend FastAPI con PostgreSQL/TimescaleDB - Frontend React con TypeScript y TailwindCSS - App movil React Native con Expo - Soporte para dispositivos GPS, Meshtastic y celulares - Video streaming en vivo con MediaMTX - Geocercas, alertas, viajes y reportes - Autenticacion JWT y WebSockets en tiempo real Documentacion completa y guias de usuario incluidas.
1081 lines
30 KiB
Bash
1081 lines
30 KiB
Bash
#!/bin/bash
|
|
# ============================================
|
|
# Sistema de Flotillas - 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/flotillas}"
|
|
REPO_URL="${REPO_URL:-https://github.com/tuorganizacion/flotillas.git}"
|
|
REPO_BRANCH="${REPO_BRANCH:-main}"
|
|
BACKUP_DIR="${BACKUP_DIR:-/var/backups/flotillas}"
|
|
|
|
# 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/flotillas-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:-flotillas}"
|
|
DB_USER="${POSTGRES_USER:-flotillas}"
|
|
|
|
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 Flotillas
|
|
# Generadas: $(date)
|
|
# IMPORTANTE: Guardar en lugar seguro y eliminar este archivo
|
|
# ============================================
|
|
|
|
# PostgreSQL
|
|
POSTGRES_HOST=localhost
|
|
POSTGRES_PORT=5432
|
|
POSTGRES_DB=flotillas
|
|
POSTGRES_USER=flotillas
|
|
POSTGRES_PASSWORD=${DB_PASSWORD}
|
|
DATABASE_URL=postgresql://flotillas:${DB_PASSWORD}@localhost:5432/flotillas
|
|
|
|
# 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=flotillas
|
|
MQTT_PASSWORD=${MQTT_PASSWORD}
|
|
|
|
# Admin inicial
|
|
ADMIN_EMAIL=admin@flotillas.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=flotillas
|
|
POSTGRES_USER=flotillas
|
|
POSTGRES_PASSWORD=${DB_PASSWORD}
|
|
DATABASE_URL=postgresql://flotillas:${DB_PASSWORD}@localhost:5432/flotillas
|
|
|
|
# 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=flotillas
|
|
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 flotillas "${MQTT_PASSWORD}"
|
|
|
|
# Configuracion
|
|
cat > /etc/mosquitto/conf.d/flotillas.conf <<EOF
|
|
# Configuracion para Sistema de Flotillas
|
|
|
|
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 flotillas-api flotillas-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 flotillas-api 2>/dev/null || true
|
|
systemctl enable flotillas-web 2>/dev/null || true
|
|
systemctl enable mediamtx 2>/dev/null || true
|
|
|
|
# Iniciar servicios
|
|
log_info "Iniciando servicios..."
|
|
systemctl start flotillas-api 2>/dev/null || log_warn "flotillas-api no pudo iniciar (puede requerir configuracion adicional)"
|
|
systemctl start flotillas-web 2>/dev/null || log_warn "flotillas-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 flotillas -d flotillas -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/flotillas <<EOF
|
|
/var/log/flotillas/*.log {
|
|
daily
|
|
missingok
|
|
rotate 14
|
|
compress
|
|
delaycompress
|
|
notifempty
|
|
create 0640 root root
|
|
sharedscripts
|
|
postrotate
|
|
systemctl reload flotillas-api > /dev/null 2>&1 || true
|
|
endscript
|
|
}
|
|
EOF
|
|
|
|
mkdir -p /var/log/flotillas
|
|
|
|
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/flotillas/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 FLOTILLAS 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: flotillas"
|
|
echo " - Usuario: flotillas"
|
|
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 flotillas-api -f"
|
|
echo " - Reiniciar API: systemctl restart flotillas-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 FLOTILLAS ${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 "$@"
|