Despliega Northstack
Pon en línea el sitio web, el panel y la API: Docker Compose en un servidor, una aplicación por host desde su Dockerfile, o Node.js simple, empezando vacío con tu propio administrador de la plataforma y actualizando las tablas tras una actualización.
Para el paquete Full Stack
Tres formas de desplegar
| Forma | Ideal para | Qué necesitas |
|---|---|---|
| Docker Compose en un servidor | Un VPS que controlas, las tres aplicaciones juntas | El paquete Full Stack, Docker en el servidor, un proxy inverso para HTTPS |
| Una aplicación por host, desde su Dockerfile | Railway, Render, Fly.io y otros hosts que construyen desde un Dockerfile | La carpeta de cada aplicación; un volumen o MySQL, y opcionalmente un bucket, para la API |
| Node.js sin más | Cualquier host con Node | Node.js 22.13 o una versión 22 posterior, o 24.11 o más reciente, y Yarn 4 en el host |
Elijas la forma que elijas, el sitio web y el panel compilan la dirección de la API en su JavaScript cuando se construyen, así que constrúyelos con las direcciones públicas, nunca con las locales.
Docker Compose en un servidor
Copia la carpeta del paquete al servidor y pon un .env junto a docker-compose.yml con las tres direcciones públicas. De ellas se derivan los orígenes permitidos de la API, los enlaces que escribe en invitaciones, restablecimientos de contraseña y retornos del pago, los enlaces de descarga de facturas, la dirección de los archivos y la dirección de la API para los frontends.
SITE_URL=https://www.your-domain.com
ADMIN_URL=https://app.your-domain.com
API_URL=https://api.your-domain.comLuego construye e inicia en segundo plano:
docker compose up --build -d- Apunta cada dominio al servidor mediante un proxy inverso que sirva HTTPS (Caddy, Nginx o Traefik), reenviando a los puertos
3030,3031y8000. - Copia
back-end/.env.exampleaback-end/.envpara las claves de pago, correo, almacenamiento, IA y MCP: el contenedor de la API lo lee cuando existe, ydocker-compose.ymlconserva los valores que deben ser distintos dentro de un contenedor. Detrás del proxy, define allíTRUST_PROXY=1, para que el límite de inicios de sesión cuente a cada visitante y no al proxy. - Sin un
JWT_SECRETpropio, la API genera uno en su primer inicio y lo guarda en el volumennorthstack-data. La base de datos y los archivos subidos también viven en ese volumen, así que haz una copia de seguridad. - Para una instalación real, inicia el volumen nuevo vacío: pon
SEED_SAMPLE_DATA=falseen el archivo.envjunto adocker-compose.yml(no enback-end/.env: Compose pasa estos tres desde allí), conADMIN_EMAILyADMIN_PASSWORDpara tu primer administrador de la plataforma, antes del primerdocker compose up. El.envjunto adocker-compose.ymlno llega a la API para esto. Consulta Empezar vacío más abajo. - Con su valor por defecto (
SEED_SAMPLE_DATA=true), el primer inicio en un volumen nuevo carga los espacios de trabajo de ejemplo y sus cuentas, todas con la contraseña publicada. Hazlas tuyas antes de que la pila sea accesible, como en Empezar con los datos de ejemplo más abajo.
La API desde su Dockerfile
Apunta el host a la carpeta de la API (back-end/ en el Full Stack). La imagen se ejecuta con NODE_ENV=production, escucha en PORT (8000 salvo que el host defina otro), responde a GET /api/health cuando su base de datos tiene el esquema, y guarda SQLite y los archivos subidos en /data.
- Monta un volumen persistente en
/data. Sin él, cada despliegue empieza con una base de datos nueva. - Define
SEED_SAMPLE_DATA=false, conADMIN_EMAILyADMIN_PASSWORD, para que un volumen nuevo empiece con tu propio administrador de la plataforma y sin datos de ejemplo. Contrue, el valor por defecto, un volumen nuevo se carga con las cuentas de ejemplo y su contraseña publicada. - Define
CORS_ORIGINcon las direcciones del sitio web y del panel (separadas por comas),FRONTEND_URLyDASHBOARD_URLcon la del panel,WEBSITE_URLcon la del sitio web,PUBLIC_API_URLcon la dirección pública de la API yPUBLIC_MEDIA_URLcon esa dirección seguida de/media. - En SQLite, un volumen sin base de datos se crea una sola vez, según lo que diga
SEED_SAMPLE_DATA; una base de datos existente nunca se vuelve a cargar y sus tablas nunca se cambian al iniciar (consulta Actualizar más abajo). - Define tu propio
JWT_SECRET, o deja que el contenedor genere uno y lo guarde en/data/.jwt-secret. - Define
TRUST_PROXY=1: una plataforma de alojamiento pone un proxy delante del contenedor. - En MySQL (
DB_TYPE=mysqly las cinco variablesDB_*), el contenedor no crea las tablas. Ejecutanode dist/database/create-admin.jsuna vez con el mismo entorno (onode dist/database/seeder.jspara una instalación de ejemplo). - Las subidas en el volumen sobreviven a un nuevo despliegue; para mantenerlas fuera del servidor, define las cinco variables
R2_*para un bucket.
El sitio web y el panel desde sus Dockerfiles
Apunta el host a la carpeta de la aplicación y dale los valores NEXT_PUBLIC_* como argumentos de construcción, no como variables de ejecución: se compilan dentro. Cada imagen sirve el servidor independiente de Next.js en PORT (3030 para el sitio web, 3031 para el panel, salvo que el host defina otro).
| Argumento de construcción | Aplicación | Valor |
|---|---|---|
NEXT_PUBLIC_API_BASE_URL | Ambos | La dirección pública de la API seguida de /api. Con su valor por defecto, http://localhost:8000/api, una aplicación desplegada llama al propio equipo del visitante. |
NEXT_PUBLIC_SITE_URL | Sitio web | La dirección pública del sitio web: enlaces canónicos, alternativas de idioma, el mapa del sitio y las tarjetas para compartir |
NEXT_PUBLIC_DASHBOARD_URL | Sitio web | La dirección pública del panel, que abren Live demo, Explore the demo, See role controls, el Sign in de /error/401 y las direcciones /auth/* del sitio |
NEXT_PUBLIC_BASE_URL | Panel | La dirección pública del panel: robots.txt, el mapa del sitio y los metadatos |
NEXT_PUBLIC_WEBSITE_URL | Panel | La dirección pública del sitio web, para los enlaces de Documentation, Privacy y Terms |
NEXT_PUBLIC_WEBSOCKET_BASE_URL | Panel | Opcional. La dirección pública de la API sin /api, para las actualizaciones de permisos en vivo; si está vacía usa NEXT_PUBLIC_API_BASE_URL sin su /api |
El servidor del sitio web también lee la API mientras renderiza el pago y su recibo. Con una dirección pública de la API que también funcione desde el servidor, no hace falta nada más; API_INTERNAL_URL en tiempo de ejecución la sustituye cuando el servidor debe usar otra dirección.
Node.js sin más
Construye cada aplicación una vez en el host y luego inicia. Define el .env de los frontends con las direcciones públicas antes de yarn build.
| Aplicación | Construcción | Inicio |
|---|---|---|
| API | yarn build, y una vez en una base de datos nueva yarn admin:create:prod | yarn start:prod |
| Panel de espacios de trabajo | yarn build | yarn start (puerto 3031, o PORT en su .env) |
| Sitio web público | yarn build | yarn start (puerto 3030) |
La API se enlaza a 0.0.0.0 y lee PORT. Mantén el archivo SQLite y MEDIA_UPLOAD_DIR en un almacenamiento que sobreviva a un despliegue, o usa MySQL y un bucket. En producción la API nunca crea ni cambia las tablas por sí sola: yarn admin:create:prod las crea con tu primer administrador de la plataforma, y yarn schema:prod las actualiza tras una actualización.
Empezar vacío, con tu propio administrador de la plataforma
Una instalación real empieza sin datos de ejemplo y con una cuenta tuya. En la carpeta de la API, después de yarn build:
yarn admin:create:prod- Crea las tablas, los roles de la plataforma y los ajustes de la plataforma, y el primer administrador de la plataforma a partir de
ADMIN_EMAILyADMIN_PASSWORD(de 8 a 128 caracteres) en el entorno o enback-end/.env. Pide en la terminal el que esté vacío, yADMIN_NAMEes opcional. - No crea ningún espacio de trabajo ni cuenta de ejemplo, y se niega si ya existe un administrador de la plataforma. Inicia sesión con esa cuenta y crea tu espacio de trabajo en el alta inicial.
yarn admin:createhace lo mismo desde el código fuente, sin construir.- Con Docker,
SEED_SAMPLE_DATA=falsehace esto en el primer inicio: conADMIN_EMAILyADMIN_PASSWORDdefinidos crea el administrador, y sin ellos crea solo las tablas y su registro indica el comando que ejecutar después,docker compose exec -u node api node dist/database/create-admin.js(condocker run,docker exec -it -u node <container> node dist/database/create-admin.js).
Nunca cargues datos de ejemplo en un servidor público
yarn seed:prod y yarn seed son solo para una instalación de ejemplo: cargan las cuentas de ejemplo con la contraseña publicada en esta guía. Cualquiera que la lea podría iniciar sesión como tu administrador de la plataforma.
Actualizar: las tablas tras una actualización
No hay migraciones, y en producción la API nunca cambia las tablas por sí sola. Tras una actualización cuyo código cambie las tablas, haz una copia de seguridad de la base de datos, construye y lleva las tablas al nuevo código antes de iniciar la API:
yarn build
yarn schema:prod
yarn start:prodyarn schema:prodno escribe datos. Añade lo nuevo, y también elimina una columna que el código ya no tiene, con sus datos, así que la copia de seguridad va primero.- Con Docker, un volumen existente se deja como está al iniciar. Cuando la nueva imagen esté en marcha, aplica el esquema en ella:
docker compose exec -u node api node dist/database/schema.js(condocker run,docker exec -u node <container> node dist/database/schema.js).
Empezar con los datos de ejemplo
Cada carga de datos crea los espacios de trabajo de ejemplo y sus personas, los seis inicios de sesión documentados y todas las demás cuentas de ejemplo, todos con la misma contraseña publicada, y la imagen de Docker carga un volumen nuevo por sí sola salvo que SEED_SAMPLE_DATA=false. Si empiezas con los datos de ejemplo, haz tuya la instalación antes de que sea accesible desde internet:
- Haz tuyo el administrador de la plataforma de ejemplo: inicia sesión como
platform@northstack.example, cambia su nombre y correo en Settings, Profile, y su contraseña en Settings, Security. - Para tu propio espacio de trabajo, regístrate en el panel con tu propio correo: el alta inicial crea el espacio de trabajo, contigo como propietario. O haz tuyo el propietario de ejemplo de la misma forma y cambia el nombre de Forma Studio en Settings, General.
- En la página Users de la plataforma, Delete las cuentas de ejemplo que no necesites, o usa Change password en las que conserves. Una cuenta que es propietaria de un espacio de trabajo se rechaza hasta que otro miembro lo posea (desde la página Team de ese espacio) o el espacio se elimine (en su Settings, Danger zone).
- Define tu propio
JWT_SECRET, para que un token de inicio de sesión creado antes del cambio deje de funcionar.
Una carga de datos crea las cuentas y los espacios de trabajo de ejemplo solo en una base de datos que aún no tiene ninguna cuenta. Cuando ya existen cuentas, volver a ejecutar yarn seed o yarn seed:prod no añade ninguna cuenta ni espacio de trabajo y solo devuelve sus permisos a los roles de plataforma integrados, así que una cuenta de ejemplo que renombraste o eliminaste nunca vuelve con la contraseña publicada.
Pasar a producción
Antes de que Northstack sea accesible desde internet:
- En el entorno de la API,
NODE_ENV=productiony unJWT_SECRETpropio, largo y aleatorio (Docker genera uno cuando no hay ninguno). En producción la API se niega a iniciar con el secreto de ejemplo o sinCORS_ORIGIN, e indica qué valor está mal. CORS_ORIGINcon el sitio web y el panel,FRONTEND_URLyDASHBOARD_URLcon el panel,WEBSITE_URLcon el sitio web,PUBLIC_API_URLcon la API yPUBLIC_MEDIA_URLcon la API seguida de/media.- Tu clave de Stripe en vivo y su webhook en
/api/billing/webhooks/stripeen la dirección de la API, conSTRIPE_WEBHOOK_SECRET: sin él la API lo indica en su registro al iniciar y rechaza cada entrega, así que las renovaciones y los pagos fallidos nunca se registran. Para PayPal, las claves de la aplicación en vivo conPAYPAL_ENV=live. - Impuestos configurados para tu país: Northstack no cobra ninguno por sí mismo.
- Los ajustes
SMTP_*, o nadie recibe invitaciones, restablecimientos de contraseña ni recibos de licencia. - La base de datos y las subidas en almacenamiento persistente, con una copia de seguridad.
- La comprobación de estado del host en
/api/health, yTRUST_PROXY=1detrás de un proxy. - Ambos frontends construidos con los valores públicos de
NEXT_PUBLIC_*. - Tu marca en cada frontend, y las páginas legales del sitio web reescritas para tu negocio y tu país.
- Sin cuentas de ejemplo: iniciado vacío con
yarn admin:create:prodoSEED_SAMPLE_DATA=false, o con las de ejemplo eliminadas o sus contraseñas cambiadas, como arriba. DEMO_MODE=falseen la API yNEXT_PUBLIC_DEMO_MODE=falseen ambos frontends, tal como se entrega.