Ir al artículo
Aniq-UI

HollinaSolución de problemas

Solución de problemas

Los errores que puedes encontrar al instalar el negocio de reservas y recibir las primeras reservas, qué causa cada uno y cómo solucionarlo.

Para el paquete Full Stack

Docker no se está ejecutando

Lo que ves
failed to connect to the docker API at unix:///…/docker.sock; check if the path is correct and if the daemon is running

Las versiones antiguas de Docker muestran "Cannot connect to the Docker daemon" en su lugar. En ambos casos, el motor de Docker no está iniciado.

  1. Abre Docker Desktop

    Inicia Docker Desktop y espera a que indique que el motor está en ejecución. En Linux, inicia el servicio: sudo systemctl start docker.

  2. Comprueba que Docker responde

    Terminal
    docker info

    Resultado esperado: Muestra una sección Server en lugar de un error.

  3. Vuelve a ejecutar tu comando de inicio

    docker compose up --build para el paquete Full Stack, o tus comandos docker build y docker run para una sola aplicación.

Un puerto ya está en uso

Lo que ves
ports are not available: exposing port TCP 0.0.0.0:3031 … bind: address already in use
Bind for 0.0.0.0:3031 failed: port is already allocated
Error: listen EADDRINUSE: address already in use :::3031

Las dos primeras líneas vienen de Docker, la última de yarn dev. Otro programa ya escucha en 3030, 3031 o 8000: a menudo una ejecución anterior de Hollina, o el servidor de desarrollo de otro proyecto.

  1. Averigua qué ocupa el puerto

    En macOS o Linux, con el puerto del mensaje:

    Terminal
    lsof -i :3031

    En Windows, en PowerShell:

    Terminal
    netstat -ano | findstr :3031
  2. Detenlo

    Cierra ese programa o detén la ejecución anterior: Ctrl+C en su terminal, docker compose down en su carpeta, o docker stop para un contenedor que iniciaste con docker run. Luego inicia Hollina de nuevo.

  3. O ejecuta Hollina en otros puertos

    Con el paquete Full Stack en Docker, crea un archivo llamado .env en la carpeta hollina-vacation-rental-full-stack, junto a docker-compose.yml, con el puerto que necesites. SITE_PORT mueve el sitio web, ADMIN_PORT el panel y API_PORT la API; las direcciones que usan las aplicaciones, incluida CORS_ORIGIN, se ajustan solas.

    hollina-vacation-rental-full-stack/.env
    ADMIN_PORT=3041

    Luego ejecuta el mismo comando otra vez. Un inicio fallido continúa donde se detuvo. Docker nombra un solo puerto ocupado cada vez: si se detiene en otro, añade ese también al .env.

    Terminalen hollina-vacation-rental-full-stack
    docker compose up --build

    Resultado esperado: La aplicación responde en su nuevo puerto, aquí localhost:3041Local.

Para una sola aplicación iniciada con docker run, cambia el número a la izquierda de -p, por ejemplo -p 3041:3031, y añade la nueva dirección al CORS_ORIGIN de la API; para el panel, define también el FRONTEND_URL de la API con ella, y para el sitio web SITE_URL. Sin Docker, los puertos están fijados en los archivos: los scripts dev y start de los frontends en package.json pasan -p 3030 y -p 3031, y la API lee PORT de su .env. Mueve la API junto con PUBLIC_MEDIA_URL y el NEXT_PUBLIC_API_BASE_URL de ambos frontends; añade la dirección de un frontend movido a CORS_ORIGIN.

Configuración

La construcción de Docker falla

La primera construcción descarga las imágenes base y todas las dependencias, y luego construye las imágenes. Si algo lo impide, se detiene con "failed to solve" y el paso que falló.

  • Sin conexión o tiempo de espera agotado: la construcción necesita acceso a internet. Vuelve a ejecutar el comando cuando tengas conexión; los pasos terminados quedan en caché.
  • No space left on device: libera espacio en Docker Desktop o revisa cuánto usa Docker con docker system df.
  • Falla siempre en el mismo paso: vuelve a construir sin la caché y luego inicia.
  • Compose rechaza el propio `docker-compose.yml`, nombrando `env_file`: tu Compose es anterior a la 2.24. Actualiza Docker Desktop, o el plugin de Compose en Linux.
