Tu aplicación funciona. Arrancaste el servidor de desarrollo, abriste http://localhost:3000, y hace lo que se supone que debe hacer. Entonces alguien te pide un enlace, y descubres que la URL de tu pantalla no significa nada para nadie más que para ti.
Hay tres formas de darle una URL pública a una aplicación localhost sin un VPS, más una opción más rápida cuando la otra persona está en tu red local, y elegir entre ellas no es una cuestión de herramientas. Es una cuestión de cuánto tiempo tiene que seguir accesible, y de si puede ejecutarse en algún sitio que no sea tu portátil. A continuación, cada camino, el comando que consigue una URL, y exactamente qué hará que esa URL deje de funcionar.
TL;DR
- Alguien en tu Wi-Fi necesita verla: vincula el servidor de desarrollo a todas las interfaces de red y pasa tu IP de la LAN. Listo en segundos, muerto en cuanto tu visitante abandona tu red.
- Necesitas un enlace que cualquiera pueda abrir durante la próxima hora: ejecuta un túnel (
cloudflared, ngrok, localtunnel, localhost.run). URL HTTPS pública en más o menos un minuto, sin cambios en el router, y muere con el proceso que la inició. - Tiene que seguir en marcha con el portátil cerrado: sube la aplicación a un plan de hosting gratuito. Eso desacopla la aplicación de tu portátil e introduce nuevas reglas sobre tarjetas de crédito, uso comercial y si tus datos sobreviven a un reinicio.
- Tu aplicación no necesita código de servidor en el momento de la petición: compílala y coloca la salida estática en un host estático. Puede seguir en línea sin tu portátil y no tiene ningún proceso de aplicación que despertar, siempre que la cuenta y los límites de uso del host lo sigan permitiendo.
- Un valor por defecto que conviene conocer:
next devypython -m http.serverya escuchan en todas las interfaces de red sin ningún flag. Si dabas por hecho que tu servidor de desarrollo era privado y solo visible desde tu portátil, no lo es.
Qué camino encaja con tu aplicación
Tres de estos cuatro caminos le dan a tu aplicación una URL pública en internet; el primero solo llega a tu propia red, lo que lo convierte a la vez en el más rápido y el más limitado. Ordénalos por cuánto tiempo tiene que sobrevivir la URL y la elección se hace prácticamente sola.
| Vía | Tiempo hasta tener una URL | Cuánto dura | Qué la mata | Para quién es |
|---|---|---|---|---|
| Misma red | Segundos | Mientras los dos estéis en la red | Tu visitante se cambia a otra Wi-Fi | Un compañero en la mesa de al lado, o tu propio teléfono |
| Túnel | Un minuto aproximadamente | Mientras el proceso se ejecuta | Cerrar el portátil, matar el terminal, alcanzar los topes del plan | Una demo, una presentación a un cliente, una prueba de webhook |
| Plan de hosting gratuito | De 10 a 30 minutos | Indefinidamente, con condiciones | Suspensión por inactividad, un sistema de archivos efímero o los términos del plan | Algo que tiene que responder mientras duermes |
| Build estático | De 10 a 20 minutos | Indefinidamente | Necesitar código del lado del servidor en el momento de la petición | Aplicaciones que se pueden generar por completo en el build o ejecutarse en el cliente |
Qué filas están a tu alcance depende de tres cosas que puedes comprobar dentro de tu propio proyecto:
- ¿La aplicación necesita ejecutar tu código de servidor en el momento de la petición? Una ruta de Flask o FastAPI, un endpoint de
server.js, o lógica de servidor específica de cada petición necesita un host del lado del servidor. El código de servidor que se ejecuta en el build no descarta automáticamente un despliegue estático: los Server Components de Next.js pueden ejecutarse durantenext build, y losGETRoute Handlers estáticos se pueden prerenderizar. Si cada petición en tiempo de ejecución puede servirse como recursos estáticos o enviarse directamente desde el navegador a una API externa, el camino estático sigue abierto. - ¿Lee o escribe un archivo que necesita conservar? Un archivo de base de datos (
.db,.sqlite), una carpeta de subidas, un archivo JSON que edita. Si es así, comprueba el modelo de almacenamiento del host antes de desplegar. Los servicios web gratuitos de Render y las instancias gratuitas de Koyeb usan almacenamiento local efímero, mientras que las Vercel Functions tienen un sistema de archivos de solo lectura con un espacio/tmptemporal. Guarda el estado persistente en un volumen duradero, una base de datos o un almacén de objetos, en lugar de suponer que el disco local de la aplicación sobrevivirá. - ¿Necesita un secreto en tiempo de ejecución? Una clave en un archivo
.envfunciona sin tocarla en los dos primeros caminos, porque la aplicación sigue ejecutándose en tu máquina. En los otros dos la vuelves a introducir en la configuración de entorno del proveedor, y no debe estar en el repositorio que subes.
Compártela en tu propia red
next dev ya escucha en todas las interfaces de red de tu máquina (eso es todo lo que significa 0.0.0.0 cuando lo ves), y lo mismo hace python -m http.server. Ninguno necesita un flag, así que el servidor de desarrollo que tienes en marcha ahora mismo probablemente ya es accesible desde tu teléfono en la misma Wi-Fi.
Next.js documenta -H como la forma de cambiar ese nombre de host, con un valor por defecto de 0.0.0.0, y la documentación de Python dice que el módulo se vincula a todas las interfaces a menos que pases --bind 127.0.0.1. Eso lo convierte en la forma más rápida de compartir una aplicación localhost: sin cuenta, sin instalación, sin despliegue. A los demás servidores de desarrollo habituales hay que decírselo.
# Already listening on all interfaces. Nothing to add.
next dev
python -m http.server 8000
streamlit run app.py
# Needs the flag.
npm run dev -- --host # Vite
flask run --host=0.0.0.0
uvicorn main:app --host 0.0.0.0 # FastAPI
La documentación de Vite: server.host tiene como valor predeterminado localhost, y acepta --host en la CLI o server.host: '0.0.0.0' en el archivo de configuración. Uvicorn usa por defecto 127.0.0.1, lo que cubre a FastAPI, ya que es lo que lo ejecuta. Streamlit deja server.address sin definir, y su referencia de configuración indica que definirlo restringe el acceso a esa única dirección: sin definir significa sin restricciones.
Después necesitas la dirección que vas a pasar. Es la IP de tu propia máquina en la red local, no localhost:
# macOS
ipconfig getifaddr en0
# Linux
hostname -I
# Windows (PowerShell)
ipconfig | findstr IPv4
Dale a tu visitante http://<that-address>:3000 y ya está dentro. La pega es la forma de todo el camino: esa dirección no significa nada fuera de tu red. En cuanto esté en otra Wi-Fi, con datos móviles o en su casa, el enlace estará muerto para él.
Nota: si el comando se ejecuta bien y el otro dispositivo sigue sin poder conectarse, casi siempre es el cortafuegos del sistema operativo, no el comando. La documentación del cortafuegos de Apple dice que macOS muestra una alerta para una aplicación que aún no has permitido y deniega la conexión hasta que actúes. Windows, en cambio, pregunta qué perfil de red se aplica, manteniendo reglas separadas para redes privadas y públicas . Elige Privada en una red doméstica o de oficina. Nunca Pública.
Ponla detrás de un túnel
Un túnel es un pequeño programa que se ejecuta junto a tu aplicación y le da una dirección HTTPS pública. Un solo comando te consigue un túnel gratuito a localhost en más o menos un minuto, y conviene saber desde el principio que la URL muere en el momento en que ese comando termina:
cloudflared tunnel --url http://localhost:3000
Nada cambia en tu router, por la dirección en la que viaja la conexión. Tu máquina abre una conexión saliente hacia el borde de red del proveedor, del mismo tipo que abre tu navegador para cargar cualquier página, y el proveedor la mantiene abierta y empuja las peticiones entrantes de vuelta por ella. Los puertos entrantes de tu lado siguen cerrados, y por eso funciona en la Wi-Fi de un hotel, en el punto de acceso de un móvil y en una conexión doméstica cuyo router no controlas.
Nota: ese último caso merece una comprobación de sesenta segundos antes de plantearte redirigir puertos. Abre la página de estado de tu router, busca la IP WAN que indica y compárala con tu IP pública real usando cualquier buscador de «cuál es mi IP». Si la IP WAN está dentro de
100.64.0.0/10, la causa probable es CGNAT. Si la IP WAN y la IP pública simplemente difieren, sabes que hay otra capa de NAT aguas arriba, pero puede ser CGNAT o un doble NAT corriente. En cualquiera de los dos casos, redirigir puertos solo en este router puede no bastar. Ese rango está reservado por la RFC 6598 como espacio de direcciones compartido, que es donde te coloca tu proveedor de internet cuando se queda sin direcciones.
Las opciones se diferencian sobre todo en lo que te piden primero.
Los túneles rápidos de Cloudflare son el comando de arriba: sin cuenta, sin dominio, un subdominio aleatorio de trycloudflare.com . Cloudflare los limita a 200 peticiones en curso, devolviendo 429 a partir de ahí, no admite Server-Sent Events, y en la misma documentación dice que los túneles gratuitos son para pruebas y desarrollo, no para desplegar un sitio web en producción.
ngrok requiere registrarse primero, y después ngrok http 3000. El plan gratuito actual te da 5 $ de uso incluido por una sola vez que no se renueva cada mes, hasta 3 endpoints en línea, 1 GB de transferencia, 20 000 peticiones HTTP/S y una página de aviso intermedia que tu visitante tiene que aceptar. También recibes un dominio de desarrollo gratuito asignado automáticamente, que ngrok anunció en 2023 para acabar con la vieja queja de que la URL cambiaba en cada reinicio.
localtunnel no necesita registro ni instalación más allá de npx: npx localtunnel --port 3000. Obtienes un subdominio aleatorio, y el README deja claro que --subdomain pide un nombre y no lo garantiza.
localhost.run no instala nada, porque usa el cliente SSH que ya trae tu sistema operativo: ssh -R 80:localhost:3000 localhost.run. Su documentación señala que no hace falta descargar nada y que no se necesita crear ninguna cuenta para los dominios gratuitos.
VS Code lo tiene en el panel Ports, práctico si ya vives dentro del editor. Exige iniciar sesión con GitHub o Microsoft, y el valor por defecto te va a jugar una mala pasada: un puerto reenviado es Privado, lo que significa que a tu visitante se le pedirá iniciar sesión con tu cuenta hasta que cambies el puerto a Público. (Bien para un compañero de equipo. Inútil para el cliente que solo quiere hacer clic en un enlace.)
Tailscale Funnel también lo hace, con dos restricciones que suelen decidirlo: la URL solo puede vivir en el dominio de tu propio tailnet, y solo puede escuchar en los puertos 443, 8443 y 10000.
Elijas lo que elijas, ten claro qué has repartido. Con un túnel público sin controles de acceso, todo lo que sirve el servidor de desarrollo es accesible para cualquiera que tenga esa URL, incluidas rutas que nunca enlazaste y cualquier interfaz de depuración que dejaras activa. Bien para una demo de quince minutos. Mucho menos bien para una URL que pegas en un Discord público.
La caducidad te pilla desprevenido porque puede parecer que la aplicación se ha roto. La mayoría de las rutas rápidas de aquí siguen dependiendo de un software de túnel que se ejecuta en tu portátil: detén cloudflared, ngrok, localtunnel o la sesión SSH de localhost.run y el reenvío se detiene. Tailscale Funnel es la excepción cuando lo ejecutas con --bg, que mantiene la configuración de Funnel en segundo plano y la restaura tras un reinicio. Ninguno de ellos puede servir tu aplicación local mientras el propio portátil esté desconectado. Puedes dejar un túnel en marcha durante días, y funcionará justo hasta que se cierre la tapa o alcances el tope de peticiones.
Un túnel es la herramienta correcta para una demo y la herramienta equivocada para el hosting: su disponibilidad es la de tu portátil.
Deja que la aplicación salga de tu máquina
Este es el primer camino en el que tu portátil deja de ser imprescindible, y el primero en el que los términos importan más que las herramientas. Lo que lo termina aquí no es un reloj. Es una suspensión por inactividad, un reinicio del sistema de archivos, o un plan que decide que tu aplicación no es el tipo de cosa que quiere en una instancia gratuita.
Las opciones de abajo van desde planes gratuitos permanentes hasta pruebas cortas. Algunas pueden mantener una aplicación en línea indefinidamente dentro de sus límites; otras se detienen tras una prueba de duración fija o exigen una cuenta de pago para el cómputo. Revisa las reglas de facturación, suspensión y almacenamiento antes de desplegar.
Los términos de los planes gratuitos de abajo se comprobaron en la página de precios o de documentación de cada proveedor el 7 de septiembre de 2026.
| Proveedor | ¿Uso comercial? | ¿Los datos sobreviven a un reinicio? | La pega |
|---|---|---|---|
| Netlify | Permitido | Sí, con Netlify Blobs o Database | Sin tarjeta para empezar; agotar todos los créditos mensuales del plan Free pausa los proyectos hasta el siguiente ciclo de facturación, salvo que mejores el plan |
| Render | No indicado | Se pierden al reiniciar | Sin tarjeta para empezar; se suspende tras 15 minutos de inactividad; el Postgres gratuito caduca 30 días después de crearse |
| Cloudflare Pages / Workers | No indicado | Sí, con KV, D1, R2 o Durable Objects | 500 builds de Pages al mes; el plan gratuito de Workers se queda en 100 000 peticiones al día |
| Vercel | No en Hobby | Se pierden al reiniciar | Hobby es solo para uso personal; el sistema de archivos de las funciones es de solo lectura |
| GitHub Pages | No permitido | Solo salida estática | Nada de negocios en línea, e-commerce ni SaaS comercial; tiempo límite de despliegue de 10 minutos |
| PythonAnywhere | No indicado | Sí | Las cuentas gratuitas solo alcanzan una lista blanca de hosts externos; la aplicación web gratuita caduca al cabo de un mes salvo que se renueve |
| Fly.io | No indicado | Sí, con un Fly Volume | Sin plan gratuito permanente: 2 horas de máquina o 7 días; las Machines de prueba se detienen automáticamente tras 5 minutos en ejecución, y la prueba incluye 20 GB de almacenamiento en volumen; las aplicaciones se detienen al terminar la prueba hasta que añadas una tarjeta |
| Koyeb | No indicado | Sin almacenamiento local duradero | Tarjeta obligatoria; Koyeb realiza y cancela una preautorización de 29 $, pero el registro selecciona Pro por defecto y cobra su coste prorrateado salvo que cambies a Starter |
| Hugging Face Spaces | No indicado | Se pierden al reiniciar | Los Static Spaces son gratuitos; Gradio y Docker suelen requerir un plan de pago, pero las cuentas personales gratuitas que cumplan los requisitos pueden alojar hasta dos Spaces de Gradio en ZeroGPU |
| Railway | No indicado | Sí, si la aplicación usa el volumen de 0,5 GB incluido | Prueba de 30 días con 5 $ de crédito único, y después un plan Free de 0 $ con 1 $ de crédito de recursos al mes; no se requiere tarjeta |
«No indicado» significa que las páginas del propio proveedor no responden a la pregunta para su plan gratuito. Trátalo como una incógnita, no como un sí ni como un no.
Tres de esas filas merecen un vistazo extra antes de empezar. Fly.io no tiene plan gratuito permanente: su prueba termina tras 2 horas de máquina o 7 días. Koyeb incluye una instancia gratuita, pero su proceso de registro y facturación requiere atención antes de desplegar. Hugging Face mantiene gratuitos los Static Spaces, mientras que los nuevos Spaces de Gradio y Docker exigen una cuenta de pago, salvo la excepción limitada de ZeroGPU. Railway ya no pertenece a esta lista de advertencias: tras su prueba de 30 días con 5 $ de crédito, ahora pasa a un plan Free de 0 $ con 1 $ de crédito de recursos al mes.
Luego está la cuestión de los datos, que es donde una aplicación que funciona se convierte en silencio en una rota. Los servicios web gratuitos de Render se ejecutan en un sistema de archivos efímero, y su documentación es tajante: todo lo que se escriba ahí, incluidas expresamente las imágenes subidas y las bases de datos SQLite locales, se pierde en cada redespliegue, reinicio y suspensión. Las funciones de Vercel se ejecutan en un sistema de archivos de solo lectura con apenas un espacio temporal, así que un archivo SQLite que escriba tu aplicación tampoco está a salvo ahí. Si tu aplicación guarda el estado en un archivo, muévelo a un almacenamiento duradero: una base de datos alojada, un almacén de objetos o un volumen persistente allí donde la plataforma lo ofrezca.
La suspensión por inactividad merece sentirse antes de comprometerse. En el plan gratuito de Render, 15 minutos de inactividad ponen el servicio a dormir, y la siguiente petición lo despierta en alrededor de un minuto, mostrando una página de carga a quien haya hecho clic en tu enlace. Para una pieza de portafolio, un encogimiento de hombros. Para un cliente que abre el enlace en una llamada, sesenta segundos muy malos.
PythonAnywhere tiene una versión más sutil de la trampa. No hay suspensión por inactividad, pero una aplicación web gratuita caduca al mes y se detiene salvo que hagas clic en el enlace de renovación que PythonAnywhere te envía por correo, y las cuentas gratuitas tienen acceso saliente a internet restringido y solo alcanzan una lista blanca de hosts externos. Una aplicación que llama a una API fuera de esa lista se queda ahí perfectamente en línea y falla en cada petición a esa API no autorizada (una forma horrible de depurar, porque nada parece caído en ningún sitio).
Publícala como sitio estático
Si nada de lo que hace tu aplicación requiere código de servidor en el momento de la petición, un host estático es lo más parecido a «configurar y olvidarse»: puede seguir en línea sin tu portátil, y no hay ningún proceso de aplicación esperando a despertarse. La cuenta y los límites de uso del host siguen aplicándose. Más aplicaciones cumplen los requisitos de lo que esperarías, y por eso la primera de esas tres preguntas merece respuesta antes de dar por hecho que necesitas un host del lado del servidor.
La regla es más estrecha que «¿tiene backend?». Tu aplicación cumple si cada petición que hace va o bien a tus propios archivos estáticos, o bien directamente del navegador a la API de otro. Consultar Supabase o una API pública desde el navegador está bien, con la única salvedad de que una clave en el código del navegador es una clave que has publicado. Lo que cierra la puerta es necesitar que tu propio código se ejecute en un servidor en cada petición.
Si cumple, el proceso es corto:
npm run build # Vite writes to dist/, a Next.js static export writes to out/
Luego despliega esa salida del build en un host estático. Cloudflare Pages, Netlify y Vercel pueden compilar desde un repositorio conectado. GitHub Pages puede publicar archivos estáticos desde una rama o usar GitHub Actions para ejecutar el build de tu framework y desplegar la salida generada.
GitHub Pages tiene restricciones lo bastante marcadas como para importar desde el principio. Solo estático, un único sitio de usuario u organización por cuenta, y unos límites de uso que declaran que no es hosting gratuito para un negocio, un sitio de e-commerce ni un SaaS comercial. Si tu aplicación va a cobrar pagos, eso la descarta antes de empezar.
Este camino no tiene caducidad del proceso de aplicación. Sigue funcionando mientras la cuenta de hosting siga activa y dentro de sus límites, y deja de encajar en cuanto la aplicación necesita trabajo del lado del servidor en el momento de la petición.
Dónde terminan los caminos gratuitos
Los caminos gratuitos fallan en sitios distintos, no todos a la vez. Un host estático ya resuelve la disponibilidad del portátil y te da una URL estable del proveedor. Un host de aplicaciones gratuito puede hacer lo mismo, y algunos ahora incluyen almacenamiento persistente. Un VPS empieza a tener sentido cuando los requisitos se acumulan: tu propio proceso del lado del servidor tiene que seguir en línea, necesitas almacenamiento persistente predecible, y las reglas de recursos o de uso del plan gratuito ya no encajan.
Ese umbral merece respeto. Una demo no es motivo para comprar un servidor, y tampoco lo es un proyecto estático con poco tráfico. Quédate en un túnel para compartir algo de corta duración, quédate en un host estático mientras la aplicación sea realmente estática, y quédate en un host de aplicaciones gratuito mientras sus límites encajen con lo que ejecutas.
Pásate a un VPS cuando necesites un servidor siempre encendido que controles tú y estés dispuesto a asumir el trabajo operativo que conlleva. Nuestro VPS Linux es una opción, y un VPS comparable de otro proveedor puede hacer el mismo trabajo. Dimensiona el servidor para la aplicación en lugar de suponer que el plan más pequeño bastará.
Construye sobre un VPS Linux con acceso root, NVMe y la potencia de AMD EPYC.
Ver planes LinuxDos cosas cambian cuando lo haces. El flujo de despliegue con push a git que te daba una plataforma de hosting deja de ser automático. Puedes recrearlo con un PaaS autoalojado como Coolify o Dokku, o construir tu propia ruta de CI/CD, y en cualquier caso ahora las actualizaciones y el mantenimiento son cosa tuya.
El otro cambio es que la máquina alberga más que la aplicación. Con mucho gusto puede ejecutar Code Server y Claude Code si prefieres que tu editor también viva ahí, lo cual es o un bonito extra o un fin de semana entero de trabajo, según tú.
Preguntas frecuentes
¿Por qué mi URL pública dejó de funcionar al cerrar el portátil?
Porque el túnel estaba ligado al proceso que lo creó, no a tu aplicación. Cerrar el portátil o matar el terminal termina ese proceso, la URL pública muere y tu aplicación sigue perfectamente. Reiniciar el túnel te da una URL nueva, salvo que la herramienta te asigne un dominio reservado. Si el enlace tiene que sobrevivir a que tu portátil se duerma, la aplicación tiene que salir de tu máquina.
¿Necesito un nombre de dominio para poner una aplicación local en una URL pública?
No, en casi todos los casos. Un túnel rápido de Cloudflare, el dominio de desarrollo asignado por ngrok, localtunnel, localhost.run y los planes de hosting gratuitos de arriba te asignan un subdominio en su propio dominio sin coste. La excepción es un túnel con nombre de Cloudflare, que necesita un dominio que ya hayas añadido a Cloudflare DNS.
¿Puede alguien en otra red Wi-Fi abrir mi dirección IP local?
No. Una dirección como 192.168.1.42 apunta al dispositivo que la tenga en la red a la que estás conectado ahora mismo, que en cualquier otra red es un dispositivo distinto o nada en absoluto. Cualquiera fuera de tu Wi-Fi necesita un túnel, un plan de hosting gratuito o un host estático.
¿Cuáles de estas opciones funcionan si mi aplicación tiene inicio de sesión y base de datos?
Los caminos de la misma red y del túnel funcionan sin cambios, porque la aplicación sigue ejecutándose en tu máquina. Un despliegue estático también puede funcionar si las peticiones de inicio de sesión y de base de datos van directamente del navegador a un servicio alojado y no hace falta ejecutar código privado del lado del servidor en cada petición. Si tu propio código de autenticación o de base de datos necesita un servidor en el momento de la petición, usa un host del lado del servidor. En un host de aplicaciones gratuito, guarda los datos persistentes en almacenamiento duradero en lugar de suponer que el sistema de archivos local de la aplicación sobrevivirá.

Debate
Comentarios
Inicia sesión para unirte al debate.