#!/bin/bash # # StreamingPro - Instalador Unificado v3.0 # Copyright (c) 2024 StreamingPro # # Uso: curl -fsSL https://install.streamingpro.es | bash # # Caracteristicas: # - Subdominio automatico: tuserver.streamingpro.es # - Validacion de licencias # - Creacion automatica de DNS # - Traefik + SSL automatico # # NO usar set -e - causa problemas con scripts interactivos via curl | bash # ============================================================================= # CONSTANTES Y CONFIGURACION # ============================================================================= VERSION="3.0.0" BASE_URL="https://install.streamingpro.es" # La Edge Function de Supabase NO se llama directamente: exige cabecera de # autorizacion y este script no la lleva. Se va siempre por el proxy de # STREAMINGPRO_API_URL, que la anade. # Directorios CENTRAL_DIR="/opt/streamingpro-central" INTERCOM_DIR="/opt/streamingpro-intercom" PROXY_DIR="/opt/streamingpro-proxy" NETWORK_NAME="streamingpro-network" # Docker Registry DOCKER_REGISTRY="sincros" # API URL para verificación de licencias (sin exponer service keys) STREAMINGPRO_API_URL="https://api.streamingpro.es" # MediaSoup WebRTC ports (solo para Intercom) MEDIASOUP_MIN_PORT=40000 MEDIASOUP_MAX_PORT=40999 # Colores RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' WHITE='\033[1;37m' NC='\033[0m' # Variables globales LANG_CODE="${STREAMINGPRO_LANG:-es}" SELECTED_PRODUCT="" SELECTED_ACTION="" SERVER_NAME="" USER_EMAIL="" LICENSE_KEY="" PUBLIC_IP="" DOMAIN="" # ============================================================================= # i18n - TRADUCCIONES # ============================================================================= t() { local key="$1" local var_name="MSG_${LANG_CODE}_${key}" echo "${!var_name}" } # --- ESPAÑOL --- MSG_es_WELCOME="Bienvenido al instalador de StreamingPro" MSG_es_SELECT_LANG="Selecciona tu idioma / Select your language" MSG_es_SPANISH="Espanol" MSG_es_ENGLISH="Ingles" MSG_es_SELECT_PRODUCT="Selecciona el producto" MSG_es_CENTRAL_DESC="Plataforma de gestion de streaming (RTSP, HLS, WebRTC)" MSG_es_INTERCOM_DESC="Sistema de intercomunicacion WebRTC para broadcast" MSG_es_SELECT_ACTION="Selecciona la accion" MSG_es_INSTALL="Instalar" MSG_es_UPDATE="Actualizar" MSG_es_UNINSTALL="Desinstalar" MSG_es_STATUS="Ver estado" MSG_es_EXIT="Salir" MSG_es_INSTALL_DESC="Instalar la aplicacion desde cero" MSG_es_UPDATE_DESC="Actualizar a la ultima version" MSG_es_UNINSTALL_DESC="Eliminar la aplicacion completamente" MSG_es_STATUS_DESC="Ver el estado de los servicios" MSG_es_ALREADY_INSTALLED="ya esta instalado en" MSG_es_REINSTALL_QUESTION="Deseas reinstalar? (se eliminaran los datos actuales)" MSG_es_NOT_INSTALLED="no esta instalado" MSG_es_INSTALL_FIRST="Debes instalarlo primero" MSG_es_CONFIRM_UNINSTALL="Estas seguro de que deseas desinstalar" MSG_es_DELETE_DATA="Deseas eliminar tambien los datos (base de datos, configuracion)?" MSG_es_UNINSTALL_CANCELLED="Desinstalacion cancelada" MSG_es_REQUIRES_ROOT="Este script debe ejecutarse como root" MSG_es_CHECKING_DOCKER="Verificando Docker..." MSG_es_DOCKER_NOT_INSTALLED="Docker no esta instalado" MSG_es_INSTALL_DOCKER_AUTO="Instalando Docker automaticamente..." MSG_es_DOCKER_INSTALLED="Docker instalado" MSG_es_CHECKING_PROXY="Verificando proxy central..." MSG_es_PROXY_NOT_FOUND="Proxy central no encontrado" MSG_es_INSTALLING_PROXY="Instalando proxy central (Traefik)..." MSG_es_PROXY_INSTALLED="Proxy central instalado" MSG_es_PROXY_FOUND="Proxy central encontrado" MSG_es_PORTS_80_443_IN_USE="Los puertos 80 y/o 443 estan en uso por otro servicio" MSG_es_STOP_CONFLICTING_SERVICES="Detener los servicios que usan esos puertos antes de continuar" MSG_es_DETECTING_PUBLIC_IP="Detectando IP publica..." MSG_es_PUBLIC_IP_DETECTED="IP publica detectada" MSG_es_PUBLIC_IP_NOT_DETECTED="No se pudo detectar la IP publica" MSG_es_CONFIG_TITLE="CONFIGURACION DE LA INSTALACION" MSG_es_LICENSE_CONFIG="Datos de Licencia" MSG_es_SERVER_NAME_PROMPT="Nombre del servidor (sera tu subdominio)" MSG_es_SERVER_NAME_EXAMPLE="Ejemplo: miempresa -> miempresa.streamingpro.es" MSG_es_SERVER_NAME_REQUIRED="El nombre del servidor es requerido" MSG_es_SERVER_NAME_INVALID="El nombre solo puede contener letras, numeros y guiones" MSG_es_EMAIL_PROMPT="Email de tu cuenta StreamingPro" MSG_es_EMAIL_REQUIRED="El email es requerido" MSG_es_LICENSE_PROMPT="Licencia del producto" MSG_es_LICENSE_REQUIRED="La licencia es requerida" MSG_es_VALIDATING_LICENSE="Validando licencia..." MSG_es_LICENSE_VALID="Licencia valida" MSG_es_LICENSE_INVALID="La licencia no es valida o no coincide con el email" MSG_es_LICENSE_ALREADY_INSTALLED="Esta licencia ya esta instalada en otro servidor" MSG_es_SUBDOMAIN_TAKEN="El subdominio no esta disponible" MSG_es_SUBDOMAIN_RESERVED="El subdominio esta reservado" MSG_es_SUBDOMAIN_AVAILABLE="Subdominio disponible" MSG_es_DNS_CONFIGURED="DNS configurado" MSG_es_DNS_ERROR="Error al configurar DNS" MSG_es_ALTERNATIVE_SUGGESTIONS="Sugerencias disponibles:" MSG_es_SELECT_ALTERNATIVE="Selecciona una opcion o escribe otro nombre" MSG_es_CUSTOM_NAME="Escribir otro nombre" MSG_es_CREATING_DNS="Creando registro DNS..." MSG_es_WAITING_DNS="Esperando propagacion DNS (puede tardar 30s)..." MSG_es_SUMMARY_TITLE="RESUMEN DE LA INSTALACION" MSG_es_PROCEED_INSTALL="Deseas proceder con la instalacion?" MSG_es_INSTALL_CANCELLED="Instalacion cancelada" MSG_es_CREATING_DIRS="Creando directorios..." MSG_es_GENERATING_CONFIG="Generando configuracion..." MSG_es_DOWNLOADING_IMAGES="Descargando imagenes..." MSG_es_STARTING_SERVICES="Iniciando servicios..." MSG_es_WAITING_SERVICES="Esperando que los servicios esten listos..." MSG_es_INSTALL_COMPLETE="INSTALACION COMPLETADA!" MSG_es_PANEL_ACCESS="Acceso al Panel:" MSG_es_API_APPS="API para Apps:" MSG_es_USEFUL_COMMANDS="Comandos utiles:" MSG_es_VIEW_LOGS="Ver logs" MSG_es_RESTART="Reiniciar" MSG_es_STOP="Detener" MSG_es_UPDATE_CMD="Actualizar" MSG_es_IMPORTANT="IMPORTANTE:" MSG_es_FIREWALL_PORTS="Asegurate de que los puertos" MSG_es_FIREWALL_OPEN="esten abiertos en tu firewall" MSG_es_YES_NO_Y="[S/n]" MSG_es_YES_NO_N="[s/N]" MSG_es_OPTION="Opcion" MSG_es_INVALID_OPTION="Opcion no valida" MSG_es_PRESS_ENTER="Presiona Enter para continuar..." MSG_es_UPDATE_SUCCESS="actualizado correctamente" MSG_es_UNINSTALL_SUCCESS="ha sido desinstalado correctamente" MSG_es_PREPARING_INSTALLER="Preparando el instalador de" MSG_es_INSTALLER_DOWNLOAD_FAILED="No se pudo descargar el instalador del producto" MSG_es_INSTALLER_CORRUPT="El instalador descargado no es valido; reintenta en unos minutos" MSG_es_STATUS_TITLE="Estado de los servicios" # --- ENGLISH --- MSG_en_WELCOME="Welcome to StreamingPro installer" MSG_en_SELECT_LANG="Selecciona tu idioma / Select your language" MSG_en_SPANISH="Spanish" MSG_en_ENGLISH="English" MSG_en_SELECT_PRODUCT="Select product" MSG_en_CENTRAL_DESC="Streaming management platform (RTSP, HLS, WebRTC)" MSG_en_INTERCOM_DESC="WebRTC intercom system for broadcast" MSG_en_SELECT_ACTION="Select action" MSG_en_INSTALL="Install" MSG_en_UPDATE="Update" MSG_en_UNINSTALL="Uninstall" MSG_en_STATUS="View status" MSG_en_EXIT="Exit" MSG_en_INSTALL_DESC="Install the application from scratch" MSG_en_UPDATE_DESC="Update to the latest version" MSG_en_UNINSTALL_DESC="Remove the application completely" MSG_en_STATUS_DESC="View services status" MSG_en_ALREADY_INSTALLED="is already installed at" MSG_en_REINSTALL_QUESTION="Do you want to reinstall? (current data will be deleted)" MSG_en_NOT_INSTALLED="is not installed" MSG_en_INSTALL_FIRST="You must install it first" MSG_en_CONFIRM_UNINSTALL="Are you sure you want to uninstall" MSG_en_DELETE_DATA="Do you also want to delete data (database, configuration)?" MSG_en_UNINSTALL_CANCELLED="Uninstall cancelled" MSG_en_REQUIRES_ROOT="This script must be run as root" MSG_en_CHECKING_DOCKER="Checking Docker..." MSG_en_DOCKER_NOT_INSTALLED="Docker is not installed" MSG_en_INSTALL_DOCKER_AUTO="Installing Docker automatically..." MSG_en_DOCKER_INSTALLED="Docker installed" MSG_en_CHECKING_PROXY="Checking central proxy..." MSG_en_PROXY_NOT_FOUND="Central proxy not found" MSG_en_INSTALLING_PROXY="Installing central proxy (Traefik)..." MSG_en_PROXY_INSTALLED="Central proxy installed" MSG_en_PROXY_FOUND="Central proxy found" MSG_en_PORTS_80_443_IN_USE="Ports 80 and/or 443 are in use by another service" MSG_en_STOP_CONFLICTING_SERVICES="Stop the services using those ports before continuing" MSG_en_DETECTING_PUBLIC_IP="Detecting public IP..." MSG_en_PUBLIC_IP_DETECTED="Public IP detected" MSG_en_PUBLIC_IP_NOT_DETECTED="Could not detect public IP" MSG_en_CONFIG_TITLE="INSTALLATION CONFIGURATION" MSG_en_LICENSE_CONFIG="License Data" MSG_en_SERVER_NAME_PROMPT="Server name (will be your subdomain)" MSG_en_SERVER_NAME_EXAMPLE="Example: mycompany -> mycompany.streamingpro.es" MSG_en_SERVER_NAME_REQUIRED="Server name is required" MSG_en_SERVER_NAME_INVALID="Name can only contain letters, numbers and hyphens" MSG_en_EMAIL_PROMPT="Your StreamingPro account email" MSG_en_EMAIL_REQUIRED="Email is required" MSG_en_LICENSE_PROMPT="Product license" MSG_en_LICENSE_REQUIRED="License is required" MSG_en_VALIDATING_LICENSE="Validating license..." MSG_en_LICENSE_VALID="License valid" MSG_en_LICENSE_INVALID="License is not valid or does not match the email" MSG_en_LICENSE_ALREADY_INSTALLED="This license is already installed on another server" MSG_en_SUBDOMAIN_TAKEN="Subdomain is not available" MSG_en_SUBDOMAIN_RESERVED="Subdomain is reserved" MSG_en_SUBDOMAIN_AVAILABLE="Subdomain available" MSG_en_DNS_CONFIGURED="DNS configured" MSG_en_DNS_ERROR="Error configuring DNS" MSG_en_ALTERNATIVE_SUGGESTIONS="Available suggestions:" MSG_en_SELECT_ALTERNATIVE="Select an option or enter another name" MSG_en_CUSTOM_NAME="Enter another name" MSG_en_CREATING_DNS="Creating DNS record..." MSG_en_WAITING_DNS="Waiting for DNS propagation (may take 30s)..." MSG_en_SUMMARY_TITLE="INSTALLATION SUMMARY" MSG_en_PROCEED_INSTALL="Do you want to proceed with the installation?" MSG_en_INSTALL_CANCELLED="Installation cancelled" MSG_en_CREATING_DIRS="Creating directories..." MSG_en_GENERATING_CONFIG="Generating configuration..." MSG_en_DOWNLOADING_IMAGES="Downloading images..." MSG_en_STARTING_SERVICES="Starting services..." MSG_en_WAITING_SERVICES="Waiting for services to be ready..." MSG_en_INSTALL_COMPLETE="INSTALLATION COMPLETED!" MSG_en_PANEL_ACCESS="Panel Access:" MSG_en_API_APPS="API for Apps:" MSG_en_USEFUL_COMMANDS="Useful commands:" MSG_en_VIEW_LOGS="View logs" MSG_en_RESTART="Restart" MSG_en_STOP="Stop" MSG_en_UPDATE_CMD="Update" MSG_en_IMPORTANT="IMPORTANT:" MSG_en_FIREWALL_PORTS="Make sure the ports" MSG_en_FIREWALL_OPEN="are open in your firewall" MSG_en_YES_NO_Y="[Y/n]" MSG_en_YES_NO_N="[y/N]" MSG_en_OPTION="Option" MSG_en_INVALID_OPTION="Invalid option" MSG_en_PRESS_ENTER="Press Enter to continue..." MSG_en_UPDATE_SUCCESS="updated successfully" MSG_en_UNINSTALL_SUCCESS="has been uninstalled successfully" MSG_en_PREPARING_INSTALLER="Preparing the installer for" MSG_en_INSTALLER_DOWNLOAD_FAILED="Could not download the product installer" MSG_en_INSTALLER_CORRUPT="The downloaded installer is not valid; try again in a few minutes" MSG_en_STATUS_TITLE="Services status" # ============================================================================= # FUNCIONES DE UTILIDAD # ============================================================================= print_banner() { clear echo -e "${CYAN}" cat << "EOF" _____ _ _ ____ / ____| | (_) | _ \ | (___ | |_ _ __ ___ __ _ _ __ ___ _ _ __ __ _| |_) |_ __ ___ \___ \| __| '__/ _ \/ _` | '_ ` _ \| | '_ \ / _` | __/| '__/ _ \ ____) | |_| | | __/ (_| | | | | | | | | | | (_| | | | | | (_) | |_____/ \__|_| \___|\__,_|_| |_| |_|_|_| |_|\__, |_| |_| \___/ __/ | |___/ EOF echo -e "${NC}" echo -e "${WHITE} $(t WELCOME) v${VERSION}${NC}" echo -e "${BLUE} ════════════════════════════════════════════════════════════${NC}" echo "" } log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warning() { echo -e "${YELLOW}[!]${NC} $1"; } log_error() { echo -e "${RED}[✗]${NC} $1"; } ask_yes_no() { local prompt="$1" default="$2" var_name="$3" local options=$([ "$default" = "y" ] && echo "$(t YES_NO_Y)" || echo "$(t YES_NO_N)") echo -e -n "${WHITE}$prompt ${CYAN}$options${NC}: " read -r response /dev/null; then log_warning "$(t DOCKER_NOT_INSTALLED)" log_info "$(t INSTALL_DOCKER_AUTO)" curl -fsSL https://get.docker.com | sh systemctl enable docker systemctl start docker fi log_success "$(t DOCKER_INSTALLED): v$(docker --version | cut -d' ' -f3 | tr -d ',')" } check_and_install_proxy() { log_info "$(t CHECKING_PROXY)" # Verificar si el proxy ya esta instalado y funcionando if docker network inspect "$NETWORK_NAME" &> /dev/null && \ docker ps --format '{{.Names}}' | grep -q "streamingpro_proxy"; then log_success "$(t PROXY_FOUND)" return 0 fi # Verificar puertos 80/443 local port80_used=false local port443_used=false if ss -tuln | grep -q ":80 "; then port80_used=true fi if ss -tuln | grep -q ":443 "; then port443_used=true fi if [ "$port80_used" = true ] || [ "$port443_used" = true ]; then echo "" log_error "$(t PORTS_80_443_IN_USE)" [ "$port80_used" = true ] && log_warning " - Puerto 80 en uso" [ "$port443_used" = true ] && log_warning " - Puerto 443 en uso" echo "" log_info "$(t STOP_CONFLICTING_SERVICES)" exit 1 fi # Instalar proxy log_warning "$(t PROXY_NOT_FOUND)" log_info "$(t INSTALLING_PROXY)" # Crear red Docker docker network inspect "$NETWORK_NAME" &> /dev/null || docker network create "$NETWORK_NAME" # Crear directorios mkdir -p "$PROXY_DIR"/{config,certs,logs} mkdir -p "$PROXY_DIR/config/dynamic" touch "$PROXY_DIR/certs/acme.json" chmod 600 "$PROXY_DIR/certs/acme.json" # Configuracion de Traefik cat > "$PROXY_DIR/config/traefik.yml" << 'EOFTRAEFIK' api: dashboard: true insecure: false entryPoints: web: address: ":80" http: redirections: entryPoint: to: websecure scheme: https websecure: address: ":443" providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false network: streamingpro-network file: directory: "/etc/traefik/dynamic" watch: true certificatesResolvers: letsencrypt: acme: email: placeholder@example.com storage: /certs/acme.json httpChallenge: entryPoint: web log: level: INFO filePath: "/logs/traefik.log" accessLog: filePath: "/logs/access.log" EOFTRAEFIK # Docker Compose cat > "$PROXY_DIR/docker-compose.yml" << EOFCOMPOSE services: traefik: image: traefik:v3.6 container_name: streamingpro_proxy restart: unless-stopped security_opt: - no-new-privileges:true ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./config/traefik.yml:/etc/traefik/traefik.yml:ro - ./config/dynamic:/etc/traefik/dynamic:ro - ./certs:/certs - ./logs:/logs networks: - ${NETWORK_NAME} networks: ${NETWORK_NAME}: external: true EOFCOMPOSE cd "$PROXY_DIR" docker compose up -d sleep 3 log_success "$(t PROXY_INSTALLED)" } # ============================================================================= # SELECCION DE IDIOMA # ============================================================================= select_language() { clear echo -e "${CYAN}" cat << "EOF" _____ _ _ ____ / ____| | (_) | _ \ | (___ | |_ _ __ ___ __ _ _ __ ___ _ _ __ __ _| |_) |_ __ ___ \___ \| __| '__/ _ \/ _` | '_ ` _ \| | '_ \ / _` | __/| '__/ _ \ ____) | |_| | | __/ (_| | | | | | | | | | | (_| | | | | | (_) | |_____/ \__|_| \___|\__,_|_| |_| |_|_|_| |_|\__, |_| |_| \___/ __/ | |___/ EOF echo -e "${NC}" echo "" echo -e "${WHITE} Selecciona tu idioma / Select your language${NC}" echo -e "${BLUE} ════════════════════════════════════════════════════════════${NC}" echo "" echo -e " ${CYAN}1)${NC} Espanol" echo -e " ${CYAN}2)${NC} English" echo "" echo -e -n " ${WHITE}Opcion / Option [1-2]:${NC} " read -r lang_choice /dev/null; then log_error "$(t INSTALLER_CORRUPT)" rm -f "$script_temporal" return 1 fi # El idioma viaja por entorno: los scripts de producto leen # STREAMINGPRO_LANG y tienen sus propias traducciones. Sin esto, quien # eligiera ingles en el menu seguia el resto del proceso en espanol. # # Y /dev/null || true rm -rf "$install_dir" fi } do_status() { local product="$1" local product_name install_dir [ "$product" = "central" ] && product_name="StreamingPro Central" && install_dir="$CENTRAL_DIR" [ "$product" = "intercom" ] && product_name="StreamingPro Intercom" && install_dir="$INTERCOM_DIR" print_banner echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" echo -e "${WHITE} $product_name - $(t STATUS_TITLE)${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" echo "" if ! is_installed "$product"; then log_warning "$product_name $(t NOT_INSTALLED)" else cd "$install_dir" docker compose ps fi echo "" echo -e -n "$(t PRESS_ENTER)" read -r