Commit ebd40d7d authored by ajlarrosa's avatar ajlarrosa

hs-12 documentacion y comandos para instalar la consola web

parent 235859f8
@echo off
echo ========================================
echo Paso 1: Instalando Statik
echo ========================================
echo.
echo Instalando statik...
go get github.com/rakyll/statik
if %ERRORLEVEL% EQU 0 (
echo.
echo OK: Statik instalado correctamente
echo.
) else (
echo.
echo ERROR: No se pudo instalar statik
echo Verifica que Go este instalado y en el PATH
echo.
pause
exit /b 1
)
pause
@echo off
echo ========================================
echo Paso 2: Ejecutando Statik
echo ========================================
echo.
echo Convirtiendo archivos estaticos de web/build en codigo Go...
echo.
statik --src=web/build
if %ERRORLEVEL% EQU 0 (
echo.
echo OK: Statik ejecutado correctamente
echo Los archivos estaticos fueron embebidos en el codigo Go
echo.
) else (
echo.
echo ERROR: No se pudo ejecutar statik
echo Verifica que:
echo 1. El directorio web/build existe y tiene contenido
echo 2. Statik este instalado (ejecuta 1-instalar-statik.bat primero)
echo.
pause
exit /b 1
)
pause
# Web Console - Guía de Instalación para Linux (Entorno Productivo)
Esta guía te ayudará a configurar y desplegar el Web Console en un entorno productivo Linux.
## Introducción
El Web Console es una aplicación web desarrollada en Go con frontend React que permite conectarse a servidores Linux mediante SSH directamente desde el navegador. Esta aplicación se integra con Cluster Panel para proporcionar una interfaz web para la gestión remota de servidores.
## Requisitos Previos
Antes de comenzar, asegúrate de tener instalado lo siguiente en tu servidor Linux:
- **Go 1.13 o superior**: [Instalación de Go](https://golang.org/doc/install)
- Verificar instalación: `go version`
- **Node.js 18**: [Instalación de Node.js](https://nodejs.org/)
- Verificar instalación: `node --version`
- **Yarn**: Instalar con npm o desde el repositorio
```bash
npm install -g yarn
# o
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update && sudo apt install yarn
```
- Verificar instalación: `yarn --version`
- **Statik**: Herramienta para embeber archivos estáticos en el binario Go
- Instalación: `go install github.com/rakyll/statik@latest`
- Nota: Asegúrate de que `$HOME/go/bin` esté en tu PATH
- **Sistema de Servicios**: systemd (incluido por defecto en la mayoría de distribuciones Linux modernas)
- **Git**: Para clonar el repositorio (si es necesario)
- **Firewall**: ufw o firewalld (dependiendo de tu distribución)
## Instalación de Dependencias
### 1. Actualizar el Sistema
```bash
sudo apt update && sudo apt upgrade -y
# o para RHEL/CentOS:
# sudo yum update -y
```
### 2. Instalar Go
```bash
# Descargar Go (ajusta la versión según la última disponible)
wget https://go.dev/dl/go1.21.5.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.21.5.linux-amd64.tar.gz
# Agregar Go al PATH
echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' >> ~/.bashrc
source ~/.bashrc
# Verificar instalación
go version
```
### 3. Instalar Node.js y Yarn
**Para Ubuntu/Debian:**
```bash
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
sudo npm install -g yarn
```
**Para RHEL/CentOS:**
```bash
curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
sudo yum install -y nodejs
sudo npm install -g yarn
```
### 4. Instalar Statik
```bash
go install github.com/rakyll/statik@latest
# Verificar que está en el PATH
statik --help
```
### 5. Clonar o Preparar el Proyecto
Si aún no tienes el código fuente:
```bash
cd /opt # o el directorio de tu elección
sudo mkdir -p /opt/web-console
sudo chown $USER:$USER /opt/web-console
cd /opt/web-console
# Clonar desde tu repositorio o copiar los archivos
```
O si ya tienes los archivos, navega al directorio:
```bash
cd /ruta/a/web-console
```
## Configuración
### 1. Instalar Dependencias de Go
```bash
go mod download
go mod verify
```
### 2. Instalar Dependencias del Frontend React
```bash
cd web
yarn install
cd ..
```
### 3. Configurar el Archivo de Configuración
El archivo de configuración principal se encuentra en `conf/config.yaml`. Este archivo controla la configuración del servidor.
Crea o edita el archivo `conf/config.yaml`:
```bash
mkdir -p conf
nano conf/config.yaml
```
Configuración de ejemplo para producción:
```yaml
site:
appname: ssh-web-console
listen_addr: :2222
runmode: prod
deploy_host: tu-dominio.com # Cambia por tu dominio real
prod:
# http path of static files and views
static_prefix: /
dev: # config used in debug mode.
# https prefix of static files only
static_prefix: /static/
static_redirect: "localhost:8080"
static_dir: ./dist/
views_prefix: /
views_dir: views/
ssh:
buffer_checker_cycle_time: 60
jwt:
jwt_secret: tu-secret-jwt-muy-seguro-cambiar-en-produccion # ¡CAMBIAR EN PRODUCCIÓN!
token_lifetime: 7200
issuer: tu-dominio.com
query_token_key: _t
```
**Importante para producción:**
- `listen_addr: :2222` - Puerto en el que escuchará el servidor
- `runmode: prod` - Debe estar en modo producción
- `deploy_host`: Configura tu dominio real
- `jwt_secret`: **Cambia esto por un secreto fuerte y único en producción**
### 4. Configurar Variables de Entorno React
Crea un archivo `.env` en el directorio `web/` con las variables de entorno necesarias:
```bash
cd web
nano .env
```
Contenido del archivo `.env`:
```env
REACT_APP_CLUSTER_URL=https://tu-cluster-panel.com
REACT_APP_API_URL=tu-dominio.com:2222
REACT_APP_ROUTER_BASE=
REACT_APP_API_HTTPS=true
```
**Nota:**
- `REACT_APP_CLUSTER_URL`: URL base completa de tu instalación de Cluster Panel (sin barra final)
- `REACT_APP_API_URL`: URL del servidor web console (opcional)
- `REACT_APP_API_HTTPS`: Configurar como `true` si usas HTTPS
```bash
cd ..
```
## Compilación
### Paso 1: Compilar el Frontend React
```bash
cd web
yarn build
cd ..
```
Esto generará los archivos estáticos en `web/build/`.
### Paso 2: Generar Archivos Statik
Statik embebe los archivos estáticos del frontend en el código Go:
```bash
statik --src=web/build
```
Esto generará archivos en el directorio `statik/`.
### Paso 3: Compilar el Servidor Go
**Compilación estándar:**
```bash
go build -o ssh-web-console-linux-amd64
```
**Compilación optimizada para producción:**
```bash
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ssh-web-console-linux-amd64
```
Esto genera un binario estático que no depende de librerías del sistema.
**Para arquitectura ARM64:**
```bash
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o ssh-web-console-linux-arm64
```
### Paso 4: Verificar el Binario
```bash
file ssh-web-console-linux-amd64
ls -lh ssh-web-console-linux-amd64
```
## Despliegue
### 1. Crear Directorio de Despliegue
```bash
sudo mkdir -p /opt/web-console
sudo mkdir -p /opt/web-console/conf
sudo mkdir -p /opt/web-console/logs
```
### 2. Copiar Archivos
```bash
# Copiar el binario
sudo cp ssh-web-console-linux-amd64 /opt/web-console/ssh-web-console
sudo chmod +x /opt/web-console/ssh-web-console
# Copiar el archivo de configuración
sudo cp conf/config.yaml /opt/web-console/conf/config.yaml
# Ajustar permisos
sudo chown -R webconsole:webconsole /opt/web-console
```
**Nota:** Si el usuario `webconsole` no existe, créalo:
```bash
sudo useradd -r -s /bin/false webconsole
```
### 3. Configurar como Servicio systemd
Crea un archivo de servicio systemd:
```bash
sudo nano /etc/systemd/system/web-console.service
```
Contenido del archivo de servicio:
```ini
[Unit]
Description=Web Console SSH Terminal Server
After=network.target
[Service]
Type=simple
User=webconsole
Group=webconsole
WorkingDirectory=/opt/web-console
ExecStart=/opt/web-console/ssh-web-console -config /opt/web-console/conf/config.yaml
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=web-console
# Seguridad
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/web-console/logs
ReadOnlyPaths=/opt/web-console/conf
[Install]
WantedBy=multi-user.target
```
**Habilitar y Iniciar el Servicio:**
```bash
# Recargar systemd
sudo systemctl daemon-reload
# Habilitar el servicio para iniciar al arrancar
sudo systemctl enable web-console
# Iniciar el servicio
sudo systemctl start web-console
# Verificar el estado
sudo systemctl status web-console
```
### 4. Verificar Logs
```bash
# Ver logs en tiempo real
sudo journalctl -u web-console -f
# Ver últimos logs
sudo journalctl -u web-console -n 50
```
### 5. Configurar Firewall
**Para Ubuntu/Debian (ufw):**
```bash
sudo ufw allow 2222/tcp
sudo ufw reload
```
**Para RHEL/CentOS (firewalld):**
```bash
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
```
### 6. Configurar Proxy Reverso (Recomendado)
Es recomendable usar un proxy reverso como Nginx o Apache para:
- Terminación SSL/TLS (HTTPS)
- Enrutamiento
- Balanceo de carga (si es necesario)
**Ejemplo de configuración Nginx:**
```nginx
upstream web-console {
server 127.0.0.1:2222;
keepalive 64;
}
server {
listen 80;
listen [::]:80;
server_name console.tu-dominio.com;
# Redirigir HTTP a HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name console.tu-dominio.com;
ssl_certificate /etc/letsencrypt/live/tu-dominio.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/tu-dominio.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://web-console;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
proxy_buffering off;
}
}
```
Después de configurar Nginx:
```bash
sudo nginx -t # Verificar configuración
sudo systemctl reload nginx # Recargar Nginx
```
## Verificación
### 1. Verificar que el Servicio está Ejecutándose
```bash
sudo systemctl status web-console
```
Deberías ver algo como:
```
Active: active (running) since ...
```
### 2. Verificar que el Puerto está Escuchando
```bash
sudo netstat -tlnp | grep 2222
# o
sudo ss -tlnp | grep 2222
```
Deberías ver que el puerto 2222 está en estado LISTEN.
### 3. Acceder desde el Navegador
Abre tu navegador y visita:
- Directo al servidor: `http://tu-servidor:2222`
- A través del proxy: `https://console.tu-dominio.com`
Deberías ver la interfaz de login del Web Console.
### 4. Probar Conexión SSH
Ingresa:
- Host: IP o hostname del servidor al que quieres conectarte
- Puerto: 22 (por defecto)
- Usuario: Tu usuario SSH
- Contraseña: Tu contraseña SSH
## Integración con Cluster Panel
Para que el Web Console funcione integrado con Cluster Panel:
1. **Configurar la URL en Cluster Panel:**
En la configuración de Cluster Panel, asegúrate de que `urlWebConsole` esté configurada con la URL del Web Console:
- Si usas proxy reverso: `https://console.tu-dominio.com`
- Si accedes directamente: `http://tu-servidor:2222`
2. **Variable de Entorno REACT_APP_CLUSTER_URL:**
Al compilar el frontend, la variable `REACT_APP_CLUSTER_URL` debe apuntar a la URL de tu Cluster Panel:
```env
REACT_APP_CLUSTER_URL=https://tu-cluster-panel.com
```
**Importante:** Después de cambiar esta variable, debes recompilar el frontend:
```bash
cd web
yarn build
cd ..
statik --src=web/build
go build -o ssh-web-console-linux-amd64
sudo systemctl restart web-console
```
3. **Probar la Integración:**
Desde Cluster Panel, al acceder a la opción de Web Console, debería cargarse el Web Console en un iframe con las credenciales ya configuradas.
## Mantenimiento
### Reiniciar el Servicio
```bash
sudo systemctl restart web-console
```
### Detener el Servicio
```bash
sudo systemctl stop web-console
```
### Iniciar el Servicio
```bash
sudo systemctl start web-console
```
### Ver Logs en Tiempo Real
```bash
sudo journalctl -u web-console -f
```
### Actualizar el Binario
```bash
# Compilar nueva versión (ver sección de Compilación)
# Detener el servicio
sudo systemctl stop web-console
# Hacer backup del binario actual
sudo cp /opt/web-console/ssh-web-console /opt/web-console/ssh-web-console.backup
# Copiar nuevo binario
sudo cp ssh-web-console-linux-amd64 /opt/web-console/ssh-web-console
sudo chmod +x /opt/web-console/ssh-web-console
# Iniciar el servicio
sudo systemctl start web-console
# Verificar
sudo systemctl status web-console
```
## Solución de Problemas Comunes
### El servicio no inicia
**Verificar logs:**
```bash
sudo journalctl -u web-console -n 100 --no-pager
```
**Problemas comunes:**
- Archivo de configuración no encontrado: Verifica la ruta en el servicio systemd
- Permisos: Asegúrate de que el usuario `webconsole` tenga permisos sobre los archivos
- Puerto en uso: Verifica si otro proceso está usando el puerto 2222
### Error: "statik: command not found"
**Solución:**
1. Asegúrate de que Go está instalado: `go version`
2. Instala Statik: `go install github.com/rakyll/statik@latest`
3. Verifica que `$HOME/go/bin` está en tu PATH
### Error al compilar el frontend
**Solución:**
1. Verifica que Node.js y Yarn están instalados: `node --version && yarn --version`
2. Elimina `node_modules` y reinstala: `rm -rf node_modules && yarn install`
3. Verifica que las variables de entorno en `.env` están configuradas correctamente
### El Web Console no se conecta con Cluster Panel
**Solución:**
1. Verifica que `REACT_APP_CLUSTER_URL` está configurada correctamente en `web/.env`
2. Recompila el frontend después de cambiar variables de entorno
3. Verifica que la URL de Cluster Panel en `urlWebConsole` coincide exactamente
4. Verifica problemas de CORS en los logs del navegador
5. Asegúrate de que ambos servicios están ejecutándose
### Problemas de CORS o postMessage
**Solución:**
1. Asegúrate de que `REACT_APP_CLUSTER_URL` apunta exactamente a la URL de Cluster Panel (mismo protocolo, dominio y puerto)
2. Si usas HTTPS, ambos servicios deben usar HTTPS
3. Verifica que el proxy reverso (si usas uno) no esté bloqueando los headers necesarios
4. Revisa la consola del navegador para ver errores específicos
### El servicio se reinicia constantemente
**Verificar logs:**
```bash
sudo journalctl -u web-console --since "10 minutes ago" --no-pager
```
**Posibles causas:**
- Error en el archivo de configuración
- Problemas de permisos
- El puerto está en uso por otro proceso
- Errores en el binario
### Problemas de rendimiento
**Optimizaciones:**
1. Ajusta `buffer_checker_cycle_time` en `config.yaml` según tus necesidades
2. Considera usar un proxy reverso con balanceo de carga si tienes muchos usuarios
3. Monitorea los recursos del sistema: `htop` o `top`
## Seguridad en Producción
### 1. Cambiar el JWT Secret
**Importante:** Cambia el `jwt_secret` en `conf/config.yaml` por un valor único y seguro:
```bash
# Generar un secreto seguro
openssl rand -base64 32
```
Actualiza el archivo `conf/config.yaml` con el nuevo secreto.
### 2. Configurar SSL/TLS
Usa un proxy reverso (Nginx/Apache) con certificados SSL válidos (Let's Encrypt) para encriptar las conexiones.
### 3. Restringir Acceso por IP (Opcional)
Si es necesario, puedes usar firewall o el proxy reverso para restringir acceso por IP:
```bash
# Ejemplo con ufw
sudo ufw allow from IP_DESDE_LA_CUAL_PERMITIR to any port 2222
```
### 4. Actualizaciones Regulares
Mantén el sistema actualizado:
```bash
sudo apt update && sudo apt upgrade -y
```
## Usando Docker (Opcional)
Si prefieres usar Docker para despliegue:
### 1. Construir la Imagen
```bash
docker build --build-arg GOMODULE=on -t web-console:latest .
```
### 2. Ejecutar el Contenedor
```bash
docker run -d \
--name web-console \
-p 2222:2222 \
-v $(pwd)/conf:/home/web/conf \
--restart unless-stopped \
web-console:latest
```
**Nota:** Asegúrate de que el archivo `conf/config.yaml` existe en el directorio montado.
### 3. Verificar
```bash
docker logs web-console
docker ps | grep web-console
```
## Referencias Adicionales
- **Repositorio del Proyecto**: [ssh-web-console](https://github.com/genshen/ssh-web-console)
- **Documentación de Go**: [golang.org/doc](https://golang.org/doc/)
- **Documentación de React**: [react.dev](https://react.dev/)
- **Documentación de systemd**: [systemd.io](https://systemd.io/)
- **Documentación de Nginx**: [nginx.org](https://nginx.org/en/docs/)
## Comandos Rápidos de Referencia
```bash
# Compilar frontend
cd web && yarn build && cd ..
# Generar statik
statik --src=web/build
# Compilar servidor
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ssh-web-console-linux-amd64
# Reiniciar servicio
sudo systemctl restart web-console
# Ver logs
sudo journalctl -u web-console -f
# Ver estado
sudo systemctl status web-console
```
## Notas Finales
- En producción, siempre usa HTTPS para las conexiones
- Mantén el sistema y las dependencias actualizadas
- Realiza backups regulares de la configuración
- Monitorea los logs regularmente para detectar problemas
- Considera usar un sistema de monitoreo (Prometheus, Grafana, etc.) para producción
- El Web Console usa JWT para autenticación de sesiones SSH
- Las credenciales SSH no se almacenan en el servidor, se envían directamente a través de WebSocket
# Web Console - Guía de Instalación para Windows (Entorno Local)
Esta guía te ayudará a configurar y ejecutar el Web Console en un entorno local de Windows.
## Introducción
El Web Console es una aplicación web desarrollada en Go con frontend React que permite conectarse a servidores Linux mediante SSH directamente desde el navegador. Esta aplicación se integra con Cluster Panel para proporcionar una interfaz web para la gestión remota de servidores.
## Requisitos Previos
Antes de comenzar, asegúrate de tener instalado lo siguiente:
- **Go 1.13 o superior**: [Descargar Go](https://golang.org/dl/)
- Verificar instalación: `go version`
- **Node.js 18**: [Descargar Node.js](https://nodejs.org/)
- Verificar instalación: `node --version`
- **Yarn**: Se instala automáticamente con Node.js o puedes instalarlo con:
```bash
npm install -g yarn
```
- Verificar instalación: `yarn --version`
- **Statik**: Herramienta para embeber archivos estáticos en el binario Go
- Instalación: `go install github.com/rakyll/statik@latest`
- Nota: Asegúrate de que `%USERPROFILE%\go\bin` esté en tu PATH
## Instalación de Dependencias
### 1. Clonar o Navegar al Directorio del Proyecto
Si aún no tienes el código fuente, clónalo desde el repositorio o navega al directorio donde está ubicado:
```bash
cd C:\wamp64\www\web-console
```
### 2. Instalar Dependencias de Go
Las dependencias de Go se descargan automáticamente al compilar. Puedes verificar que están disponibles ejecutando:
```bash
go mod download
go mod verify
```
### 3. Instalar Dependencias del Frontend React
Navega al directorio `web` e instala las dependencias:
```bash
cd web
yarn install
cd ..
```
## Configuración
### 1. Configurar el Archivo de Configuración
El archivo de configuración principal se encuentra en `conf/config.yaml`. Este archivo controla la configuración del servidor.
Asegúrate de que el archivo `conf/config.yaml` existe y tiene una configuración similar a esta:
```yaml
site:
appname: ssh-web-console
listen_addr: :2222
runmode: prod
deploy_host: localhost
prod:
# http path of static files and views
static_prefix: /
dev: # config used in debug mode.
# https prefix of static files only
static_prefix: /static/
# redirect static files requests to this address
static_redirect: "localhost:8080"
static_dir: ./dist/
views_prefix: /
views_dir: views/
ssh:
buffer_checker_cycle_time: 60
jwt:
jwt_secret: secret.local.console
token_lifetime: 7200
issuer: issuer.local.ssh
query_token_key: _t
```
**Importante para desarrollo local:**
- `listen_addr: :2222` - Puerto en el que escuchará el servidor
- `runmode: prod` - Modo de ejecución (prod o dev)
- Ajusta el puerto si el 2222 ya está en uso
### 2. Configurar Variables de Entorno React (Producción)
Si estás compilando para producción, necesitas configurar las variables de entorno React antes de compilar el frontend.
Crea un archivo `.env` en el directorio `web/` con el siguiente contenido:
```env
REACT_APP_CLUSTER_URL=http://localhost:8000
REACT_APP_API_URL=localhost:2222
REACT_APP_ROUTER_BASE=
REACT_APP_API_HTTPS=false
```
**Nota:**
- `REACT_APP_CLUSTER_URL`: URL base de tu instalación de Cluster Panel (sin barra final)
- `REACT_APP_API_URL`: URL del servidor web console (opcional, por defecto usa window.location.host)
- Ajusta estas URLs según tu configuración local
Para desarrollo, estas variables son opcionales, pero se recomienda configurarlas si planeas usar la integración con Cluster Panel.
## Compilación Paso a Paso
### Método 1: Usando el Script build-and-run.bat (Recomendado)
El proyecto incluye un script batch que automatiza todo el proceso:
1. **Editar el Script (si es necesario):**
Abre `build-and-run.bat` y verifica las rutas:
- `ROOT_DIR`: Debe apuntar a tu directorio del proyecto
- `STATIK_PATH`: Debe apuntar a la ubicación de `statik.exe`
Ejemplo de configuración:
```batch
set "ROOT_DIR=C:\wamp64\www\web-console"
set "STATIK_PATH=C:\ProgramasGo\bin\statik.exe"
```
2. **Ejecutar el Script:**
Simplemente ejecuta:
```bash
build-and-run.bat
```
El script:
- Compilará el frontend React
- Ejecutará Statik para embeber los archivos estáticos
- Compilará el servidor Go
- Iniciará el servidor automáticamente
### Método 2: Compilación Manual
Si prefieres hacerlo paso a paso o el script no funciona, sigue estos pasos:
#### Paso 1: Compilar el Frontend React
```bash
cd web
yarn build
cd ..
```
Esto generará los archivos estáticos en `web/build/`.
#### Paso 2: Generar Archivos Statik
Statik embebe los archivos estáticos del frontend en el código Go:
```bash
statik --src=web/build
```
Esto generará archivos en el directorio `statik/`.
#### Paso 3: Compilar el Servidor Go
```bash
go build -o ssh-web-console.exe
```
Esto generará el ejecutable `ssh-web-console.exe` en el directorio actual.
## Ejecución
### Opción 1: Ejecución Directa
Si compilaste manualmente, ejecuta el binario:
```bash
ssh-web-console.exe
```
### Opción 2: Especificar Archivo de Configuración Personalizado
Si quieres usar un archivo de configuración en otra ubicación:
```bash
ssh-web-console.exe -config ruta/a/otro/config.yaml
```
### Opción 3: Ejecutar con build-and-run.bat
El script `build-and-run.bat` compila y ejecuta automáticamente.
## Verificación
1. **Verificar que el Servidor está Ejecutándose:**
El servidor debería mostrar un mensaje como:
```
listening on port :2222
```
2. **Acceder desde el Navegador:**
Abre tu navegador y visita:
```
http://localhost:2222
```
Deberías ver la interfaz de login del Web Console.
3. **Probar Conexión SSH:**
Ingresa:
- Host: IP o hostname del servidor al que quieres conectarte
- Puerto: 22 (por defecto)
- Usuario: Tu usuario SSH
- Contraseña: Tu contraseña SSH
## Integración con Cluster Panel
Para que el Web Console funcione integrado con Cluster Panel:
1. **Configurar la URL en Cluster Panel:**
En la configuración de Cluster Panel, asegúrate de que `urlWebConsole` esté configurada con la URL del Web Console:
```
http://localhost:2222
```
2. **Variable de Entorno REACT_APP_CLUSTER_URL:**
Al compilar el frontend, la variable `REACT_APP_CLUSTER_URL` debe apuntar a la URL de tu Cluster Panel:
```env
REACT_APP_CLUSTER_URL=http://localhost:8000
```
(Ajusta el puerto según tu configuración de Cluster Panel)
3. **Probar la Integración:**
Desde Cluster Panel, al acceder a la opción de Web Console, debería cargarse el Web Console en un iframe con las credenciales ya configuradas.
## Solución de Problemas Comunes
### Error: "statik: command not found"
**Solución:**
1. Instala Statik: `go install github.com/rakyll/statik@latest`
2. Asegúrate de que `%USERPROFILE%\go\bin` esté en tu PATH
3. Reinicia la terminal después de agregar al PATH
### Error: "yarn: command not found"
**Solución:**
1. Instala Node.js desde [nodejs.org](https://nodejs.org/)
2. Instala Yarn globalmente: `npm install -g yarn`
3. Verifica la instalación: `yarn --version`
### Error: "port 2222 already in use"
**Solución:**
1. Cambia el puerto en `conf/config.yaml`:
```yaml
listen_addr: :2223
```
2. O cierra el proceso que está usando el puerto 2222
### Error al compilar el frontend: "openssl-legacy-provider"
**Solución:**
El script de compilación ya incluye la opción `NODE_OPTIONS=--openssl-legacy-provider` en `package.json`. Si aún tienes problemas:
1. Actualiza Node.js a una versión más reciente
2. O ejecuta manualmente: `set NODE_OPTIONS=--openssl-legacy-provider && yarn build`
### El Web Console no se conecta con Cluster Panel
**Solución:**
1. Verifica que `REACT_APP_CLUSTER_URL` esté configurada correctamente en el archivo `.env` del directorio `web/`
2. Recompila el frontend después de cambiar las variables de entorno
3. Verifica que la URL de Cluster Panel en `urlWebConsole` coincida con la URL donde está ejecutándose
### Problemas de CORS o postMessage
**Solución:**
1. Asegúrate de que `REACT_APP_CLUSTER_URL` apunte exactamente a la URL de Cluster Panel (mismo protocolo, dominio y puerto)
2. Verifica que ambos servicios estén ejecutándose
3. Revisa la consola del navegador para ver errores específicos
## Referencias Adicionales
- **Repositorio del Proyecto**: [ssh-web-console](https://github.com/genshen/ssh-web-console)
- **Documentación de Go**: [golang.org/doc](https://golang.org/doc/)
- **Documentación de React**: [react.dev](https://react.dev/)
- **Documentación de Statik**: [github.com/rakyll/statik](https://github.com/rakyll/statik)
## Notas Adicionales
- Para desarrollo, puedes usar `runmode: dev` en `config.yaml` para habilitar características de desarrollo
- El servidor acepta conexiones desde cualquier IP. En producción, considera agregar restricciones de seguridad
- Las credenciales SSH no se almacenan en el servidor, se envían directamente a través de WebSocket
- El Web Console usa JWT para autenticación de sesiones SSH
## Comandos Rápidos de Referencia
```bash
# Compilar frontend
cd web && yarn build && cd ..
# Generar statik
statik --src=web/build
# Compilar servidor
go build -o ssh-web-console.exe
# Ejecutar servidor
ssh-web-console.exe
# Ejecutar todo con el script
build-and-run.bat
```
@echo off
setlocal
set "ROOT_DIR=C:\wamp64\www\web-console"
set "WEB_DIR=%ROOT_DIR%\web"
set "STATIK_PATH=C:\ProgramasGo\bin\statik.exe"
echo ========================================
echo Build y Ejecucion de Web-Console
echo ========================================
echo.
echo [1/4] Compilando frontend React...
pushd "%WEB_DIR%"
if %ERRORLEVEL% NEQ 0 (
echo ERROR: No se pudo cambiar al directorio web
pause
exit /b 1
)
call yarn build
if %ERRORLEVEL% NEQ 0 (
echo.
echo ERROR: Fallo la compilacion del frontend
popd
pause
exit /b 1
)
popd
echo.
echo OK: Frontend compilado exitosamente
echo.
echo [2/4] Ejecutando Statik...
pushd "%ROOT_DIR%"
if %ERRORLEVEL% NEQ 0 (
echo ERROR: No se pudo cambiar al directorio raiz
pause
exit /b 1
)
"%STATIK_PATH%" --src=web/build
if %ERRORLEVEL% NEQ 0 (
echo.
echo ERROR: Fallo la ejecucion de Statik
popd
pause
exit /b 1
)
echo.
echo OK: Statik ejecutado exitosamente
echo.
echo [3/4] Compilando servidor Go...
go build -o ssh-web-console.exe
if %ERRORLEVEL% NEQ 0 (
echo.
echo ERROR: Fallo la compilacion del servidor Go
popd
pause
exit /b 1
)
echo.
echo OK: Servidor Go compilado exitosamente
echo.
echo [4/4] Iniciando servidor web-console...
echo.
ssh-web-console.exe
if %ERRORLEVEL% NEQ 0 (
echo.
echo ERROR: El servidor se cerro con errores
popd
pause
exit /b 1
)
popd
pause
# Script para compilar web-console completamente
# Autor: Generado automaticamente
# Descripcion: Compila el frontend React, ejecuta statik y compila el servidor Go
$ErrorActionPreference = "Stop"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Script de Compilacion de Web-Console " -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# Variables
$ROOT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
$WEB_DIR = Join-Path $ROOT_DIR "web"
$ENV_FILE = Join-Path $WEB_DIR ".env.local"
Write-Host "[1/5] Verificando directorios..." -ForegroundColor Yellow
if (-not (Test-Path $WEB_DIR)) {
Write-Host "ERROR: Directorio web no encontrado: $WEB_DIR" -ForegroundColor Red
exit 1
}
# Verificar o crear .env.local
Write-Host "[2/5] Configurando variables de entorno..." -ForegroundColor Yellow
if (-not (Test-Path $ENV_FILE)) {
Write-Host " Creando archivo .env.local..." -ForegroundColor Gray
$clusterUrl = Read-Host " Ingresa REACT_APP_CLUSTER_URL (ej: localhost o http://localhost:8080) [default: localhost]"
if ([string]::IsNullOrWhiteSpace($clusterUrl)) {
$clusterUrl = "localhost"
}
Set-Content -Path $ENV_FILE -Value "REACT_APP_CLUSTER_URL=$clusterUrl"
Write-Host " OK: Archivo .env.local creado con REACT_APP_CLUSTER_URL=$clusterUrl" -ForegroundColor Green
} else {
Write-Host " OK: Archivo .env.local ya existe" -ForegroundColor Green
$envContent = Get-Content $ENV_FILE -Raw
if ($envContent -match "REACT_APP_CLUSTER_URL") {
Write-Host " OK: REACT_APP_CLUSTER_URL esta configurado" -ForegroundColor Green
Write-Host " Contenido actual:" -ForegroundColor Gray
Get-Content $ENV_FILE | ForEach-Object { Write-Host " $_" -ForegroundColor Gray }
} else {
Write-Host " ADVERTENCIA: REACT_APP_CLUSTER_URL no encontrado en .env.local" -ForegroundColor Yellow
$clusterUrl = Read-Host " Ingresa REACT_APP_CLUSTER_URL (ej: localhost o http://localhost:8080) [default: localhost]"
if ([string]::IsNullOrWhiteSpace($clusterUrl)) {
$clusterUrl = "localhost"
}
Add-Content -Path $ENV_FILE -Value "`nREACT_APP_CLUSTER_URL=$clusterUrl"
Write-Host " OK: REACT_APP_CLUSTER_URL agregado: $clusterUrl" -ForegroundColor Green
}
}
# Verificar Node.js y yarn
Write-Host "[3/5] Verificando dependencias..." -ForegroundColor Yellow
try {
$nodeVersion = node --version 2>&1
Write-Host " OK: Node.js instalado: $nodeVersion" -ForegroundColor Green
} catch {
Write-Host " ERROR: Node.js no encontrado. Por favor instalalo primero." -ForegroundColor Red
exit 1
}
try {
$yarnVersion = yarn --version 2>&1
Write-Host " OK: Yarn instalado: v$yarnVersion" -ForegroundColor Green
} catch {
Write-Host " ERROR: Yarn no encontrado. Instalando yarn..." -ForegroundColor Yellow
npm install -g yarn
if ($LASTEXITCODE -ne 0) {
Write-Host " ERROR: Error al instalar yarn" -ForegroundColor Red
exit 1
}
Write-Host " OK: Yarn instalado" -ForegroundColor Green
}
try {
$goVersion = go version 2>&1
Write-Host " OK: Go instalado: $goVersion" -ForegroundColor Green
} catch {
Write-Host " ERROR: Go no encontrado. Por favor instalalo primero." -ForegroundColor Red
exit 1
}
# Compilar frontend React
Write-Host "[4/5] Compilando frontend React..." -ForegroundColor Yellow
Push-Location $WEB_DIR
try {
Write-Host " Instalando dependencias de Node.js (si es necesario)..." -ForegroundColor Gray
yarn install --silent 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Host " ADVERTENCIA: Algunas advertencias durante yarn install (continuando...)" -ForegroundColor Yellow
}
Write-Host " Compilando con yarn build..." -ForegroundColor Gray
yarn build 2>&1 | ForEach-Object {
if ($_ -match "Compiled|error|Error|Failed|failed") {
$color = if ($_ -match "error|Error|Failed|failed") { "Red" } else { "Gray" }
Write-Host " $_" -ForegroundColor $color
}
}
if ($LASTEXITCODE -eq 0) {
Write-Host " OK: Frontend compilado exitosamente" -ForegroundColor Green
} else {
Write-Host " ERROR: Error al compilar el frontend" -ForegroundColor Red
Pop-Location
exit 1
}
} catch {
Write-Host " ERROR: Error durante la compilacion del frontend: $_" -ForegroundColor Red
Pop-Location
exit 1
}
Pop-Location
# Verificar que web/build existe
$BUILD_DIR = Join-Path $WEB_DIR "build"
if (-not (Test-Path $BUILD_DIR)) {
Write-Host " ERROR: Directorio web/build no encontrado despues de la compilacion" -ForegroundColor Red
exit 1
}
Write-Host " OK: Directorio web/build verificado" -ForegroundColor Green
# Instalar statik si no esta instalado
Write-Host "[5/5] Preparando statik..." -ForegroundColor Yellow
Push-Location $ROOT_DIR
try {
Write-Host " Verificando si statik esta instalado..." -ForegroundColor Gray
$statikInstalled = Get-Command statik -ErrorAction SilentlyContinue
if (-not $statikInstalled) {
Write-Host " Instalando statik..." -ForegroundColor Gray
go get github.com/rakyll/statik 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host " OK: Statik instalado" -ForegroundColor Green
} else {
Write-Host " ADVERTENCIA: No se pudo instalar statik automaticamente" -ForegroundColor Yellow
Write-Host " Intenta manualmente: go get github.com/rakyll/statik" -ForegroundColor Yellow
}
} else {
Write-Host " OK: Statik ya esta instalado" -ForegroundColor Green
}
Write-Host " Ejecutando statik --src=web/build..." -ForegroundColor Gray
statik --src=web/build 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host " OK: Statik ejecutado exitosamente" -ForegroundColor Green
} else {
Write-Host " ERROR: Error al ejecutar statik" -ForegroundColor Red
Write-Host " Verifica que el directorio web/build exista y tenga contenido" -ForegroundColor Yellow
Pop-Location
exit 1
}
Write-Host " Compilando servidor Go..." -ForegroundColor Gray
go build -o ssh-web-console.exe 2>&1 | ForEach-Object {
if ($_ -match "error|Error") {
Write-Host " $_" -ForegroundColor Red
}
}
if ($LASTEXITCODE -eq 0) {
Write-Host " OK: Servidor Go compilado exitosamente" -ForegroundColor Green
$exePath = Join-Path $ROOT_DIR "ssh-web-console.exe"
if (Test-Path $exePath) {
Write-Host " OK: Ejecutable creado: $exePath" -ForegroundColor Green
}
} else {
Write-Host " ERROR: Error al compilar el servidor Go" -ForegroundColor Red
Pop-Location
exit 1
}
} catch {
Write-Host " ERROR: Error durante la compilacion: $_" -ForegroundColor Red
Pop-Location
exit 1
}
Pop-Location
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " OK: Compilacion completada exitosamente " -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Para ejecutar web-console:" -ForegroundColor Yellow
Write-Host " cd C:\wamp64\www\web-console" -ForegroundColor Gray
Write-Host " .\ssh-web-console.exe" -ForegroundColor Gray
Write-Host ""
Write-Host "El servidor escuchara en: http://localhost:2222" -ForegroundColor Gray
Write-Host ""
No preview for this file type
...@@ -398,7 +398,6 @@ const FileTrans = ({ ...@@ -398,7 +398,6 @@ const FileTrans = ({
}, },
onUploadProgress: (percent: number) => { onUploadProgress: (percent: number) => {
setUploadStatus({ isUploading: true, hasError: false, percent: percent }); setUploadStatus({ isUploading: true, hasError: false, percent: percent });
console.log(percent);
}, },
onUploadError: () => { onUploadError: () => {
setUploadStatus({ isUploading: false, hasError: true, percent: 0 }); setUploadStatus({ isUploading: false, hasError: true, percent: 0 });
......
...@@ -10,35 +10,22 @@ import apiRouters from '../config/api_routers'; ...@@ -10,35 +10,22 @@ import apiRouters from '../config/api_routers';
const Signin = (props: RouteComponentProps) => { const Signin = (props: RouteComponentProps) => {
React.useEffect(() => { React.useEffect(() => {
const handleMessage = (event: MessageEvent) => { const handleMessage = (event: MessageEvent) => {
console.log('Signin.tsx - Message received:', event);
console.log('Origin:', event.origin);
console.log('Data:', event.data);
// Validar que el mensaje tenga los datos necesarios
if (!event.data || typeof event.data !== 'object') { if (!event.data || typeof event.data !== 'object') {
console.log('Signin.tsx - Invalid message format');
return; return;
} }
// Validar origen: REACT_APP_CLUSTER_URL debe estar contenido en el origen recibido
const clusterUrl = process.env.REACT_APP_CLUSTER_URL; const clusterUrl = process.env.REACT_APP_CLUSTER_URL;
if (!clusterUrl) { if (!clusterUrl) {
console.log(
'Signin.tsx - REACT_APP_CLUSTER_URL not configured, rejecting message',
);
return; return;
} }
// Normalizar origen: quitar protocolo y puerto para comparación flexible
const normalizeOrigin = (url: string) => { const normalizeOrigin = (url: string) => {
try { try {
// Si ya es una URL completa, extraer el hostname
if (url.includes('://')) { if (url.includes('://')) {
const urlObj = new URL(url); const urlObj = new URL(url);
return urlObj.hostname.toLowerCase(); return urlObj.hostname.toLowerCase();
} }
// Si es solo hostname, devolverlo en lowercase y limpiar
return url return url
.toLowerCase() .toLowerCase()
.replace(/^https?:\/\//, '') .replace(/^https?:\/\//, '')
...@@ -46,7 +33,6 @@ const Signin = (props: RouteComponentProps) => { ...@@ -46,7 +33,6 @@ const Signin = (props: RouteComponentProps) => {
.split('/')[0] .split('/')[0]
.trim(); .trim();
} catch { } catch {
// Si falla el parsing, intentar limpiar manualmente
return url return url
.toLowerCase() .toLowerCase()
.replace(/^https?:\/\//, '') .replace(/^https?:\/\//, '')
...@@ -59,48 +45,17 @@ const Signin = (props: RouteComponentProps) => { ...@@ -59,48 +45,17 @@ const Signin = (props: RouteComponentProps) => {
const originHostname = normalizeOrigin(event.origin); const originHostname = normalizeOrigin(event.origin);
const clusterHostname = normalizeOrigin(clusterUrl); const clusterHostname = normalizeOrigin(clusterUrl);
console.log('Signin.tsx - Origin validation:', {
originalOrigin: event.origin,
normalizedOrigin: originHostname,
originalClusterUrl: clusterUrl,
normalizedClusterUrl: clusterHostname,
});
if (originHostname !== clusterHostname) { if (originHostname !== clusterHostname) {
console.log(
'Signin.tsx - Origin not allowed:',
event.origin,
'(normalized:',
originHostname,
')',
'Expected:',
clusterUrl,
'(normalized:',
clusterHostname,
')',
);
return; return;
} }
console.log(
'Signin.tsx - Origin allowed:',
event.origin,
'Matches:',
clusterUrl,
);
// Verificar que el mensaje tenga los campos necesarios
if (event.data.host && event.data.username && event.data.password) { if (event.data.host && event.data.username && event.data.password) {
console.log('Signin.tsx - Valid message received, processing...');
doSignin(event.data); doSignin(event.data);
} else {
console.log('Signin.tsx - Message missing required fields');
} }
}; };
window.addEventListener('message', handleMessage); window.addEventListener('message', handleMessage);
// Cleanup
return () => { return () => {
window.removeEventListener('message', handleMessage); window.removeEventListener('message', handleMessage);
}; };
...@@ -108,9 +63,6 @@ const Signin = (props: RouteComponentProps) => { ...@@ -108,9 +63,6 @@ const Signin = (props: RouteComponentProps) => {
const { t } = useTranslation(['signin']); const { t } = useTranslation(['signin']);
const doSignin = (data: Record<string, string>) => { const doSignin = (data: Record<string, string>) => {
console.log('Signin.tsx - Received data:', data);
// Normalizar datos recibidos (lowercase, trim)
const normalizedData = { const normalizedData = {
host: String(data.host || '') host: String(data.host || '')
.toLowerCase() .toLowerCase()
...@@ -120,12 +72,6 @@ const Signin = (props: RouteComponentProps) => { ...@@ -120,12 +72,6 @@ const Signin = (props: RouteComponentProps) => {
passwd: String(data.password || '').trim(), passwd: String(data.password || '').trim(),
}; };
console.log('Signin.tsx - Normalized data:', {
...normalizedData,
passwd: '***',
});
// Validar que todos los campos requeridos estén presentes
if ( if (
!normalizedData.host || !normalizedData.host ||
!normalizedData.username || !normalizedData.username ||
...@@ -144,26 +90,21 @@ const Signin = (props: RouteComponentProps) => { ...@@ -144,26 +90,21 @@ const Signin = (props: RouteComponentProps) => {
passwd: normalizedData.passwd, passwd: normalizedData.passwd,
}) })
.then((response) => { .then((response) => {
console.log(response);
try { try {
if (!response.data || response.data.has_error) { if (!response.data || response.data.has_error) {
switch (response.data.message) { switch (response.data.message) {
case 0: case 0:
console.log(t('signin:form_has_error'));
toaster.danger(t('signin:form_has_error')); toaster.danger(t('signin:form_has_error'));
break; break;
case 1: case 1:
console.log(t('signin:form_error_passport'));
toaster.danger(t('signin:form_error_passport')); toaster.danger(t('signin:form_error_passport'));
break; break;
case 2: case 2:
console.log(t('signin:form_error_ssh_login'));
toaster.danger(t('signin:form_error_ssh_login')); toaster.danger(t('signin:form_error_ssh_login'));
break; break;
} }
if (window && window.parent) { if (window && window.parent) {
console.log('Send Message has error');
window.parent.postMessage( window.parent.postMessage(
{ {
message: 'close', message: 'close',
...@@ -176,7 +117,6 @@ const Signin = (props: RouteComponentProps) => { ...@@ -176,7 +117,6 @@ const Signin = (props: RouteComponentProps) => {
if (!response.data.addition) { if (!response.data.addition) {
toaster.danger(t('signin:form_error_remote_server')); toaster.danger(t('signin:form_error_remote_server'));
if (window && window.parent) { if (window && window.parent) {
console.log('Send Message Else');
window.parent.postMessage( window.parent.postMessage(
{ {
message: 'close', message: 'close',
...@@ -199,10 +139,10 @@ const Signin = (props: RouteComponentProps) => { ...@@ -199,10 +139,10 @@ const Signin = (props: RouteComponentProps) => {
} }
} catch (e) { } catch (e) {
const errorMessage = e instanceof Error ? e.message : String(e); const errorMessage = e instanceof Error ? e.message : String(e);
console.log(errorMessage); toaster.danger(
toaster.danger(t('signin:form_error_ssh_login')); t('signin:form_error_ssh_login') + ': ' + errorMessage,
);
if (window && window.parent) { if (window && window.parent) {
console.log('Send Message Error 1');
window.parent.postMessage( window.parent.postMessage(
{ {
message: 'close', message: 'close',
...@@ -215,10 +155,8 @@ const Signin = (props: RouteComponentProps) => { ...@@ -215,10 +155,8 @@ const Signin = (props: RouteComponentProps) => {
}) })
.catch((e: unknown) => { .catch((e: unknown) => {
const errorMessage = e instanceof Error ? e.message : String(e); const errorMessage = e instanceof Error ? e.message : String(e);
console.log(errorMessage);
toaster.danger(t('signin:form_error_ssh_login') + ': ' + errorMessage); toaster.danger(t('signin:form_error_ssh_login') + ': ' + errorMessage);
if (window && window.parent) { if (window && window.parent) {
console.log('Send Message Error 2');
window.parent.postMessage( window.parent.postMessage(
{ {
message: 'close', message: 'close',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment