Red local (LAN) vs red de Docker: son dos cosas distintas

 

Red local (LAN) vs red de Docker: son dos cosas distintas

Estás mezclando dos conceptos que se llaman "red" pero no tienen nada que ver. Vamos a separarlos, porque tu intuición es correcta en parte pero apunta al lugar equivocado.

1. Las dos "redes" que están en juego

Red de Docker (laravel)

Es una red virtual interna que Docker crea entre los contenedores. Solo existe dentro del host. Ninguna máquina de tu LAN puede "verla" ni acceder a ella directamente. Sirve para que app hable con db por nombre (db:3306) o nginx con app (app:9000).

Esta red no tiene nada que ver con que tu app sea visible en la LAN. Es un tema puramente interno de Docker.

Red local / LAN (tu router)

Es la red física de tu casa/oficina. Tu PC tiene una IP tipo 192.168.1.50, tu celular 192.168.1.51, etc. Para que otro dispositivo vea tu Laravel, tiene que poder hacer http://192.168.1.50:8000.

Aquí es donde importa el mapeo de puertos del compose, no la red de Docker.

2. El puente entre ambas: ports: en docker-compose.yml

Cuando escribes:

yaml
ports:
  - "8000:80"

Docker hace algo llamado port publishing: abre el puerto 8000 en el host y lo redirige al 80 del contenedor. Por defecto, se abre en 0.0.0.0, es decir, en todas las interfaces del host, incluyendo la IP de tu LAN.

Esto significa que automáticamente:

  • Tú: http://localhost:8000 ✅

  • Otro PC en tu LAN: http://192.168.1.50:8000 ✅ (donde 192.168.1.50 es la IP de tu host)

Ya funciona sin que toques nada. No necesitas cambiar la red de Docker.

¿Cuándo NO funcionaría?

Solo si escribieras algo como:

yaml
ports:
  - "127.0.0.1:8000:80"    # <-- solo accesible desde el propio host

Ese 127.0.0.1: delante restringe el puerto a localhost. Tú no lo tienes así, así que estás bien.

3. Por qué entonces "no se ven" a veces

Hay tres culpables típicos cuando algo no se ve en la LAN, y ninguno es la red de Docker:

a) El firewall del host

Ubuntu, Windows y macOS traen firewalls que bloquean puertos entrantes por defecto. Si otro PC no puede conectar, revisa:

bash
# Ubuntu
sudo ufw status
sudo ufw allow 8000/tcp
sudo ufw allow 5173/tcp

b) VITE_API_URL apunta a localhost

Este es el error más común y el más importante para tu caso. En frontend/.env tienes:

env
VITE_API_URL=http://localhost:8000/api

Cuando otro PC abre http://192.168.1.50:5173, el navegador de ese PC descarga el bundle de React y ejecuta el fetch a http://localhost:8000/api/hello. Pero localhost para ese PC es él mismo, no tu host. Resultado: error de conexión.

Solución: usa la IP de tu host en la LAN:

env
VITE_API_URL=http://192.168.1.50:8000/api

O mejor, dinámico (funciona desde cualquier máquina):

env
VITE_API_URL=http://${window.location.hostname}:8000/api

Pero eso no funciona en .env porque Vite solo reemplaza variables en build/dev. Lo más práctico:

js
// frontend/src/App.jsx
const API = import.meta.env.VITE_API_URL || `http://${window.location.hostname}:8000/api`
fetch(`${API}/hello`)

Así, si abres desde localhost, usa localhost; si abres desde 192.168.1.50, usa 192.168.1.50. Sin tocar el .env.

c) Vite y su HMR

Vite por defecto sirve en localhost. Ya lo tienes bien configurado con host: '0.0.0.0', pero el HMR (hot reload) usa websockets y a veces necesita saber la IP pública del host. Añade esto a frontend/vite.config.js:

js
server: {
  host: '0.0.0.0',
  port: 5173,
  strictPort: true,
  watch: { usePolling: true },
  hmr: {
    host: '192.168.1.50',   // <-- IP de tu host en la LAN
    clientPort: 5173,
  },
},

O si quieres que funcione sin hardcodear la IP:

js
hmr: {
  clientPort: 5173,
},

Suele bastar con clientPort; el navegador remoto usará su propio hostname.

4. La red de Docker laravel no se toca para esto

Recapitulando, para que se vea en la LAN NO necesitas:

  • Cambiar la red laravel.

  • Poner los contenedores en network_mode: host.

  • Crear redes macvlan o cosas raras.

Solo necesitas:

  1. Que los ports: estén publicados sin 127.0.0.1: delante (ya lo están).

  2. Abrir esos puertos en el firewall del host.

  3. Que VITE_API_URL use la IP del host (o sea dinámico).

  4. Configurar el HMR de Vite.

5. ¿Y si quisiera que los contenedores tuvieran IPs de la LAN?

Se puede, con macvlan, pero es una mala idea para desarrollo:

  • Cada contenedor tendría su propia IP 192.168.1.x.

  • El router tendría que asignar IPs o reservarlas.

  • Rompe el aislamiento de Docker y complica el DNS interno entre contenedores.

  • No lo necesitas para nada.

El patrón estándar (y el que ya usas) es: los contenedores viven en su red interna, y publicas los puertos que quieras al host. El host es el único punto de contacto con la LAN. Es más simple, más seguro y más portable.

6. Cómo verificarlo paso a paso

En tu host, averigua su IP LAN:

bash
hostname -I | awk '{print $1}'
# o
ip addr show | grep "inet " | grep -v 127.0.0.1

Supongamos 192.168.1.50. Desde otro PC de la LAN:

bash
curl http://192.168.1.50:8000/api/hello

Si responde → el port publishing funciona.
Si no → es firewall (paso 3a).

Luego desde el navegador de otro PC:

text
http://192.168.1.50:5173

Si carga la app pero falla el fetch → es VITE_API_URL (paso 3b).

7. Resumen

Concepto¿Sirve para LAN?Qué hace
Red Docker laravel❌ NoComunicación interna entre contenedores
ports: "8000:80"✅ SíPublica el puerto en el host y lo hace accesible desde la LAN
Firewall del host⚠️ Bloquea si no se abreDeja pasar el tráfico entrante
VITE_API_URL⚠️ Debe usar la IP LANPara que el navegador remoto sepa a dónde llamar
hmr.host / clientPort⚠️ ConfigurarPara que el hot reload funcione desde otro PC

No estás mal en pensar en la red, solo que la red relevante para "que se vea en la LAN" es la del host, no la de Docker. La red laravel es un asunto interno de Docker y no afecta la visibilidad externa

Comentarios

Entradas más populares de este blog

12. Hola Mundo en Docker.

2.1-Instalación de Docker (nuevo método oficial), configuración de un proyecto Laravel con Nginx y MySQL en contenedores

11¿Qué es Docker? y ¿Por qué debo saberlo?