server: proxy, host y las opciones de desarrollo
La clave server de Vite: proxy para hablar con APIs sin CORS, host y port para exponer el dev server, cors y allowedHosts para no dejar la puerta abierta, y las opciones de desarrollo que más se tocan en 2026.
El servidor de desarrollo de Vite es una pieza distinta del build: no empaqueta, sirve módulos bajo demanda y recarga en caliente. La clave server gobierna ese servidor, y su opción estrella —proxy— resuelve el problema que todo frontend encuentra el primer día: cómo hablar con una API en otro puerto sin chocar contra CORS. Junto a ella, host y port deciden quién puede alcanzar tu dev server, y un grupo de opciones de seguridad —cors, allowedHosts— existe porque un servidor de desarrollo abierto a la red es una superficie de ataque real. Esta lección cubre el server que de verdad se configura.
- Configurar
proxypara hablar con APIs sin tropezar con CORS. - Exponer el dev server con
host,portystrictPort. - Entender
corsyallowedHostscomo límites de seguridad. - Afinar la experiencia de desarrollo con
open,warmupyhmr.
proxy: el navegador cree que todo es el mismo origen
El navegador aplica la política del mismo origen: una página servida en un puerto no puede llamar por defecto a una API en otro sin que esta devuelva las cabeceras CORS correctas. En desarrollo eso es una fricción constante, porque tu front vive en un puerto de Vite y tu backend en otro. El proxy la elimina: le dices a Vite que ciertas rutas se reenvíen a otro servidor, y como la petición del navegador va siempre al origen de Vite, no hay cruce de orígenes que bloquear.
import { defineConfig } from "vite"
export default defineConfig({
server: {
proxy: {
// string corto: /api se reenvia a http://localhost:8080/api
"/api": "http://localhost:8080",
// objeto: control total
"/v2": {
target: "https://backend.internal",
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/v2/, ""),
},
// websockets
"/socket": {
target: "ws://localhost:5174",
ws: true,
},
// clave como expresion regular
"^/legacy/.*": {
target: "http://localhost:9000",
changeOrigin: true,
},
},
},
})
Las tres opciones que marcan la diferencia son changeOrigin, secure y rewrite. changeOrigin reescribe la cabecera Host para que el backend crea que la petición vino de él mismo —imprescindible con hosts virtuales o APIs en la nube—. secure en false acepta certificados HTTPS autofirmados, típico de backends de desarrollo. Y rewrite transforma la ruta antes de reenviarla, para quitar un prefijo que solo existe en tu lado y no en el del servidor real.
flowchart LR A[navegador] --> B[vite dev server 5173] B --> C[la ruta casa con una regla de proxy] C --> D[reenvia al backend 8080] D --> E[respuesta vuelve por vite] E --> A style C fill:#89b4fa,color:#11111b
host, port y el acceso desde la red
Por defecto el dev server solo escucha en localhost, alcanzable únicamente desde tu máquina. Poner host en true lo hace escuchar en todas las interfaces, y entonces un móvil o un compañero en la misma red pueden abrirlo por tu IP local: la forma canónica de probar en un dispositivo real. port fija el puerto y strictPort decide qué pasa si está ocupado: por defecto Vite salta al siguiente libre, pero en un pipeline donde otra herramienta espera un puerto exacto conviene que falle en vez de moverse.
server: {
host: true, // escucha en todas las interfaces, accesible desde la LAN
port: 5173,
strictPort: true, // falla si el puerto esta ocupado en vez de saltar
open: "/panel", // abre el navegador directamente en esa ruta
warmup: {
clientFiles: ["./src/main.ts", "./src/App.vue"],
},
}
open arranca el navegador por ti, y si le das una ruta abre directamente en ella. warmup es una optimización más fina y moderna: le adelantas a Vite qué archivos vas a pedir primero para que los transforme antes de que los solicites, recortando el tiempo hasta la primera pantalla en proyectos grandes. Es gratis y casi nadie lo usa.
Un detalle que ahorra depuraciones: cuando sirves la app bajo un subdirectorio, la clave base y el server.origin deben concordar con esa ruta pública, o los assets se pedirán a una URL que no existe. Es el mismo mapa de rutas que impone el proxy, visto ahora desde el lado de los recursos estáticos en lugar del de las llamadas a la API.
proxy
Reenvía rutas a otro servidor para disolver CORS en desarrollo. Recuerda replicarlo en el reverse proxy de producción.
host
En true escucha en toda la red y expone el dev server a otros dispositivos. Ábrelo solo cuando de verdad lo necesites.
allowedHosts
La lista de nombres con los que se puede alcanzar el servidor. Tu defensa contra el DNS rebinding.
warmup
Precalienta los archivos de entrada para recortar el tiempo hasta la primera pantalla. Gratis y casi siempre olvidado.
cors, allowedHosts y seguridad en dev
Un dev server no es un juguete inofensivo: sirve tu código fuente y, mal expuesto, deja que un sitio malicioso o un host suplantado lea cosas que no debería. Por eso las versiones recientes de Vite endurecieron los defaults, y conviene entender las dos palancas. cors controla qué orígenes externos pueden pedir recursos a tu dev server; dejarlo abierto de par en par ya no es el default. allowedHosts es la defensa contra el DNS rebinding: la lista de nombres de host con los que se puede llegar a tu servidor, para que un dominio atacante que resuelva a tu IP no pueda hablar con él.
server: {
cors: false,
allowedHosts: ["app.local", ".mi-tunel.dev"],
hmr: {
overlay: true,
},
}
Es tentador poner host en true, cors abierto y allowedHosts en permitir todo para que algo funcione ya. Cada una de esas decisiones amplía la superficie de ataque de una máquina que tiene tu código y, a menudo, tus tokens de desarrollo en memoria. Abre solo lo justo: host cuando de verdad pruebes en otro dispositivo, un origen concreto en cors, y el nombre exacto de tu túnel en allowedHosts. La comodidad de hoy no vale un incidente de seguridad mañana.
server configura el dev server, que sirve módulos sin transformar y con recarga en caliente. Cuando ejecutas la vista previa de un build ya empaquetado, manda la clave preview, que tiene sus propias opciones de port, host y proxy. No las confundas: probar producción en local usa preview, y su config es independiente de la de desarrollo.
https, hmr y watch: afinar el bucle
Cerrado el proxy y el acceso, quedan tres opciones que afinan el bucle de desarrollo minuto a minuto: el cifrado, la reconexión en caliente y el vigilante de archivos. Ninguna es glamurosa, y las tres deciden si trabajar en el proyecto se siente instantáneo o pastoso.
A veces necesitas HTTPS en desarrollo: para probar APIs que exigen origen seguro, service workers, o cookies con atributos estrictos que el navegador solo respeta sobre TLS. La opción https acepta las rutas del certificado y la clave, y en la práctica se combina con un plugin que genera certificados de confianza local para no pelearte con los avisos del navegador.
server: {
https: { key: "./certs/key.pem", cert: "./certs/cert.pem" },
hmr: { host: "localhost", protocol: "ws", overlay: true },
watch: {
ignored: ["**/coverage/**", "**/.git/**"],
},
}
El reemplazo de módulos en caliente casi nunca hay que tocarlo, pero cuando el dev server vive tras un proxy o en un puerto distinto del que ve el usuario, hmr deja fijar el host, el puerto o el protocolo del websocket para que el cliente sepa a dónde reconectarse. El overlay decide si los errores se pintan sobre la página o solo van a la consola.
watch ajusta el vigilante de archivos. ignored excluye carpetas que no aportan —artefactos de cobertura, salidas de otras herramientas— y que, vigiladas, solo gastan recursos y disparan recargas espurias. En proyectos grandes o sobre sistemas de archivos de red, afinar el watcher es la diferencia entre un dev server ágil y uno que consume un núcleo entero sin motivo.
Dentro de un contenedor, de WSL o de un volumen montado, los eventos nativos del sistema de archivos a menudo no se propagan al proceso de Vite, y guardar un archivo no dispara la recarga. El escape es activar el sondeo en server.watch: en vez de esperar eventos, Vite pregunta por cambios en intervalos. Funciona siempre, a cambio de más CPU, así que resérvalo para los entornos donde los eventos nativos fallan, no para tu máquina local.
El proxy de Vite hace algo casi mágico: disuelve CORS haciendo que, desde el punto de vista del navegador, backend y frontend compartan origen. Pero esa palabra —ilusión— es la clave que hay que interiorizar. En desarrollo, Vite se pone en medio y reenvía; en producción, Vite no existe, y esa misma unidad de origen tiene que fabricarla otra pieza: un reverse proxy real, un Nginx, un Caddy, un router de tu plataforma edge, que enrute /api al backend y el resto al build estático. Quien no entiende que el proxy es solo un andamio de desarrollo despliega, funciona en local y se estrella en producción con errores de CORS que en dev nunca vio, porque el andamio se quedó en su máquina. La lección profunda es que el dev server y el servidor de producción resuelven el mismo problema —quién responde a cada ruta— con mecanismos distintos, y que tu trabajo es mantener las dos topologías coherentes: la del proxy de Vite y la del reverse proxy de despliegue deben describir el mismo mapa de rutas. Cuando ese mapa coincide, dev predice producción; cuando diverge, dev miente. Y un dev server que miente sobre cómo se comportará producción es peor que no tener dev server, porque te da confianza justo donde deberías tener dudas. Configura proxy, sí, pero documenta a su lado la regla de despliegue equivalente, y trata las dos como una sola verdad expresada en dos lugares.
- Levanta un backend en otro puerto y configura
server.proxypara reenviar/apia él; confirma en la pestaña de red que no hay error de CORS. - Añade
changeOriginy unrewriteque quite el prefijo/api, y verifica en el backend que la ruta llega limpia. - Pon
hostentruey abre el dev server desde tu móvil en la misma red por la IP local. - Ajusta
allowedHostspara permitir solo un nombre concreto y comprueba que otro es rechazado. - Escribe, junto a tu
proxy, la regla de reverse proxy equivalente que necesitarías en producción para el mismo/api.