Terminalen hollina-vacation-rental-full-stack
docker compose build --no-cache
docker compose up

En un paquete de una sola aplicación, añade --no-cache a tu comando docker build.

Un primer inicio que parece atascado suele estar todavía cargando la empresa de demostración. El sitio web y el panel solo se inician cuando la API indica que está en buen estado.

Yarn dice que su versión es 1.22

Lo que ves
This project's package.json defines "packageManager": "yarn@4…". However the current global version of Yarn is 1.22…

Cada aplicación fija Yarn 4 a través de Corepack. Este mensaje significa que Corepack aún no está habilitado, así que respondió en su lugar el Yarn global antiguo.

Terminal
corepack enable

Luego ejecuta yarn install otra vez. Si tu Node.js no tiene Corepack (Node.js 25 y posteriores lo omiten), instálalo antes con npm install -g corepack. No se usan npm ni pnpm: cada aplicación incluye su propio yarn.lock.

Una instalación o un inicio falla con una versión antigua de Node.js

Cada aplicación declara Node.js 22 o más reciente, y las imágenes de Docker funcionan con Node.js 24. Un Node.js más antiguo se nota en una instalación que no logra construir un paquete, o en una aplicación que se detiene al iniciar.

Terminal
node -v

Si muestra una versión inferior a la 22, instala Node.js 22 o más reciente, ejecuta corepack enable otra vez (en Node.js 25 y posteriores, antes npm install -g corepack), luego elimina la carpeta node_modules de la aplicación y ejecuta yarn install otra vez. Con Docker nada de esto se aplica: las imágenes traen su propio Node.js.

La API se detiene antes de iniciarse

Lo que ves
The API cannot start: JWT_SECRET is not set. Set it in back-end/.env to the output of: …
The API cannot start: JWT_SECRET is still the example value from .env.example, so anyone can sign a token for any account. …
The API cannot start: CORS_ORIGIN is not set. List the website and booking dashboard origins, comma separated, …

La API revisa sus ajustes antes de iniciarse y muestra una línea por cada problema. Las causas:

  • No hay archivo `.env`, o `JWT_SECRET` está vacío. Crea el archivo en la carpeta de la API con cp .env.example .env.
  • `JWT_SECRET` sigue siendo el valor de ejemplo con `NODE_ENV=production`. Cualquiera podría firmar un token con el ejemplo público, así que un inicio en producción lo rechaza. Genera tu propio secreto.
  • `CORS_ORIGIN` está vacío con `NODE_ENV=production`. Escribe las direcciones del sitio web y del panel, separadas por comas.

Genera un secreto con:

Terminal
node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"

Con Docker no necesitas uno: un contenedor sin un JWT_SECRET propio, o con el de ejemplo, genera un secreto y lo guarda en el volumen de datos.

El sitio web no tiene alojamientos y nadie puede iniciar sesión

Lo que ves
→ No database at /data/database.sqlite. Creating the tables, no data (set SEED_DEMO_DATA=true for the demo).

La base de datos se creó solo con tablas. Eso ocurre cuando el contenedor de la API se inicia en un volumen nuevo sin SEED_DEMO_DATA=true, cuando el paquete Full Stack se ejecuta con SEED_DEMO_DATA=false en el .env junto a docker-compose.yml, o, sin Docker, cuando se ejecutó yarn db:sync en lugar de yarn seed. No hay alojamientos ni ninguna cuenta con la que iniciar sesión.

  • Sin Docker: ejecuta yarn seed en la carpeta de la API. Añade la empresa de demostración y sus cuentas a las tablas que ya tienes.
  • Full Stack en Docker: quita SEED_DEMO_DATA=false del .env, y luego docker compose down -v y docker compose up. El volumen de datos se crea de nuevo con la empresa de demostración.
  • Contenedor de la API: elimina el contenedor, borra su volumen y vuelve a ejecutarlo con -e SEED_DEMO_DATA=true, como en Empieza de cero con datos de demostración nuevos, más abajo.

El contenedor nunca vuelve a cargar datos en una base de datos existente, diga lo que diga SEED_DEMO_DATA, así que la variable solo importa en un volumen nuevo.

