Skip to content

Instantly share code, notes, and snippets.

@a-luna
Last active February 28, 2023 18:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save a-luna/316f1f8ed95d9c138eb04eecc3ba348d to your computer and use it in GitHub Desktop.
Save a-luna/316f1f8ed95d9c138eb04eecc3ba348d to your computer and use it in GitHub Desktop.
Shell Script: Build NGINX from Source with Third Party Modules (Cache Purge, GeoIP2), Completely Non-Interactive, No User Input Required
#!/bin/bash -e
# build_nginx_from_source.sh
# Author: Aaron Luna
# Website: alunablog.com
#
# This script downloads the source code for the latest version of NGINX
# (libraries required to build various NGINX modules are also downloaded)
# and builds NGINX according to the options specified in the ./configure
# command. Many of the possible configuration options are explained at
# the link below:
#
# https://www.nginx.com/resources/wiki/start/topics/tutorials/installoptions/
#
# This script includes examples of various ways NGINX can be customized
# such as: specifying the version of OpenSSL or GeoIP libraries to use,
# adding modules NOT enabled by default and adding third-party modules
# such as the GeoIP2 and cache purge modules.
#
# This script produces a .deb package file which can be used to
# uninstall this version of NGINX via apt-get remove nginx or
# dpkg ––remove nginx. The .deb package can also be used to install
# this version of nginx on another system with the same architecture.
# For more info on the checkinstall program which creates the .deb
# package, please see:
#
# https://wiki.debian.org/CheckInstall
#
# After NGINX is built, all of the source code is added to a .tar.gz
# archive file and stored in the $INSTALL_PKG_PATH along with the .deb
# package file. Finally, the script creates the systemd unit file and
# UFW app profile settings file and copies them to their correct
# locations. Finally, the nginx service is enabled and the server is
# rebooted to verify that nginx automatically starts.
##########################################################################
##########################################################################
# Environment Variables: KEEP UP TO DATE WITH MOST RECENT VERSION NUMBERS
#
# Check for latest NGINX version here:
# http://www.nginx.org/en/download.html
NGINX_VER=1.13.12
# Check for latest PCRE version here:
# https://sourceforge.net/projects/pcre/files/pcre/
# NOTE: NGINX requires the orignal PCRE library, NOT PCRE2
PCRE_VER=8.42
# Check for latest zlib version here:
# http://zlib.net
ZLIB_VER=1.2.11
# Check for latest OpenSSL version here:
# https://www.openssl.org/source/
# NOTE: NGINX can be built with either version 1.1.0.x or 1.0.2.x
# Per the website: The latest stable version is the 1.1.0 series.
# The 1.0.2 series is the Long Term Support (LTS) release, supported
# until 31st December 2019. The 0.9.8, 1.0.0 and 1.0.1 versions are
# now out of support and should not be used.
OPENSSL_VER=1.1.0h
#OPENSSL_VER=1.0.2o
# GeoIP databases are updated on the first Tuesday of each month,
# change the value below to the most recent corresponding date
# in YYYYMMDD format, prefixed with the underscore character
# Check for latest GeoIP databases here:
# https://dev.maxmind.com/geoip/geoip2/geolite2/
GEOIP_VER=_20180403
# IMPORTANT NOTE:
# The NGINX source files and the .deb package generated by this script
# are both needed to install this customized build on another system.
# The folder structure must be exactly the same on the system using the
# .deb package as it is on this machine.
#
# Thus, it is not a good idea to use a path containing the user's home
# folder in the value of the $DOWNLOAD_PATH environment variable (the same
# username must be used for the install on both systems if the $DOWNLOAD_PATH
# contains the user's home folder).
#
# Directory where all source files used to build NGINX will be stored
# temporarily:
DOWNLOAD_PATH=/opt
# Name of the folder where the .deb package file and archive (.tar.gz) file
# will be stored.
INSTALL_PKG_FOLDER=save
# Name of the folder where downloaded source files will be stored,
# this directory and all contents will be removed after NGINX is
# successfully installed.
SRC_FOLDER=src_files
##########################################################################
# Constant strings DO NOT EDIT THESE VALUES
#
EXT=.tar.gz
EXT_DB=.mmdb
NGINX_PRE=nginx-
PCRE_PRE=pcre-
ZLIB_PRE=zlib-
OPENSSL_PRE=openssl-
GEOIP1_PRE=GeoLite2-City
GEOIP2_PRE=GeoLite2-Country
##########################################################################
# Computed Environment Variables DO NOT EDIT THESE VALUES
#
SRC_PATH=${DOWNLOAD_PATH}/${SRC_FOLDER}
INSTALL_PKG_PATH=${DOWNLOAD_PATH}/${INSTALL_PKG_FOLDER}
NGINX_SRC_PATH=${SRC_PATH}/${NGINX_PRE}${NGINX_VER}
PCRE_SRC_PATH=${SRC_PATH}/${PCRE_PRE}${PCRE_VER}
ZLIB_SRC_PATH=${SRC_PATH}/${ZLIB_PRE}${ZLIB_VER}
OPENSSL_SRC_PATH=${SRC_PATH}/${OPENSSL_PRE}${OPENSSL_VER}
NGINX_SRC_TAR=${NGINX_PRE}${NGINX_VER}${EXT}
PCRE_SRC_TAR=${PCRE_PRE}${PCRE_VER}${EXT}
ZLIB_SRC_TAR=${ZLIB_PRE}${ZLIB_VER}${EXT}
OPENSSL_SRC_TAR=${OPENSSL_PRE}${OPENSSL_VER}${EXT}
GEOIP1_DB_TAR=${GEOIP1_PRE}${EXT}
GEOIP2_DB_TAR=${GEOIP2_PRE}${EXT}
GEOIP1_DB_FOLDER=${GEOIP1_PRE}${GEOIP_VER}
GEOIP2_DB_FOLDER=${GEOIP2_PRE}${GEOIP_VER}
GEOIP1_DB_FILE=${GEOIP1_PRE}${EXT_DB}
GEOIP2_DB_FILE=${GEOIP2_PRE}${EXT_DB}
ALL_SRC_FILES_TAR=${NGINX_PRE}${NGINX_VER}-src_files${EXT}
##########################################################################
# BEGIN SCRIPT EXECUTION
#
# NOTE: If building NGINX on Amazon EC2 instance with ubuntu 16.04 or 17.10
# use the following command which is commented out in line 166:
# "sudo apt update && sudo DEBIAN_FRONTEND=noninteractive apt upgrade -y"
# (and comment out line 165)
#
# if you call "sudo apt upgrade -y" without the noninteractive
# setting a prompt asking for a decision re: grub version conflict
# will cause the script to hang. If run as part of a packer template,
# the user will be unable to interact with the prompt and must cancel
# the script via Ctrl+C.
#
# I tested this with ubuntu versions 14.04, 16.04 and 17.10 with
# VM instances from 3 different vendors (Amazon EC2, VMWare Fusion,
# VirtualBox) and the issue only occurrs with EC2 instances running 16.04.
# It is unknown if this issue exists with older distributions or
# VM instances from other vendors.
#
##########################################################################
# Add Maxmind PPA to apt sources
sudo add-apt-repository ppa:maxmind/ppa -y
# Update OS - SEE NOTE ABOVE IF INSTALLING ON UBUNTU 16.04 or 17.10 ON AMAZON EC2
sudo apt update && sudo apt upgrade -y
#sudo apt update && sudo DEBIAN_FRONTEND=noninteractive apt upgrade -y
sudo apt autoremove -y
# Install build tools (gcc, g++, etc)
sudo apt install build-essential -y
# Install libraries required by GeoIP2 module to read MaxMind database files
sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin -y
# Install checkinstall to create .deb package file
sudo apt install checkinstall -y
# Install Uncomplicated Firewall (UFW) since NGINX app profile
# is created after install and directory is assumed to exist
sudo apt install ufw -y
# Create a directory to store all the source files
sudo mkdir -p $SRC_PATH
cd $SRC_PATH
# Download and extract the source code for the latest version of NGINX
sudo wget http://nginx.org/download/$NGINX_SRC_TAR && \
sudo tar xzf $NGINX_SRC_TAR
# PCRE, zlib and OpenSSL libraries are needed by various NGINX modules,
# download and extract the latest version of these as well
sudo wget https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/${PCRE_SRC_TAR} && \
sudo tar xzf $PCRE_SRC_TAR
sudo wget http://zlib.net/${ZLIB_SRC_TAR} && \
sudo tar xzf $ZLIB_SRC_TAR
sudo wget https://www.openssl.org/source/${OPENSSL_SRC_TAR} && \
sudo tar xzf $OPENSSL_SRC_TAR
# Download (third party) NGINX modules: cache purge and GeoIP2
# The GeoIP module included with NGINX only works with v1 MaxMind database files
# V2 database files are far superior, see here for more info:
# https://dev.maxmind.com/geoip/geoip2/whats-new-in-geoip2/
sudo git clone --recursive https://github.com/FRiCKLE/ngx_cache_purge.git
sudo git clone --recursive https://github.com/leev/ngx_http_geoip2_module.git
# Remove source code archive files and navigate to the NGINX source directory
sudo rm -rf *.tar.gz
cd $NGINX_SRC_PATH
# Choose the configuration options that are required for this build of NGINX:
sudo ./configure \
--prefix=/usr/share/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--user=www-data \
--group=www-data \
--build=Ubuntu \
--http-client-body-temp-path=/var/lib/nginx/body \
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
--http-proxy-temp-path=/var/lib/nginx/proxy \
--http-scgi-temp-path=/var/lib/nginx/scgi \
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
--with-openssl=$OPENSSL_SRC_PATH \
--with-openssl-opt=enable-ec_nistp_64_gcc_128 \
--with-openssl-opt=no-nextprotoneg \
--with-openssl-opt=no-weak-ssl-ciphers \
--with-openssl-opt=no-ssl3 \
--with-pcre=$PCRE_SRC_PATH \
--with-pcre-jit \
--with-zlib=$ZLIB_SRC_PATH \
--with-compat \
--with-file-aio \
--with-threads \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_sub_module \
--with-http_stub_status_module \
--with-http_v2_module \
--with-http_secure_link_module \
--with-mail \
--with-mail_ssl_module \
--with-stream \
--with-stream_realip_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-debug \
--add-module=../ngx_http_geoip2_module \
--add-module=../ngx_cache_purge \
--with-cc-opt='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' \
--with-ld-opt='-Wl,-z,relro -Wl,--as-needed'
# Build nginx with the specified configuration
sudo make
# Create a .deb package (instead of running `sudo make install`)
sudo checkinstall --install=no -y
# Install the .deb package, this allows uninstall via apt-get
sudo dpkg -i nginx_${NGINX_VER}-1_amd64.deb
# Move the .deb package to a new folder since we are going to create an
# archive from the directory containing the downloaded source code files,
# which is our current working directory
sudo mkdir -p $INSTALL_PKG_PATH
sudo mv nginx_${NGINX_VER}-1_amd64.deb ${INSTALL_PKG_PATH}/nginx_${NGINX_VER}-1_amd64.deb
# Create an archive containing all the source files needed to build NGINX and
# compress the files using the .tar.gz format
cd $INSTALL_PKG_PATH
sudo tar -zcf $ALL_SRC_FILES_TAR $SRC_PATH
# Make both .deb package and source files archive executable by all users
sudo chmod 755 nginx*.*
# Create a directory at /var/lib/nginx to prevent the NGINX config
# file from failing verification in next command (sudo nginx -t)
sudo mkdir -p /var/lib/nginx
# Verify NGINX version and verify configuration options match what
# was specified with the ./configure command
echo
echo 'Verify NGINX version and config options below:'
echo
sudo nginx -t && sudo nginx -v && sudo nginx -V
# Create folders for nginx multiple virtual host config
cd /etc/nginx
sudo mkdir sites-available
sudo mkdir sites-enabled
# Create firewall app profile (UFW) for NGINX
# If provisioning an Amazon EC2 instance this does not need to be enabled
# if the same rule set is applied via security group
sudo touch nginx
echo '[Nginx HTTP]' | sudo tee -a nginx
echo 'title=Web Server (Nginx, HTTP)' | sudo tee -a nginx
echo 'description=Small, but very powerful and efficient web server' | sudo tee -a nginx
echo 'ports=80/tcp' | sudo tee -a nginx
echo | sudo tee -a nginx
echo '[Nginx HTTPS]' | sudo tee -a nginx
echo 'title=Web Server (Nginx, HTTPS)' | sudo tee -a nginx
echo 'description=Small, but very powerful and efficient web server' | sudo tee -a nginx
echo 'ports=443/tcp' | sudo tee -a nginx
echo | sudo tee -a nginx
echo '[Nginx Full]' | sudo tee -a nginx
echo 'title=Web Server (Nginx, HTTP + HTTPS)' | sudo tee -a nginx
echo 'description=Small, but very powerful and efficient web server' | sudo tee -a nginx
echo 'ports=80,443/tcp' | sudo tee -a nginx
# Move the file so UFW can read it. UFW is disabled by default
sudo mv nginx /etc/ufw/applications.d/nginx
# Create systemd unit file for NGINX
sudo touch nginx.service
echo '[Unit]' | sudo tee -a nginx.service
echo 'Description=A high performance web server and a reverse proxy server' | sudo tee -a nginx.service
echo 'After=network.target' | sudo tee -a nginx.service
echo | sudo tee -a nginx.service
echo '[Service]' | sudo tee -a nginx.service
echo 'Type=forking' | sudo tee -a nginx.service
echo 'PIDFile=/run/nginx.pid' | sudo tee -a nginx.service
echo $'ExecStartPre=/usr/sbin/nginx -t -q -g \'daemon on; master_process on;\'' | sudo tee -a nginx.service
echo $'ExecStart=/usr/sbin/nginx -g \'daemon on; master_process on;\'' | sudo tee -a nginx.service
echo $'ExecReload=/usr/sbin/nginx -g \'daemon on; master_process on;\' -s reload' | sudo tee -a nginx.service
echo 'ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid' | sudo tee -a nginx.service
echo 'TimeoutStopSec=5' | sudo tee -a nginx.service
echo 'KillMode=mixed' | sudo tee -a nginx.service
echo | sudo tee -a nginx.service
echo '[Install]' | sudo tee -a nginx.service
echo 'WantedBy=multi-user.target' | sudo tee -a nginx.service
# Move the file to correct location so NGINX can be started,
# stopped and reloaded with global commands
sudo mv nginx.service /etc/systemd/system/nginx.service
# Remove all source files
sudo rm -rf $SRC_PATH
# Start and enable NGINX service
sudo systemctl start nginx.service && sudo systemctl enable nginx.service
# Verify NGINX is running
sudo systemctl status nginx.service
# Reboot the server
sudo shutdown -r now
# Log in after the reboot is complete, and verify NGINX is running
# sudo systemctl status nginx.service
@EnergeticPixels
Copy link

@a-luna, I am trying to follow your gist for building NGINX from source. Box I am building on is a Debian 10 (vagrant/virtualbox). Everything goes really well until your coding line 273, where we are installing the .deb package. My error says
dpkg: error: cannot access archive 'nginx_1.19.2-1_amd64.deb': No such file or directory. I am still a probie with *NIX type of software. The line above my failure looks to complete like it should "sudo make install", but I cannot seem to find the .deb package that is supposed to be made. I uploaded my project to https://github.com/EnergeticPixels/nginx-nodejs-mongo.git. NGINX development is in the develop/nginx branch. My line 128 in the nginx_from_source.sh file is where the issue surfaces. Any help/direction would be happily received.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment