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:80 mapeado a localhost
  • Nginx o Apache en tu máquina
  • WebSockets (WSS) a través del túnel HTTPS
Conexión saliente únicamente. El cliente abre conexión hacia el VPS (puerto 7000). Por eso funciona detrás de NAT, firewall corporativo o VPN sin reglas especiales.

Requisitos

ComponenteVersión mínimaNotas
Node.js18+Para el CLI dtunnel
frpc0.61.xCliente del broker frp (releases)
Servidor localCualquier 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.

Tras actualizar, los túneles abiertos siguen activos hasta que ejecutes dtunnel down. No hace falta reiniciar el servidor remoto.

Inicio rápido

  1. 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.
  2. Abre el túnel (URL aleatoria, plan gratuito):
    dtunnel --port 88080

    Salida esperada:

    https://a7f3c2.dtunnel.desarrollado.com  ⟶  http://localhost:88080
    http://a7f3c2.dtunnel.desarrollado.com   ⟶  http://localhost:88080
  3. Prueba desde el navegador o con curl:
    curl -I https://a7f3c2.dtunnel.desarrollado.com
  4. Detén el túnel cuando termines:
    dtunnel down
El puerto de dtunnel --port debe coincidir con el puerto donde escucha tu aplicación local. Si Vite usa 5173, ejecuta dtunnel --port 5173.

Referencia CLI

ComandoDescripció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-apimi-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)

ConceptoQué esEjemplo¿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)
Analogía rápida: el subdominio es la dirección, la reserva es registrar que esa dirección es tuya, y el túnel es el camino abierto ahora mismo hacia tu 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 down el túnel se cierra; la URL deja de funcionar.
  • No existe el comando reserve sin 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.

Error frecuente: ejecutar 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é guardaEl nombre en tu cuentaLa conexión en curso
¿Sirve HTTP por sí solo?NoSí (mientras esté abierto)
¿Sigue tras dtunnel down?No
Comando típicodtunnel reserve mi-apidtunnel --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ímiteQué cuentaGratis (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

ComponentePuertoAcceso
Nginx (TLS)443Público
API Node3001Solo vía /api en apex
frps vhost HTTP18080Interno (Nginx → frps)
frps control7000Público (clientes frpc)

Resumen en 5 pasos

  1. El CLI pide un subdominio a la API y lanza frpc.
  2. frpc se conecta al broker (puerto 7000) con autenticación por token.
  3. Un visitante abre https://nombre.dtunnel.desarrollado.com.
  4. Nginx termina TLS y reenvía a frps, que enruta al túnel activo.
  5. frpc reenvía la petición a 127.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
SubdominioAleatorio en cada túnelFijo si lo reservaste (reserve)
Túneles simultáneos1Hasta 5 (según plan)
Nombres reservables0 — no puedes usar reserveHasta 5 (según plan)
HTTPS
Cuenta requeridaNoSí (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

VariableDefaultDescripció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 --port sigue en ejecución (no cerraste la terminal sin down).
  • 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 status debe mostrar conexión).
  • Reservar un nombre no basta: necesitas dtunnel --port N -s nombre con el túnel en marcha.
  • Con --subdomain, el nombre debe estar reservado en tu cuenta (dtunnel reserve o 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
TramoProtocoloProtección
Visitante → VPSHTTPS / TLSCifrado + certificado wildcard
Nginx → frpsHTTP localhostSolo red interna del VPS
frpc → frpsTCP :7000Token auth.token de frp
frpc → tu appHTTP 127.0.0.1Solo loopback en tu PC
CLI → APIHTTPSJWT tras login (cuentas)
SSL automático: no configures certificados en tu app local. Hestia renueva el wildcard de Let's Encrypt; el CLI solo imprime la URL https://subdominio.dtunnel.desarrollado.com.
Responsabilidad del desarrollador: la URL pública es accesible por quien la conozca (como ngrok). Añade autenticación en tu app para rutas de admin, APIs sensibles o datos privados.

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 down cuando termines de desarrollar.
  • No commitees ~/.dtunnel/config.json ni frpc.toml (contienen tokens).