Probar APIs locales (localhost) que necesitan recibir webhooks o callbacks de servicios externos requiere exponer temporalmente tu servidor de desarrollo local a internet. Servicios de tunelización como ngrok, NPort, Cloudflare Tunnel y otros, crean conexiones seguras que le dan a tu localhost una URL pública.
Por qué necesitas la tunelización de localhost
Estás construyendo una API que se integra con servicios de terceros. Todo funciona en tu laptop: los endpoints responden correctamente, los datos fluyen sin problemas. Luego intentas probar los callbacks de webhooks de Stripe, GitHub, Twilio o cualquier otro servicio externo.
Problema: Los servicios externos no pueden alcanzar localhost:3000. Tu servidor de desarrollo no es accesible desde internet.
Escenarios comunes donde esto interrumpe tu flujo de trabajo:
1. Pruebas de Webhooks
Servicios como Stripe envían confirmaciones de pago, GitHub envía eventos de repositorio, Slack envía eventos de interacción, todo como solicitudes POST a tu API. Durante el desarrollo, estos servicios necesitan una URL pública para enviar webhooks.

2. URLs de Callback de OAuth
Al implementar "Iniciar sesión con Google", "Iniciar sesión con GitHub" o cualquier flujo de OAuth, el proveedor de autenticación redirige a los usuarios de vuelta a tu aplicación con un código de autorización. La URL de redirección debe ser accesible públicamente y coincidir con la que registraste con el proveedor.

