Ir al artículo
Aniq-UI

TicketoryDespliega Ticketory

Despliega Ticketory

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 sin más.

Para el paquete Full Stack

Tres formas de desplegar

FormaIdeal paraQué necesitas
Docker Compose en un servidorUn VPS que controlas, las tres aplicaciones juntasEl paquete Full Stack, Docker en el servidor, un proxy inverso para HTTPS
Una aplicación por host, desde su DockerfileRailway, Render, Fly.io y otros hosts que construyen desde un DockerfileLa carpeta de cada aplicación; un volumen o MySQL y un bucket para la API
Node.js sin másCualquier host con NodeNode.js 22 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. Los orígenes permitidos de la API, las direcciones a las que las páginas de pago devuelven a los compradores, los enlaces de descarga de las entradas, las direcciones de las imágenes y la dirección de la API de los frontends se construyen todos a partir de ellas. REVALIDATE_SECRET sustituye al valor local por defecto que comparten el sitio web y la API para actualizar las páginas de evento al instante.

.env junto a docker-compose.yml
SITE_URL=https://www.your-domain.com
ADMIN_URL=https://dashboard.your-domain.com
API_URL=https://api.your-domain.com
MEDIA_HOSTNAME=api.your-domain.com
REVALIDATE_SECRET=a-long-random-string

MEDIA_HOSTNAME es opcional, un host o varios separados por comas (añade el host de tu bucket cuando las subidas van a uno): las imágenes de esos hosts https las redimensiona Next.js, y cualquier otra imagen se carga tal cual. Luego construye e inicia en segundo plano:

Terminal
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, 3031 y 8000.
  • Detrás de ese proxy, define TRUST_PROXY=1 en back-end/.env, para que los límites de inicio de sesión, formulario de contacto y escaneo de la puerta cuenten a cada visitante y no al proxy. El contenedor de la API lee back-end/.env cuando existe, que es también donde van las claves de pago, correo, IA y almacenamiento.
  • Sin un JWT_SECRET propio, la API genera uno en su primer inicio y lo guarda en el volumen ticketory-data. La base de datos, las subidas y las exportaciones CSV también viven en ese volumen, así que haz una copia de seguridad.
  • El primer inicio en un volumen nuevo crea los organizadores de ejemplo salvo que SEED_DEMO_DATA=false esté en el .env. Para tus propios eventos, inicia sin ellos y con tu propio propietario, como en Puesta en marcha con tu propio espacio de trabajo, 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 escucha en PORT (8000 salvo que el host defina otro), responde GET /api/health en cuanto su base de datos responde, y guarda SQLite, las subidas y las exportaciones CSV en /data.

  • Monta un volumen persistente en /data. Sin uno, cada despliegue empieza con una base de datos vacía.
  • Define CORS_ORIGIN con las direcciones del sitio web y del panel (separadas por comas), FRONTEND_URL con la del panel, STOREFRONT_URL con la del sitio web, PUBLIC_API_URL con la dirección pública de la API y PUBLIC_MEDIA_URL con esa dirección seguida de /media.
  • El valor por defecto de la imagen es SEED_DEMO_DATA=false: un volumen nuevo recibe solo las tablas, y el primer inicio de la API crea entonces tu espacio de trabajo y su propietario a partir de OWNER_EMAIL y OWNER_PASSWORD (mira más abajo). Define SEED_DEMO_DATA=true en su lugar para tener los organizadores de ejemplo. Una base de datos existente nunca se vuelve a llenar con datos de ejemplo.
  • 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=mysql y las cinco variables DB_*), el contenedor no crea las tablas. Ejecuta una vez node dist/database/seeder.js (datos de ejemplo) o node dist/database/sync-schema.js (tablas vacías) con el mismo entorno.
  • Las subidas en el volumen sobreviven a un nuevo despliegue; para mantenerlas fuera del servidor, define las cinco variables R2_* para un bucket.
  • Define REVALIDATE_SECRET con el mismo valor largo y aleatorio en la API y en el sitio web, y STOREFRONT_INTERNAL_URL cuando la API llegue al sitio web en una dirección distinta de STOREFRONT_URL.

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ónAplicaciónValor
NEXT_PUBLIC_API_BASE_URLAmbosLa dirección pública de la API seguida de /api
NEXT_PUBLIC_SITE_URLAmbosLa dirección pública del sitio web: las URL canónicas y el mapa del sitio en el sitio web, el enlace "Ver sitio web" y las vistas previas de eventos en el panel
NEXT_PUBLIC_DASHBOARD_URLAmbosLa dirección pública del panel: adonde el "Sell tickets" del sitio web envía a los organizadores, y la imagen para compartir del propio panel
NEXT_PUBLIC_MEDIA_HOSTNAMEAmbosOpcional. Los hosts https que sirven las imágenes (el dominio de la API, el de tu bucket, o ambos), separados por comas
NEXT_PUBLIC_WEBSOCKET_BASE_URLPanelLa dirección pública de la API sin /api, para las notificaciones en directo

