Setup NGINX on an Alpine Docker Container with ModSecurity and Redis Cache


Set up an Alpine Docker Container

Why use Alpine Linux for your Docker container? Alpine makes a great docker container, because it is so small and optimized to be run in RAM. It is also fast. Furthermore, nearly every official Docker image has a tag for Alpine. So basically, it is optimized for size, speed and is easy.

Install Alpine Linux using Dockerfile

In the event that you’re not familiar with the concept, every Docker image is composed of several layers, one for each command in a Dockerfile (and those in its base image).

Include the following in your Dockerfile:

   Dockerfile


FROM alpine:latest

RUN rm -rf /var/cache/apk/* \
    && rm -rf /tmp/*

 




The FROM instruction initializes a new build stage and sets the Base Image for subsequent instructions. As such, a valid Dockerfile must start with a FROM instruction. The image can be any valid image – it is especially easy to start by pulling an image from the Public Repositories.

 

/var/cache is intended for cached data from applications. Such data is locally generated as a result of time-consuming I/O or calculation. The application must be able to regenerate or restore the data. Unlike /var/spool , the cached files can be deleted without data loss. Within the context of our Docker setup, over time, newer packages will replace older ones; the cache directory will contain all older versions of packages. For our purposes, we delete this cache on reboot.

 

Setup NGINX on Docker with ModSecurity and Redis

ModSecurity is a toolkit for real-time web application monitoring, logging, and access control. If you are concerned about security/firewalls then this is recommended. Read here: https://www.modsecurity.org/about.html and https://en.wikipedia.org/wiki/ModSecurity.

If you want ModSecurity then you will need to compile it into NGINX, meaning a few extra instructions to get this going. This means you’ll have to clone the ModSecurity GitHub repository and build the library from its source code.

The following are the required build tools, mandatory dependencies, and most of the optional dependencies on Debian: bison, flex, make, automake, gcc, pkg-config, libtool, doxygen, git, curl, zlib1g-dev, libxml2-dev, libpcre3-dev, build-essential, libyajl-dev, yajl-tools, liblmdb-dev, rdmacm-utils, libgeoip-dev, libcurl4-openssl-dev, liblua5.2-dev, libfuzzy-dev, openssl and libssl-dev. Equivalents need to be identified for Alpine Linux.

Redis is a caching system and can be added to NGINX for performance.

The details of Redis and ModSecurity are outside the scope of this article.




NGINX is written in C so I include the C libraries and compiler in order to be able to compile it with ModSecurity.

The following libraries are required for this setup:
gcc # For nginx, modsecurity. GNU Compiler Collection, a free, open-source compiler system. Mandatory in order to compile nginx
libc-dev # For nginx .Meta package to pull in correct libc (standard C library). See https://pkgs.alpinelinux.org/package/v3.3/main/armhf/libc-dev
linux-headers # See https://unix.stackexchange.com/questions/47330/what-exactly-are-linux-kernel-headers
zlib-dev # For nginx, modsecurity
openrc # For nginx. Alpine Linux uses OpenRC for its init system.
autoconf # For nginx
automake # Fornginx, modsecurity
git # For modsecurity, nginx
libressl-dev # Fornginx, modsecurity
geoip-dev # For modsecurity. ID user IP geolocation and related characteristics of internet users
lmdb-dev # For modsecurity. Lightning Memory-Mapped Database (LMDB) is a software library that provides a high-performance embedded transactional database in the form of a key-value store
pcre-dev # For nginx, modsecurity
libtool # For modsecurity. Compile, link, install, execute
libxml2-dev # For modsecurity. Libxml2 is the XML C parser and toolkit
yajl-dev # For modsecurity. YAJL is a small event-driven (SAX-style) JSON parser written in ANSI C
pkgconf # For modsecurity.
wget # For nginx
zlib-dev # For nginx
g++ # For modsecurity. g++ and make on Alpine replace “build-essential” on Ubuntu. To compile c++
libcurl # For modsecurity
make # For nginx, modsecurity
redis # For nginx. Webserver caching

 

Here is the Dockerfile to build an NGINX dynamic module. Other required files are start-nginx-server.sh, my_webapp_nginx.conf, nginx.conf

Dockerfile

   Dockerfile


FROM alpine:latest

RUN rm -rf /var/cache/apk/* \
    && rm -rf /tmp/*

RUN cat /etc/apk/repositories

RUN apk add --update gcc \
                     libc-dev \
                     linux-headers \
                     zlib-dev \
                     openrc \
                     autoconf \
                     automake \
                     git \
                     libressl-dev \
                     geoip-dev \
                     lmdb-dev \
                     pcre-dev \
                     libtool \
                     libxml2-dev \
                     yajl-dev \
                     pkgconf \
                     wget \
                     zlib-dev \
                     g++ \
                     libcurl \
                     make \
                     redis


# Mod_Security Setup
RUN git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
WORKDIR /ModSecurity
RUN git submodule init \
    && git submodule update \
    && ./build.sh \
    && ./configure \
    && make \
    && make install \
    && make clean

WORKDIR /
RUN git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git \
    && wget http://nginx.org/download/nginx-1.17.0.tar.gz \
    && tar zxvf nginx-1.17.0.tar.gz

WORKDIR /nginx-1.17.0
RUN  ./configure --with-compat --with-http_ssl_module \
    && make \
    && make install \
    && make clean \
    && mkdir /etc/nginx \
    && mkdir /etc/nginx/modules/ \
    && mkdir /usr/local/nginx/modules/ \
    && mkdir /var/log/nginx

RUN ./configure --with-compat --with-http_ssl_module --add-dynamic-module=../ModSecurity-nginx \
    && make \
    && make modules \
    && ls -la /etc/nginx \
    && cp /nginx-1.17.0/objs/ngx_http_modsecurity_module.so /usr/local/nginx/modules/ngx_http_modsecurity_module.so \
    && make clean

WORKDIR /
RUN mkdir /etc/nginx/modsec \
    && echo "load_module modules/ngx_http_modsecurity_module.so;" >> /etc/nginx/nginx.conf \
    && cp /usr/local/nginx/conf/mime.types /etc/nginx/

ADD nginx_config/modsecurity.conf /etc/nginx/modsec/modsecurity.conf
ADD nginx_config/modsec.main.conf  /etc/nginx/modsec/main.conf

# Nginx Config
ADD nginx_config/my_webapp_nginx.conf /etc/nginx/conf.d/
ADD nginx_config/nginx.conf /etc/nginx/nginx.conf

# Install productlisting_framework Libraries
ENV PYTHONUNBUFFERED 1
RUN mkdir /run/nginx
RUN mkdir /my_webapp

ADD start-nginx-server.sh /my_webapp/

RUN chmod 777 /my_webapp/start-nginx-server.sh

EXPOSE 8000
RUN adduser -D nginx
ENTRYPOINT /my_webapp/start-nginx-server.sh

start-nginx-server.sh

   start-nginx-server.sh


"echo ""starting""
/usr/bin/redis-server &
/usr/local/nginx/sbin/nginx -c /etc/nginx/nginx.conf &
/bin/bash"


my_webapp_nginx.conf

   my-webapp-nginx.conf


"# configuration of the server

server {
    modsecurity off;
    modsecurity_rules_file /etc/nginx/modsec/main.conf;

    # the port your site will be served on
    listen      8000;
    port_in_redirect off;

    # the domain name it will serve for
    server_name my_webapp.co.za www.my_webapp.co.za;
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;

 }

}"


nginx.conf

   nginx.conf


user nginx;

# Set number of worker processes automatically based on number of CPU cores.
worker_processes auto;

# Enables the use of JIT for regular expressions to speed-up their processing.
pcre_jit on;
load_module modules/ngx_http_modsecurity_module.so;

# Configures default error logger.
error_log /var/log/nginx/error.log warn;

# Includes files with directives to load dynamic modules.
include /etc/nginx/modules/*.conf;


events {
	# The maximum number of simultaneous connections that can be opened by
	# a worker process.
	worker_connections 1024;
}

http {

    perl_set $uri_lowercase 'sub {
      my $r = shift;
      my $uri = $r->uri;
      $uri = lc($uri);
      return $uri;
    }';


	# Includes mapping of file name extensions to MIME types of responses
	# and defines the default type.
	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	# Name servers used to resolve names of upstream servers into addresses.
	# It's also needed when using tcpsocket and udpsocket in Lua modules.
	#resolver 208.67.222.222 208.67.220.220;

	# Don't tell nginx version to clients.
	server_tokens off;

	# Specifies the maximum accepted body size of a client request, as
	# indicated by the request header Content-Length. If the stated content
	# length is greater than this size, then the client receives the HTTP
	# error code 413. Set to 0 to disable.
	client_max_body_size 1m;

	# Timeout for keep-alive connections. Server will close connections after
	# this time.
	keepalive_timeout 65;

	# Sendfile copies data between one FD and other from within the kernel,
	# which is more efficient than read() + write().
	sendfile on;

	# Don't buffer data-sends (disable Nagle algorithm).
	# Good for sending frequent small bursts of data in real time.
	tcp_nodelay on;

	# Causes nginx to attempt to send its HTTP response head in one packet,
	# instead of using partial frames.
	#tcp_nopush on;


	# Path of the file with Diffie-Hellman parameters for EDH ciphers.
	#ssl_dhparam /etc/ssl/nginx/dh2048.pem;

	# Specifies that our cipher suits should be preferred over client ciphers.
	ssl_prefer_server_ciphers on;

	# Enables a shared SSL cache with size that can hold around 8000 sessions.
	ssl_session_cache shared:SSL:2m;


	# Enable gzipping of responses.
	#gzip on;

	# Set the Vary HTTP header as defined in the RFC 2616.
	gzip_vary on;

	# Enable checking the existence of precompressed files.
	#gzip_static on;


	# Specifies the main log format.
	log_format main '$remote_addr - $remote_user [$time_local] "$request" '
			'$status $body_bytes_sent "$http_referer" '
			'"$http_user_agent" "$http_x_forwarded_for"';

	# Sets the path, format, and configuration for a buffered log write.
	access_log /var/log/nginx/access.log main;


	# Includes virtual hosts configs.
	include /etc/nginx/conf.d/*.conf;
}

Pin It on Pinterest

Share This