Simple web server in Bash using Ncat
Introduction
If you need to create a very simple web server and cannot find a suitable piece of software, e.g. for some specific purpose, you can use Bash to implement it by yourself. An example might be a custom Prometheus Exporter as mentioned below.
Prerequisities
The most important tool besides Bash that is used for listening on the specified port is Ncat. Ncat is started from the main web server script and if a request arrives, it invokes a Bash function exported from the main script. This function than handles the request and it's output is sent back to the connected client by Ncat.
An important prerequisity besides the ncat
command is that the /bin/sh
command is a symlink to /bin/bash
, not to another shell. Otherwise the Bash handler function export doesn't work properly (note the export -f ...
commands in the script).
Hello world web server
Let's assume that we want to create a web server with name baxic-web-server located in /opt
that is able to print static preconfigured strings.
Let's create a directory /opt/baxic-web-server
and place there the following executable script with name baxic-web-server.sh
.
#!/bin/bash
PROGNAME='baxic-web-server.sh'
CONFFILE="/opt/${PROGNAME%.sh}/${PROGNAME%.sh}.conf"
export PROGNAME CONFFILE
# read_config_file
# read configuration file
read_config_file() {
unset PORT
unset STRING
if [[ ! -f "$CONFFILE" || ! -r "$CONFFILE" ]]; then
echo "$PROGNAME: configuration file '$CONFFILE' not found"
exit 2
fi
. "$CONFFILE"
if [[ -z "$PORT" ]]; then
echo "$PROGNAME: port not configured"
exit 2
fi
}
read_config_file
# handler
# handler for separate requests
handler() {
local httpget
local response response_len
read httpget
response="$(
echo "${STRING[@]}"
)"
response_len="$(echo "$response" | wc -c)"
echo 'HTTP/1.1 200 OK'
echo "Content-Length: $response_len"
echo 'Content-Type: text/plain'
echo "Date: $(date -R -u | sed -r 's#\+0000$#GMT#')"
echo
echo "$response"
return 0
}
export -f handler
export -f read_config_file
# handle requests on port
ncat -k -l "$PORT" -c 'read_config_file && handler'
# exit
exit 0
Then let's add it's configuration file baxic-web-server.conf
to the same directory.
PORT='8080'
STRING[0]='Hello world!'
STRING[1]='And bye!'
Now the web server can be started.
/opt/baxic-web-server/baxic-web-server.sh
And tested from a browser or using curl
.
curl -i http://localhost:8080
Hello world SSL web server
To create a SSL script version, the script can be modified just a little bit to run Ncat with SSL and specify the certificate and key.
#!/bin/bash
PROGNAME='baxic-web-server-ssl.sh'
CONFFILE="/opt/${PROGNAME%.sh}/${PROGNAME%.sh}.conf"
PORT='8443'
export PROGNAME CONFFILE
export PORT
# read_config_file
# read configuration file
read_config_file() {
unset PORT
unset STRING
unset SSL_CRT
unset SSL_KEY
if [[ ! -f "$CONFFILE" || ! -r "$CONFFILE" ]]; then
echo "$PROGNAME: configuration file '$CONFFILE' not found"
exit 2
fi
. "$CONFFILE"
if [[ -z "$PORT" ]]; then
echo "$PROGNAME: port not configured"
exit 2
fi
if [[ -z "$SSL_CRT" || -z "$SSL_KEY" ]]; then
echo "$PROGNAME: ssl certificate or key not configured"
exit 2
fi
}
read_config_file
# handler
# handler for separate requests
handler() {
local httpget
local response response_len
read httpget
response="$(
echo "${STRING[@]}"
)"
response_len="$(echo "$response" | wc -c)"
echo 'HTTP/1.1 200 OK'
echo "Content-Length: $response_len"
echo 'Content-Type: text/plain'
echo "Date: $(date -R -u | sed -r 's#\+0000$#GMT#')"
echo
echo "$response"
return 0
}
export -f handler
export -f read_config_file
# handle requests on port
ncat --ssl --ssl-cert "$SSL_CRT" --ssl-key "$SSL_KEY" -k -l "$PORT" -c 'read_config_file && handler'
# exit
exit 0
This example adds the paths to the certificate and key to the configuration file.
PORT='8443'
SSL_CRT='/etc/ssl/certs/ssl-cert-snakeoil.pem'
SSL_KEY='/etc/ssl/private/ssl-cert-snakeoil.key'
STRING[0]='Hello world!'
STRING[1]='And bye!'
It also assumes, that both the script and configuration file are located in the directory /opt/baxic-web-server-ssl
or in /opt/baxic-web-server
with a symlink from /opt/baxic-web-server-ssl
to /opt/baxic-web-server
.
Summary
The Hello world web server script shown above is very simple and prints just a static message, doesn't log anything, separates the SSL and non-SSL version etc. However, it can be easily extended depending on the expected functionality - mainly the handler
and read_config
functions.
As already mentioned, for example the Baxic Command Exporter or Baxic SNMP Exporter scripts are based on this approach.
Inserted: | 2021-04-17 21:44:54 |
Last updated: | 2021-05-02 07:11:24 |