Flujos de trabajo modernos para desarrolladores e1rea e integraciones avanzadas de infraestructura
Descubre por qué los proxies HTTP estándar caen en las conexiones de Server Actions de Next.js 15+ y Vite WebSocket HMR, y cómo mantener recargas en caliente en menos de un milisegundo a través de túneles remotos.

Quick answer
Túnel Vite 6 y acciones de servidor de Next.js: Solución HMR: webhook testing answer
For local webhook testing, run your app locally, expose it with a public HTTPS tunnel, and paste the stable callback URL into the provider dashboard.
How do I test webhooks on localhost?
Start your local server, open a public HTTPS tunnel to that port, configure the provider webhook URL, and inspect events in your local logs.
Why does a stable webhook URL matter?
Stable URLs prevent provider dashboards from needing manual callback updates every time you restart a tunnel.
Esta guía ofrece estrategias técnicas para proxying de servidores de desarrollo locales, reenvío de spans de telemetría, routing de webhooks multitenant y conexión de vistas previas en la nube a instancias efímeras de bases de datos.
1. Recarga en caliente entre fronteras: Túnel Vite 6 y acciones de servidor de Next.js sobre proxies con soporte HMR
Los proxies inversos HTTP tradicionales (como Nginx por defecto o túneles SSH básicos) rompen aplicaciones web con estado porque evalúan el tráfico de forma sin estado. Herramientas modernas como Vite 6 y Next.js 15+ dependen de conexiones bidireccionales de baja latencia para sincronizar estados del cliente, compilar módulos del servidor y procesar Server Actions.
+-------------------------------------------------------------------------------+
| TÚNEL PÚBLICO EN LA NUBE |
| https://dev-tenant.app.example.com |
+-------------------------------------------------------------------------------+
|
| TLS Terminal e1 WSS Upgrade
v
+-------------------------------------------------------------------------------+
| PROXY INVERSO CON SOporte HMR |
| - Reescritura de cabecera Host (Verificación de origen) |
| - Manejo de actualización HTTP/1.1 (101 Switching Protocols) |
| - Pings Keep-Alive e1 mapeo dinámico de puertos del cliente |
+-------------------------------------------------------------------------------+
|
+--------------------------+--------------------------+
| (gRPC / TCP multiplexado) | (Acciones de servidor HTTP/2)
v v
+-----------------------+ +-----------------------+
| Servidor de desarrollo Vite | | Router de la app Next.js |
| (localhost:5173) | | (localhost:3000) |
| | | |
| - WebSocket HMR Path: | | - Host permitido CSRF: |
| /_vite_hmr | | dev-tenant.example |
+-----------------------+ +-----------------------+
Por qué los proxies tradicionales rompen HMR y Server Actions
- Framing WebSocket eliminado: Los proxies HTTP estándar tratan las solicitudes entrantes como pares cortos de solicitud/respuesta. Cuando Vite intenta un intercambio
Upgrade: websocketen HTTP/1.1 para establecer su canal HMR, los proxies sin estado no mantienen el socket TCP persistente. Esto obliga a Vite a recargas continuas de fallback. - Cabeceras Host y verificaciones CSRF en Next.js 15+: Las acciones de servidor de Next.js se ejecutan mediante solicitudes POST HTTP usando IDs de endpoint ocultos. Para prevenir ataques CSRF, Next.js inspecciona las cabeceras
OriginyHost. Si un túnel reescribeHost: localhost:3000sin coincidir con la URL pública del túnel, Next.js bloquea la invocación. - Puertos WebSocket incompatibles: Vite inyecta un script en el navegador que intenta abrir una conexión WebSocket al puerto HMR. Si el navegador conecta a https://app.example.com (puerto 443) pero Vite indica al cliente abrir un socket en
ws://localhost:5173, la seguridad del navegador bloquea la conexión.
Arquitectura de preservación para Vite 6
Para mantener HMR en menos de un milisegundo sobre túneles públicos (como Cloudflare Tunnels, frp o ngrok), configura el servidor WebSocket interno de Vite para desacoplar su puerto de escucha interno del puerto público para el cliente.
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
server: {
host: '0.0.0.0',
port: 5173,
strictPort: true,
hmr: {
// El hostname público expuesto por tu túnel
host: 'vite-tunnel.dev.example.com',
// Forzar al cliente usar HTTPS/WSS en lugar del puerto interno 5173
clientPort: 443,
protocol: 'wss',
path: '/_vite_hmr',
},
// Evitar caídas de conexión HMR por desajuste de host
cors: true,
},
});
Configuración del túnel de acciones de servidor de Next.js 15+
Para Next.js 15, actualiza next.config.ts para permitir invocar Server Actions a través de túneles de desarrollo públicos.
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
experimental: {
serverActions: {
// Lista blanca de orígenes del túnel para pasar verificaciones CSRF
allowedOrigins: [
'next-tunnel.dev.example.com',
'*.tunnel.dev.example.com',
],
},
},
};
export default nextConfig;
2. Routing de trazas distribuidas desde staging en la nube a tu interfaz Jaeger local
Al depurar microservicios en entornos de staging, rastrear una solicitud asíncrona a través de múltiples servicios es vital. Sin embargo, enviar datos de telemetría a un backend central crea ruido y dificulta la aislamiento.
Usando colectores OpenTelemetry (OTLP), los ingenieros de backend pueden proxyar flujos de telemetría a una instancia local de Jaeger UI sin contaminar el almacenamiento remoto.
+-----------------------------------------------------------------------------------+
| CLÚSTER DE STAGING EN LA NUBE |
| |
| +---------------------+ +---------------------+ +-------------------+ |
| | Microservicio de autenticación | ---e | Microservicio de pedidos | ---e | Servicio de pagos | |
| +---------------------+ +---------------------+ +-------------------+ |
| | |
| | OTLP / gRPC (Puerto 4317) |
| v |
| +---------------------------------------+ |
| | Colector OTLP en staging | |
| +---------------------------------------+ |
+------------------------------------------|----------------------------------------+
|
| Routing vía Tailscale/SSH
v
+-----------------------------------------------------------------------------------+
| ESTACIÓN DE TRABAJO DEL DESARROLLADOR |
| |
| +-----------------------------------------------------------------------------+ |
| | Colector OpenTelemetry local | |
| | - Recibe: OTLP / gRPC en 127.0.0.1:4317 | |
| | - Filtro: attributes["x-developer-id"] == "dev-alice" | |
| +-----------------------------------------------------------------------------+ |
| | |
| v OTLP / gRPC (Inseguro) |
| +-----------------------------------------------------------------------------+ |
| | Contenedor Jaeger local | |
| | - Puerto de ingestión: 4317 | |
| | - UI web: http://localhost:16686 | |
| +-----------------------------------------------------------------------------+ |
+-----------------------------------------------------------------------------------+
El problema de secuestro de trazas
Enviar spans de trazas directamente a almacenes en la nube como Datadog, Honeycomb o una instancia compartida de AWS OpenSearch presenta dos problemas:
- Contaminación de índices: Los logs de depuración y payloads mal formados ensucian los paneles de producción y staging.
- Latencia y límites de tasa: Exportar spans de alto volumen por internet aumenta costos y riesgos de superar límites del proveedor.
Arquitectura: Enrutamiento selectivo OTLP inverso
Los ingenieros pueden aislar y reenviar trazas usando cabeceras contextuales (como x-developer-id: dev-alice) procesadas por un conector de enrutamiento de OpenTelemetry.
Paso 1: Configuración del colector OTLP en staging
Configura el colector OTLP en staging para evaluar atributos entrantes y enrutar spans etiquetados a través de un pipeline gRPC inverso a una máquina local.
# otel-collector-staging.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 1s
send_batch_size: 256
exporters:
# Destino estándar en la nube
otlp/staging_backend:
endpoint: "tempo-staging.internal.net:4317"
tls:
insecure: true
# Destino del túnel inverso apuntando a la máquina del desarrollador
otlp/dev_alice_local:
endpoint: "host.docker.internal:14317"
tls:
insecure: true
connector:
routing:
default_exporters: [otlp/staging_backend]
from_attribute: "x-developer-id"
table:
- value: "dev-alice"
exporters: [otlp/dev_alice_local]
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [routing]
Paso 2: Establecer el túnel inverso y la ingestión local
Establece un túnel SSH inverso desde tu estación de trabajo al gateway de staging, mapeando el puerto 14317 en el nodo de staging al puerto 4317 localmente.
# Establecer túnel gRPC SSH inverso
ssh -R 14317:localhost:4317 developer@staging-gateway.internal.net -N
Ejecuta un contenedor Jaeger ligero (configurado con ingestión OTLP nativa):
docker run -d --name jaeger-local \
-e COLLECTOR_OTLP_ENABLED=true \
-p 16686:16686 \
-p 4317:4317 \
jaegertracing/all-in-one:latest
Cuando una solicitud HTTP con la cabecera x-developer-id: dev-alice entra en staging, todo su árbol de trazas se ramifica y transmite directamente a tu interfaz Jaeger local en http://localhost:16686.
3. Probando webhooks de Stripe Connect locales con subdominios multitenant dinámicos
Probar plataformas SaaS multitenant requiere aislar eventos para organizaciones distintas. Cuando se construyen arquitecturas multitenant usando Stripe Connect (donde una plataforma gestiona múltiples cuentas conectadas), depurar webhooks en un único endpoint oculta problemas de resolución dinámica de inquilinos.
NUBE STRIPE
|
+----------------------+----------------------+
| Evento webhook de conexión |
| Cuenta: acct_tenant_A | Cuenta: acct_tenant_B
v v
+------------------------------+ +------------------------------+
| https://tenant-a.tunnel.dev | | https://tenant-b.tunnel.dev |
+------------------------------+ +------------------------------+
| |
+----------------------+----------------------+
|
v
+-------------------------------+
| PROXY INGRESO WILDCARD |
| *.tunnel.dev -e9> localhost:8080|
+-------------------------------+
|
v
+-------------------------------+
| ROUTER MULTITENANT LOCAL |
| Extrae cabecera Host |
| Mapea Tenant A vs Tenant B |
+-------------------------------+
Configuración de routing de webhooks multitenant
Usa un proxy inverso con comodín (como frp o caddy) para apuntar *.tunnel.yourdomain.dev a tu router local.
1. Configuración de Caddy (Router de ingreso local)
# Caddyfile - Proxy local multitenant con comodín
*.tunnel.dev.localhost {
tls internal
@tenant_a header_regexp host Host ^([a-zA-Z0-9-]+)\.tunnel\.dev\.localhost$
handle {
reverse_proxy localhost:3000 {
header_up Host {http.request.host}
header_up X-Forwarded-Host {http.request.host}
}
}
}
2. Script avanzado de reenvío de webhooks multitenant
En lugar de ejecutar comandos stripe listen por cada inquilino, usa este script proxy multi-tenant en Node.js. Escucha eventos de Stripe y los reenvía dinámicamente a la subdominio local correspondiente según el account del evento.
// scripts/stripe-multitenant-proxy.ts
import Stripe from 'stripe';
import axios from 'axios';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2026-01-28',
});
// Mapea IDs de cuentas conectadas de Stripe a subdominios locales
const TENANT_MAPPING: Record<string, string> = {
'acct_1N01AAA000000000': 'acme',
'acct_1N02BBB000000000': 'globex',
};
async function handleWebhookEvent(event: Stripe.Event) {
const connectedAccountId = event.account;
const tenantSlug = connectedAccountId ? TENANT_MAPPING[connectedAccountId] : 'app';
if (!tenantSlug) {
console.warn(`[WARN] ID de cuenta no mapeado: ${connectedAccountId}`);
return;
}
const targetUrl = `http://${tenantSlug}.tunnel.dev.localhost:3000/api/webhooks/stripe`;
try {
console.log(`[REENVIO] Evento ${event.type} -e ${targetUrl}`);
await axios.post(targetUrl, event, {
headers: {
'Stripe-Signature': 'firma_local_simulada',
'Content-Type': 'application/json',
'Host': `${tenantSlug}.tunnel.dev.localhost`,
},
});
} catch (err: any) {
console.error(`[ERROR] Fallo en envío webhook: ${err.message}`);
}
}
4. Exponiendo instancias locales de Supabase y Postgres a despliegues de vista previa en la nube (Vercel/Netlify)
Los flujos de trabajo con ramas feature crean despliegues efímeros en plataformas como Vercel o Netlify. Sin embargo, proporcionar estado de base de datos aislado para cada vista previa puede ser complicado.
Usando túneles TCP de capa 4 (como ngrok tcp, bore o frp), puedes exponer de forma segura tu instancia local de PostgreSQL o Supabase en Docker directamente a los despliegues en la nube.
+-----------------------------------------------------------------------------+
| VERCEL / NETLIFY PRUEBA #42 |
| https://app-git-feature-pr42.vercel.app |
| |
| DATABASE_URL = postgresql://postgres:pass@tcp.tunnel.dev:19432/postgres |
+-----------------------------------------------------------------------------+
|
| TCP cifrado (Puerto 19432)
v
+-----------------------------------------------------------------------------+
| Proxy TCP inverso |
| - TLS passthrough / pipeline TCP puro |
+-----------------------------------------------------------------------------+
|
| Túnel inverso seguro
v
+-----------------------------------------------------------------------------+
| Estación de trabajo del desarrollador |
| |
| +-----------------------------------------------------------------------+ |
| | Firewall local de Postgres / Proxy PgBouncer | |
| | - Escucha en 127.0.0.1:5432 | |
| | - Restringe SSL / Valida límites de sesión | |
| +-----------------------------------------------------------------------+ |
| | |
| v |
| +-----------------------------------------------------------------------+ |
| | Instancia de Supabase en Docker | |
| | - Motor PostgreSQL (Puerto 5432) | |
| | - API PostgREST (Puerto 54321) | |
| | - Sistema de autenticación GoTrue (Puerto 9999) | |
| +-----------------------------------------------------------------------+ |
+-----------------------------------------------------------------------------+
Comparación de protocolos: Capa 4 (TCP) vs Capa 7 (HTTP)
- Proxies HTTP (Capa 7): No aptos para motores de base de datos. Esperan HTTP/WebSockets simples, rompen protocolos de wire como
StartupMessagede Postgres y descartan conexiones no HTTP. - Túneles TCP (Capa 4): Envían paquetes TCP en bruto en la capa de transporte, manteniendo intactos los protocolos de wire.
Exponiendo la pila local de Supabase vía FRP (Fast Reverse Proxy)
Para tunelizar tu pila local de Supabase, configura frp para exponer PostgreSQL (puerto 5432) y PostgREST (puerto 54321) sobre TCP en capa 4.
Configuración del servidor (frps.ini en el gateway remoto)
[common]
bind_port = 7000
vhost_extra_db_port = 19432
Configuración del cliente (frpc.ini en la estación de trabajo del desarrollador)
[common]
server_addr = gateway.tudominio.dev
server_port = 7000
[supabase-postgres-tcp]
type = tcp
local_ip = 127.0.0.1
local_port = 54322
remote_port = 19432
[supabase-postgrest-http]
type = http
local_ip = 127.0.0.1
local_port = 54321
custom_domains = api-pr42.tunnel.tudominio.dev
Automatización con GitHub Actions y API de Vercel
Automatiza tus flujos de trabajo en pull requests configurando variables de entorno en despliegues efímeros usando una acción de GitHub.
# .github/workflows/preview-environment.yml
name: Inyector de base de datos en vista previa
on:
pull_request:
types: [opened, synchronize]
jobs:
attach-local-db:
runs-on: ubuntu-latest
steps:
- name: Inyectar URL dinámica del túnel de base de datos en vista previa de Vercel
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
run: |
PR_NUM=${{ github.event.number }}
# Construir URL de base de datos dinámica apuntando al puerto TCP asignado
TUNNEL_DB_URL="postgresql://postgres:postgres@gateway.tudominio.dev:19432/postgres?sslmode=require"
# Asignar cadena de conexión a la base de datos en entorno de vista previa de Vercel
curl -X POST "https://api.vercel.com/v10/projects/${VERCEL_PROJECT_ID}/env" \
-H "Authorization: Bearer ${VERCEL_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"key": "DATABASE_URL",
"value": "'"${TUNNEL_DB_URL}"'",
"type": "encrypted",
"target": ["preview"],
"gitBranch": "${{ github.head_ref }}"
}'
Resumen arquitectónico: proxies inversos y patrones de integración
| Patrón | Capa de protocolo | Mejor uso | Casos límite y advertencias |
|---|---|---|---|
| Proxy HMR | Capa 7 (HTTP/WSS) | Recarga en caliente local en Vite 6 / Next.js 15+ a través de túneles remotos | Requiere lista blanca allowedOrigins en Next.js y sobrescribir explícitamente clientPort en Vite. |
| Enrutamiento de trazas OTLP | Capa 7 (gRPC / HTTP/2) | Aislar spans de microservicios localmente vía OpenTelemetry | Requiere middleware de propagación de cabeceras (x-developer-id) entre servicios. |
| Subdominios dinámicos | Capa 7 (HTTP/SNI) | Simulación de webhooks y rutas de checkout multitenant SaaS | Requiere certificados SSL wildcard (*.domain.dev) o instalación de CA local. |
| Túneles inversos TCP en capa 4 | Capa 4 (TCP puro) | Vincular entornos en la nube de Vercel/Netlify con bases de datos locales | Alta concurrencia puede agotar pools locales; usar PgBouncer localmente. |
Related InstaTunnel pages
Continue from this article into the most relevant product guides and workflows.
Related Topics
Keep building with InstaTunnel
Read the docs for implementation details or compare plans before you ship.