Background
I have a Synology NAS which runs using Synology's DSM OS. I can access this via its quickconnect cloud system. Unfortunately this only allows for DSM's web interface even though it's sometimes useful to access the NAS remotely via SFTP or SSH.
The usual way to achieve this might be to forward ports from the internet through the router firewall to tne NAS on the local network (also called opening a port). Unfortunately, not all networks are setup to allow port forwarding. To overcome this, I recently setup ngrok on the NAS to allow access permanently via SFTP and on-demand via SSH.
Setup
First ngrok needs to be setup by following the steps shown on the ngrok website.
Next, I installed python3 via the DSM package manager because I monitor the SFTP ngrok tunnel using a python script.
To setup ngrok, the following needs to be done:
- Login to your ngrok account.
- Retrieve your authtoken.
- Setup a TCP address endpoint for the sftp tunnel; the ssh tunnel will be randomly generated.
/volume1/ngrok/
).The ngrok configuration (/volume1/ngrok/config.yml
) was added.
Its job is to pre-configure the ngrok tunnels.
authtoken: # THIS IS THE NGROK AUTHTOKEN FOR THE ACCOUNT BEING USED
region: us # THIS IS THE REGION CODE AS PER YOUR SETUP IN NGROK
tunnels:
sftp:
addr: 123 # THIS IS THE NAS SFTP PORT (INTEGER) WHICH IS CONFIGURED IN DSM.
proto: tcp
remote-addr: 1.tcp.us.ngrok.io:12345 # THIS IS THE NGROK TCP TUNNEL PREVIOUSLY CREATED (PUBLIC_ADDRESS:PUBLIC_PORT)
ssh:
addr: 1234 # THIS IS THE NAS SSH PORT (INTEGER) WHICH IS CONFIGURED IN DSM.
proto: tcp
The monitoring script (/volume1/ngrok/sftp_tunnel_watchdog.py
) was added.
Its job is to ensure that the SFTP tunnel remains accessible.
It does this by checking if the port is open via ngrok, and if not it kills and restarts the ngrok tunnel.
import socket
import os
import time
import signal
ngrok_host = [STR: PUBLIC ADDRESS]
ngrok_port = [INT: PUBLIC PORT]
def checkNgrok():
# checking if the port is open via ngrok
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex( (ngrok_host, ngrok_port) )
if result == 0:
sock.close()
return True
else:
sock.close()
return False
while True: # forever
try: # don't want this to ever stop...
if checkNgrok():
print(" > ngrok port is open - nothing to do.")
else:
print(" > ngrok port is not open - kill the process and relaunch tunnel.")
# if the ngrok process is still running, kill it
for line in os.popen("ps -ef | grep \"ngrok start\""):
if "sftp" in line:
print(" > killing process.")
fields = line.split()
# extracting Process ID from the output
pid = fields[1]
# terminating process
os.kill(int(pid), signal.SIGKILL)
# start the ngrok tunnel
print(" > starting process.")
cmd = "/volume1/ngrok/ngrok start sftp -config /volume1/ngrok/config.yml -log=stdout > /dev/null &"
os.system(cmd)
except:
None
print()
time.sleep(10)
Via the DSM task scheduler, the following tasks were created:
- Launch the SFTP tunnel monitoring script (as root and triggered on boot):
python3 /volume1/ngrok/sftp_ngrok_watchdog.py &
- SSH tunnel (as root at a time in the past as it will be run manually via DSM when needed):
/volume1/ngrok/ngrok start ssh -config /volume1/ngrok/config.yml
Monitoring
On the ngrok website, there are various pages which will help you control or view the status of active tunnels.
- The endpoint status page tells you the hostnames the active tunnels which is needed for ssh random hostnames.
- The tunnel agent sessions page lets you stop the active sessions tunnel which is useful to stop the ssh tunnel.