El inicio de sesión falla

  • Comprueba la cuenta. El panel en el puerto 3031 acepta admin@hollina.example con Admin@123, o manager@hollina.example con Manager@123. El sitio web no tiene cuentas.
  • "Invalid email or password" responde igual a una contraseña incorrecta, a un correo desconocido y a una base de datos sin cuentas. Revisa los puntos siguientes por orden.
  • La base de datos no tiene cuentas cuando se creó con SEED_DEMO_DATA=false. Consulta El sitio web no tiene alojamientos y nadie puede iniciar sesión, más arriba.
  • "Demasiados intentos. Inténtalo de nuevo más tarde" Diez inicios de sesión fallidos desde una dirección en 15 minutos bloquean el formulario para esa dirección hasta que el fallo más antiguo tenga 15 minutos. Espera, o reinicia la API: el recuento se guarda en su memoria.
  • "Error de red. Comprueba tu conexión e inténtalo de nuevo" significa que el panel no puede llegar a la API: consulta el siguiente problema.
  • Cambiaste una contraseña y ya no la tienes: empieza de nuevo con datos de demostración nuevos, más abajo.

El inicio de sesión falla

  • Comprueba la cuenta y la ruta. Los administradores inician sesión en POST /api/auth/login; el Super Admin de la carga inicial es admin@hollina.example con Admin@123. Un inicio de sesión fallido responde 401 con el mismo mensaje tanto si el correo como si la contraseña es incorrecto.
  • Ninguna cuenta funciona: la base de datos se creó sin la empresa de demostración. Ejecuta yarn seed, o inicia el contenedor con -e SEED_DEMO_DATA=true en un volumen nuevo.
  • Una respuesta `429` significa que una dirección falló 10 inicios de sesión en 15 minutos. Se levanta cuando el fallo más antiguo cumple 15 minutos, o cuando la API se reinicia. RATE_LIMIT_LOGIN cambia el número.

El inicio de sesión falla

El panel inicia sesión contra la API de Hollina, así que la cuenta tiene que existir allí. En una API con datos iniciales, inicia sesión con admin@hollina.example y Admin@123. Si ninguna cuenta funciona, o la API se inició sin sus datos de demostración (ejecuta yarn seed en su carpeta, o inicia su contenedor en un volumen nuevo con -e SEED_DEMO_DATA=true), o la aplicación no puede llegar a la API: consulta el siguiente problema. El sitio web no tiene cuentas.

Las páginas dicen "Algo salió mal. Inténtalo de nuevo."

Lo que ves
Something went wrong. Try again.
Access to XMLHttpRequest at 'http://localhost:8000/api/…' from origin 'http://localhost:3041' has been blocked by CORS policy

El sitio web muestra la primera línea, y el panel dice "Network error", cuando el navegador no puede usar la API. La consola del navegador muestra la segunda línea cuando un frontend funciona en una dirección que la API no acepta. La API responde a los navegadores solo desde las direcciones de CORS_ORIGIN, que por defecto es http://localhost:3030 y http://localhost:3031. Un sitio web o un panel movido a otro puerto, o servido en tu propio dominio, es rechazado hasta que figure en la lista.

El .env de la API
CORS_ORIGIN=http://localhost:3030,http://localhost:3041
FRONTEND_URL=http://localhost:3041
  • Escribe cada dirección exactamente como la muestra el navegador, con el esquema y el puerto y sin barra final, separadas por comas. Luego reinicia la API.
  • FRONTEND_URL es la dirección del panel, desde la que se conectan sus notificaciones en directo, y SITE_URL la del sitio web, adonde un procesador de pagos devuelve al huésped. Mueve cada una junto con su aplicación.
  • Para un contenedor de la API, pasa los mismos valores con -e, por ejemplo -e CORS_ORIGIN=http://localhost:3030,http://localhost:3041.
  • Con el paquete completo en Docker no editas estos valores: los configuran SITE_PORT, ADMIN_PORT, SITE_URL y ADMIN_URL en el .env junto a docker-compose.yml.
  • Un frontend que no llega a la API en absoluto, porque está detenida o en otra dirección, falla de la misma forma pero sin la línea de CORS. Comprueba que localhost:8000/api/healthLocal responde y que NEXT_PUBLIC_API_BASE_URL del frontend apunta a esa API.

