feat(manager): add remote VM support via NEXUS_SERVER_HOST
- config.py: add NEXUS_SERVER_HOST env var for cross-VM deployment - health_service.py: graceful Redis failure when only localhost-bound - systemd service: document remote VM configuration - README: add dedicated 'VM separada' installation section - .env.example: new file with remote connection examples
This commit is contained in:
25
manager/.env.example
Normal file
25
manager/.env.example
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Nexus Instance Manager — Environment Variables
|
||||||
|
# Copy to .env and fill in your values.
|
||||||
|
|
||||||
|
# ─── Database (REQUIRED) ───────────────────────────────────────────────────
|
||||||
|
# If manager runs on a separate VM, use the IP of the PostgreSQL server.
|
||||||
|
MASTER_DB_URL=postgresql://nexus:PASSWORD@192.168.10.91/nexus_autopartes
|
||||||
|
TENANT_DB_URL_TEMPLATE=postgresql://nexus:PASSWORD@192.168.10.91/{db_name}
|
||||||
|
|
||||||
|
# ─── Remote Nexus Server IP (for VM-separated deployment) ──────────────────
|
||||||
|
# IP or hostname of the server running POS, Dashboard, Quart, Redis.
|
||||||
|
NEXUS_SERVER_HOST=192.168.10.91
|
||||||
|
|
||||||
|
# ─── Security (REQUIRED) ───────────────────────────────────────────────────
|
||||||
|
MANAGER_JWT_SECRET=change-me-to-a-random-64-char-hex-string
|
||||||
|
|
||||||
|
# ─── Demo Defaults ─────────────────────────────────────────────────────────
|
||||||
|
DEMO_DEFAULT_DAYS=14
|
||||||
|
DEMO_DEFAULT_PIN=0000
|
||||||
|
|
||||||
|
# ─── Redis (OPTIONAL — health check only) ──────────────────────────────────
|
||||||
|
# Redis may only listen on localhost. If so, health check will show warning.
|
||||||
|
REDIS_URL=redis://192.168.10.91:6379/0
|
||||||
|
|
||||||
|
# ─── Internal ──────────────────────────────────────────────────────────────
|
||||||
|
POS_DIR=/home/Autopartes/pos
|
||||||
@@ -35,11 +35,12 @@ manager/
|
|||||||
│ └── index.html # Single Page App
|
│ └── index.html # Single Page App
|
||||||
├── scripts/
|
├── scripts/
|
||||||
│ └── init_manager.py # Inicialización de DB + admin
|
│ └── init_manager.py # Inicialización de DB + admin
|
||||||
└── systemd/
|
├── systemd/
|
||||||
└── nexus-manager.service
|
│ └── nexus-manager.service # Servicio systemd
|
||||||
|
└── README.md # Documentación completa
|
||||||
```
|
```
|
||||||
|
|
||||||
## Instalación rápida
|
## Instalación rápida (mismo servidor)
|
||||||
|
|
||||||
### 1. Dependencias
|
### 1. Dependencias
|
||||||
|
|
||||||
@@ -65,8 +66,8 @@ Esto crea:
|
|||||||
Asegúrate de que estas variables estén disponibles (en systemd o `.env`):
|
Asegúrate de que estas variables estén disponibles (en systemd o `.env`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
MASTER_DB_URL=postgresql://postgres@/nexus_autoparts
|
MASTER_DB_URL=postgresql://postgres@localhost/nexus_autoparts
|
||||||
TENANT_DB_URL_TEMPLATE=postgresql://postgres@/{db_name}
|
TENANT_DB_URL_TEMPLATE=postgresql://postgres@localhost/{db_name}
|
||||||
MANAGER_JWT_SECRET=genera-un-segredo-largo-aqui
|
MANAGER_JWT_SECRET=genera-un-segredo-largo-aqui
|
||||||
POS_DIR=/home/Autopartes/pos
|
POS_DIR=/home/Autopartes/pos
|
||||||
REDIS_URL=redis://localhost:6379/0
|
REDIS_URL=redis://localhost:6379/0
|
||||||
@@ -100,6 +101,76 @@ server {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Instalación en Máquina Virtual separada (misma red local)
|
||||||
|
|
||||||
|
Si el manager corre en una VM diferente al servidor principal (donde está PostgreSQL + POS):
|
||||||
|
|
||||||
|
### Requisitos de red
|
||||||
|
- PostgreSQL del servidor principal debe escuchar en `0.0.0.0:5432` (verificar `listen_addresses = '*'` en `postgresql.conf`)
|
||||||
|
- POS (5001), Dashboard (5000) y Quart (5002) ya escuchan en `0.0.0.0` por defecto
|
||||||
|
- Redis puede estar solo en `127.0.0.1`; en ese caso el health check mostrará advertencia pero no afecta el funcionamiento
|
||||||
|
|
||||||
|
### 1. Clonar el repo en la VM
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.consultoria-as.com/consultoria-as/Autoparts-DB.git /home/Autopartes
|
||||||
|
cd /home/Autopartes/manager
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Instalar dependencias
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Configurar variables para conexión remota
|
||||||
|
|
||||||
|
Crea `/home/Autopartes/manager/.env` o edita el servicio systemd:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# IP del servidor principal donde corre PostgreSQL y POS
|
||||||
|
NEXUS_SERVER_HOST=192.168.10.91
|
||||||
|
|
||||||
|
# PostgreSQL remoto (cambiar localhost por la IP del servidor)
|
||||||
|
MASTER_DB_URL=postgresql://nexus:PASSWORD@192.168.10.91/nexus_autoparts
|
||||||
|
TENANT_DB_URL_TEMPLATE=postgresql://nexus:PASSWORD@192.168.10.91/{db_name}
|
||||||
|
|
||||||
|
# Redis remoto (puede no funcionar si Redis solo escucha en localhost)
|
||||||
|
REDIS_URL=redis://192.168.10.91:6379/0
|
||||||
|
|
||||||
|
# Seguridad
|
||||||
|
MANAGER_JWT_SECRET=genera-un-segredo-largo-aqui
|
||||||
|
POS_DIR=/home/Autopartes/pos
|
||||||
|
```
|
||||||
|
|
||||||
|
**Nota importante:** La VM manager no necesita una instalación completa del POS. Solo necesita:
|
||||||
|
- Los archivos de `manager/`
|
||||||
|
- Los archivos de `pos/` (para reutilizar `tenant_manager.py` y migraciones)
|
||||||
|
- Conectividad TCP al puerto 5432 del servidor principal
|
||||||
|
|
||||||
|
### 4. Inicializar DB y admin
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/Autopartes/manager
|
||||||
|
python scripts/init_manager.py --email admin@nexus.local --password TU_PASSWORD
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Systemd
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp systemd/nexus-manager.service /etc/systemd/system/
|
||||||
|
# Edita el archivo y cambia localhost por la IP del servidor en MASTER_DB_URL y NEXUS_SERVER_HOST
|
||||||
|
nano /etc/systemd/system/nexus-manager.service
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable nexus-manager
|
||||||
|
systemctl start nexus-manager
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Uso
|
## Uso
|
||||||
|
|
||||||
### Crear una demo
|
### Crear una demo
|
||||||
@@ -122,8 +193,11 @@ server {
|
|||||||
- Ve a **Migraciones** para ver la versión de schema de cada tenant
|
- Ve a **Migraciones** para ver la versión de schema de cada tenant
|
||||||
- **Ejecutar todas pendientes** aplica migraciones en TODOS los tenants
|
- **Ejecutar todas pendientes** aplica migraciones en TODOS los tenants
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Notas de seguridad
|
## Notas de seguridad
|
||||||
|
|
||||||
- Cambia `MANAGER_JWT_SECRET` en producción
|
- Cambia `MANAGER_JWT_SECRET` en producción
|
||||||
- El panel expone acciones destructivas (delete/reset); protege el acceso con firewall o VPN
|
- El panel expone acciones destructivas (delete/reset); protege el acceso con firewall o VPN
|
||||||
- Usa HTTPS en producción
|
- Usa HTTPS en producción
|
||||||
|
- Si despliegas en VM separada, asegúrate de que el firewall del servidor principal permite conexiones desde la IP de la VM manager al puerto 5432 (PostgreSQL)
|
||||||
|
|||||||
@@ -34,11 +34,15 @@ DEMO_DEFAULT_DAYS = int(os.environ.get("DEMO_DEFAULT_DAYS", "14"))
|
|||||||
DEMO_DEFAULT_PIN = os.environ.get("DEMO_DEFAULT_PIN", "0000")
|
DEMO_DEFAULT_PIN = os.environ.get("DEMO_DEFAULT_PIN", "0000")
|
||||||
DEMO_SUBDOMAIN_PREFIX = os.environ.get("DEMO_SUBDOMAIN_PREFIX", "demo")
|
DEMO_SUBDOMAIN_PREFIX = os.environ.get("DEMO_SUBDOMAIN_PREFIX", "demo")
|
||||||
|
|
||||||
|
# ─── Remote Nexus Server (for VM-separated manager) ────────────────────────
|
||||||
|
# Set this to the IP/hostname of the server running POS/PostgreSQL/Redis
|
||||||
|
NEXUS_SERVER_HOST = os.environ.get("NEXUS_SERVER_HOST", "127.0.0.1")
|
||||||
|
|
||||||
# ─── Services Health Check ─────────────────────────────────────────────────
|
# ─── Services Health Check ─────────────────────────────────────────────────
|
||||||
POS_URL = os.environ.get("POS_URL", "http://127.0.0.1:5001/pos/health")
|
POS_URL = os.environ.get("POS_URL", f"http://{NEXUS_SERVER_HOST}:5001/pos/health")
|
||||||
DASHBOARD_URL = os.environ.get("DASHBOARD_URL", "http://127.0.0.1:5000/")
|
DASHBOARD_URL = os.environ.get("DASHBOARD_URL", f"http://{NEXUS_SERVER_HOST}:5000/")
|
||||||
QUART_URL = os.environ.get("QUART_URL", "http://127.0.0.1:5002/")
|
QUART_URL = os.environ.get("QUART_URL", f"http://{NEXUS_SERVER_HOST}:5002/")
|
||||||
REDIS_URL = os.environ.get("REDIS_URL", "redis://localhost:6379/0")
|
REDIS_URL = os.environ.get("REDIS_URL", f"redis://{NEXUS_SERVER_HOST}:6379/0")
|
||||||
|
|
||||||
# ─── Paths ─────────────────────────────────────────────────────────────────
|
# ─── Paths ─────────────────────────────────────────────────────────────────
|
||||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import psycopg2
|
|||||||
import redis
|
import redis
|
||||||
from config import (
|
from config import (
|
||||||
MASTER_DB_URL, REDIS_URL, POS_URL, DASHBOARD_URL, QUART_URL,
|
MASTER_DB_URL, REDIS_URL, POS_URL, DASHBOARD_URL, QUART_URL,
|
||||||
TENANT_DB_URL_TEMPLATE
|
TENANT_DB_URL_TEMPLATE, NEXUS_SERVER_HOST
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ def check_postgresql():
|
|||||||
|
|
||||||
|
|
||||||
def check_redis():
|
def check_redis():
|
||||||
"""Check Redis connectivity."""
|
"""Check Redis connectivity. May be unreachable if Redis only binds to localhost."""
|
||||||
try:
|
try:
|
||||||
r = redis.from_url(REDIS_URL, socket_connect_timeout=3)
|
r = redis.from_url(REDIS_URL, socket_connect_timeout=3)
|
||||||
info = r.info()
|
info = r.info()
|
||||||
@@ -41,6 +41,11 @@ def check_redis():
|
|||||||
"used_memory_human": info.get("used_memory_human", "?"),
|
"used_memory_human": info.get("used_memory_human", "?"),
|
||||||
"connected_clients": info.get("connected_clients", 0)
|
"connected_clients": info.get("connected_clients", 0)
|
||||||
}
|
}
|
||||||
|
except redis.ConnectionError:
|
||||||
|
return {
|
||||||
|
"status": "warning",
|
||||||
|
"error": "Redis unreachable. If manager runs on a separate VM, ensure Redis binds to 0.0.0.0 or a VPN interface, or that a tunnel is active."
|
||||||
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {"status": "error", "error": str(e)}
|
return {"status": "error", "error": str(e)}
|
||||||
|
|
||||||
@@ -121,6 +126,10 @@ def check_systemd_service(service_name):
|
|||||||
def get_full_health_report():
|
def get_full_health_report():
|
||||||
"""Aggregate health report for all services."""
|
"""Aggregate health report for all services."""
|
||||||
return {
|
return {
|
||||||
|
"_meta": {
|
||||||
|
"nexus_server_host": NEXUS_SERVER_HOST,
|
||||||
|
"note": "disk/memory are local to this manager VM. PostgreSQL/HTTP checks target the remote Nexus server."
|
||||||
|
},
|
||||||
"postgresql": check_postgresql(),
|
"postgresql": check_postgresql(),
|
||||||
"redis": check_redis(),
|
"redis": check_redis(),
|
||||||
"pos": check_http_service("pos", POS_URL),
|
"pos": check_http_service("pos", POS_URL),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Nexus Instance Manager (Control Central)
|
Description=Nexus Instance Manager (Control Central)
|
||||||
After=network.target postgresql.service
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
@@ -9,13 +9,28 @@ WorkingDirectory=/home/Autopartes/manager
|
|||||||
ExecStart=/usr/local/bin/gunicorn -w 2 --threads 4 -b 0.0.0.0:5003 "app:create_app()"
|
ExecStart=/usr/local/bin/gunicorn -w 2 --threads 4 -b 0.0.0.0:5003 "app:create_app()"
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|
||||||
|
# ─── Local Paths ───────────────────────────────────────────────────────────
|
||||||
Environment=PYTHONUNBUFFERED=1
|
Environment=PYTHONUNBUFFERED=1
|
||||||
Environment=PYTHONPATH=/home/Autopartes/manager:/home/Autopartes/pos
|
Environment=PYTHONPATH=/home/Autopartes/manager:/home/Autopartes/pos
|
||||||
|
Environment=POS_DIR=/home/Autopartes/pos
|
||||||
|
|
||||||
|
# ─── Database (UPDATE FOR REMOTE VM) ───────────────────────────────────────
|
||||||
|
# If manager runs on a separate VM, change localhost to the IP of the
|
||||||
|
# PostgreSQL server (e.g. 192.168.10.91).
|
||||||
Environment=MASTER_DB_URL=postgresql://postgres@localhost/nexus_autoparts
|
Environment=MASTER_DB_URL=postgresql://postgres@localhost/nexus_autoparts
|
||||||
Environment=TENANT_DB_URL_TEMPLATE=postgresql://postgres@localhost/{db_name}
|
Environment=TENANT_DB_URL_TEMPLATE=postgresql://postgres@localhost/{db_name}
|
||||||
|
|
||||||
|
# ─── Remote Nexus Server IP ────────────────────────────────────────────────
|
||||||
|
# Set to the IP/hostname of the server running POS/Dashboard/Quart/Redis.
|
||||||
|
# Leave as 127.0.0.1 if manager runs on the same server.
|
||||||
|
Environment=NEXUS_SERVER_HOST=127.0.0.1
|
||||||
|
|
||||||
|
# ─── Security (CHANGE THIS) ────────────────────────────────────────────────
|
||||||
Environment=MANAGER_JWT_SECRET=change-me-to-a-random-64-char-hex-string
|
Environment=MANAGER_JWT_SECRET=change-me-to-a-random-64-char-hex-string
|
||||||
Environment=POS_DIR=/home/Autopartes/pos
|
|
||||||
Environment=REDIS_URL=redis://localhost:6379/0
|
# ─── Redis (optional, health check only) ───────────────────────────────────
|
||||||
|
Environment=REDIS_URL=redis://127.0.0.1:6379/0
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
Reference in New Issue
Block a user