Ngrok Setup on Synology NAS

3 years ago | 11 April, 2021 | X minute read.

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:

  1. Login to your ngrok account.
  2. Retrieve your authtoken.
  3. Setup a TCP address endpoint for the sftp tunnel; the ssh tunnel will be randomly generated.

I'm placing all the files needed in this article together in an accessible location on one of the data volumes (/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.

DSM, NAS, NGROK, PORTS, PYTHON, SYNOLOGY, TUNNEL