3. Integración de API de Terceros
Algunas APIs requieren URLs de callback para operaciones asíncronas. Por ejemplo, los servicios de transcodificación de video notifican a tu API cuando el procesamiento se completa, o los procesadores de pago confirman transacciones.
4. Desarrollo de Aplicaciones Móviles
Probar tu API desde un dispositivo móvil en la misma red a menudo falla porque la aplicación móvil no puede resolver localhost. Un túnel te proporciona una URL que funciona desde cualquier dispositivo.
5. Demostraciones a Clientes
A veces necesitas mostrar trabajo en progreso a clientes o interesados. Desplegar a staging por cada pequeño cambio ralentiza la iteración. Una URL pública temporal permite a los clientes probar tu entorno de desarrollo.
Cómo funciona la tunelización de localhost
Los servicios de tunelización crean una conexión segura entre sus servidores en la nube y tu máquina local:
Servicio Externo → Servicio de Tunelización (URL pública) → Conexión Segura → Tu Localhost:3000
El proceso:
- Inicias un cliente de túnel en tu máquina apuntando a tu puerto local
- El cliente se conecta a la infraestructura en la nube del servicio de tunelización
- El servicio asigna una URL pública (por ejemplo,
https://abc123.ngrok.io) - Las solicitudes entrantes a esa URL pública se reenvían a través de la conexión cifrada a tu localhost
- Tu servidor local recibe la solicitud como si viniera directamente del cliente
- Las respuestas fluyen de vuelta a través del túnel al solicitante
Esto sucede de forma transparente. Tu servidor local no necesita saber que está detrás de un túnel.
Comparando Servicios de Tunelización Populares
Aquí están las opciones más populares en 2026, con sus fortalezas y limitaciones:
ngrok (El más Popular)
Ideal para: Proyectos establecidos, equipos que buscan fiabilidad
ngrok http 3000

Ventajas:
- Estándar de la industria con documentación extensa
- Interfaz de usuario de inspector web para ver todas las solicitudes
- Dominios personalizados en planes de pago
- Funcionalidad de reenvío de solicitudes (replay)
- Terminación TLS
Desventajas:
- La capa gratuita tiene un límite de sesión de 2 horas
- URLs aleatorias en la capa gratuita (cambian en cada sesión)
- El precio comienza en $10/mes por URLs persistentes
Capa Gratuita:
- 1 agente en línea
- 40 conexiones/minuto
- URLs aleatorias que expiran
Planes de Pago: $8-$20/mes

NPort (Alternativa Gratuita en Ascenso)
Ideal para: Desarrolladores que evitan costos de suscripción

nport start 3000
Ventajas:
- Completamente gratuito y de código abierto
- Sin límites de tiempo de sesión
- Subdominios personalizados disponibles
- Opción autoalojada
- Conjunto de características similar al nivel gratuito de ngrok
Desventajas:
- Comunidad más pequeña (menos tutoriales)
- Menos maduro (lanzado en 2025)
- Sin soporte comercial
Capa Gratuita:
- Túneles ilimitados
- Sin límites de tiempo
- Subdominios personalizados

Esta es la herramienta que está ganando tracción en Dev.to, ya que los desarrolladores buscan alternativas a ngrok sin costos continuos.
Cloudflare Tunnel (Ideal para Entornos Cercanos a Producción)
Ideal para: Equipos que ya usan Cloudflare, túneles de larga duración

cloudflared tunnel --url http://localhost:3000
Ventajas:
- Infraestructura de nivel empresarial
- Protección contra DDoS incluida
- Se integra con Cloudflare Zero Trust
- Sin límites de ancho de banda
- Gratuito para la mayoría de los casos de uso
Desventajas:
- Configuración más compleja
- Requiere cuenta de Cloudflare
- Excesivo para pruebas simples de webhooks
Capa Gratuita:
- Ancho de banda ilimitado
- Túneles ilimitados
- Protección contra DDoS
Localtunnel (El más Simple)
Ideal para: Pruebas rápidas y puntuales, sin instalación
npx localtunnel --port 3000
Ventajas:
- No requiere registro
- Configuración cero
- Sin instalación (se ejecuta a través de npx)
- Código abierto
Desventajas:
- Poco fiable (frecuentemente caído)
- Sin inspección de solicitudes
- Solo URLs aleatorias
- Documentación mínima

Capa Gratuita:
- Todo es gratuito
- Sin restricciones de características
Tailscale Funnel (Ideal para Equipos)
Ideal para: Compartir en equipo de forma privada, demostraciones seguras

tailscale serve https / http://localhost:3000
tailscale funnel 443 on
Ventajas:
- Basado en WireGuard (rápido, seguro)
- Privado por defecto (solo visible para tu red Tailscale)
- Puede exponerse públicamente cuando sea necesario
- Excelente para la colaboración en equipo
Desventajas:
- Requiere configuración de Tailscale
- Curva de aprendizaje más pronunciada
- Diseñado principalmente para redes privadas
Capa Gratuita:
- Hasta 100 dispositivos
- Ancho de banda ilimitado

Tabla Comparativa
| Característica | ngrok | NPort | Cloudflare Tunnel | Localtunnel | Tailscale |
|---|---|---|---|---|---|
| Precio | Gratis/$10+ | Gratis | Gratis | Gratis | Gratis/Pago |
| Límite de Sesión | 2 horas | Ninguno | Ninguno | Ninguno | Ninguno |
| Dominio Personalizado | Pago | Gratis | Sí | No | Sí |
| Inspector de Solicitudes | Sí | Básico | No | No | No |
| Complejidad de Configuración | Baja | Baja | Media | Muy Baja | Media |
| Fiabilidad | Excelente | Buena | Excelente | Pobre | Excelente |
| Ideal Para | Pruebas de producción | Desarrolladores conscientes del costo | Empresarial | Pruebas rápidas | Compartir en equipo |
Configurando Tu Primer Túnel Localhost
Recorramos la configuración con las herramientas más comunes. Usaremos una API Express de Node.js como ejemplo, pero esto funciona con cualquier servidor local.
Ejemplo: Servidor API Local
// server.js
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => {
console.log('Webhook received:', req.body);
res.json({ received: true });
});
app.get('/health', (req, res) => {
res.json({ status: 'healthy' });
});
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
Opción 1: Usando ngrok
Paso 1: Instalar ngrok
# macOS
brew install ngrok
# Windows (via Chocolatey)
choco install ngrok
# Linux
curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | \
sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && \
echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | \
sudo tee /etc/apt/sources.list.d/ngrok.list && \
sudo apt update && sudo apt install ngrok
Paso 2: Autenticar (opcional pero recomendado)
ngrok config add-authtoken YOUR_AUTH_TOKEN
Paso 3: Iniciar el túnel
ngrok http 3000
Salida:
Session Status online
Account you@example.com (Plan: Free)
Version 3.5.0
Region United States (us)
Forwarding https://abc123.ngrok.io -> http://localhost:3000
Tu API ahora es accesible en https://abc123.ngrok.io.
Paso 4: Probarlo
curl https://abc123.ngrok.io/health
# {"status":"healthy"}
Opción 2: Usando NPort (Alternativa Gratuita)
Paso 1: Instalar NPort
npm install -g nport-cli
# or
curl -sSL https://nport.io/install.sh | bash
Paso 2: Iniciar el túnel
nport start 3000 --subdomain myapi
Salida:
✓ Tunnel started successfully
Public URL: https://myapi.nport.io
Local URL: http://localhost:3000
Paso 3: Probarlo
curl https://myapi.nport.io/health
# {"status":"healthy"}
Opción 3: Usando Cloudflare Tunnel
Paso 1: Instalar cloudflared
# macOS
brew install cloudflare/cloudflare/cloudflared
# Linux
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
Paso 2: Túnel rápido (no se requiere registro)
cloudflared tunnel --url http://localhost:3000
Salida:
2026-01-27T12:00:00Z INF Your quick tunnel is: https://xyz789.trycloudflare.com
Para túneles persistentes (requiere cuenta de Cloudflare):
# Login
cloudflared tunnel login
# Create tunnel
cloudflared tunnel create myapi
# Configure and run
cloudflared tunnel --config config.yml run myapi
Probando Webhooks con Apidog
Ahora que tu localhost es accesible públicamente, probemos los webhooks sistemáticamente usando Apidog.
¿Por qué combinar Tunelización + Apidog?
La tunelización resuelve el acceso; Apidog resuelve la verificación:
- El servicio de tunelización hace que tu localhost sea accesible
- Apidog prueba las respuestas de tu API, valida datos, automatiza escenarios
Configurando Pruebas de Webhooks en Apidog
Paso 1: Importar o Crear Tu API
- Abre Apidog

