A secure tunneling solution that allows you to expose your local servers to the internet through custom subdomains. Built with Node.js, WebSocket, and SSL support.
- 🔒 Secure SSL tunneling with Let's Encrypt
- 🌐 Custom subdomain support (*.dfanso.dev)
- 🚀 HTTP/2 support
- 🔄 WebSocket-based tunneling
- 📦 Official npm client package: @dfanso/tunnel-client
- 🛡️ Production-ready with error handling
Internet (HTTPS) -> Tunnel Server (dfanso.dev) -> WebSocket -> Local Server
- Node.js 16+
- Let's Encrypt SSL certificate
- Domain with wildcard DNS (*.dfanso.dev)
- Add a CNAME record for your domain to point to the tunnel server
git clone https://github.com/dfanso/tunnel-server.git
cd tunnel-server
npm install
Create a .env
file:
NODE_ENV=production
DOMAIN=dfanso.dev
HTTP_PORT=80
HTTPS_PORT=443
WS_PORT=8080
SSL_DIR=/etc/letsencrypt/live/dfanso.dev
- Install certbot:
sudo apt-get install certbot
- Generate wildcard certificate:
sudo certbot certonly --manual --preferred-challenges dns -d *.dfanso.dev -d dfanso.dev
# First install the Cloudflare certbot plugin
sudo apt install python3-certbot-dns-cloudflare # for Ubuntu/Debian
# Create a Cloudflare API token configuration file
sudo mkdir -p /etc/cloudflare
sudo nano /etc/cloudflare/cloudflare.ini
# Add these lines to cloudflare.ini:
# dns_cloudflare_email = your-cloudflare-email@example.com
# dns_cloudflare_api_key = your-global-api-key
# Secure the file
sudo chmod 600 /etc/cloudflare/cloudflare.ini
# Then run certbot with the Cloudflare plugin
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /etc/cloudflare/cloudflare.ini -d *.dfanso.dev -d dfanso.dev
- Follow certbot instructions to add DNS TXT records
Development:
npm run dev
Production:
npm run build
npm start
The recommended way to connect to this tunnel server is using our official npm package @dfanso/tunnel-client.
- Install the package:
npm install @dfanso/tunnel-client
- Basic usage:
const TunnelClient = require('@dfanso/tunnel-client');
const tunnel = new TunnelClient({
subdomain: 'myapp', // Will be myapp.dfanso.dev
targetPort: 3000 // Your local server port
});
tunnel.connect()
.then(({ url }) => {
console.log(`Server is accessible at: ${url}`);
})
.catch(console.error);
- With Express.js:
const TunnelClient = require('@dfanso/tunnel-client');
const express = require('express');
const app = express();
app.use(express.json());
app.get('/', (req, res) => {
res.send('Hello from tunneled server!');
});
const server = app.listen(3000, () => {
const tunnel = new TunnelClient({
subdomain: 'myapp',
targetPort: 3000
});
tunnel.connect()
.then(({ url }) => {
console.log(`Server is accessible at: ${url}`);
})
.catch(console.error);
});
{
tunnelServer: 'wss://dfanso.dev:8080', // Tunnel server URL
subdomain: 'myapp', // Your subdomain
targetPort: 3000, // Your local server port
localPort: 0, // Random port (optional)
rejectUnauthorized: true // Verify SSL (recommended)
}
The client emits the following events:
connect
: When tunnel connection is establisheddisconnect
: When tunnel connection is losterror
: When an error occursrequest
: When a request comes through the tunnel
- All traffic is encrypted with SSL
- Automatic HTTP to HTTPS redirection
- WebSocket connections are secured
- Client verification through SSL
├── src/
│ ├── index.ts # Server entry point
│ ├── server/
│ │ ├── HttpServer.ts # HTTP/HTTPS server
│ │ └── WebSocketServer.ts# WebSocket handling
│ └── services/
│ └── TunnelService.ts # Tunnel management
├── lib/
│ └── tunnel-client.js # Client library
└── examples/
└── example.js # Usage examples
Start the test server:
node test-server.js
Connect with test client:
node test-client.js
Test endpoints:
curl https://test.dfanso.dev/
curl -X POST https://test.dfanso.dev/api/data -d '{"hello":"world"}'
- Set up SSL certificates
- Configure environment variables
- Start with process manager:
npm install -g pm2
pm2 start npm --name "tunnel-server" -- start
MIT
DFanso (https://github.com/dfanso)