El servidor del sitio web también consulta la API mientras renderiza las páginas de evento, recinto y organizador y el mapa del sitio. 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 anula cuando el servidor debe usar otra dirección. REVALIDATE_SECRET también es una variable de ejecución del sitio web, nunca un argumento de construcció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ónConstrucciónInicio
APIyarn build, y luego una vez yarn seed:prod (datos de ejemplo) o yarn db:sync:prod (tablas vacías)yarn start:prod
Sitio web públicoyarn buildyarn start (puerto 3030)
Panel del organizadoryarn buildyarn start (puerto 3031)

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.

Puesta en marcha con tu propio espacio de trabajo

Los organizadores de ejemplo y sus inicios de sesión sirven para probar Ticketory. Para tus propios eventos, empieza con una base de datos nueva sin ellos: en una base de datos sin cuenta de personal ni espacio de trabajo, el primer inicio de la API crea los datos base (los 29 permisos, los cuatro roles, los ajustes del sitio y las tres categorías de eventos), un espacio de trabajo vacío y su propietario.

  1. Define las variables del propietario

    En back-end/.env, o en la configuración de tu host para la API. Con Docker Compose, ponlas en el .env junto a docker-compose.yml junto con SEED_DEMO_DATA=false: Compose lee ese archivo primero y luego back-end/.env, cuyo valor gana donde ambos definen uno.

    back-end/.env
    OWNER_EMAIL=you@your-domain.com
    OWNER_PASSWORD=a-long-password-of-your-own
    OWNER_NAME=Your Name
    WORKSPACE_NAME=Your organisation

    Resultado esperado: OWNER_NAME y WORKSPACE_NAME son opcionales (Owner y Ticketory si no se definen), y ambos se cambian después, en tu perfil y en Settings, General. La contraseña necesita al menos 10 caracteres, y con NODE_ENV=production se rechazan el valor del ejemplo de .env.example y la contraseña de las cuentas de ejemplo.

  2. Empieza sin los datos de ejemplo, en una base de datos nueva

    Sin Docker, en la carpeta de la API: yarn build, luego yarn db:sync:prod (no yarn seed), luego yarn start:prod. Con Docker Compose, mantén SEED_DEMO_DATA=false en el .env junto a docker-compose.yml y ejecuta docker compose up --build -d sobre un volumen nuevo (docker compose down -v borra uno existente, con todos sus datos). Un contenedor de la API solo arranca sin -e SEED_DEMO_DATA=true, con las variables pasadas con --env-file .env o -e.

    Resultado esperado: El registro de la API dice Clean start: created the workspace "Your organisation" and its Owner, con el correo.

    ¿Tienes problemas?
  3. Inicia sesión y configura el espacio de trabajo

    Inicia sesión en el panel con OWNER_EMAIL y OWNER_PASSWORD. El espacio de trabajo está vacío: añade un recinto y luego tu primer evento. Su moneda es USD hasta que la cambies en Settings, General, lo que puedes hacer hasta que se pague la primera entrada. Después invita a tu equipo desde la página Team, a cada uno con el rol que necesita.

  • Ocurre una sola vez. En cuanto existe cualquier cuenta de personal, las variables del propietario se ignoran, así que un reinicio o una segunda copia de la API no crea nada más, y después puedes quitar OWNER_PASSWORD de la configuración. La contraseña nunca se imprime.
  • yarn seed y una base de datos llena con los datos de ejemplo nunca las leen: esa base de datos ya tiene personal.
  • El panel no tiene página de registro. Cada otra cuenta de personal se añade con Invite member en la página Team, con un rol y una contraseña que compartes tú mismo (no se envía nada por correo).

Empezar en cambio desde los datos de ejemplo