2. Crea un nuevo proyecto

3. Añade tu endpoint de webhook:

- Método: POST
- URL:
{{base_url}}/webhook - Encabezados:
Content-Type: application/json
Paso 2: Configurar Variables de Entorno
Configura dos entornos:
Desarrollo (Tunelizado):
{
"base_url": "https://abc123.ngrok.io"
}
Producción:
{
"base_url": "https://api.yourapp.com"
}
Esto te permite probar el mismo endpoint localmente y en producción con un solo clic.
Paso 3: Crear Escenarios de Prueba
Prueba qué sucede cuando llegan los webhooks:
Ejemplo: Prueba de Webhook de Pago de Stripe
// Request Body
{
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_test123",
"amount": 2000,
"currency": "usd",
"status": "succeeded"
}
}
}
Aserciones en Apidog:
- El código de estado es igual a 200
- La respuesta contiene
received: true - El tiempo de respuesta es < 1000ms
- El Content-Type es
application/json
Paso 4: Simular Servicios de Terceros
En lugar de activar webhooks reales de Stripe o GitHub, simúlalos en Apidog:
- Copia ejemplos de payloads de webhook de la documentación del servicio
- Crea casos de prueba con varios escenarios (éxito, fallo, casos límite)
- Ejecuta todos los escenarios contra tu localhost tunelizado
- Verifica que tu API maneje cada caso correctamente
Probando Callbacks de OAuth
Escenario: Estás implementando "Iniciar sesión con Google"
Paso 1: Inicia el túnel con un subdominio personalizado
ngrok http 3000 --subdomain myapp
# URL: https://myapp.ngrok.io
Paso 2: Configura la redirección de OAuth en Google Console
Establece la URL de callback: https://myapp.ngrok.io/auth/google/callback
Paso 3: Prueba el flujo en Apidog
- Haz una solicitud a
/auth/googlepara obtener la URL de autorización - Sigue la redirección manual o programáticamente
- Verifica que el callback reciba el código de autorización
- Asegúrate de que el intercambio de tokens funcione correctamente
Paso 4: Validar el almacenamiento de tokens
Usa Apidog para:
- Verifica que los tokens se almacenen de forma segura
- Prueba el flujo de actualización de tokens
- Asegúrate de que los tokens caducados se manejen correctamente
Casos de Uso Comunes
1. Probando Webhooks de Pago (Stripe, PayPal)
Desafío: Los proveedores de pago envían webhooks para eventos como cargos exitosos, reembolsos, disputas.
Solución:
# Start tunnel
ngrok http 3000
# Configure webhook URL in Stripe dashboard
# https://abc123.ngrok.io/webhook/stripe
# Use Stripe CLI to forward test webhooks
stripe listen --forward-to localhost:3000/webhook/stripe
# Trigger test events
stripe trigger payment_intent.succeeded
Prueba con Apidog:
- Crea casos de prueba para cada tipo de evento
- Verifica la idempotencia (manejo de webhooks duplicados)
- Prueba la verificación de firma
- Asegúrate de que las actualizaciones de la base de datos se realicen correctamente
2. Probando Comandos de Bot de Slack/Discord
Desafío: Las plataformas de chat envían eventos de interacción cuando los usuarios hacen clic en botones o ejecutan comandos.
Solución:
# Start tunnel
nport start 3000 --subdomain myslackbot
# Configure in Slack API:
# Interactivity URL: https://myslackbot.nport.io/slack/interactions
# Slash Commands: https://myslackbot.nport.io/slack/commands
Prueba con Apidog:
- Simula clics en botones
- Prueba las respuestas de comandos de barra
- Verifica el tiempo de respuesta (Slack requiere respuestas en <3s)
- Prueba respuestas diferidas con
response_url
3. Probando Webhooks de SMS/Voz (Twilio)
Desafío: Twilio envía webhooks cuando llegan SMS o se reciben llamadas de voz.
Solución:
cloudflared tunnel --url http://localhost:3000
Configura los webhooks de TwiML para que apunten a la URL de tu túnel.
Prueba con Apidog:
- Simula payloads de SMS entrantes
- Prueba diferentes tipos de mensajes (MMS, SMS)
- Verifica la validación de firma de Twilio
- Prueba la generación de TwiML de respuesta
4. Pruebas de API de Aplicaciones Móviles
Desafío: Probar tu API desde un dispositivo físico o emulador.
Problema con localhost:
// Esto falla desde un dispositivo móvil
fetch('http://localhost:3000/api/users')
Solución con túnel:
// Esto funciona desde cualquier lugar
fetch('https://myapi.ngrok.io/api/users')
Prueba con Apidog:
- Genera documentación de API con la URL base tunelizada
- Comparte con el equipo móvil
- Los desarrolladores móviles pueden probar contra tu servidor de desarrollo en vivo
- Cambia a URLs de staging/producción cuando esté listo
5. Probando Webhooks de GitHub/GitLab
Desafío: Probar webhooks de repositorio (push, pull request, issues) localmente.
Solución:
# Start tunnel
ngrok http 4000
# Configure in GitHub repo settings:
# Webhook URL: https://abc123.ngrok.io/github/webhook
# Content type: application/json
# Events: Push, Pull requests
Prueba con Apidog:
- Simula eventos de push
- Prueba eventos de PR abiertos/cerrados
- Verifica la validación de firma (X-Hub-Signature)
- Prueba la lógica de filtrado de ramas
Mejores Prácticas de Seguridad
Exponer localhost a internet crea riesgos de seguridad. Sigue estas prácticas:
1. Usa Solo HTTPS
Todos los servicios de tunelización proporcionan HTTPS por defecto. Nunca uses HTTP simple para túneles:
# Good
ngrok http 3000
# Creates https://abc123.ngrok.io
# Bad (don't do this)
ngrok http --scheme=http 3000
2. Implementa la Verificación de Firma de Webhook
No confíes ciegamente en los webhooks entrantes. Verifica las firmas:
const crypto = require('crypto');
function verifyStripeSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
app.post('/webhook/stripe', (req, res) => {
const signature = req.headers['stripe-signature'];
if (!verifyStripeSignature(req.body, signature, process.env.STRIPE_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process webhook
});
3. Restringe el Acceso con Autenticación Básica
Añade autenticación a tu túnel:
# ngrok with basic auth
ngrok http 3000 --auth="username:password"
# NPort with basic auth
nport start 3000 --auth username:password
Ahora las solicitudes necesitan credenciales:
curl -u username:password https://abc123.ngrok.io/webhook
4. Usa Secretos Específicos del Entorno
Nunca hagas commit de secretos de webhook o claves API:
// .env.development
STRIPE_WEBHOOK_SECRET=whsec_test_abc123
WEBHOOK_TUNNEL_URL=https://abc123.ngrok.io
// .env.production
STRIPE_WEBHOOK_SECRET=whsec_live_xyz789
WEBHOOK_URL=https://api.yourapp.com
5. Monitoriza el Acceso al Túnel
Usa el inspector de solicitudes para vigilar actividades sospechosas:
# ngrok provides a web interface at:
http://localhost:4040
# View all requests, responses, replay attacks
6. Limita la Duración del Túnel
No dejes los túneles ejecutándose indefinidamente:
# Auto-expire tunnel after 1 hour
ngrok http 3000 --session-duration 1h
7. Valida las Fuentes de Solicitudes
Verifica las direcciones IP entrantes o usa listas blancas:
const allowedIPs = [
'192.0.2.1', // Stripe webhook IPs
'198.51.100.0/24'
];
app.use('/webhook', (req, res, next) => {
const clientIP = req.ip;
if (!allowedIPs.includes(clientIP)) {
return res.status(403).send('Forbidden');
}
next();
});
Resolución de Problemas Comunes
Problema 1: La URL del Túnel Cambia en Cada Sesión
Problema: Los túneles gratuitos de ngrok usan URLs aleatorias que cambian con cada reinicio. Los webhooks configurados con la URL antigua dejan de funcionar.
Soluciones:
- Usa un plan de pago para URLs estáticas:
ngrok http 3000 --domain=myapp.ngrok.app
- Cambia a NPort con subdominios personalizados gratuitos:
nport start 3000 --subdomain myapp
# Always https://myapp.nport.io
- Actualiza los webhooks programáticamente a través de API cuando el túnel se inicie
Problema 2: Los Webhooks Exceden el Tiempo de Espera
Problema: Tu servidor local tarda demasiado en responder. Servicios como Slack requieren respuestas en 3 segundos.
Solución:
Procesa asincrónicamente:
app.post('/webhook', async (req, res) => {
// Acknowledge immediately
res.json({ received: true });
// Process in background
processWebhookAsync(req.body).catch(console.error);
});
async function processWebhookAsync(data) {
// Do slow work here (database, external APIs, etc.)
await heavyProcessing(data);
}
Prueba los tiempos de espera con Apidog configurando límites de tiempo de espera agresivos en los escenarios de prueba.
Problema 3: Errores CORS desde el Navegador
Problema: El frontend que hace solicitudes a la URL del túnel obtiene errores CORS.
Solución:
Configura los encabezados CORS:
const cors = require('cors');
app.use(cors({
origin: [
'http://localhost:3001', // Your frontend dev server
'https://abc123.ngrok.io' // Your tunnel URL
],
credentials: true
}));
Problema 4: Límite de Velocidad en la Capa Gratuita
Problema: Los túneles gratuitos tienen límites de conexión (ngrok: 40/min).
Soluciones:
- Agrupa las solicitudes de prueba en Apidog en lugar de realizar pruebas individuales rápidas
- Usa múltiples túneles para diferentes servicios
- Actualiza a un plan de pago si realizas muchas pruebas
- Cambia a un servicio ilimitado como Cloudflare Tunnel o NPort
Problema 5: El Túnel se Desconecta Frecuentemente
Problema: La inestabilidad de la red causa caídas del túnel.
Solución:
Usa systemd/pm2 para reiniciar automáticamente:
# Create systemd service
sudo nano /etc/systemd/system/ngrok.service
[Unit]
Description=ngrok tunnel
After=network.target
[Service]
Type=simple
User=youruser
WorkingDirectory=/home/youruser
ExecStart=/usr/local/bin/ngrok http 3000
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
sudo systemctl enable ngrok
sudo systemctl start ngrok
Problema 6: No se Puede Alcanzar el Túnel desde una Red Específica
Problema: Los firewalls corporativos o redes restrictivas bloquean el tráfico del túnel.
Soluciones:
- Usa Cloudflare Tunnel (raramente bloqueado)
- Cambia la región del túnel a una más cercana a ti:
ngrok http 3000 --region eu
- Usa Tailscale para una red privada en lugar de un túnel público
Patrones Avanzados
Patrón 1: Tunelización Multi-Puerto
Expón múltiples servicios simultáneamente:
# Terminal 1: API server
ngrok http 3000
# Terminal 2: Frontend dev server
ngrok http 3001
# Terminal 3: Webhook worker
ngrok http 3002
O usa el archivo de configuración de ngrok:
# ~/.ngrok2/ngrok.yml
tunnels:
api:
proto: http
addr: 3000
frontend:
proto: http
addr: 3001
worker:
proto: http
addr: 3002
ngrok start --all
Patrón 2: Túnel + Docker Compose
# docker-compose.yml
version: '3'
services:
api:
build: .
ports:
- "3000:3000"
ngrok:
image: ngrok/ngrok:latest
command:
- "http"
- "api:3000"
environment:
NGROK_AUTHTOKEN: ${NGROK_AUTHTOKEN}
docker-compose up
Patrón 3: Inyección Dinámica de URL del Túnel
Actualiza automáticamente tu aplicación con la URL del túnel:
// start-tunnel.js
const ngrok = require('ngrok');
const fs = require('fs');
(async function() {
const url = await ngrok.connect(3000);
console.log(`Tunnel started: ${url}`);
// Update .env file
fs.appendFileSync('.env', `\nTUNNEL_URL=${url}\n`);
// Update Stripe webhook
await updateStripeWebhook(url);
})();
Patrón 4: Reenvío de Solicitudes a Múltiples Entornos
Prueba el mismo webhook contra desarrollo, staging y producción:
// webhook-multiplexer.js
app.post('/webhook', async (req, res) => {
const environments = [
'http://localhost:3000',
'https://staging.api.com',
'https://api.yourapp.com'
];
// Forward to all environments
const results = await Promise.all(
environments.map(env =>
fetch(`${env}/webhook`, {
method: 'POST',
headers: req.headers,
body: JSON.stringify(req.body)
})
)
);
res.json({ forwarded: results.length });
});
Conclusión
Probar APIs locales que reciben webhooks o callbacks no requiere desplegar a staging por cada cambio. Los servicios de tunelización crean URLs públicas temporales que permiten a los servicios externos alcanzar tu entorno de desarrollo.
Comienza con la capa gratuita de cualquier herramienta. Si las pruebas de webhooks se convierten en una parte diaria de tu flujo de trabajo, considera los planes de pago para URLs estáticas y características adicionales. Pero para la mayoría de los desarrolladores, los servicios de tunelización gratuitos combinados con las capacidades de prueba de API de Apidog proporcionan todo lo necesario para probar APIs locales de manera efectiva.