La pestaña de la página de un alojamiento dice "Alojamiento" en Docker

El propio servidor del sitio web lee el título del alojamiento para la pestaña del navegador, el primer renderizado de las páginas de inicio y de alojamiento y el mapa del sitio. Dentro de un contenedor, localhost es el propio contenedor, así que ese servidor no puede llegar a una API de tu equipo en http://localhost:8000. La página sigue cargando en el navegador, que llega a la API directamente.

Inicia el contenedor del sitio web con la dirección de la API tal como la ve el servidor:

Terminal
docker run -p 3030:3030 -e API_INTERNAL_URL=http://host.docker.internal:8000/api --add-host=host.docker.internal:host-gateway hollina-website

La pila completa en Docker lo define por ti (http://api:8000/api). Sin Docker no hace falta.

Las fotografías de los alojamientos no cargan

Las fotografías de la carga inicial las sirve la API en /media/hollina/…, y cada dirección de fotografía se construye a partir de PUBLIC_MEDIA_URL, que por defecto es http://localhost:8000/media. Una fotografía se rompe cuando esa dirección no llega a la API desde el navegador.

  • La API funciona en otro puerto o dominio. Configura PUBLIC_MEDIA_URL con la dirección pública de la API seguida de /media, por ejemplo -e PUBLIC_MEDIA_URL=http://localhost:8010/media con docker run -p 8010:8000. Con el paquete completo en Docker, API_PORT y API_URL lo configuran por ti.
  • La API se movió después del primer inicio. Reiníciala con el nuevo PUBLIC_MEDIA_URL: al iniciarse, apunta cada fotografía guardada a esa dirección, y su registro dice "Pointed … stored media URLs at …".
  • Los archivos subidos a un bucket no cargan. R2_PUBLIC_URL debe ser la dirección pública del bucket, y el bucket debe permitir lecturas públicas.
  • Las fotografías cargan, pero a tamaño completo. Los frontends solo redimensionan las fotografías de los hosts https de NEXT_PUBLIC_MEDIA_HOSTNAME (con Docker Compose, MEDIA_HOSTNAME), cada uno escrito solo como host y separados por comas, como api.your-company.com,pub-1234.r2.dev. Cualquier otra fotografía, como una de una API en localhost, se carga tal cual. Vuelve a construir el frontend después de cambiarlo.

La página de un alojamiento dice "No se pudo cargar el mapa."

El mapa dibuja sus teselas desde OpenFreeMap por defecto, así que necesita acceso a internet, y el servicio no promete disponibilidad. Comprueba la conexión, o define NEXT_PUBLIC_MAP_STYLE_LIGHT (y NEXT_PUBLIC_MAP_STYLE_DARK para el tema oscuro) con el estilo MapLibre de otro proveedor y vuelve a construir el sitio web.

Un cambio en el .env de un frontend no tiene efecto

Cada valor NEXT_PUBLIC_* se compila en el JavaScript que carga el navegador cuando se construye la aplicación. Cambiar el archivo no cambia nada hasta que la aplicación se vuelve a construir.

Cómo lo ejecutasDespués de cambiar un valor
yarn devDetenlo y vuelve a ejecutar yarn dev.
yarn build y yarn startVuelve a ejecutar yarn build y luego yarn start.
Docker ComposeEjecuta docker compose up --build. Configura el valor en el .env junto a docker-compose.yml, no en la carpeta de la aplicación.
docker build para una aplicaciónVuelve a construir la imagen con el valor como --build-arg.

Una reserva pagada se queda pendiente

Lo que ves
We are confirming your payment.
This is taking longer than usual.

Lo que confirma una reserva con tarjeta o PayPal es el webhook del procesador, nunca que el huésped vuelva al sitio. Hasta que llega, la página de la reserva espera, la reserva sigue pending y retiene sus noches durante 30 minutos, y luego un barrido la cancela por caducada.

  • Stripe: STRIPE_WEBHOOK_SECRET falta o es incorrecto, así que se rechaza todo webhook de Stripe. En local, ejecuta stripe listen --forward-to localhost:8000/api/webhooks/payments/stripe, pon el secreto que imprime en el .env de la API y reinicia la API. En un servidor, crea el endpoint en Stripe con la dirección pública de tu API.
  • PayPal: la página de retorno captura el pedido mediante POST /api/bookings/:reference/settle; el webhook necesita PAYPAL_WEBHOOK_ID, el id de una suscripción a PAYMENT.CAPTURE.COMPLETED en /api/webhooks/payments/paypal.
  • stripe trigger checkout.session.completed no confirma nada: un evento provocado no lleva referencia de reserva. En su lugar, completa un pago de prueba real en el navegador, con la tarjeta 4242 4242 4242 4242.

Se rechaza una reserva, una pregunta o una reseña

Lo que ves
Your payment was declined. Try another card or another way to pay.
That payment method is not available. Choose another way to pay.
Too many requests were sent from this connection. Please wait a few minutes and try again.
The selected dates do not meet the minimum stay.
  • Rechazada: sin un procesador, el simulador incluido rechaza un número de tarjeta que termina en 0, a propósito, para que se vea el camino del fallo. Cualquier otro número se acepta.
  • Método de pago no disponible: la API ya no acepta ese método, como PayPal cuando solo hay Stripe configurado, la tarjeta cuando solo hay PayPal, o el pago a la llegada después de desactivar su interruptor. No se escribió nada y no se retiene ninguna noche: recarga el pago, que entonces ofrece solo lo que la API acepta.
  • Se rechaza una pregunta o una reseña: el mensaje de una pregunta va de 10 a 4000 caracteres y el comentario de una reseña de 10 a 2000, y el formulario lo indica bajo el campo antes de enviar.
  • Demasiadas peticiones: cada dirección puede enviar cinco reservas, cinco preguntas y cinco reseñas en diez minutos. Mientras pruebas, espera o reinicia la API: los recuentos viven en su memoria.
  • Fechas rechazadas: cada alojamiento tiene su propio número mínimo de noches y máximo de huéspedes, un check-in no puede estar en el pasado, y las noches que retiene otra reserva o un bloqueo están ocupadas. Las reservas cubren [check-in, check-out), así que un huésped puede llegar el día en que otro se va.
  • Cancelación en línea rechazada: un huésped cancela desde la página de su reserva mientras está pendiente o confirmada y el check-in está al menos a siete días; después, la página indica que contacte con el anfitrión, que aún puede cancelar desde el panel.
  • Detrás de un proxy inverso, todos los visitantes pueden parecer el proxy y compartir una misma cuota: consulta el siguiente problema.

Todos los visitantes reciben "Too many" detrás de un proxy

El inicio de sesión, el pago, el formulario de preguntas y el de reseñas están limitados por dirección de visitante. Detrás de un proxy inverso, todos los visitantes pueden parecer la única dirección del proxy y compartir una misma cuota. Indica a la API cuántos proxies hay delante de ella:

El .env de la API
TRUST_PROXY=1

RATE_LIMIT_LOGIN cambia el número de inicios de sesión fallidos permitidos. Las cuentas están en la memoria de la API, así que un reinicio las borra.

El asistente dice que aún no está conectado

Lo que ves
The assistant is not connected yet. Add a Google Gemini key as GOOGLE_API_KEY in the API's .env file, restart the API, then ask again.

El asistente responde solo con Google Gemini, con la clave de GOOGLE_API_KEY en el .env de la API. En .env.example esa línea está comentada, así que un archivo copiado empieza limpio con el asistente desactivado y nada facturado.

  • Quita el # delante de GOOGLE_API_KEY, pega tu clave real de Google AI Studio sobre el ejemplo y reinicia la API.
  • Con Docker Compose la API también lee back-end/.env, así que basta con docker compose up otra vez; un contenedor de API suelto necesita --env-file .env -e NODE_ENV=production en su docker run.
  • Recarga la página del panel después del reinicio.

El asistente no puede responder con el modelo elegido

Lo que ves
{model} has no requests left on this API key right now. Pick a different model from the list above the chat, or try again in a few minutes.

Google rechazó la petición porque el cupo de la clave para ese modelo está agotado por ahora, o el modelo no tiene capacidad en este momento, y el mensaje nombra el modelo. El asistente ejecuta solo el modelo que elegiste: nunca cambia a otro por sí mismo ni reintenta por su cuenta. Elige otro modelo en la lista sobre el chat, o espera unos minutos y pulsa Reintentar. Los cupos se cuentan por modelo, así que otro suele responder todavía.

En modo demostración, el asistente pide la clave propia del visitante

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

Lo que dice el asistente de una demostración pública cuando se agotan sus mensajes gratuitos, y cómo dar más a los visitantes.

MySQL no arranca o no carga los datos

La API crea sus tablas en una base de datos que ya existe; no crea la base de datos en sí. Crea primero una base de datos vacía, pon su nombre en DB_DATABASE en el .env de la API y luego ejecuta yarn seed (o yarn db:sync para las tablas sin datos de demostración).

  • Revisa los cinco valores de conexión DB_* y que DB_TYPE=mysql.
  • Con NODE_ENV=production la API en ejecución nunca crea tablas, así que uno de esos comandos tiene que ejecutarse antes del primer inicio (yarn seed:prod o yarn db:sync:prod después de yarn build).
  • La imagen de Docker crea la base de datos por sí sola solo con SQLite. Con MySQL, ejecuta tú mismo una vez la carga de datos o el comando del esquema.

El contenedor de la API no encuentra su entrypoint

Lo que ves
exec /usr/local/bin/docker-entrypoint.sh: no such file or directory

El script tiene finales de línea de Windows, que un editor o Git en Windows pueden añadir. El Dockerfile de la API incluido los elimina durante la construcción, así que esto solo aparece con una imagen construida a partir de un Dockerfile modificado. Conserva su línea sed -i 's/\r$//', o guarda el script con finales de línea LF, y vuelve a construir sin la caché.

El comando unzip falla o la carpeta se ve distinta

Lo que ves
caution: filename not matched:  hollina-…zip

Ese mensaje significa que hay dos ZIP del mismo paquete en la carpeta, como una descarga anterior junto a la nueva, y el * del comando coincidió con ambos. Elimina el ZIP más antiguo y ejecuta el comando otra vez, o escribe el nombre completo del archivo en lugar del *.

Ejecuta los siguientes comandos dentro de la carpeta en la que se extrae el ZIP. Si falta el comando unzip, extráelo con tu gestor de archivos; algunas herramientas añaden una carpeta extra con el nombre del ZIP, así que entra en la interior.

PaqueteCarpetaContiene
Full Stackhollina-vacation-rental-full-stackadmin-dashboard, back-end, storefront, docker-compose.yml
Stays Websitehollina-websiteDockerfile, package.json, .env.example
Booking Dashboardhollina-booking-dashboardDockerfile, package.json, .env.example
API Backendhollina-backendDockerfile, docker-entrypoint.sh, package.json, .env.example

Empieza de cero con datos de demostración nuevos

Esto elimina tus datos

Todo lo que creaste en local se elimina, y la empresa de demostración se carga de nuevo.

Con el paquete Full Stack en Docker, desde la carpeta hollina-vacation-rental-full-stack:

Terminalen hollina-vacation-rental-full-stack
docker compose down -v
docker compose up

Con un solo contenedor de la API, elimina primero el contenedor (docker ps -a lo lista, docker rm -f con su id lo elimina), luego borra el volumen hollina-api-data y ejecútalo de nuevo. El paquete Full Stack guarda sus datos en otro volumen, hollina-data, así que esto nunca lo toca.

Terminal
docker volume rm hollina-api-data
docker run -p 8000:8000 -v hollina-api-data:/data -e SEED_DEMO_DATA=true hollina-api

Sin Docker, detén la API y luego, en su carpeta:

Terminal
rm -f database.sqlite* && yarn seed

En PowerShell:

Terminal
Remove-Item database.sqlite*; yarn seed

Ejecutar yarn seed de nuevo sobre una base de datos que conservas no es un restablecimiento: nunca restablece una contraseña y no añade nada dos veces, reescribe los alojamientos, reservas y ajustes de la empresa incluidos con sus valores originales, y conserva los alojamientos, reservas y otras filas que creaste. yarn db:reset elimina todas las tablas, tanto en SQLite como en MySQL; ejecuta yarn seed después.

¿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.