TAM SFTP proxy

A Node.js application to handle SFTP communication between RB's NetSuite account and the local SFTP server.

Installation

In this section we will talk through the setup of the application, it's dependencies. We will assume that you have admin access and the server has been installed.

Setup SSH and the HTTPS routes

Add the user(s)

Login to the server and become the root user

$ sudo su -

Make a user for Midwest and give them a password.

$ adduser midwest

To manage rights, put midwest in a group

$ addgroup revolution
$ usermod -a -G revolution midwest
$ usermod -a -G revolution {node user name here}

Construct the file structure

The main sftp root is stored in a folder on the main root directory. Create the folders and assign permissions. At this point we wont create the sftp folders.

$ cd ..
$ mkdir store
$ cd store
$ mkdir jail
$ chmod 755 jail/
$ cd jail
$ mkdir midwest
$ chown midwest:revolution midwest/

Now to allow the user connection, update the sshd config file

$ nano /etc/ssh/sshd_config

Comment out line 77

# Subsystem sftp /usr/lib/openssh/sftp-server

Then append:

subsystem sftp internal-sftp
match user midwest
    chrootDirectory /store/jail
    ForceCommand internal-sftp
    AllowTCPForwarding no
    X11Forwarding no

Press ctrl+x then enter to save these changes. Then restart or run:

$ service sshd restart

You can then test the SFTP connection with the midwest user and password. If you need the IP of the server you can run ifconfig.

If the test was sucessful, you may want to set up the endpoint folders in the midwestg folder.

midwest
    in
        grn
        shipconf
    out
        asn
        pick
        ra
        sku

node.js and the application iteself

Node is the runtime environment needed to run the application. Instead of installing node directly, you will need to install node version manager.

$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash

Restart the machine then install the latest long-term-support node version.

$ nvm install --ltsnode

You can check the node version using this command:

$ node -v
v8.11.1

Connect to the server using FileZilla and your admin user. Make a folder in your home folder called RB Proxy. Bundle a local copy of the project (without the node_moules) and upload it to the RB Proxy folder. Back in putty, navigate to the RB Proxy folder and extract the archive.

$ tar -xf RBProxyv0.2.0.tar.xz

Navigate into the extracted folder and install dependencies.

$ npm install

Then install the auto-starter pm2

$ npm install -g pm2
$ pm2 start ./bin/www.js

This will start with a fancy splash screen. To make pm2 autostart on error or boot run the command

$ pm2 startup systemd

This will give you a command to run as root, so do that now.

To restart the proxy application run, the following:

pm2 restart ./bin/www.js

To monitor the proxy application, the following:

pm2 monit

Nginx

Nginx handles the certificate and initial routing. To install Nginx

$ sudo apt-get update
$ sudo apt-get install nginx

Let Nginx through the firewall

$ sudo ufw allow 'Nginx Full'

Setup server blocks and certificate

As part of the setup of the VM in azure, it will have a domin name, like fhlmidwest.westeurope.cloudapp.azure.com so we will need to tie this to the ssl cert. We will route nginx to use that domain for the node app and ssl certificate. Edit the conf file

Set the server location routing

    location / {
            proxy_pass http://localhost:3001;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
    }

If you are setting the server up for the first time, get your certificate

ensure that python is installed

python -v

if not install it.

To allow Nginx to use the lets-encrypt certificate, install the certbot software

$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt update
$ sudo apt install python-certbot-nginx

Then run for the route once you have set it up. Link it to your own email and set all traffic to route to https.

$ sudo certbot --nginx -d mai-ubuntu-fhl.northeurope.cloudapp.azure.com

This should conclude server setup.

Server

The server will listen and reply on port 3001 or through any routed addresses.

/

This route shows the server uptime and links to the other routes.

/api

This route will accept POST requests and will need the header Content-Type: application/json. The details of the request will be specified in the JSON body. Note that the body must be valid JSON and not be a string. Below we will detail the functions of the api

list

To get the contents of a known directory, set the method as list and set your required directory.

{
    "method"    : "list",
    "directory" : "/out/sku/"
}

This will return false on error or will return an array of strings

[
    "file1.ext",
    "file2.ext"
]

upload

To upload a file to a known directory; set method to upload, name your file, directory and encode your file as a base 64 string.

{
    "method"    : "upload",
    "fileName"  : "text.txt",
    "directory" : "/out/sku/",
    "data"      : "aGVsbG8gd29ybGQ="
}

This will return false on error or true on sucessful upload.

download

To download a known file, set method to download and set your filename and directory.

{
    "method"    : "download",
    "fileName"  : "text.txt",
    "directory" : "/out/sku/"
}

This will return false on error or a JSON body with only a data attribute containg a base 64 encoded file contents.

{
    "data" : "aGVsbG8gd29ybGQ="
}

delete

To remove a known file, set method to delete and set your filename and directory.

{
    "method"    : "delete",
    "fileName"  : "text.txt",
    "directory" : "/out/sku/"
}

This will return false on error or or true on sucessful deletion.

/read-me

Renders this readme as HTML.

/error-log

Any uncaught errors are appended to the error file. This route will render said text file.

/irp

This route accepts POST requests and the body must contain an options object and optionally a data string

{
    "data" : "hello"
    {
        "hostname"    : "irp.server.com",
        "path"        : "/route.aspx?api",
        "method"      : "POST",
        "headers"     : {
            "Authorization" : "Basic dXNlcm5hbWU6cGFzc3dvcmQ="
        }
    }

Sources

Most of this is taken, with modification, from a number of guides.