Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | |||
selfhost:ssh_tunnel [2024/02/07 16:38] – willy | selfhost: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 (/ | ||
- | You need also to create an SSH key, and prepare the tunnels config folder **/ | ||
- | <code bash> | ||
- | > useradd -m tunnel | ||
- | > su - tunnel | ||
- | > ssh-keygen | ||
- | > mkdir tunnels | ||
- | > mkdir logs | ||
- | </ | ||
- | |||
- | Add tunnels configurations like this under **/ | ||
- | <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=# | ||
- | REMOTE_USER=tunnel # remote user to login as | ||
- | |||
- | REMOTE_TO_HOME=\ | ||
- | " | ||
- | " | ||
- | " | ||
- | " | ||
- | |||
- | HOME_TO_REMOTE= # list of ports forwarded from local to remote | ||
- | </ | ||
- | |||
- | Remember to " | ||
- | |||
- | 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 **/ | ||
- | <code bash> | ||
- | #!/bin/bash | ||
- | |||
- | function log() | ||
- | { | ||
- | echo $(date) - $@ >> $LOG | ||
- | } | ||
- | |||
- | Add this to .ssh/config for keepalive: | ||
- | < | ||
- | |||
- | Host * | ||
- | ServerAliveInterval 60 | ||
- | </ | ||
- | |||
- | cd $HOME | ||
- | TUNNELS=$(ls tunnels) | ||
- | |||
- | TUNNEL_PIDS= | ||
- | for i in $TUNNELS | ||
- | do | ||
- | # Spin a shell for each tunnel | ||
- | ( | ||
- | NAME=$i | ||
- | CONFIG=tunnels/ | ||
- | LOG=logs/ | ||
- | |||
- | log " | ||
- | |||
- | # Iterate forever | ||
- | while true | ||
- | do | ||
- | # Spin up a sub-shell to ensure we reload the config properly each iteration | ||
- | (log " | ||
- | source $CONFIG | ||
- | |||
- | log " | ||
- | if ping -c 10 -W 5 $REMOTE_SERVER &> /dev/null | ||
- | then | ||
- | log " | ||
- | |||
- | LOGIN_IDENTITY= | ||
- | test ! -z $SSH_IDENTITY && LOGIN_IDENTITY=" | ||
- | LOGIN_AS=$USER | ||
- | test ! -z $REMOTE_USER | ||
- | |||
- | REMOTES=" | ||
- | LOCALS= | ||
- | for i in $REMOTE_TO_HOME; | ||
- | for i in $HOME_TO_REMOTE; | ||
- | |||
- | COMMAND=" | ||
- | |||
- | log "Run: ' | ||
- | $COMMAND &>> | ||
- | 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 " | ||
- | kill -9 $ssh_pid | ||
- | while ps -p $ssh_pid; do sleep 1; done | ||
- | fi | ||
- | done | ||
- | |||
- | # get return code | ||
- | wait $ssh_pid | ||
- | log " | ||
- | sleep 10 # after disconnection, | ||
- | else | ||
- | log "It seems that ' | ||
- | sleep 5 # wait a bit before retry ping | ||
- | fi | ||
- | ) # close iteration shell | ||
- | done | ||
- | )& # close tunnel shell | ||
- | TUNNEL_PIDS=" | ||
- | done | ||
- | |||
- | wait | ||
- | </ | ||
- | |||
- | and set it as executable: | ||
- | <code bash> | ||
- | > chmod +x / | ||
- | </ | ||
- | |||
- | Now create the startup script **/ | ||
- | <file txt 99-tunnels.start> | ||
- | #!/bin/bash | ||
- | |||
- | start-stop-daemon -b -m -p / | ||
- | </ | ||
- | |||
- | Share tunnel' | ||
- | |||