Wednesday, 10 January 2018

TUSD server on Production

TUS ( is HTTP based protocol used for resumable file upload. TUSD ( is official implementation of the TUS protocol.
For one of our project, we have decided to use TUSD for uploading large number of files from many locations over unreliable internet connection.
For running TUSD on production, first thing came to our mind was how to make it secure. TUSD does not accept HTTPS connection, neither it has any built in layer for verification/authentication checks. Authentication can be done using the hooks system of TUSD.
So we decided to move the security layer out of TUSD and let it focus on its primary task of resumable file uploading.
Accordingly we introduced HAProxy in front of TUSD server.

  • TUSD server will run as normal user on default port 1080 and HAProxy will listen on default HTTP/HTTPS ports and proxy pass the requests to TUSD server.
  • SSL Security certificate will be deployed on HAProxy and HAProxy will do the SSL offloading. TUSD will receive plain HTTP traffic from HAProxy.
  • We will enable basic HTTP authentication in HAProxy and HAProxy will authenticate the incoming connections before forwarding it to TUSD server.
  • HAProxy will only proxy a specific URL traffic to the backend TUSD server. It will not forward the whole traffic to TUSD server, so any connection attempt to the default HTTP/HTTPS port on the public IP will not be forwarded to TUSD.

For this document I used Ubuntu 16.04, TUSD Version: 0.9.0 and HAProxy Version 1.7.
As we will run TUSD behind HAProxy, so have to add -behind-proxy flag while starting TUSD to inform TUSD that it is running behind a proxy and have to give attention to the special headers sent by the proxy.

Let’s see the configs for this setup

TUSD service:

Description= TUSD File Upload Server

ExecStart=/bin/bash -ce "exec /app/tusd/tusd -dir /data/tusupload  -hooks-dir /app/tusd/hooks -behind-proxy  >> /logs/tusd/tusd.log 2>&1"
# file size
# cpu time
# virtual memory size
# open files
# processes/threads
# total threads (user+kernel)


HAProxy config file:

userlist UL1
                user httpuser insecure-password abcdefghijklmnop

                log /dev/log       local0
                log /dev/log       local1 notice
                chroot /var/lib/haproxy
                stats socket /run/haproxy/admin.sock mode 660 level admin
                stats timeout 30s
                user haproxy
                group haproxy

                # Default SSL material locations
                ca-base /etc/ssl/certs
                crt-base /etc/ssl/private

                # Default ciphers to use on SSL-enabled listening sockets.
                # For more information, see ciphers(1SSL). This list is from:
                # An alternative list with additional directives can be obtained from
                ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
                ssl-default-bind-options no-sslv3

                log          global
                mode    http
                option   httplog
                option   dontlognull
                timeout connect 5000
                timeout client  50000
                timeout server  50000
                errorfile 400 /etc/haproxy/errors/400.http
                errorfile 403 /etc/haproxy/errors/403.http
                errorfile 408 /etc/haproxy/errors/408.http
                errorfile 500 /etc/haproxy/errors/500.http
                errorfile 502 /etc/haproxy/errors/502.http
                errorfile 503 /etc/haproxy/errors/503.http
                errorfile 504 /etc/haproxy/errors/504.http

frontend localhost
    bind *:80
    bind *:443 ssl crt /etc/ssl/my_certs/my_cert.pem
    redirect scheme https if !{ ssl_fc }
    mode http

    acl tusdsvr hdr(host) -i   
    use_backend tus-backend if tusdsvr

#########################Backend Settings##########################
backend tus-backend
#HTTP basic Authentication check
      acl AuthOkay_UsersAuth http_auth(UL1)
      http-request auth realm UserAuth if !AuthOkay_UsersAuth

#Setting X-Forwarded-Proto header to https to let TUSD know that it is behind HTTPS proxy and should return https URLs.   
     http-request set-header X-Forwarded-Proto "https"
     http-request add-header X-Forwarded-For %[src]

     mode     http      

    server   server1 localhost:1080  check fall 3 rise 2

Saturday, 6 January 2018

Strange ext4 error: cannot create regular file … No space left on device !!!

Today I was copying a folder containing large number of small files (around 1,25,000) into a backup partition (/dev/mapper/vg_ema_data-lv_ema_data) on my Ubuntu 16.04 VM with ext4 file system. That folder size was 250MB, and the backup partition had around 45GB of free space. One of the sub-directory of that folder has around 45,000 files with long file names like 3_8_25438833_11_3_4081_2017_12_08_13_07_55_2017_12_09_11_15_01_2018_01_02_13_38_42_2018_01_06_11_29_12_2018_01_06_11_37_07_2018_01_06_11_48_09_2018_01_06_13_16_01_2018_01_06_13_21_13_2018_01_06_13_52_55_2018_01_06_14_47_22.json

When I started copying, after some time the copy operation started giving me error of  "cannot create regular file" and“no space left on device” on my backup partition (while copying the files of the folder containing long file names). As that partition had 45GB space, so running out of space was out of question, so I thought maybe I consumed the number of Inodes in the backup partition. I checked Inodes of that partition and found that large number of inodes were free.

After searching a lot I found one excellent blog which wrote about dir_index of ext4. Please read that blog for details of the issue and I am not going to repeat that here.

So I decided to check and disable dir_index for my backup partition (/dev/mapper/vg_ema_data-lv_ema_data).
To check whether dir_index is enabled or not, I used tune2fs command as mentioned in the blog.

# tune2fs -l /dev/mapper/vg_ema_data-lv_ema_data | grep -o dir_index

If the above command outputs dir_index, that means dir_index is enabled for that partition, if it outputs nothing that means dir_index is not enabled.
Once I came to know that dir_index is enabled in my /dev/mapper/vg_ema_data-lv_ema_data partition, so I decied to disable it.

So I used the following command:

# tune2fs -O "^dir_index" /dev/mapper/vg_ema_data-lv_ema_data
to disable dir_index.

After disabling dir_index I tried to copy that directory again, and wow my copy operation successfully completed this time.