Instalar Heskala on-premise
Cómo instalar y correr Heskala on-premise: bajá el bundle desde GitHub Releases, ejecutá el instalador y en pocos minutos tenés tu ERP corriendo 100% en tu infraestructura.
Qué es on-prem
Sección titulada «Qué es on-prem»Heskala en modo on-prem corre 100% en tu infraestructura: backend de Convex self-hosted, base SQLite y frontend servido como estático. La activación se hace con una licencia firmada (token ECDSA) que define qué módulos incluidos, cuántos usuarios y cuántas sucursales tenés.
Requisitos
Sección titulada «Requisitos»- Docker 20.10+ (con
docker composev2) - 2 GB de RAM disponibles
- 10 GB de disco para los datos
- Linux, macOS o Windows con WSL2
- Conexión a internet (para bajar el bundle, las imágenes y validar la licencia la primera vez)
No necesitás acceso al código fuente ni a ninguna cuenta de GitHub. El bundle se descarga desde este sitio y las imágenes
ghcr.io/heskala/frontendyghcr.io/heskala/convex-deployerdesde GHCR (ambas públicas).
Instalación express (un solo comando)
Sección titulada «Instalación express (un solo comando)»Si solo querés levantarlo y empezar:
curl -sL https://docs.heskala.com/downloads/heskala-onprem-0.8.0.tar.gz \ | tar -xz -C /tmp heskala-onprem-0.8.0 \ && bash /tmp/heskala-onprem-0.8.0/install.shEl bundle se hostea en este sitio (público) porque el repo de GitHub es privado y sus release assets no son accesibles sin auth. El one-liner funciona para cualquiera, sin cuenta ni token.
El script:
- Verifica que Docker esté corriendo
- Crea
~/heskala-onpremy copia el compose desde el bundle - Genera un
INSTANCE_SECRETrandom - Te pregunta el
INSTANCE_NAME(default:heskala-onprem) - Levanta los 4 servicios y espera al backend
healthy - Genera el admin key y lo guarda en
.admin-key(chmod 600) - Arranca el
deployer, que sube las funciones y setea las env vars necesarias - Imprime las URLs y los próximos pasos
Para personalizar (directorio, RESEND_API_KEY, etc.):
# Directorio custombash /tmp/heskala-onprem-0.8.0/install.sh /opt/heskala
# Con Resend habilitadoRESEND_API_KEY=re_xxx bash /tmp/heskala-onprem-0.8.0/install.sh
# Nombre de instancia customHESKALA_INSTANCE=mi-empresa bash /tmp/heskala-onprem-0.8.0/install.shPara upgrade a una versión más nueva, bajá el nuevo bundle y corré el install apuntando al directorio existente:
curl -sL https://docs.heskala.com/downloads/heskala-onprem-0.8.0.tar.gz \ | tar -xz -C /tmp heskala-onprem-0.8.0 \ && bash /tmp/heskala-onprem-0.8.0/install.sh /opt/heskalaEl script detecta que el stack ya existe y solo hace docker compose pull + up -d sin perder datos.
Para ver qué versiones están disponibles para descargar: https://docs.heskala.com/downloads/
Configuración: correo y URL pública
Sección titulada «Configuración: correo y URL pública»Todo se configura por variables de entorno en el .env (o pasándolas al
install.sh). Las de correo y URL son las que más se ajustan:
| Variable | Para qué | Default |
|---|---|---|
SITE_URL | URL pública de tu instalación. Se usa en los links de los correos (invitaciones, reset de contraseña, etc.). | https://erp.heskala.com |
RESEND_API_KEY | API key de Resend para enviar correos. Sin ella, los flujos de email quedan deshabilitados (el resto funciona igual). | — |
RESEND_FROM_EMAIL | Dirección del remitente. Debe usar un dominio verificado en tu cuenta de Resend; si no, Resend rechaza el envío. | no-reply@erp.heskala.com |
RESEND_FROM_NAME | Nombre visible del remitente. | Heskala |
# En el .env de tu instalación:SITE_URL=https://erp.micliente.comRESEND_API_KEY=re_xxxxxxxxRESEND_FROM_EMAIL=no-reply@micliente.comRESEND_FROM_NAME=Mi Empresa⚠️ Si cambiás
RESEND_API_KEYa tu propia cuenta pero no seteásRESEND_FROM_EMAIL, Resend intentará enviar desdeno-reply@erp.heskala.com—un dominio que tu cuenta no tiene verificado— y fallará. Seteá siempre tu propio remitente con un dominio verificado. Del mismo modo, seteáSITE_URLpara que los links de los correos no apunten aerp.heskala.com.
Quickstart con Docker (Plan C, manual)
Sección titulada «Quickstart con Docker (Plan C, manual)»Si preferís hacerlo paso a paso o querés entender qué hace cada cosa:
# 1. Descomprimí el bundle y entrá al directoriotar -xzf heskala-onprem-0.8.0.tar.gzcd heskala-onprem-0.8.0cp .env.example .env# Editá .env (INSTANCE_NAME, INSTANCE_SECRET, RESEND_API_KEY, etc.)
# 2. Generar el admin key (lo necesita el deployer para subir funciones)docker compose up -d backend dashboarddocker compose exec backend ./generate_admin_key.sh# Anotá el admin key, pegalo en .env como CONVEX_SELF_HOSTED_ADMIN_KEY
# 3. Levantar todo (backend, dashboard, deployer, frontend)docker compose up -d# El deployer corre una vez, sube las funciones y setea env vars, después termina.
# 4. Abrí http://localhost:3000# El frontend se sirve desde el contenedor `frontend` (nginx),# que internamente habla con el contenedor `backend` (Convex).El compose levanta 4 servicios:
| Servicio | Imagen | Puerto host | Función |
|---|---|---|---|
backend | ghcr.io/get-convex/convex-backend | 3210 | Convex API (queries, mutations, auth, DB) |
dashboard | ghcr.io/get-convex/convex-dashboard | 6791 | Panel admin interno (DB, logs, env vars) |
frontend | ghcr.io/heskala/frontend | 3000 | App Heskala (UI del usuario final) |
deployer | ghcr.io/heskala/convex-deployer | — | Deploya las funciones de Convex y setea env vars (corre una vez) |
El usuario navega a http://localhost:3000. El frontend (nginx) hace
proxy de /api/* (queries, mutations, auth), /.well-known/* (JWKS de
Convex Auth), /license/* y /download/* al backend internamente, así no
hace falta exponer el puerto 3210. El bundle del frontend usa
window.location.origin, no una URL hardcodeada al backend.
Obtener tu token de licencia
Sección titulada «Obtener tu token de licencia»Antes de llegar al dashboard necesitás un token de licencia firmado
(es un JWT ECDSA que el backend valida contra su clave pública embebida).
El token define el tier, qué módulos se muestran en el sidebar, y los
límites de seats y sucursales.
Camino 1: Pedilo desde el formulario público (recomendado)
Sección titulada «Camino 1: Pedilo desde el formulario público (recomendado)»Andá a https://docs.heskala.com/solicitar-licencia/, completá el form con tus datos (nombre, correo, empresa, edición, cantidad de usuarios) y listo. Te llega el token firmado al mail en pocas horas (lo revisa Serlis y lo aprueba).
La licencia es de un solo uso: una vez que la activás en tu instalación on-prem, queda asociada a tu empresa. No se puede re-usar en otro servidor.
Camino 2: Pedirlo por mail
Sección titulada «Camino 2: Pedirlo por mail»Si preferís no usar el formulario, mandanos un mail a licencias@heskala.com con:
- Nombre y razón social
- Email de contacto
- Edición (
onprem) - Cantidad de usuarios
- Tipo (
lifetimeosubscriptionanual)
Camino 3: Compilar desde código fuente (dev / test)
Sección titulada «Camino 3: Compilar desde código fuente (dev / test)»Si tenés el código fuente y la clave privada, podés generar tokens vos mismo:
# Starter, 2 usuarios, 1 sucursal, lifetimeLICENSE_TEST_PRIVATE_KEY="$(cat /tmp/prod-private.txt)" \ npx tsx scripts/issue-test-license.ts \ --tier starter --seats 2 --cust "Mi Empresa" --type lifetime
# Pro, 5 usuarios, 10 sucursales, 1 añoLICENSE_TEST_PRIVATE_KEY="$(cat /tmp/prod-private.txt)" \ npx tsx scripts/issue-test-license.ts \ --tier pro --seats 5 --cust "Mi Empresa" --type annual --days 365
# All (todos los módulos), sin límite de sucursales, 3 usuarios, lifetimeLICENSE_TEST_PRIVATE_KEY="$(cat /tmp/prod-private.txt)" \ npx tsx scripts/issue-test-license.ts \ --tier all --seats 3 --cust "Mi Empresa" --type lifetimeEl script imprime el token a stdout. Copialo desde un archivo (no del terminal) para evitar caracteres invisibles:
npx tsx scripts/issue-test-license.ts --tier starter --seats 2 \ --cust "Mi Empresa" --type lifetime > /tmp/licencia.txtcat /tmp/licencia.txt | pbcopy # macOS# xclip -selection clipboard < /tmp/licencia.txt # LinuxLa
LICENSE_TEST_PRIVATE_KEYtiene que corresponder a la clave pública embebida en el frontend (lib/licensing/public-key.ts). Si el token lo firmás con una clave distinta, el backend lo rechaza confirma_no_valida.
Después de obtener el token
Sección titulada «Después de obtener el token»El token es un string largo que empieza con lic_. Pegalo en la pantalla
de /setup de tu instalación on-prem. Si te aparece firma_no_valida,
mirá “Problemas comunes” más abajo (casi siempre es un caracter
invisible en el portapapeles).
El servicio deployer
Sección titulada «El servicio deployer»La imagen ghcr.io/get-convex/convex-backend es una imagen runtime:
viene sin tus funciones pre-cargadas, sin env vars, sin JWT keys. En SaaS,
Convex Cloud deploya todo automáticamente; en self-hosted, hay que hacerlo
manualmente.
El deployer resuelve esto: es un sidecar que:
- Espera a que
backendestéhealthy - Lee el
CONVEX_SELF_HOSTED_ADMIN_KEYde.env - Corre
npx convex deploypara subir todas las funciones - Genera un par de claves RSA con
josey las setea comoJWT_PRIVATE_KEYyJWKS(necesarias para Convex Auth) - Setea
EDITION=onprem,LICENSE_PUBLIC_KEY(baked en la imagen del deployer, debe coincidir con la del frontend) y otras env vars críticas - Termina (
restart: "no")
Después de que el deployer completa, el backend ya tiene todo lo
necesario para que el frontend se conecte y arranque la primera
activación.
Setup atómico
Sección titulada «Setup atómico»El primer acceso con base vacía te lleva directo a /setup. En un solo
submit:
- Se crea la cuenta del administrador.
- Se aprovisiona la empresa, la branch principal, el rol admin con full-access y la subscription con los módulos y límites del token.
- Redirección a
/dashboard.
No hay wizard de pasos en on-prem: el tier, los módulos y los límites ya vienen firmados en la licencia — no hay nada que el usuario tenga que elegir.
Tier system
Sección titulada «Tier system»El token de licencia define tres campos clave:
| Campo | Significado |
|---|---|
mods | Lista de módulos habilitados (clientes, ventas, facturas, etc.) |
seats | Máximo de usuarios (0 = ilimitado) |
mb | Máximo de sucursales (0 o ausente = ilimitado) |
Tres tiers disponibles:
| Tier | Módulos | seats | mb (sucursales) |
|---|---|---|---|
starter | 47 módulos (sistema + comercial + fiscal completo) | configurable | 1 |
pro | 47 módulos (igual que starter) | configurable | 10 |
all | todos los disponibles en onprem (~64) | configurable | sin límite |
Starter y Pro comparten los mismos módulos: ambos incluyen todo el fiscal (facturación, exoneraciones, anulaciones, notas crédito/débito, correlativos SAR). La diferencia entre ellos son los límites de usuarios y sucursales, no los features.
Para los ejemplos de cómo emitir un token con cada tier, mirá Obtener tu token de licencia más arriba.
Qué verificar
Sección titulada «Qué verificar»Una vez en el dashboard:
- Sidebar: solo aparecen los módulos habilitados en tu licencia.
- URL a un módulo fuera del tier: redirige a “módulo no incluido”.
- Usuarios: invitá hasta el límite de
seats; el siguiente queda bloqueado. - Sucursales: solo se pueden crear hasta
mbbranches. - Sin suscripción en la UI: el panel de Suscripción no aparece en on-prem — la licencia se gestiona fuera del producto.
Caveats
Sección titulada «Caveats»- Código propietario excluido de las imágenes: las imágenes
ghcr.io/heskala/frontendyghcr.io/heskala/convex-deployerse construyen con la lógica de negocio de los módulos premium (operaciones, reportes) y la emisión de licencias removida antes de compilar. Tu servidor corre el producto, pero no recibe ese código fuente. - Seguridad “honor system” (solo datos en runtime): la licencia firmada se valida al boot y en cada heartbeat. Un usuario con acceso root al servidor puede modificar los valores de su propia base (módulos habilitados, límites) directamente, ya que la firma no protege los datos en runtime. Esto se resuelve en próximas versiones con heartbeat activo contra un servidor central.
- Plan C (v0.6.0+): la imagen del frontend en
ghcr.io/heskala/frontendes pública y se rebuilda en cada release tag. Eldocker-compose.ymldel bundle ya la apunta al tag del release, así que condocker compose pull && docker compose up -dactualizás. - Multi-arch (v0.7.0+): la imagen se publica como manifest list con
variantes para
linux/amd64ylinux/arm64. El pull es nativo en Mac M1/M2/M3/M4, servidores Linux amd64, AWS Graviton, Oracle Ampere y Raspberry Pi — sin emulación.
Problemas comunes
Sección titulada «Problemas comunes»”firma_no_valida” al activar la licencia
Sección titulada «”firma_no_valida” al activar la licencia»Si el servidor responde firma_no_valida aunque tu token “se ve” bien,
es muy probable que tenga un char invisible o modificado (zero-width
space, BOM, soft-hyphen, etc.). El cliente ya limpia esos chars al
pegar, pero a veces el clipboard introduce uno antes. Soluciones:
- Si el token lo recibiste por mail/chat, pegalo primero en un editor plano (TextEdit, VS Code) y de ahí al input, para que no arrastre formato ni caracteres invisibles.
- Si persiste, pedile a Heskala que te reenvíe el token (puede haberse cortado o alterado al copiarlo).
docker compose pull falla al bajar frontend o deployer
Sección titulada «docker compose pull falla al bajar frontend o deployer»Si el pull de ghcr.io/heskala/frontend o ghcr.io/heskala/convex-deployer
falla con denied / unauthorized / manifest unknown, es porque ese
paquete de GHCR quedó privado (GHCR publica los paquetes privados por
defecto). Ambas imágenes deben estar en visibilidad Public:
- Entrá a
https://github.com/orgs/heskala/packages/container/<frontend|convex-deployer>/settings - Danger Zone → Change visibility → Public (una por imagen).
Verificá desde una máquina sin login:
docker logout ghcr.iodocker pull ghcr.io/heskala/frontend:latestdocker pull ghcr.io/heskala/convex-deployer:latestUna vez públicas, las versiones que publiques después siguen siendo públicas (no hay que repetirlo por release).
El frontend se queda cargando y no llega al dashboard
Sección titulada «El frontend se queda cargando y no llega al dashboard»- Confirmá que los servicios estén arriba:
docker compose ps(backendhealthy, frontendrunning). - El
deployercorre una vez en la primera instalación y sube las funciones al backend. Revisá que haya terminado bien:docker compose logs deployer. Si ves errores oHTTP actions not enabled, volvé a correrlo:docker compose up -d deployer. - Revisá los logs del backend:
docker compose logs -f backend.
El sidebar muestra módulos que no deberían estar
Sección titulada «El sidebar muestra módulos que no deberían estar»Si cambiaste el tier de la licencia y el sidebar sigue mostrando los
módulos del tier anterior, el token quedó cacheado en el localStorage
del browser. Limpiá:
- DevTools (F12) → Application → Local Storage →
http://localhost:3000 - Borrá todas las keys que empiezan con
heskala.license. - Hard refresh (Cmd+Shift+R)
- Pegá el nuevo token
Cambié el token pero el backend no lo reconoce
Sección titulada «Cambié el token pero el backend no lo reconoce»Cada token está firmado para una instalación/versión. Si actualizaste a una
versión nueva y el token deja de validar (firma_no_valida), puede ser que
esa versión haya rotado la clave de licencia: pedile a Heskala un token nuevo
para tu instalación. Antes de pegar el nuevo, limpiá el viejo del
localStorage (ver arriba).
Soporte
Sección titulada «Soporte»Para reportar problemas o pedir nuevas features del flujo on-prem, contactanos por los canales habituales.