Diglet is an fully encrypted reverse HTTPS tunnel server and client. It enables you to securely make any HTTP(S) server running behind a restrictive NAT or firewall accessible from the internet.
Diglet depends on Node.js 10 and the appropriate packages for building native modules for your platform.
# install nodejs via node version manager
# skip this step on windows and just install the package from nodejs.org
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
# source node version manager
source ~/.bashrc
# install nodejs lts release
nvm install 10
# install build dependencies (debian based)
# apt install build-essential
#
# install build dependencies (macos / osx)
# xcode-select --install
#
# install build dependencies (windows)
# npm install -g windows-build-tools
# install diglet using node package manager
npm install -g github:tacticalchihuahua/diglet
Once you have the diglet
package installed, you can use it to establish a
reverse tunnel from a local HTTP(S) server to a diglet server on the internet.
By default, diglet is configured to use a test server diglet.me
. Don't
depend on it, but if it's online you can feel free to test with it. It is
recommended to run your own diglet server, which is described in detail in the
next section.
Setting up a tunnel is easy. Let's say you have a website running at
localhost:8080
:
diglet tunnel --port 8080
Diglet will establish a tunnel and print your unique public URL to the console.
If you would like more verbose logging, which can be useful for debugging, add
the --debug
flag to the above command. Your unique URL includes a subdomain
that is a 160 bit hash of your public key. The private portion of this key is
generated automatically every time you run diglet.
If you want to re-use the same URL every time you create a tunnel, pass the
--save
flag and it will be saved to $HOME/.diglet.prv
and that key will be
used going forward when called with the --load
option. Note that if you use a
saved key, you must not load the same key when running multiple tunnels on the
same host or you will get unexpected results.
After setting up your own server, create a configuration file to reflect this
at the path $HOME/.digletrc
:
Hostname=mydomain.tld
TunnelPort=8443
This guide makes a few assumptions about the providers you will use for your server and for your domains, however this should translate to any number of other providers.
- Login or create an account at Digital Ocean, then navigate to Droplets > Create. Under Distributions, select Debian.
- Diglet does not require very many resources, so you may safely select the cheapest option with 1 vCPU + 1GB Memory.
- Be sure to add your SSH public key to the droplet so we are able to log into it when we are ready.
- Name your droplet something memorable like "diglet-server" and create it.
- When your droplet is finished being created, take note of its IP address, because we'll need it for the next step.
- Login or create an account at Namecheap, then either purchase a new domain or navigate to your existing domain list.
- Navigate to Advanced DNS and create a two new A records:
@ -> <droplet ip address>
* -> <droplet ip address>
- You'll want to set the TTL to the lowest available option, because we want this to propagate as quickly as possible so we can generate our SSL certificate.
SSH into your droplet with ssh root@<your droplet ip address>
and install
LetsEncrypt's certbot-auto
program. The version that is in the Debian
repositories does not support wildcard certs, so you must install with:
# download the certbot program
wget https://dl.eff.org/certbot-auto
# make it executable
chmod +x certbot-auto
# request certificates for your domain and wildcard subdomain
./certbot-auto certonly --manual -d *.mydomainname.tld,mydomainname.tld \
--agree-tos \
--no-bootstrap --manual-public-ip-logging-ok --preferred-challenges dns-01 \
-m your-email-address \
--server https://acme-v02.api.letsencrypt.org/directory
Certbot will do some work and respond with something similar to:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.tunnel.bookch.in with the following value:
20BbljVikhE2Hc4O6LsFoBuxUNSycRkioV2sezLnVLA
Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Log back into Namecheap and navigate back to Domain List > Domain > Advanced
DNS and create a new TXT record according to the instructions provided by
certbot. Set TTL to 1 minute and save. Come back to your SSH session where
certbot is waiting and press enter. Certbot will verify the TXT record and
issue you a wildcard subdomain certificate and private key will be placed in
/etc/letsencrypt/live/mydomain.tld/
. Note that path, because you'll need it
in the next step where we will configure our Diglet server.
Install Diglet on your droplet according to the instructions in the
Installation section. Note that if you are installing and running
diglet as root, you need to append --unsafe-perm
to the install
command.
Create a file called .digletrc
in the home directory (/root/.digletrc
),
containing the following:
Hostname = mydomain.tld
ProxyPort = 443
RedirectPort = 80
TunnelPort = 8443
ServerPrivateKey = /etc/letsencrypt/live/mydomain.tld/privkey.pem
ServerSSLCertificate = /etc/letsencrypt/live/mydomain.tld/fullchain.pem
Be sure to replace mydomain.tld
with your domain name. When you are ready
go ahead and run diglet server
to start up your server!
You can run Diglet in the background and have it restart automatically in the
unlikely event the process crashes using the
forever
package.
npm install -g forever # add --unsafe-perm if running as root
Then start Diglet using forever with:
forever start $(which diglet)
Refer to the forever documentation for more information on how to monitor your process.
Diglet also supports a whitelist feature that prevents arbitrary clients from establishing tunnels. This is an optional feature that allows you to set a list of client tunnel identifiers in your configuration file. The identifiers are the RMD-160 hash of the user's public key.
For example, if you want to only allow the identity
3b7bc044d717e272cde960a8da782846425fd59c
to establish a tunnel, add the
following to your .digletrc
:
Whitelist[]=3b7bc044d717e272cde960a8da782846425fd59c
Repeat as many of these lines as you like to add more authorized clients.
Diglet is a relatively simple machine. It consists of only 4 classes: Server, Proxy, Tunnel, and Handshake. A server performs two duties: it listens for HTTPS requests on the internet and forwards them through a pool of tunnels associated with a proxy.
When a client establishes a tunnel, it connects to a TCP socket on the Diglet server over TLS. The server issues a challenge to the client which the client signs using ECDSA to authenticate it's identity. This is the handshake and if it's successful, the client keeps the socket open and the server adds it to a pool of other connections ("tunnels") from this same client.
This connection pool is associated with the client's identity key and is called a "proxy". When the diglet server receives a HTTPS request on the "front", it parses the subdomain, matches it against the currently managed proxies. If it finds a proxy that matches, it selects one of the open tunnels back to the client and pipes the incoming request through it.
On the client's end, every tunnel that is established is connected to an open socket to a local HTTP(S) service running on the client's computer (but not accessible directly over the internet). When the diglet proxy forwards an incoming request down the tunnel, it is received by the client and forwarded straight through to the client's local server which responds and the resulting response get piped back through the tunnel, up to the diglet server, and on through to the host that made the original HTTPS request.
Every connection along this path is secured with TLS, making all messages sent over the wire fully encrypted, even if the server running on the client's computer is not secured with SSL. Every time a a tunnel is used, it is disposed of and new tunnel is opened in its place. This allows for a fairly high number of requests to be serviced at any given moment. Diglet will even queue requests until a new tunnel is opened if all tunnels are exhausted or if the client disconnects or has a poor connection.
Diglet intentionally does not support cleartext connections and by default is configured to redirect all requests to port 80 to port 443. We recommend using the browser extension HTTPSEverywhere, since this technique still allows an attacker to intercept and redirect the original request if HTTPS is not explicity used. Diglet does, however, modify the response sent back from your tunneled server to include a HTTP Strict Transport Security (HSTS) header so that there should only ever be a single unencrypted request that has to be redirected for a user if they mistakenly try to access your tunnel over HTTP.
You can establish a reverse tunnel programmatically from other Node.js programs easily. Just install diglet as a dependency of your project:
npm install diglet --save
Import the module and use the Tunnel
class:
const { Tunnel } = require('@tacticalchihuahua/diglet');
const options = {
localAddress: '127.0.0.1',
localPort: 8080,
remoteAddress: 'mydigletserver.tld',
remotePort: 8443,
logger: console, // optional
privateKey: require('crypto').randomBytes(32) // optional
};
const tunnel = new Tunnel(options);
tunnel.once('disconnected', function(err) {
console.error(err);
});
tunnel.once('connected', function() {
console.log(tunnel.url);
});
tunnel.open();
git clone https://gitlab.com/tacticalchihuahua/diglet.git
cd diglet
npm install
npm run release # releases for all platforms will be in dist/
Diglet - Fully Encrypted Reverse HTTPS Tunnel
Copyright (C) 2019 Lily Anne Hall.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses/.