Una base de datos llena con los datos de ejemplo conserva sus cuatro organizadores y sus cuentas. Si empiezas desde ella, hazla tuya antes de que sea accesible desde internet:

  1. Haz tuyo al propietario de ejemplo: cambia su nombre y correo en Settings, Profile, y su contraseña en Settings, Security. Es la única cuenta que pertenece a todos los espacios de trabajo de ejemplo, y ninguna pantalla añade un miembro existente a otro espacio de trabajo, así que consérvala en lugar de sustituirla por una cuenta nueva.
  2. Quita de la página Team de cada espacio de trabajo a los miembros de ejemplo que no necesites, o cambia sus contraseñas. Remove saca a un miembro del espacio de trabajo en el que estás; la cuenta se borra con su último espacio de trabajo. No puedes eliminarte a ti mismo, y cada espacio de trabajo conserva un propietario.
  3. Define el nombre del espacio de trabajo, el correo de soporte, la moneda, la comisión de reserva, la zona horaria y las notificaciones del equipo en Settings, General y Notifications. La moneda se bloquea cuando se cobra el primer pedido pagado.
  4. Archiva o cancela los eventos de ejemplo y sustituye los recintos de ejemplo por los tuyos, con sus planos de asientos. No hay pantalla ni ruta para crear otro espacio de trabajo, así que renombra uno en Settings, General para tu propio negocio.
  5. Los asistentes crean sus propias cuentas en el sitio web, o compran como invitados. El asistente de ejemplo son datos de ejemplo: bórralo con el resto.

Actualizar una instalación que ya usas

Con NODE_ENV=production, la API nunca cambia las tablas por sí misma. Tras una actualización que añade una columna o una tabla, sincroniza el esquema una vez en la base de datos existente, antes de iniciar la nueva versión. Esta añade la columna locale en orders (el idioma de los correos de cada pedido) y la tabla event_reminders.

Sin Docker, en la carpeta de la API:

Terminal
yarn build
yarn db:sync:prod

No escribe filas y conserva tus datos. Con Docker, el contenedor deja en paz una base de datos existente, así que tras docker compose up --build -d ejecuta el mismo script una vez en el contenedor de la API en marcha, y luego reinícialo (para un contenedor de la API solo, docker exec -u node <container> node dist/database/sync-schema.js, y luego docker restart <container>):

Terminal
docker compose exec -u node api node dist/database/sync-schema.js
docker compose restart api

Con NODE_ENV=development, como con yarn dev, la API actualiza las tablas por sí sola al iniciar.

Pasar a producción

Antes de que Ticketory sea accesible desde internet:

  1. En el entorno de la API, NODE_ENV=production y un JWT_SECRET largo y aleatorio propio (Docker genera uno cuando no hay ninguno). En producción la API se niega a iniciar sin CORS_ORIGIN y dice qué valor falta.
  2. CORS_ORIGIN con el sitio web y el panel, FRONTEND_URL con el panel, STOREFRONT_URL con el sitio web, PUBLIC_API_URL con la API y PUBLIC_MEDIA_URL con la API seguida de /media.
  3. TICKET_SECRET definido una vez, antes de la primera venta: firma los códigos QR, y cambiarlo después anula todas las entradas ya vendidas.
  4. Tus claves reales de Stripe o PayPal, y los webhooks registrados en cada proveedor en /api/webhooks/stripe y /api/webhooks/paypal en la dirección de la API. Con una clave real definida, Test payment desaparece del pago.
  5. Impuestos configurados para tu país: Ticketory no cobra ninguno por sí mismo.
  6. RESEND_API_KEY y MAIL_FROM, o los asistentes no reciben correos de entradas, códigos de registro ni restablecimientos de contraseña.
  7. La base de datos, las subidas y las exportaciones CSV en almacenamiento persistente, con copia de seguridad.
  8. La comprobación de estado del host en /api/health, y TRUST_PROXY=1 detrás de un proxy.
  9. Ambos frontends construidos con los valores públicos NEXT_PUBLIC_*, y el mismo REVALIDATE_SECRET en la API y en el sitio web.
  10. En el sitio web, tu marca en src/config/brand.config.ts, y los textos de privacidad, condiciones y cancelación en messages/legal reescritos para tu negocio y tu país.
  11. Tu propio espacio de trabajo desde un inicio limpio, o las contraseñas de ejemplo cambiadas y las cuentas de ejemplo que no necesitas eliminadas.
  12. DEMO_MODE=false en la API y NEXT_PUBLIC_DEMO_MODE=false en ambos frontends, tal como se entrega.

No para datos de venta reales

yarn setup:fresh construye, elimina todas las tablas y carga los datos, cada vez que se ejecuta, y yarn db:reset elimina todas las tablas. Sirven para un entorno completamente nuevo, nunca como comando de inicio o de construcción.

¿Te atascaste en un paso?

Busca una solución antes de empezar de nuevo.

Solución de problemas

Preferencias de Cookies

Utilizamos cookies para mejorar tu experiencia de navegación, analizar el tráfico del sitio y personalizar el contenido. Al hacer clic en "Aceptar Todo", consientes nuestro uso de cookies para análisis y publicidad personalizada.