Documentación
dtunnel expone un servidor web en tu máquina local como una URL pública HTTPS bajo
*.dtunnel.desarrollado.com. No necesitas abrir puertos en el router ni configurar DNS.
Introducción
dtunnel es un túnel HTTP/HTTPS tipo ngrok o Tunnelmole, alojado en
dtunnel.desarrollado.com. Tu aplicación sigue escuchando en
localhost; el cliente dtunnel mantiene una conexión saliente hacia el servidor
y enruta el tráfico de Internet hacia tu proceso local.
Funciona con cualquier stack que escuche en un puerto TCP local:
- Servidores de desarrollo: Vite, Next.js, Create React App, Flask, Django, etc.
- APIs REST y GraphQL
- Contenedores Docker con
-p 8080:80mapeado a localhost - Nginx o Apache en tu máquina
- WebSockets (WSS) a través del túnel HTTPS
Requisitos
| Componente | Versión mínima | Notas |
|---|---|---|
| Node.js | 18+ | Para el CLI dtunnel |
| frpc | 0.61.x | Cliente del broker frp (releases) |
| Servidor local | — | Cualquier app en 127.0.0.1:PUERTO |
Instalación
Versión actual del CLI: 1.0.5 · Comprueba la tuya con dtunnel version
Instalador universal (Linux, macOS y WSL)
Este método instala automáticamente la versión correcta de frpc y el CLI
dtunnel para tu sistema. No requiere Node.js.
curl -O https://install.desarrollado.com/dtunnel/install && sudo bash install
Opcionalmente, audita el script antes de ejecutarlo:
curl https://install.desarrollado.com/dtunnel/install
Espejo alternativo:
curl -O https://dtunnel.desarrollado.com/install/dtunnel/install && sudo bash install
Instalar con Node.js
La mejor opción para desarrolladores Node.js/JavaScript/TypeScript o Windows sin WSL.
Requiere Node.js 16 o superior. frpc se descarga automáticamente la primera vez que abres un túnel
(o con dtunnel install-frpc) en ~/.dtunnel/bin/.
npm install -g @desarrollado/dtunnel
Paquete en npmjs.com/@desarrollado/dtunnel (v1.0.5).
Comprueba la instalación:
dtunnel version
dtunnel --help
Actualizar dtunnel
Consulta el changelog para ver qué incluye cada versión.
Primero comprueba qué versión tienes instalada:
dtunnel version
Versión publicada actualmente: 1.0.5
Linux / macOS / WSL (instalador curl)
Vuelve a ejecutar el instalador; sobrescribe frpc y dtunnel en /usr/local/bin:
curl -O https://install.desarrollado.com/dtunnel/install && sudo bash install
dtunnel version
Node.js / npm
npm install -g @desarrollado/dtunnel@latest
dtunnel version
Para instalar una versión concreta:
npm install -g @desarrollado/dtunnel@1.0.5
Windows sin WSL
Usa npm (arriba). Para actualizar solo frpc: dtunnel install-frpc
o borra ~/.dtunnel/bin/ y vuelve a abrir un túnel.
dtunnel down.
No hace falta reiniciar el servidor remoto.
Inicio rápido
-
Levanta tu app local en un puerto, por ejemplo
88080:python -m http.server 88080 # o: npm run dev → suele ser puerto 3000, 5173, etc. -
Abre el túnel (URL aleatoria, plan gratuito):
dtunnel --port 88080Salida esperada:
https://a7f3c2.dtunnel.desarrollado.com ⟶ http://localhost:88080 http://a7f3c2.dtunnel.desarrollado.com ⟶ http://localhost:88080 -
Prueba desde el navegador o con curl:
curl -I https://a7f3c2.dtunnel.desarrollado.com -
Detén el túnel cuando termines:
dtunnel down
dtunnel --port debe coincidir con el puerto donde escucha tu aplicación local.
Si Vite usa 5173, ejecuta dtunnel --port 5173.
Referencia CLI
| Comando | Descripción |
|---|---|
dtunnel --port <N> |
Abre un túnel con subdominio aleatorio (sin cuenta). No abre reserva. |
dtunnel -p 3000 -s mi-api |
Abre un túnel usando el nombre mi-api que ya reservaste antes |
dtunnel register |
Crear cuenta (email + contraseña mín. 8 caracteres) |
dtunnel login |
Iniciar sesión; guarda token en ~/.dtunnel/config.json |
dtunnel reserve <nombre> |
Guarda un nombre en tu cuenta (no abre túnel). Ej.: mi-api → mi-api.dtunnel.desarrollado.com |
dtunnel status |
Estado del túnel local (subdominio, puerto, PID, URLs) |
dtunnel --list up |
Listar túneles activos (local y, con sesión, los de tu cuenta) |
dtunnel version |
Versión instalada del CLI |
dtunnel install-frpc |
Descargar o actualizar frpc en ~/.dtunnel/bin/ |
dtunnel down |
Detener el proceso frpc local |
dtunnel --help |
Ayuda resumida |
Archivos locales del cliente:
~/.dtunnel/config.json— token de sesión (si hiciste login)~/.dtunnel/tunnel.json— estado del túnel activo (subdominio, URLs, PID)~/.dtunnel/frpc.toml— configuración generada al abrir túnel~/.dtunnel/bin/frpc— binario del cliente (auto-instalado en v1.0.5+)~/.dtunnel/frpc.pid— PID del proceso frpc activo
Cuentas, subdominios y reservas
En dtunnel conviven tres ideas distintas. Mezclarlas es la causa más habitual de errores («subdominio no reservado», «404 en la URL», etc.).
Tres conceptos (no son lo mismo)
| Concepto | Qué es | Ejemplo | ¿Cuándo existe? |
|---|---|---|---|
| Subdominio | El nombre de tu URL pública | mi-api en https://mi-api.dtunnel.desarrollado.com |
Siempre que hay túnel activo; o guardado en tu cuenta si lo reservaste |
| Túnel | La conexión viva entre tu PC y el servidor | dtunnel --port 3000 en ejecución |
Solo mientras frpc está activo (dtunnel down lo cierra) |
| Reserva | Reclamar un nombre para tu cuenta | dtunnel reserve mi-api |
Permanente mientras tu cuenta esté activa (aunque no haya túnel abierto) |
localhost.
Reservar un nombre no hace que la URL responda sola: necesitas abrir el túnel después.
Sin cuenta (gratis)
dtunnel --port 80
# → https://c349cc8e.dtunnel.desarrollado.com (nombre aleatorio)
- Cada vez que abres un túnel obtienes un subdominio aleatorio.
- No puedes elegir el nombre ni reutilizarlo en otra sesión.
- Al hacer
dtunnel downel túnel se cierra; la URL deja de funcionar. - No existe el comando
reservesin cuenta.
Con cuenta: dos pasos separados
Para tener siempre la misma URL necesitas reservar el nombre una vez y abrir el túnel cuando quieras usarlo. Son acciones distintas.
Paso 1 — Reservar el nombre (una sola vez)
dtunnel register # o dtunnel login
dtunnel reserve mi-api # guarda "mi-api" en tu cuenta — NO abre túnel
También puedes reservar desde el panel web tras
iniciar sesión.
En este punto https://mi-api.dtunnel.desarrollado.com aún no responde:
solo has reclamado el nombre.
Paso 2 — Abrir el túnel con ese nombre
dtunnel --port 3000 --subdomain mi-api
# → https://mi-api.dtunnel.desarrollado.com ⟶ http://localhost:3000
Aquí sí se crea el túnel activo. Mientras el comando esté en marcha (o frpc siga corriendo),
la URL pública apunta a tu máquina. Al cerrar con dtunnel down la URL deja de responder,
pero la reserva de mi-api sigue en tu cuenta para la próxima vez.
dtunnel -s mi-api sin haber hecho
dtunnel reserve mi-api antes. La API rechazará la petición porque el nombre no está en tu cuenta.
Reserva vs túnel activo
Reserva (reserve) | Túnel activo (--port) | |
|---|---|---|
| Qué guarda | El nombre en tu cuenta | La conexión en curso |
| ¿Sirve HTTP por sí solo? | No | Sí (mientras esté abierto) |
¿Sigue tras dtunnel down? | Sí | No |
| Comando típico | dtunnel reserve mi-api | dtunnel --port 3000 -s mi-api |
Dos límites distintos (con cuenta)
No confundas cuántos nombres puedes guardar con cuántas conexiones puedes tener abiertas a la vez:
| Límite | Qué cuenta | Gratis (anónimo) | Con cuenta (ej.) |
|---|---|---|---|
| Túneles simultáneos | Cuántas conexiones activas a la vez | 1 | 5 (según plan) |
| Subdominios reservados | Cuántos nombres puedes reclamar con reserve |
0 (no aplica) | 5 (según plan) |
Puedes reservar varios nombres (mi-api, staging, demo…) y usar uno u otro
al abrir cada túnel con -s. Ver también Límites y planes.
Reglas de nombres
- Longitud: 3–32 caracteres
- Solo letras minúsculas, números y guiones (
a-z,0-9,-) - Bloqueados para todos:
www,api,admin,mail,ftp,dtunnel - Primero en reservar gana el nombre (mientras la cuenta esté activa)
Flujo completo de referencia
# Día 1 — configuración inicial
dtunnel register
dtunnel reserve mi-api
# Cada vez que quieras exponer tu app
dtunnel --port 3000 --subdomain mi-api
# … trabajas con la misma URL …
dtunnel down
# Día 2 — la reserva sigue; solo abres de nuevo
dtunnel --port 3000 --subdomain mi-api
Casos de uso
React / Vite / Next.js
npm run dev # anota el puerto (ej. 5173)
dtunnel --port 5173
Node.js / Express
node server.js # escucha en 3000
dtunnel --port 3000
Docker
Publica el puerto en localhost y tunela ese puerto:
docker run -p 8080:80 nginx:alpine
dtunnel --port 8080
Webhooks (Stripe, GitHub, IFTTT…)
Configura la URL del webhook como https://<tu-sub>.dtunnel.desarrollado.com/ruta.
El proveedor enviará POST/GET a tu app local a través del túnel.
Probar en móvil o con un compañero
Comparte la URL HTTPS que imprime el CLI. Cualquier dispositivo con Internet puede acceder mientras el túnel esté activo en tu máquina.
WebSocket (WSS)
Las apps que usan wss:// sobre la misma URL HTTP funcionan sin configuración adicional
en el cliente dtunnel; el tráfico pasa por el túnel HTTPS.
API REST
Base URL: https://dtunnel.desarrollado.com/api
Salud del servicio
GET /api/health
# → { "ok": true, "service": "dtunnel-api" }
Registro e inicio de sesión
POST /api/auth/register
Content-Type: application/json
{ "email": "tu@email.com", "password": "minimo8chars" }
POST /api/auth/login
{ "email": "tu@email.com", "password": "..." }
# → { "token": "...", "email": "..." }
Crear túnel
POST /api/tunnels
Content-Type: application/json
{ "port": 88080 }
# Con cuenta (header Authorization: Bearer <token>)
{ "port": 3000, "subdomain": "mi-api" }
# Respuesta
{
"subdomain": "a7f3c2",
"httpUrl": "http://a7f3c2.dtunnel.desarrollado.com",
"httpsUrl": "https://a7f3c2.dtunnel.desarrollado.com",
"server": "dtunnel.desarrollado.com",
"serverPort": 7000,
"token": "...",
"persistent": false
}
Reservar subdominio
POST /api/subdomains/reserve
Authorization: Bearer <token>
{ "name": "mi-api" }
GET /api/me
Authorization: Bearer <token>
# → { "email": "...", "subdomains": ["mi-api"] }
Cómo funciona
dtunnel conecta tu localhost con una URL pública HTTPS bajo
*.dtunnel.desarrollado.com. No necesitas abrir puertos en el router ni configurar DNS.
Arquitectura
flowchart TB
subgraph INET["Internet"]
U["Cliente HTTP / Webhook"]
end
subgraph VPS["VPS HestiaCP"]
NG["Nginx :443"]
WEB["Web estática + Admin"]
API["API Node :3001"]
FRPS["frps :18080 / :7000"]
NG --> WEB
NG --> API
NG --> FRPS
end
subgraph PC["Tu PC"]
CLI["dtunnel CLI"]
FRPC["frpc"]
APP["127.0.0.1:PUERTO"]
CLI --> API
CLI --> FRPC
FRPC --> APP
end
U -->|HTTPS| NG
FRPC <-->|TCP 7000| FRPS
Secuencia: abrir un túnel
sequenceDiagram participant Dev as Desarrollador participant CLI as dtunnel CLI participant API as API participant FRPC as frpc participant FRPS as frps Dev->>CLI: dtunnel --port 88080 CLI->>API: POST /api/tunnels API-->>CLI: subdomain, token, server CLI->>FRPC: frpc -c ~/.dtunnel/frpc.toml FRPC->>FRPS: auth + registro subdominio Note over FRPC,FRPS: Túnel activo mientras frpc corre
Secuencia: visita HTTP
sequenceDiagram participant User as Visitante participant NG as Nginx participant FRPS as frps participant FRPC as frpc participant App as localhost:88080 User->>NG: GET https://mi-app.dtunnel.desarrollado.com NG->>FRPS: proxy a vhost :18080 FRPS->>FRPC: túnel del subdominio mi-app FRPC->>App: GET http://127.0.0.1:88080 App-->>User: respuesta
Puertos en el VPS
| Componente | Puerto | Acceso |
|---|---|---|
| Nginx (TLS) | 443 | Público |
| API Node | 3001 | Solo vía /api en apex |
| frps vhost HTTP | 18080 | Interno (Nginx → frps) |
| frps control | 7000 | Público (clientes frpc) |
Resumen en 5 pasos
- El CLI pide un subdominio a la API y lanza
frpc. frpcse conecta al broker (puerto 7000) con autenticación por token.- Un visitante abre
https://nombre.dtunnel.desarrollado.com. - Nginx termina TLS y reenvía a
frps, que enruta al túnel activo. frpcreenvía la petición a127.0.0.1:PUERTO.
Límites y planes
«URL fija» significa que puedes reutilizar el mismo nombre cada vez que abres un túnel (tras reserve).
No significa que la URL esté siempre en línea: hace falta tener el túnel activo con dtunnel --port.
| Gratis (anónimo) | Registrado | |
|---|---|---|
| Subdominio | Aleatorio en cada túnel | Fijo si lo reservaste (reserve) |
| Túneles simultáneos | 1 | Hasta 5 (según plan) |
| Nombres reservables | 0 — no puedes usar reserve | Hasta 5 (según plan) |
| HTTPS | Sí | Sí |
| Cuenta requerida | No | Sí (registro gratuito) |
Panel de administración
Superadmins pueden gestionar usuarios, planes, precios y límites en dtunnel.desarrollado.com/admin.html (requiere cuenta con permisos admin).
Desde el panel puedes:
- Ver estadísticas de usuarios y túneles activos
- Cambiar plan o desactivar cuentas
- Crear y editar planes (precio, límites de túneles y subdominios)
- Cerrar túneles activos en el servidor
- Ajustar el límite de túneles anónimos
Variables de entorno
| Variable | Default | Descripción |
|---|---|---|
DTUNNEL_API_URL |
https://dtunnel.desarrollado.com/api |
URL base de la API (solo si usas otro entorno) |
El token de sesión y credenciales frp los gestiona el CLI; no hace falta exportar DTUNNEL_TOKEN manualmente.
Solución de problemas
Instala frpc al ejecutar dtunnel
En v1.0.5+ el CLI intenta descargar frpc automáticamente. Si falla, ejecuta
dtunnel install-frpc o usa el instalador curl (Linux/macOS/WSL). Comprueba con
frpc --version o ~/.dtunnel/bin/frpc --version.
502 Bad Gateway en la URL pública
- Comprueba que
dtunnel --portsigue en ejecución (no cerraste la terminal sindown). - Verifica que tu app local responde:
curl http://127.0.0.1:PUERTO - El puerto del CLI debe coincidir con el de tu app.
404 en el subdominio
- El túnel no está activo en tu máquina (
dtunnel statusdebe mostrar conexión). - Reservar un nombre no basta: necesitas
dtunnel --port N -s nombrecon el túnel en marcha. - Con
--subdomain, el nombre debe estar reservado en tu cuenta (dtunnel reserveo panel web).
Connection refused al conectar frpc
- Firewall bloqueando salida TCP al puerto 7000 del servidor.
- Red corporativa que bloquea conexiones salientes no estándar.
Límite de túneles alcanzado
Ejecuta dtunnel down antes de abrir otro. Plan gratuito: 1 túnel; registrado: hasta 5.
La URL no carga desde otro dispositivo
- Usa la URL HTTPS que muestra el CLI.
- El túnel solo existe mientras tu PC ejecuta
frpc(no es hosting permanente en plan gratuito).
Más ayuda
Email: dtunnel@desarrollado.com · Obtener ayuda · GitHub · npm
Seguridad y SSL/TLS
dtunnel usa TLS en el borde (Nginx + Let's Encrypt) para que todas las URLs públicas
sean https://. El tráfico entre visitante e Internet está cifrado hasta el VPS;
dentro del servidor, Nginx reenvía en HTTP a frps en localhost.
Mapa de cifrado y zonas de confianza
flowchart TB
subgraph EXT["Zona pública — TLS activo"]
V["Cliente HTTPS"]
V -->|"TLS 1.2/1.3 :443"| NGX["Nginx"]
CERT["Cert Let's Encrypt\n*.dtunnel.desarrollado.com"]
CERT -.-> NGX
end
subgraph DMZ["VPS — no expuesto directamente"]
NGX -->|"proxy_pass HTTP"| FRP["frps :18080"]
API["API :3001\nJWT + HTTPS vía /api"]
NGX --> API
end
subgraph OUT["Conexión saliente autenticada"]
FRP <-->|"TCP :7000\nauth.token"| CLIENT["frpc en tu PC"]
end
subgraph LOOP["Loopback — tu máquina"]
CLIENT --> APP["127.0.0.1:PUERTO"]
end
style EXT fill:#2b4278,color:#dce1ff
style DMZ fill:#282a31,color:#e3e2e9
style OUT fill:#424659,color:#dee0f9
style LOOP fill:#1e4e4f,color:#bcebec
Handshake SSL (visitante)
sequenceDiagram participant B as Navegador participant NG as Nginx :443 participant LE as Let's Encrypt participant FR as frps → frpc B->>NG: ClientHello (SNI: mi-app.dtunnel.desarrollado.com) NG->>B: ServerHello + certificado wildcard Note over B,NG: TLS establecido — tráfico cifrado B->>NG: GET / (HTTPS) NG->>FR: HTTP interno al túnel mi-app FR->>B: respuesta (cifrada en el camino de vuelta)
Autenticación del túnel (frp)
sequenceDiagram
participant CLI as dtunnel CLI
participant API as API
participant FRPC as frpc
participant FRPS as frps
CLI->>API: POST /api/tunnels (opcional: Bearer JWT)
API-->>CLI: subdomain + frp token + server:7000
CLI->>FRPC: frpc.toml con auth.token
FRPC->>FRPS: login con token
alt token inválido
FRPS-->>FRPC: rechazado
else token válido
FRPS-->>FRPC: túnel registrado
end
| Tramo | Protocolo | Protección |
|---|---|---|
| Visitante → VPS | HTTPS / TLS | Cifrado + certificado wildcard |
| Nginx → frps | HTTP localhost | Solo red interna del VPS |
| frpc → frps | TCP :7000 | Token auth.token de frp |
| frpc → tu app | HTTP 127.0.0.1 | Solo loopback en tu PC |
| CLI → API | HTTPS | JWT tras login (cuentas) |
https://subdominio.dtunnel.desarrollado.com.
Buenas prácticas
- Comparte solo la URL HTTPS que muestra el CLI.
- No expongas paneles de admin sin login propio en la aplicación.
- Con cuenta registrada, solo tú puedes reservar y usar tus subdominios.
- Cierra el túnel con
dtunnel downcuando termines de desarrollar. - No commitees
~/.dtunnel/config.jsonnifrpc.toml(contienen tokens).