#!/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