Installation
Instalar con Portainer, QNAP o NAS
Despliega QuoteNode en un NAS o en un host Docker gestionado por Portainer con instrucciones de configuración completas.
Instalar con Portainer, QNAP o NAS
Usa esta ruta si ejecutas Docker a través de Portainer, QNAP Container Station, Synology o una plataforma similar. La interfaz exacta difiere según el fabricante, pero el stack Docker Compose subyacente es el mismo.
Cuándo usarlo
- Ya operas stacks Docker a través de una interfaz de gestión de contenedores.
- Entiendes cómo la plataforma mapea volúmenes y puertos.
- Puedes verificar backups fuera de la interfaz del NAS.
Qué puede no funcionar
- Los enlaces públicos no funcionan fuera de la LAN a menos que NAT, DNS, proxy y HTTPS estén configurados.
- Los modos de suspensión del NAS pueden interrumpir el servicio.
- Algunas UIs Docker de NAS reescriben archivos compose o variables de entorno; verifica el stack renderizado antes de confiar en él.
- Los backups almacenados solo en el mismo NAS no protegen contra un fallo del NAS.
Requisitos previos
- Soporte de Docker Compose v2 en tu plataforma.
- Soporte de volúmenes persistentes para datos PostgreSQL, subidas, PDFs y backups.
- Al menos 2 GB de RAM disponibles y 10 GB de espacio libre en disco.
- Una URL estable: IP de red local para uso interno, o dominio público detrás de un proxy inverso para enlaces de clientes.
Paso 1 — Crear el archivo de configuración
Crea un archivo .env (o define variables a través de la interfaz de entorno de tu plataforma). Reemplaza la URL con tu dirección NAS real o dominio público:
Para un despliegue solo NAS interno:
# Database
DB_URL=jdbc:postgresql://postgres:5432/quotenode
DB_USERNAME=quotenode
DB_PASSWORD=change-me-to-something-random-32-chars
DB_NAME=quotenode
# ============================================================
# SECURITY SECRETS — UNIQUE to this installation.
# SAVE THIS FILE and keep a secure backup.
# ============================================================
DB_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
TIMING_TOKEN_SECRET=change-me-timing-secret-min-32-chars
PUBLIC_LINK_PASSWORD_SESSION_SECRET=change-me-session-secret-min-32
# Internal NAS URL
CORS_ALLOWED_ORIGINS=http://nas.local
DOMAIN=nas.local
# La IP del cliente se detecta automáticamente tras proxies internos y CDNs (incluido Cloudflare) — déjalo vacío.
# Defínelo solo para un proxy inusual cuyo par de transporte sea una dirección PÚBLICA a confiar (IP/CIDR o nombre de host).
SECURITY_TRUSTED_PROXIES=
# Application
LOG_LEVEL=INFO
SPRING_PROFILES_ACTIVE=prod
Para un dominio público detrás de un proxy inverso:
CORS_ALLOWED_ORIGINS=https://crm.example.com
DOMAIN=crm.example.com
Guarda tu
.envinmediatamente. Si pierdesDB_ENCRYPTION_KEY, los campos cifrados quedan permanentemente ilegibles.
Paso 2 — Crear el stack Docker Compose
Usa el editor de stacks en Portainer o en la interfaz Docker de tu NAS, o crea un archivo docker-compose.yml:
services:
postgres:
image: postgres:18-alpine
cpus: 4.0
mem_limit: 512m
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
PGDATA: /var/lib/postgresql/data # required for the postgres:18 image
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME}"]
interval: 10s
timeout: 5s
retries: 10
restart: unless-stopped
gotenberg:
image: gotenberg/gotenberg:8
cpus: 2.0
mem_limit: 448m
environment:
LOG_LEVEL: info
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:3000/health"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
backend:
image: ghcr.io/lesisty7/quotenode/quotenode-api:latest
cpus: 4.0
mem_limit: 1792m
depends_on:
postgres: { condition: service_healthy }
gotenberg: { condition: service_healthy }
env_file: .env
environment:
SPRING_PROFILES_ACTIVE: prod
JOBS_MODE: web
PDF_ENABLED: "true"
PDF_GOTENBERG_URL: http://gotenberg:3000
volumes:
- backend_uploads:/app/data/uploads
- backend_pdfs:/app/data/pdfs
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
interval: 15s
timeout: 10s
retries: 5
start_period: 45s
restart: unless-stopped
frontend:
image: ghcr.io/lesisty7/quotenode/quotenode-frontend:latest
cpus: 2.0
mem_limit: 192m
depends_on:
backend: { condition: service_healthy }
ports:
- "80:80"
- "443:443"
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:80/"]
interval: 15s
timeout: 5s
retries: 3
restart: unless-stopped
volumes:
postgres_data:
backend_uploads:
backend_pdfs:
Conflictos de puertos: Si tu NAS ya usa el puerto 80 o 443, cambia el lado izquierdo del mapeo
ports(ej."8080:80") y actualizaCORS_ALLOWED_ORIGINSen consecuencia (ej.http://nas.local:8080).
Paso 3 — Desplegar y verificar
Inicia el stack a través de la interfaz de tu plataforma o vía SSH:
docker compose up -d
docker compose logs -f backend
Espera hasta ver Started QuoteNodeApplication.
Paso 4 — Abrir QuoteNode
Navega a tu URL del NAS (ej. http://nas.local o https://crm.example.com).
Credenciales de acceso por defecto:
| Campo | Valor |
|---|---|
[email protected] | |
| Contraseña | Admin123! |
Cambia la contraseña por defecto inmediatamente tras iniciar sesión.
Lista de verificación de persistencia
Verifica que estos elementos estén mapeados a volúmenes persistentes (no a almacenamiento efímero del contenedor):
| Dato | Por qué importa |
|---|---|
| PostgreSQL data | Base de datos principal de la aplicación |
| Uploads | Imágenes de producto, logos, adjuntos |
| Generated PDFs | Archivos de ofertas y documentos |
| Backups | Archivos de backup locales (si el worker de backup está habilitado) |
| GeoIP database | Datos opcionales de control de acceso |
¿Qué está ejecutándose?
| Contenedor | Qué hace | Uso de RAM |
|---|---|---|
postgres | Almacena todos tus datos | ~256 MB |
backend | Servidor API Java, lógica de negocio | ~512 MB – 1,5 GB |
gotenberg | Convierte HTML a PDF (basado en Chromium) | ~200 MB |
frontend | Sirve la interfaz web + reverse proxy | ~20 MB |
Total: aproximadamente 1,5 – 2,5 GB de RAM.
Mantener seguros tus secretos
| Secreto | Qué protege | Si se pierde |
|---|---|---|
DB_PASSWORD | Acceso a la base de datos | Recuperable — reiniciar vía herramientas de administración PostgreSQL |
DB_ENCRYPTION_KEY | Códigos MFA, contraseña SMTP, clave API FX, campos PII | Permanentemente ilegible |
TIMING_TOKEN_SECRET | Tokens anti-timing-attack | Regenerar — los usuarios se re-autentican |
PUBLIC_LINK_PASSWORD_SESSION_SECRET | Sesiones de enlaces públicos | Regenerar — las sesiones activas expiran |
Guarda backups de
.envfuera del NAS. Un fallo del NAS que destruya tu única copia deDB_ENCRYPTION_KEYhace los datos cifrados irrecuperables.
Siguientes pasos recomendados
- Configura backups en una ubicación fuera del NAS.
- Prueba la generación de PDF después del primer despliegue.
- Si quieres una ruta de despliegue público más sencilla, considera Coolify en un VPS.