In this blog post, I’ll show you how to easily create an SSH tunnel to a remote Linux server using a nice tool called Mole. I have learned that one of the big knocks against SSH tunnels is the complexity of creating them, commands involved, and less documentation around this topic. For end users, it can be difficult to master SSH commands, but My SSH commands cheatsheet can help get you get to speed with SSH.
Perception of Open Source
The Open Source community has been pretty helpful in changing people perception of Linux and its myriad of tools. On fair criticism, Linux is no longer viewed as “that thing” for Geeks, nowadays, users with little technical experience can use it and learn as they break things a little, lol!
Introduction to Mole
The tool we’ll use to create SSH tunnel on Linux is Mole. Mole is a cli application to create ssh tunnels, forwarding a local port to a remote endpoint through an ssh server.
Mole helps you access computers and services blocked by a firewall, as long as the user has ssh access to a computer with access to the target computer or service.
+----------+ +----------+ +----------+
| | | | | |
| | | Firewall | | |
| | | | | |
| Local | tunnel +----------+ tunnel | Jump |
| Computer |--------------------------------| Server |
| | +----------+ | |
| | | | | |
| | | Firewall | | |
| | | | | |
+----------+ +----------+ +----------+
|
|
| tunnel
|
|
+----------+
| |
| |
| |
| |
| Remote |
| Computer |
| |
| |
| |
+----------+
With Mole, you can also access a service that is listening only on a local address with the help of Port forwarding. Learn how to Create Port Forwarding on CentOS 7 with Firewalld.
Also, note that Server and Remote
Computer could potentially be the same machine.
+-------------------+ +--------------------+
| Local Computer | | Remote / Server |
| | | |
| | | |
| (172.17.0.10: | tunnel | |
| 50001) |-------------| (172.17.0.100:22) |
| tunnel client | | tunnel server |
| | | | | |
| | port | | | port |
| | forward | | | forward |
| | | | | |
| (127.0.0.1:3306) | | (127.0.0.1:50000) |
| local address | | | |
| | | | local |
| | | | conn. |
| | | | |
| | | (127.0.0.1:3306) |
| | | remote address |
| | | +----+ |
| | | | DB | |
| | | +----+ |
+-------------------+ +--------------------+
Highlighted Features of Mole
- Auto local address selection: find a port available and start listening to it, so the flag
-local
doesn’t need to be given every time you run the app. - Aliases: save your tunnel settings under an alias, so it can be reused later.
- Leverage the SSH Config File: Use some options (e.g. username, identity key, and port), specified in
$HOME/.ssh/config
whenever possible, so there is no need to have the same SSH server configuration in multiple places.
How to install Mole on Linux / macOS
Installing Mole on Linux is through an installation script that can be downloaded with curl
curl -O https://raw.githubusercontent.com/davrodpin/mole/master/tools/install.sh
Once the script is downloaded, make it executable then install
chmod +x install.sh
sudo ./install.sh
This script will install mole under,/usr/local/bin
but it needs administrator privileges in order to deploy the file. It may require you to type your sudo password.
You can confirm file location and version using the commands:
$ which mole
/usr/local/bin/mole
$ mole version
2.0.0
To view help page, use the --help
option
$ mole --help
ool to create ssh tunnels focused on resiliency and user experience.
Usage:
mole [command]
Available Commands:
add Adds an alias for a ssh tunneling configuration
delete Deletes an alias for a ssh tunneling configuration
help Help about any command
misc A set of miscelaneous commands
show Shows configuration details about ssh tunnel aliases
start Starts a ssh tunnel
stop Stops an instance of mole
version Prints the version for mole
Flags:
-h, --help help for mole
Use "mole [command] --help" for more information about a command.
How to Use Mole to create SSH tunnel
Let’s look at few examples on how to use Mole to create SSH tunnel
#1: Provide all supported options
Create a tunnel with below details:
- On localhost port 8080
- With alias
tunnel1
- To Web Server IP 192.168.130.11:80
- Remote ssh user is jkmutai, SSH server used is 192.168.207.2:22
- The authentication method is Public/Private SSH keys
- SSH Public key location
~/.ssh/id_rsa.pub
- SSH Private Key
~/.ssh/id_rsa
You need to have copied your Public ssh key to the remote SSH server used to tunnel
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
Import remote SSH server fingerprint by doing an ssh to the server 192.168.130.11:80 through SSH Server 192.168.207.2:22, we’ll execute the following commands:
ssh -i ~/.ssh/id_rsa [email protected]
To create a tunnel to our Web Server on
mole start local \
--verbose \
--source 127.0.0.1:8080 \
--destination 192.168.130.11:80 \
--server [email protected]:22 \
--key ~/.ssh/id_rsa
For available start
command flags view with:
mole start local --help
Output command:
INFO[0000] instance identifier is cbd5bb88
DEBU[0000] generating an empty config struct
DEBU[0000] server: [name=192.168.207.2, address=192.168.207.2:22, user=jkmutai]
DEBU[0000] tunnel: [channels:[[source=127.0.0.1:8080, destination=192.168.130.11:80]], server:192.168.207.2:22]
DEBU[0000] known_hosts file used: /home/jkmutai/.ssh/known_hosts
DEBU[0000] connection to the ssh server is established server="[name=192.168.207.2, address=192.168.207.2:22, user=jkmutai]"
INFO[0000] tunnel channel is waiting for connection destination="192.168.130.11:80" source="127.0.0.1:8080"
DEBU[0000] start sending keep alive packets
Another example:
mole start local \
--verbose \
--source 192.168.200.8:8080 \
--destination 192.168.200.5:9090 \
--server [email protected]:22 \
--key ~/.ssh/id_rsa
Creating alias
Let’s consider example where we’re using alias to save configurations.
mole add alias local tunnel1 \
--verbose \
--source 192.168.200.8:8080 \
--destination 192.168.200.5:9090 \
--server [email protected]:22 \
--key ~/.ssh/id_rsa
List created aliases:
$ mole show alias
[aliases]
[aliases.tunnel1]
name = "tunnel1"
type = "local"
verbose = true
insecure = false
detach = false
source = ["192.168.200.8:8080"]
destination = ["192.168.200.5:9090"]
server = "[email protected]:22"
key = "/home/jkmutai/.ssh/id_rsa"
keep-alive-interval = "10s"
connection-retries = 3
wait-and-retry = "3s"
ssh-agent = ""
timeout = "3s"
config = "$HOME/.ssh/config"
rpc = false
rpc-address = "127.0.0.1:0"
To start the tunnel, use
$ mole start alias tunnel1
INFO[0000] instance identifier is tunnel1
DEBU[0000] generating an empty config struct
DEBU[0000] server: [name=192.168.200.5, address=192.168.200.5:22, user=jkmutai]
DEBU[0000] tunnel: [channels:[[source=192.168.200.8:8080, destination=192.168.200.5:9090]], server:192.168.200.5:22]
DEBU[0000] known_hosts file used: /home/jkmutai/.ssh/known_hosts
DEBU[0000] connection to the ssh server is established server="[name=192.168.200.5, address=192.168.200.5:22, user=jkmutai]"
INFO[0000] tunnel channel is waiting for connection destination="192.168.200.5:9090" source="192.168.200.8:8080"
DEBU[0000] start sending keep alive packets
#2: Use the ssh config file to lookup a given server host
You can add ssh configuration for remote SSH server to ~/.ssh/config
, then call its name while running mole.
$ vim ~/.ssh/config
Host myserver
User mole
Hostname 127.0.0.1
Port 2022
IdentityFile /path-to-ssh-priv-key
Then create a tunnel
mole start local \
--verbose \
--source 127.0.0.1:8080 \
--destination 172.17.0.100:80 \
--server myserver
#3: Let mole to randomly select the local endpoint
You should have noticed we specified the local port 8080
to use for tunneling traffic with option -local 127.0.0.1:8080
. Mole can randomly choose unused TCP port for you.
For this, example 2 will change to
mole start local \
--destination 172.17.0.100:80 \
--server myserver
A local address to access from will be printed out
INFO[0000] tunnel channel is waiting for connection destination="172.17.0.100:80" source="127.0.0.1:40525"
Confirm that you can access a web server on a remote server using the tunnel.
#4: Bind the local address to 127.0.0.1 by specifying only the source port
Consider example below:
mole start local \
--source :8080 \
--destination 172.17.0.100:80 \
--server myserver
#5: Connect to a remote service that is running on 127.0.0.1 by specifying only the destination port
See commands shared below:
mole start local \
--source 127.0.0.1:8080 \
--destination :80 \
--server myserver
#6: Create an alias
With an alias there is no need to remember the tunnel settings afterwards. See below:
$ mole add alias local myalias \
--source :8080 \
--destination 172.17.0.100:80 \
--server user@example.com:22
$ mole start alias myalias
#7: Start mole in background
See below example:
$ mole add alias local example \
--source :8080 \
--destination 172.17.0.100:80 \
--server [email protected]:22
$ mole start alias example --detach
#8: Leveraging LocalForward from SSH configuration file
Refer to configurations shared below:
$ vim ~/.ssh/config
Host example
User mole
Hostname 127.0.0.1
Port 22122
LocalForward 21112 192.168.33.11:80
IdentityFile test-env/ssh-server/keys/key
$ mole start local --server example
INFO[0000] tunnel channel is waiting for connection destination="192.168.33.11:80" source="127.0.0.1:21112"
#9: Create multiple tunnels using a single ssh connection
Consider this example:
$ mole start local \
--source :9090 \
--source :9091 \
--destination 192.168.33.11:80 \
--destination 192.168.33.11:8080 \
--server example
INFO[0000] tunnel channel is waiting for connection destination="192.168.33.11:8080" source="127.0.0.1:9091"
INFO[0000] tunnel channel is waiting for connection destination="192.168.33.11:80" source="127.0.0.1:9090"
#10: Show logs of any detached mole instance
Let’s consider an example:
$ mole start local \
--detach \
--source :9090 \
--source :9091 \
--destination 192.168.33.11:80 \
--destination 192.168.33.11:8080 \
--server example
INFO[0000] instance identifier is afb046da
INFO[0000] execute "mole stop afb046da" if you like to stop it at any time
$ mole show logs --follow afb046da
time="2021-09-17T13:57:10-07:00" level=info msg="instance identifier is 1879de9f"
time="2021-09-17T13:57:10-07:00" level=debug msg="generating an empty config struct"
time="2021-09-17T13:57:10-07:00" level=debug msg="server: [name=127.0.0.01, address=127.0.0.01:22122, user=mole]"
time="2021-09-17T13:57:10-07:00" level=debug msg="tunnel: [channels:[[source=127.0.0.1:9888, destination=192.168.33.11:80]], server:127.0.0.01:22122]"
time="2021-09-17T13:57:10-07:00" level=debug msg="connection to the ssh server is established" server="[name=127.0.0.01, address=127.0.0.01:22122, user=mole]"
time="2021-09-17T13:57:10-07:00" level=info msg="tunnel channel is waiting for connection" destination="192.168.33.11:80" source="127.0.0.1:9888"
time="2021-09-17T13:57:10-07:00" level=debug msg="start sending keep alive packets"
#11: Show the running configuration of all/any mole instance
Use the commands:
mole show instances
mole show instances <ID>
I hope these few examples were helpful in helping you create an SSH tunnel to a remote server, which could be behind a firewall. You can contribute to this Project on Github.