Proxmox / VPS (Notas Operativas)#
Este documento registra el estado actual del host Proxmox y los cambios que se han hecho para preparar el despliegue de SignalDashPro en contenedores (LXC).
Host Proxmox (PVE)#
- Public IP:
185.209.230.42 - Proxmox UI:
https://185.209.230.42:8006/ - SSH al host Proxmox: puerto
22 - OS host: Debian 13 (trixie)
- Proxmox VE:
proxmox-ve 9.1.0,pve-manager 9.1.5 - Kernel:
6.14.11-4-pve - Time sync:
chrony(NTP activo en el host). Los CTs heredan el reloj del host.
Nota: el acceso SSH por 2201 no es el host, es un DNAT hacia un contenedor (ver sección NAT).
Red / Bridge#
- Bridge principal usado por CTs:
vmbr0 - Subred interna CTs:
192.168.100.0/24 - Gateway:
192.168.100.254
Storage#
local(dir) activo- Templates disponibles localmente:
debian-13-standard_13.1-2_amd64.tar.zstdebian-12-standard_12.12-1_amd64.tar.zstubuntu-24.04-standard_24.04-2_amd64.tar.zst
Firewall / NAT (iptables)#
En el host existe un script de reglas:
- Archivo:
/etc/iptables.rules - Se carga por systemd:
iptables-load.service(enabled)
Reglas relevantes (resumen):
- Políticas por defecto:
INPUT DROPFORWARD DROPOUTPUT ACCEPT- Permisos de administración:
22/tcp(SSH host)8006/tcp(UI Proxmox)- NAT/Masquerade:
POSTROUTING MASQUERADEpara192.168.100.0/24 -> eth0- DNAT de puertos públicos hacia CTs (ejemplos ya existentes):
80/81/443 -> 192.168.100.2(nginx proxy manager, CT 103)8007 -> 192.168.100.3:8006(PMG, CT 104)2201 -> 192.168.100.8:22(CT 102 "web")2202 -> 192.168.100.10:22(CT 110 "signaldashpro")
Observaciones detectadas:
- En
/etc/iptables.ruleshay puertos declarados como UDP para servicios típicamente TCP (por ejemplo5432,587,993) mientras el DNAT está en TCP. Esto conviene revisarlo antes de exponer servicios nuevos.
Proxmox firewall:
pve-firewallestá corriendo, pero el estado reportadisabled/running(daemon activo, políticas Proxmox deshabilitadas). En la práctica, las reglas efectivas son las de/etc/iptables.rules.
Contenedores existentes (antes de cambios)#
CTs detectados:
100(ollama) stopped101(dns) running102(web) running103(nginxproxymanager) running104(pmg) running105(wireguard) running106(correo) running107(postgresql) running
PostgreSQL interno (CT 107)#
- CT:
107(hostname=postgresql) - IP:
192.168.100.7 - Puerto:
5432/tcp(escucha en0.0.0.0:5432)
Uso recomendado:
- Los servicios en la subred
192.168.100.0/24deben usar192.168.100.7:5432directamente (sin el mapping local:5433).
Cambio realizado: CT para SignalDashPro#
Se creó un contenedor LXC para desplegar SignalDashPro:
- CTID:
110 - Hostname:
signaldashpro - Template:
local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst - Recursos:
- CPU:
2 cores - RAM:
2048 MB - Swap:
512 MB - Disco:
20Genlocal - Red:
- Bridge:
vmbr0 - IP:
192.168.100.10/24 - GW:
192.168.100.254 - Features:
nesting=1,keyctl=1(útil si instalamos Docker dentro del CT)- Arranque:
onboot=1- Estado:
running
Acceso SSH externo (public -> CT 110):
185.209.230.42:2202->192.168.100.10:22
Nota: aunque existe el DNAT :2202, en algunos momentos el CT110 puede rechazar autenticación por password (hardening/sshd). El método confiable para operar CT110 es entrar al host Proxmox por :22 y ejecutar pct exec 110 ....
Config file:
/etc/pve/lxc/110.conf
Deploy actual (CT 110)#
En CT 110 ya se instaló Docker y se levantó el stack (sin Postgres local; se usa el Postgres externo del CT 107).
- Código en CT110 (release activo):
/opt/signaldashpro/current currentes un symlink:/opt/signaldashpro/current -> /opt/signaldashpro/releases/<timestamp>-<sha>- Env compartido (fuera de git, persistente):
/opt/signaldashpro/env/.env.binance.demo.month - En cada release hay un link:
/opt/signaldashpro/current/env/.env.binance.demo.month -> /opt/signaldashpro/env/.env.binance.demo.month - Storage compartido (persistente):
/opt/signaldashpro/storage - En cada release hay un link:
/opt/signaldashpro/current/storage -> /opt/signaldashpro/storage - Compose usado en CT110:
/opt/signaldashpro/current/deploy/docker-compose.ct110.yml - En este repo vive la misma definición en
deploy/docker-compose.ct110.yml - Puertos expuestos en CT110:
- Backend:
8096 - Frontend:
3000 - Docs:
8001(redirige/ -> /docs/)
Automatizacion (systemd timers)#
Para operar 30 dias con evidencia y backups, se agregaron systemd timers.
En CT110:
- signaldashpro-daily.timer: smoke + evidencia (escribe logs en storage/logs/ops/ y JSON en storage/logs/evidence/).
- signaldashpro-alerts.timer: notificaciones Slack/Teams (solo corre si hay SLACK_WEBHOOK_URL o TEAMS_WEBHOOK_URL en el env del backend).
- signaldashpro-storage-backup.timer: backup diario de storage/ a /opt/backups/signaldashpro/ con retencion de 14.
En CT107 (Postgres):
- signaldashpro-db-backup.timer: pg_dump diario a /var/backups/signaldashpro/ con retencion de 14.
Notas de tiempo:
- En CT110 y CT107 se configuró Time zone: UTC para que logs/timers sean consistentes.
- systemd-timesyncd se salta en contenedores por ConditionVirtualization=!container; la sincronizacion NTP ocurre en el host (chrony).
Comandos:
systemctl list-timers --all | grep signaldashpro
systemctl status signaldashpro-daily.service signaldashpro-alerts.service signaldashpro-storage-backup.service
Notas importantes de docker compose:
docker-composecarga variables desde un.enven el mismo directorio del compose.- En CT110 se resolvió enlazando
deploy/.envhacia../.env:
# Opcion A (recomendada): no dependas del symlink, usa env-file explicito
cd /opt/signaldashpro/current/deploy
docker compose --env-file ../.env -f docker-compose.ct110.yml up -d --build
# Opcion B: mantener `deploy/.env -> ../.env` (si prefieres el comportamiento "por default")
cd /opt/signaldashpro/current
ln -sf ../.env deploy/.env
cd /opt/signaldashpro/current/deploy
docker compose -f docker-compose.ct110.yml up -d --build
Deploy (release inmutable) via pct + tarball#
Si el repo en GitHub es privado, curl https://github.com/.../archive/<sha>.tar.gz desde CT110 puede devolver 404 sin token. El flujo estable es:
git archiveen tu PC (donde ya tienes el repo)scpal host Proxmoxpct pushal CT110- extraer al nuevo release y mover el symlink
current
El procedimiento completo está descrito en HANDOFF.md (sección "Deploy rapido en CT110").
Acceso / Operación básica#
Entrar al CT desde el host:
pct enter 110
Ver estado/listado:
pct status 110
pct list
PostgreSQL / permisos (CT 107)#
El backend hace pequeñas migraciones al iniciar (por ejemplo ALTER TABLE ... para asegurar volúmenes como BIGINT).
Si las tablas fueron creadas por postgres (superuser), el rol de la app puede tener GRANT pero no puede hacer ALTER TABLE sin ser el owner.
Se aplicó el fix: cambiar ownership de todas las tablas/secuencias del schema public al rol signaldashpro.
Referencia de ejecución (desde el host, dentro del CT107):
pct exec 107 -- bash -lc "runuser -u postgres -- psql -P pager=off -d signaldashpro -v ON_ERROR_STOP=1 <<'SQL'
ALTER SCHEMA public OWNER TO signaldashpro;
SELECT format('ALTER TABLE public.%I OWNER TO signaldashpro;', tablename)
FROM pg_tables WHERE schemaname = 'public';
\\gexec
SELECT format('ALTER SEQUENCE public.%I OWNER TO signaldashpro;', sequence_name)
FROM information_schema.sequences WHERE sequence_schema = 'public';
\\gexec
SQL"
Nginx Proxy Manager (CT 103)#
Recomendación: exponer todo por NPM (CT103) y evitar abrir nuevos DNAT.
Proxies típicos:
sdp.perlatec.net->192.168.100.10:3000(frontend)api.sdp.perlatec.net->192.168.100.10:8096(backend)docs.sdp.perlatec.net->192.168.100.10:8001(mkdocs)
Let’s Encrypt en NPM requiere que el DNS apunte correctamente al public IP (185.209.230.42) y que estén abiertos 80/443 hacia NPM (ya están DNAT a 192.168.100.2).
Estado actual (2026-02-09):
https://sdp.perlatec.netresponde200(frontend).https://api.sdp.perlatec.netresponde200(backend).- CORS validado para
Origin: https://sdp.perlatec.neten endpoints privados como/binance/account.
Nota: si Chrome muestra errores viejos (CORS/500) despues de un deploy, suele ser cache; probar hard refresh o incognito.
Próximos pasos (pendientes)#
- Operacion 30 dias (demo):
- Mantener jobs (
market_sync, cola, alertas) estables y con evidencia diaria. - Observabilidad minima:
- Definir retencion/rotacion de logs del host/containers y alertas por caidas.
- Seguridad:
- Evitar exponer puertos nuevos por DNAT; centralizar en NPM.
- Evaluar autenticacion para el API si se mantiene publico.
Seguridad (importante)#
- No guardar credenciales en git.
env/.env.sshestá pensado para uso local y debe permanecer ignorado por git.