Tu primera web con Firebase Hosting: pruébala en local antes de publicar

Prepara una web con dos páginas, arráncala en el emulador oficial de Firebase Hosting y comprueba cambios y errores 404 sin publicar ni crear una cuenta.

Quieres preparar una web con Firebase Hosting, pero todavía no necesitas publicarla. Antes de elegir un dominio o desplegar, hay algo más pequeño que podemos comprobar: qué archivos se van a servir, si los enlaces funcionan y qué pasa cuando una página no existe.

Vamos a hacerlo con dos archivos HTML y el emulador oficial de Hosting. Al terminar verás tu página en el navegador, cambiarás un título y comprobarás un error 404 real. No crearemos un proyecto remoto ni iniciaremos sesión en Google.

Ilustración original de una web en miniatura junto a una carpeta public, como representación de una práctica local de Firebase Hosting.

Portada conceptual generada con IA. Las capturas de los pasos siguientes sí proceden de la ejecución real del ejemplo.

Qué necesitas y qué vamos a probar

Un ordenador con Node.js 24 y npm, un editor de texto, un navegador y una terminal. No necesitas saber programar en JavaScript: nuestra web tiene HTML y CSS; Node se utiliza para ejecutar la herramienta de Firebase.

Si no tienes Node, instala una versión compatible desde su sitio oficial. Para repetir esta prueba se ha utilizado Node 24.19.0 y Firebase CLI 15.34.0 en macOS 27.0.1. El descargable fija esa versión del CLI y sus dependencias mediante package-lock.json. La referencia del CLI explica sus requisitos y opciones de instalación; conviene revisarlos de nuevo cuando actualices las herramientas.

No instalaremos el CLI de forma global. Lo dejaremos dentro de la carpeta de esta práctica, para no sustituir el que uses en otros proyectos. La primera instalación descarga paquetes públicos y utiliza espacio en disco. El código propio del ejemplo tiene licencia MIT; Firebase CLI conserva su licencia y las de sus dependencias.

Esta práctica local no requiere cuenta de Google, tarjeta ni recursos cloud. Hosting remoto es otro paso: tiene planes, cuotas y posibles costes que se deben revisar antes de publicar. Aquí no elegimos un plan ni prometemos alojamiento ilimitado. Cuotas y precios oficiales de Hosting.

Descarga el ejemplo completo y extrae la carpeta firebase-hosting-local. No trabajes directamente dentro del ZIP.

1. Revisar la carpeta antes de ejecutar nada

Dentro encontrarás:

firebase-hosting-local/
  public/
    index.html
    acerca.html
  firebase.json
  package.json
  package-lock.json
  comprobar.mjs
  LEEME.md
  LICENSE

La carpeta public contiene lo que queremos que vea el navegador. firebase.json indica cómo servirlo. package.json prepara los comandos del ejercicio y fija la herramienta que vamos a utilizar.

El resto es material de apoyo. No hay claves, archivos de una cuenta ni un SDK conectado a una base de datos.

2. Comprobar qué Node está usando tu terminal

Abre la terminal dentro de la carpeta extraída, donde está package.json, y ejecuta:

node --version
npm --version

Para seguir este ejemplo, node --version debe mostrar una versión 24.x. Si tu editor y tu terminal utilizan versiones distintas, resuélvelo antes de seguir. Tener Node instalado en alguna parte del ordenador no garantiza que ese comando esté utilizando la versión que esperabas.

En Windows puedes utilizar PowerShell. Los archivos no dependen de macOS, pero la comprobación de esta entrega se ha realizado en macOS: no se ha probado Windows ni Linux durante su preparación.

3. Instalar la herramienta en esta carpeta

npm ci

El comando utiliza el archivo de bloqueo incluido y crea node_modules. No publica la web ni necesita firebase login. No añadas -g: queremos una instalación local a la práctica.

Después, consulta la versión local:

npm exec -- firebase --version

En este descargable debe aparecer 15.34.0. Los comandos npm run de los siguientes pasos usan esa herramienta local; no dependen de que un firebase global tenga otra versión.

4. Entender las dos decisiones de firebase.json

Abre firebase.json. La parte principal es:

{
  "hosting": {
    "public": "public",
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "headers": [{
      "source": "**",
      "headers": [{"key": "Cache-Control", "value": "no-store"}]
    }]
  },
  "emulators": {
    "hosting": {"host": "127.0.0.1", "port": 5005},
    "ui": {"enabled": false},
    "singleProjectMode": true
  }
}

hosting.public señala la carpeta que se sirve. El puerto 5005 pertenece a esta práctica local; no será el puerto público de una futura web en Firebase.

La dirección 127.0.0.1 limita el acceso a este ordenador. La cabecera no-store facilita comprobar los cambios sin conservar respuestas en caché; es una decisión del ejercicio, no una recomendación general para el rendimiento de una web publicada. Configuración de Hosting.

Captura real del archivo firebase.json del ejemplo, abierto como texto: carpeta public y emulador en 127.0.0.1:5005.

Archivo real del descargable. No es un formulario de la consola Firebase.

5. Arrancar solo el emulador de Hosting

npm run hosting

Ese nombre corto ejecuta:

firebase emulators:start --only hosting --project demo-cloud-basico --config firebase.json

El identificador demo-cloud-basico pertenece al modo de demostración de los emuladores; no estamos seleccionando un proyecto de producción. --only hosting acota el recorrido al servidor de Hosting. No arrancamos Firestore, Authentication ni Functions.

Deja la terminal abierta. Busca el mensaje que indica que Hosting sirve los archivos y su dirección local. La guía oficial explica este uso del emulador de Hosting para probar antes de publicar.

Captura de la salida real del emulador oficial: sirve public y anuncia el servidor local en 127.0.0.1:5005.

Salida original de la ejecución, guardada y abierta como texto. No es una terminal dibujada ni una pantalla de un proyecto cloud. El aviso de que no arranca Emulator UI es normal aquí: la hemos desactivado y Hosting no la necesita para servir estas páginas.

6. Abrir la página que está sirviendo Firebase

Abre http://127.0.0.1:5005/.

Captura real de la página principal servida por Firebase Hosting en local, con el título Mi primera web de práctica y enlaces a dos rutas.

La respuesta comprobada es HTTP 200. La página se identifica expresamente como ejemplo del emulador local.

Ahora estás haciendo una petición HTTP al emulador. Es diferente de abrir index.html con doble clic y una dirección file://: queremos comprobar cómo se sirve la carpeta y cómo se resuelven sus rutas.

Si no aparece la página, comprueba primero que la terminal siga abierta y que hayas escrito el puerto 5005. Que la herramienta anuncie que está lista no basta: la página tiene que responder.

7. Seguir un enlace hasta otro archivo

Pulsa Abrir la segunda página. Se abrirá /acerca.html.

Captura real de la segunda página HTML del ejemplo servida por el emulador, con un enlace para volver al inicio.

Segunda respuesta HTTP 200. El enlace de regreso lleva a la portada local.

Ese archivo está dentro de public. No hemos creado una ruta con código de servidor ni una base de datos. Para esta web pequeña basta con conservar un nombre de archivo y un enlace que coincidan, incluidas las mayúsculas.

8. Ver un 404 que no debemos ocultar

Vuelve al inicio y pulsa Comprobar una ruta que no existe. El enlace apunta a /no-existe.html, un archivo que deliberadamente no hemos incluido.

Captura real de la página 404 que devuelve el emulador de Firebase Hosting para una ruta inexistente.

Esta petición devuelve HTTP 404. Es el resultado esperado de este paso, no una prueba fallida del tutorial.

No añadimos una regla que envíe todas las rutas a index.html para hacer desaparecer el error. Ese tipo de reescritura puede ser adecuado en una aplicación con enrutamiento propio, pero nuestra web tiene archivos separados. Primero hay que entender qué estás sirviendo.

La respuesta a /firebase.json también se ha comprobado: devuelve 404, porque el archivo de configuración está fuera de public.

9. Cambiar algo y comprobar que cambia de verdad

Abre public/index.html en tu editor. Dentro de <h1>, sustituye:

<h1>Mi primera web de práctica</h1>

por:

<h1>Mi web actualizada</h1>

Guarda el archivo y recarga la página en el navegador. No basta con dejar abierta la pestaña: este ejemplo no incorpora recarga automática del navegador.

