koalp / tunneller

Allow internal services, running on localhost, to be accessed over the internet..

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Go Report Card license Release

Table of Contents

tunneller

Tunneller allows you to expose services which are running on localhost, or on your local network, to the entire internet.

This is very useful for testing webhooks, the generation of static-site compilers, and similar things.

Overview

Assuming you have a service running within your local network, perhaps a HTTP server you could access via http://localhost:8080/, you can expose that to the entire internet by running:

$ tunneller client -expose localhost:8080 -name=example

This will output something like this:

..
Visit http://example.tunneller.steve.fi/ to see your content

The location listed will now be publicly visible to all remote hosts. As the name implies there is a central-host involved which is in charge of routing/proxying to your local network - in this case that central host is tunneller.steve.fi, but the important thing is that you can run your own instance of that server.

This is a self-hosted alternative to a system such as ngrok.

How it works

When a client is launched it creates a web-socket connection to the default remote end-point, tunneller.steve.fi, and keeps that connection alive. A name is also sent for that connection.

Next, when a request comes in for foo.tunneller.steve.fi the server can look for an open web-socket connection with the name foo, and route the request through it:

  • The server sends a "Fetch this URL" request to the client.
  • The client makes the request to fetch the URL
    • This will succeed, because the client is running inside your network and can access localhost, and any other "internal" resources.
  • The response is sent back to the server
    • And from there it is routed back to the requested web-browser.

Installation

There are two ways to install this project from source, which depend on the version of the go version you're using.

NOTE: If you prefer you can find binary releases upon our release page

Source Installation go <= 1.11

If you're using go before 1.11 then the following command should fetch/update tunneller, and install it upon your system:

 $ go get -u github.com/skx/tunneller

Source installation go >= 1.12

If you're using a more recent version of go (which is highly recommended), you need to clone to a directory which is not present upon your GOPATH:

git clone https://github.com/skx/tunneller
cd tunneller
go install

If you don't have a golang environment setup you should be able to download a binary for GNU/Linux from our release page.

Installation Self-Hosted Server

If you wish to host your own central-server things are a little more complex:

  • You'll need to create a DNS-entry tunneller.example.com
  • You'll also need to setup a wildcard DNS entry for *.tunneller.example.com to point to the same host.
  • Finally you'll need to setup nginx/apache to proxy to the tunneller application.
    • By default this will listen upon 127.0.0.1:8080.

You can find a sample configuration file for Apache2 beneath the apache2 directory.

WSS options

If you want to setup an encrypted remote endpoint (using apache mod_ssl, for example) you can use the wss:// prefix to connect to a secure websocket (eg. -tunnel wss://tunneller.example.com). If no prefix is set on the -tunnel option ws:// is assumed.

In case the SSL certificate you have installed on your webserver is self-signed or you are just testing, you can use the -insecure option to allow connection to unverified domains.

See the apache2 folder for documentation on how to setup an encrypted websocket.

Usage with docker

Build the image

Use docker build --tag=tunneller . to build the image under the tunneller:latest tag.

Run the server

Use docker run --publish 8080:8080 --name tunneller tunneller on your server by replacing to run the image as server.

To run the image and expose a specific port, use your desired port intead of 8080.

Run the client

To run the client, you need to give it access to the host network. Run it by running docker run --network host --name tunneller-client tunneller client -expose 8080. Replace 8080 by the port number you want to expose.

Github Setup

This repository is configured to run tests upon every commit, and when pull-requests are created/updated. The testing is carried out via .github/run-tests.sh which is used by the github-action-tester action.

Releases are automated in a similar fashion via .github/build, and the github-action-publish-binaries action.

Implementation Issues

This is a really simple application, but it was more fiddly to implement than I expected, primarily because of issues with using websockets:

  • Websocket reads/writes block.
  • Keeping the connection alive is fiddly, and requires the use of keep-alives.
    • But these can't overlap with the "real" communication.
    • Hence the mutex-use.

It would be much simpler to implement a system like this using a RabbitMQ, mosquitto, or some other message-bus:

  • Client connects to the message-bus.
    • When a HTTP-request must be made it would be sent down the bus.
    • The reply would get posted back via the same route.

The downside to using a message-bus is security; a client could easily sniff messages meant for other clients. In a secure-environment this wouldn't matter, but hosting the central-endpoint publicly this would be a mistake.

(Similarly you could use a Redis instance as the central queue, but exposing a Redis host to the internet would be a recipe for compromise.)

If I were running this software at scale I'd probably look at using a queue though; we could create a per-client topic avoiding the issue of security. The downside to that would be we'd need to register:

 $ tunneller register --login=steve --password=bar

Once that was complete we could connect to the MQ queue, and subscribe to "#steve" - assuming that the registration created an MQ-user for us, and that the ACLs on the queue would be setup such that the user steve couldn't subscripe to the topic belonging to another client (e.g. "#bob").

About

Allow internal services, running on localhost, to be accessed over the internet..

License:GNU General Public License v2.0


Languages

Language:Go 84.6%Language:Shell 8.3%Language:Dockerfile 3.6%Language:HCL 3.5%