User Tools

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
selfhost:ssh_tunnel [2024/02/07 16:38] willyselfhost:ssh_tunnel [2024/02/08 17:28] (current) – removed willy
Line 1: Line 1:
-==== SSH Tunneling ==== 
- 
-There are many ways to provide access **to** the internal server from **outside**. Let's briefly summarize them: 
-  * You have no CG-NAT: get a public IP and port-forward to your internal server (very rare today) 
-  * Get a VPN with port-forwarding (require a third party service) 
-  * Setup a tunnel to an external server 
- 
-I will show you the third case, because it's the solution that gives you the biggest opportunities. A VPN is also nice, but there are not many VPN supporting port-forwarding and they also tend to be expensive. Renting a VPS on the other hand, can be very cheap and since you only need it to get into your services (outgoing bandwidth is not affected) you don't even need some high tier network package with it. 
- 
-==== On Local Host ==== 
- 
-Create a new user called **tunnel**. 
-Leave tunnel home folder on root partition (/home/tunnel) to avoid tunnel failure if partitions don't mount. 
-You need also to create an SSH key, and prepare the tunnels config folder **/home/tunnel/tunnels** and log folder **/home/tunnel/logs**: 
-<code bash> 
- > useradd -m tunnel 
- > su - tunnel 
- > ssh-keygen 
- > mkdir tunnels 
- > mkdir logs 
-</code> 
- 
-Add tunnels configurations like this under **/home/tunnel/tunnels/main**: 
-<file txt main> 
-REMOTE_SERVER=99.99.99.99 # your remote server IP - don't use name, use IP 
-REMOTE_SERVER_SSH_PORT=22 # your remote server SSH port 
-HOME_SERVER_REMOTE_SSH_PORT=5022 # the port your local server SSH will be accessible from remote 
-SSH_IDENTITY=# optional path to private ssh key, leave empty for default 
-REMOTE_USER=tunnel # remote user to login as 
- 
-REMOTE_TO_HOME=\ 
-"127.0.0.1:8080:127.0.0.1:80 "\ 
-"127.0.0.1:8443:127.0.0.1:8443 "\ 
-"0.0.0.0:6022:10.70.43.99:22 "\ 
-"0.0.0.0:12112:127.0.0.1:12112 " # list of ports forwarded from remote to local 
- 
-HOME_TO_REMOTE= # list of ports forwarded from local to remote 
-</file> 
- 
-Remember to "ssh" manually at least once each host to accept host keys! 
- 
-You can create as many tunnels as you like. Note that SSH port will always be forwarded anyway, so you want one file for each remote host. 
- 
-Now create this script under **/home/tunnel/tunnel.sh**: 
-<code bash> 
-#!/bin/bash 
- 
-function log() 
-{ 
-        echo $(date) - $@ >> $LOG 
-} 
- 
-Add this to .ssh/config for keepalive: 
-<code> 
- 
-Host * 
-    ServerAliveInterval 60 
-</code> 
- 
-cd $HOME 
-TUNNELS=$(ls tunnels) 
- 
-TUNNEL_PIDS= 
-for i in $TUNNELS 
-do 
-        # Spin a shell for each tunnel 
-        ( 
-        NAME=$i 
-        CONFIG=tunnels/$NAME 
-        LOG=logs/tunnel-$NAME 
- 
-        log "Starting operations for tunnel '$NAME'..." 
- 
-        # Iterate forever 
-        while true 
-        do 
-                # Spin up a sub-shell to ensure we reload the config properly each iteration 
-                (log "Reading configuration from '$CONFIG'..." 
-                source $CONFIG 
- 
-                log "Testing if remote server '$REMOTE_SERVER' is reachable..." 
-                if ping -c 10 -W 5 $REMOTE_SERVER &> /dev/null 
-                then 
-                        log "Remote server '$REMOTE_SERVER' is reachable!" 
- 
-                        LOGIN_IDENTITY= 
-                        test ! -z $SSH_IDENTITY && LOGIN_IDENTITY="-i $SSH_IDENTITY" 
-                        LOGIN_AS=$USER 
-                        test ! -z $REMOTE_USER  && LOGIN_AS="-l $REMOTE_USER" 
- 
-                        REMOTES="-R0.0.0.0:$HOME_SERVER_REMOTE_SSH_PORT:127.0.0.1:22" # SSH port we always export 
-                        LOCALS= 
-                        for i in $REMOTE_TO_HOME; do REMOTES="$REMOTES -R$i"; done 
-                        for i in $HOME_TO_REMOTE; do LOCALS="$LOCALS -L$i"; done 
- 
-                        COMMAND="ssh $LOCALS $REMOTES $LOGIN_IDENTITY $LOGIN_IDENTITY $LOGIN_AS -p $REMOTE_SERVER_SSH_PORT $REMOTE_SERVER -nNT" 
- 
-                        log "Run: '$COMMAND'..." 
-                        $COMMAND &>> $LOG & 
-                        ssh_pid=$! 
- 
-                        # Wait a bit to ensure command is running... 
-                        sleep 1 
- 
-                        # until SSH returns, check network, because SSH might hang for a long time. 
-                        while ps -p $ssh_pid &> /dev/null 
-                        do 
-                                if ping -c 2 -W 2 $REMOTE_SERVER &> /dev/null 
-                                then 
-                                        sleep 30 
-                                else 
-                                        # Network is down? forcing ssh to stop 
-                                        log "WATCHDOG: Detected '$REMOTE_SERVER' is NOT reachable! Killing command." 
-                                        kill -9 $ssh_pid 
-                                        while ps -p $ssh_pid; do sleep 1; done 
-                                fi 
-                        done 
- 
-                        # get return code 
-                        wait $ssh_pid 
-                        log "Command returned code '$?'. Retrying..." 
-                        sleep 10 # after disconnection, wait a bit before retrying 
-                else 
-                        log "It seems that '$REMOTE_SERVER' is not reachable. Wait and retry..." 
-                        sleep 5 # wait a bit before retry ping 
-                fi 
-                ) # close iteration shell 
-        done 
-        )& # close tunnel shell 
-        TUNNEL_PIDS="$TUNNEL_PIDS "$! 
-done 
- 
-wait 
-</code> 
- 
-and set it as executable: 
-<code bash> 
- > chmod +x /home/tunnel/tunnel.sh 
-</code> 
- 
-Now create the startup script **/etc/local.d/99-tunnels.start**: 
-<file txt 99-tunnels.start> 
-#!/bin/bash 
- 
-start-stop-daemon -b -m -p /var/run/tunnel.pid -n tunnel -u tunnel /home/tunnel/tunnel.sh 
-</file> 
- 
-Share tunnel's **/home/tunnel/.ssh/id_rsa.pub** with remote host, paste it inside **authorized_hosts** file of remote tunnel user. 
- 
  

This website uses technical cookies only. No information is shared with anybody or used in any way but provide the website in your browser.

More information