Captura real de la página después de guardar y recargar: el encabezado muestra Mi web actualizada.

El archivo se modificó de verdad antes de esta captura. Después se restauró para que el ZIP empiece con el título inicial.

Si sigues viendo el título anterior, confirma que editas el archivo de esta carpeta y que has guardado. Cambiar otra copia del ZIP no cambia el servidor que ya tienes arrancado.

10. Detener el servidor de la práctica

Vuelve a la terminal que ejecuta el emulador y pulsa Ctrl+C. Espera a que termine.

Al recargar la dirección local, dejará de responder. Los HTML siguen en tu carpeta: detener el emulador no los borra. Para continuar otro día, vuelve a abrir la terminal en esa carpeta y ejecuta npm run hosting.

Si 5005 está ocupado por otro programa, detén esta práctica, cambia emulators.hosting.port en firebase.json y utiliza la nueva dirección. No cierres un proceso ajeno sin saber qué está haciendo. El conjunto de emuladores también puede reservar puertos para su coordinación; consulta la salida real si aparece un conflicto.

11. Ejecutar la comprobación incluida

Restaura primero el encabezado original si lo habías cambiado y detén tu emulador. Después ejecuta:

npm run comprobar

El script arranca otro emulador oficial, utiliza el mismo firebase.json y comprueba:

  • Inicio y segunda página con HTTP 200.
  • Archivo inexistente y configuración fuera de public con HTTP 404.
  • Cabecera Cache-Control: no-store.
  • Edición real del título, lectura del cambio y restauración del archivo original.

Al terminar detiene el proceso que ha creado y guarda prueba-emulador.log en la carpeta. No toca un proyecto remoto. Si el puerto ya responde, se detiene antes de probar para no confundir otro servidor con el de este ejercicio.

La prueba incluida también se ha ejecutado desde una extracción nueva del ZIP, con la instalación local de sus dependencias. No sustituye revisar tus propios cambios en el navegador, pero evita quedarnos solo con una pantalla de arranque correcta.

12. Si el emulador arranca pero devuelve un error 500

Este problema apareció al preparar el artículo. Con Firebase CLI 13.23.1 y Node 23.10.0, el emulador anunciaba que estaba listo, pero la primera petición devolvía 500. En la salida aparecía:

TypeError: Cannot read properties of undefined (reading 'getTime')

La excepción procedía de la dependencia Superstatic utilizada por esa instalación. No era un error de permisos de una cuenta de Firebase ni un problema que se arreglase iniciando sesión.

La combinación verificada para esta entrega es Firebase CLI 15.34.0 con Node 24.19.0. Su versión de Superstatic contempla mtimeMs en la lectura de fechas de los archivos. Con esa combinación se repitieron la página inicial, el segundo HTML, el 404 y la edición, esta vez correctamente. Código oficial de Firebase CLI para esta versión.

No hemos parcheado a mano un archivo de node_modules, cambiado permisos del sistema ni sustituido la herramienta global del ordenador. El descargable utiliza su propia versión local. Si te ocurre algo parecido, compara las versiones y lee el primer error del log antes de cambiar la configuración de tu web.

Lo que has preparado y el siguiente paso

Ya tienes una web estática pequeña, un directorio público acotado y una forma de probarla. Todavía no está publicada en Internet. Esta entrega no verifica CDN, HTTPS remoto, cuotas de un proyecto, permisos IAM ni despliegue.

Firebase Hosting y Firebase App Hosting son productos distintos; este ejercicio es de Hosting estático. Tampoco contiene Firestore ni reglas de acceso a datos. Esos permisos se tratarán aparte.

Para publicar habría que elegir un proyecto autorizado, revisar el plan y sus cuotas, comprobar de nuevo el directorio público y ejecutar un despliegue consciente. Lo veremos en otra entrega con su propia prueba remota. No hace falta adelantar ese paso para aprender cómo funcionan los archivos y las rutas.

Ejemplo, capturas y vista previa comprobados el 20 de octubre de 2026. Chrome 153 en una sesión aislada y una ventana estrecha de 390 píxeles; no teléfono físico. El descargable contiene el código, las instrucciones y la comprobación, con licencia MIT para el material propio.