Title: Nginx as a TCP/UDP relay
       Author: Solène
       Date: 24 February 2021
       Tags: openbsd nginx networking
       Description: 
       
       # Introduction
       
       In this tutorial I will explain how to use Nginx as a TCP or UDP relay
       as an alternative to Haproxy or Relayd.  This mean nginx will be able
       to accept requests on a port (TCP/UDP) and relay it to another backend
       without knowing about the content.  It also permits to negociates a TLS
       session with the client and relay to a non-TLS backend.  In this
       example I will explain how to configure Nginx to accept TLS requests to
       transmit it to my Gemini server Vger, Gemini protocol has TLS as a
       requirement.
       
       I will explain how to install and configure Nginx and how to parse logs
       to obtain useful information.  I will use an OpenBSD system for the
       examples.
       
       It is important to understand that in this context Nginx is not doing
       anything related to HTTP.
       
       # Installation
       
       On OpenBSD we need the package nginx-stream, if you are unsure about
       which package is required on your system, search which package provide
       the file ngx_stream_module.so .  To enable Nginx at boot, you can use
       rcctl enable nginx.
       
 (HTM) Nginx stream module core documentation
 (HTM) Nginx stream module log documentation
       
       # Configuration
       
       The default configuration file for nginx is /etc/nginx/nginx.conf , we
       will want it to listen on port 1965 and relay to 127.0.0.1:11965.
       
       ```Nginx configuration file
       worker_processes  1;
       
       load_module modules/ngx_stream_module.so;
       
       events {
          worker_connections 5;
       }
       
       stream {
           log_format basic '$remote_addr $upstream_addr [$time_local] '
                            '$protocol $status $bytes_sent $bytes_received '
                            '$session_time';
       
           access_log logs/nginx-access.log basic;
       
           upstream backend {
               hash $remote_addr consistent;
               server 127.0.0.1:11965;
           }
           server {
               listen 1965 ssl;
               ssl_certificate /etc/ssl/perso.pw:1965.crt;
               ssl_certificate_key /etc/ssl/private/perso.pw:1965.key;
               proxy_pass backend;
           }
       }
       ```
       
       In the previous configuration file, the backend defines the
       destination, multiples servers could be defined, with weights and
       timeouts, there is only one in this example.
       
       The server block will tell on which port Nginx should listen and if it
       has to handle TLS (which is named ssl because of history), usual TLS
       configuration can be used here, then for a request, we have to tell to
       which backend Nginx have to relay the connections.
       
       The configuration file defines a custom log format that is useful for
       TLS connections, it includes remote host, backend destination,
       connection status, bytes transffered and duration.
       
       # Log parsing
       
       ## Using awk to calculate time performance
       
       I wrote a quite long shell command parsing the log defined earlier that
       display the number of requests, and median/min/max session time.
       
       ```awk command to parse nginx custom log defined earlier
       $ awk '{ print $NF }' /var/www/logs/nginx-access.log | sort -n |  awk '{ data[NR] = $1 } END { print "Total: "NR" Median:"data[int(NR/2)]" Min:"data[2]" Max:"data[NR] }'
       Total: 566 Median:0.212 Min:0.000 Max:600.487
       ```
       
       ## Find bad clients using awk
       
       Sometimes in the logs there are clients that obtains a status 500,
       meaning the TLS connection haven't been established correctly.  It may
       be some scanner that doesn't try a TLS connection, if you want to get
       statistics about those and see if it would be worth to block them if
       they do too many attempt, it is easy to use awk to get the list.
       
       ```awk command reporting clients with a status 500
       awk '$(NF-3) == 500 { print $1 }' /var/www/logs/nginx-access.log
       ```
       
       ## Using goaccess for real time log visualization
       
       It is also possible to use the program Goaccess to view logs in real
       time with many information, it is really an awesome program.
       
       ```goaccess command line with lot of parameters
       goaccess --date-format="%d/%b/%Y" \
                --time-format="%H:%M:%S" \
                --log-format="%h %r [%d:%t %^] TCP %s %^ %b %L" /var/www/logs/nginx-access.log
       ```
       
 (HTM) Goaccess official website
       
       # Conclusion
       
       I was using relayd before trying Nginx with stream module, while relayd
       worked fine it doesn't provide any of the logs Nginx offer.  I am
       really happy with this use of Nginx because it is a very versatile
       program that shown to be more than a http server over time.  For a
       minimal setup I would still recommend lighter daemon such as relayd.