Building NginX v.1.9.10 from source

Installing any software by compiling the package from source is the best way to get the latest versions.

I’ll build NginX with mod_security, geoip and srcache support. Srcache lets NginX use Memcache to store its cache.

As of today the latest version is NginX v.1.9.10, that’s what we’ll install.

Dealing with GeoIP. The process is no different from what’s described in this article:

cd /usr/local/src  
wget http://www.maxmind.com/download/geoip/api/c/GeoIP-latest.tar.gz  
tar xf GeoIP-latest.tar.gz && cd GeoIP-1.*  
./configure  
make  
make install

During install a message flashed by in the console:

Libraries have been installed in:  
/usr/local/lib

I suspect that’s exactly where it got installed. Let’s make a symlink just in case. I’m worried nginx won’t find the library there:

ln -s /usr/local/lib/libGeoIP.so.1.6.0 /usr/lib/libGeoIP.so.1

Dealing with srcache
You can find the list of releases on this page:
https://github.com/openresty/srcache-nginx-module/tags

Installation follows the standard instructions. Download, unpack, and add it to the nginx build with --add-module=:

cd /usr/local/src  
wget https://github.com/openresty/srcache-nginx-module/archive/v0.30.tar.gz  
tar xf v0.30.tar.gz

Now for NginX itself. Download and unpack:

cd /usr/local/src  
wget http://nginx.org/download/nginx-1.9.10.tar.gz  
tar xf nginx-1.9.10.tar.gz  
cd nginx-1.9.10

Enable mod_security and http_stub_status_module during configuration. I need http_stub_status_module for more detailed server monitoring through NewRelic:

./configure -prefix=/opt/nginx -user=nginx -group=nginx -with-http_ssl_module -with-http_realip_module -with-http_gzip_static_module -with-http_auth_request_module -add-module=/usr/local/src/modsecurity-2.9.0/nginx/modsecurity -with-http_stub_status_module **-add-module=/usr/local/src/srcache-nginx-module-0.30**  
make -j 2  
make install

Create a script to run the daemon. I couldn’t find one in the package:

vim /etc/init.d/nginx

Content from the official site is in the spoiler below

/etc/init.d/nginx
</p> ```bash #! /bin/sh ### BEGIN INIT INFO # Provides: nginx # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: nginx init.d dash script for Ubuntu <=9.10. # Description: nginx init.d dash script for Ubuntu <=9.10. ### END INIT INFO #------------------------------------------------------------------------------ # nginx - this Debian Almquist shell (dash) script, starts and stops the nginx # daemon for ubuntu 9.10 and lesser version numbered releases. # # description: Nginx is an HTTP(S) server, HTTP(S) reverse \ # proxy and IMAP/POP3 proxy server. This \ # script will manage the initiation of the \ # server and it's process state. # # processname: nginx # config: /usr/local/nginx/conf/nginx.conf # pidfile: /acronymlabs/server/nginx.pid # Provides: nginx # # Author: Jason Giedymin # <jason.giedymin AT gmail.com>. # # Version: 2.0 02-NOV-2009 jason.giedymin AT gmail.com # Notes: nginx init.d dash script for Ubuntu <=9.10. # # This script's project home is: # http://code.google.com/p/nginx-init-ubuntu/ # #------------------------------------------------------------------------------ # MIT X11 License #------------------------------------------------------------------------------ # # Copyright (c) 2009 Jason Giedymin, http://Amuxbit.com formerly # http://AcronymLabs.com # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # Functions #------------------------------------------------------------------------------ . /lib/lsb/init-functions #------------------------------------------------------------------------------ # Consts #------------------------------------------------------------------------------ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/opt/nginx/sbin/nginx PS="nginx" PIDNAME="nginx" #lets you do $PS-slave PIDFILE=$PIDNAME.pid #pid file PIDSPATH=/var/run DESCRIPTION="Nginx Server..." RUNAS=root #user to run as SCRIPT_OK=0 #ala error codes SCRIPT_ERROR=1 #ala error codes TRUE=1 #boolean FALSE=0 #boolean lockfile=/var/lock/subsys/nginx NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf" #------------------------------------------------------------------------------ # Simple Tests #------------------------------------------------------------------------------ #test if nginx is a file and executable test -x $DAEMON || exit 0 # Include nginx defaults if available if [ -f /etc/default/nginx ] ; then . /etc/default/nginx fi #set exit condition #set -e #------------------------------------------------------------------------------ # Functions #------------------------------------------------------------------------------ setFilePerms(){ if [ -f $PIDSPATH/$PIDFILE ]; then chmod 400 $PIDSPATH/$PIDFILE fi } configtest() { $DAEMON -t -c $NGINX_CONF_FILE } getPSCount() { return `pgrep -f $PS | wc -l` } isRunning() { if [ $1 ]; then pidof_daemon $1 PID=$? if [ $PID -gt 0 ]; then return 1 else return 0 fi else pidof_daemon PID=$? if [ $PID -gt 0 ]; then return 1 else return 0 fi fi } #courtesy of php-fpm wait_for_pid () { try=0 while test $try -lt 35 ; do case "$1" in 'created') if [ -f "$2" ] ; then try='' break fi ;; 'removed') if [ ! -f "$2" ] ; then try='' break fi ;; esac #echo -n . try=`expr $try + 1` sleep 1 done } status(){ isRunning isAlive=$? if [ "${isAlive}" -eq $TRUE ]; then echo "$PIDNAME found running with processes: `pidof $PS`" else echo "$PIDNAME is NOT running." fi } removePIDFile(){ if [ $1 ]; then if [ -f $1 ]; then rm -f $1 fi else #Do default removal if [ -f $PIDSPATH/$PIDFILE ]; then rm -f $PIDSPATH/$PIDFILE fi fi } start() { log_daemon_msg "Starting $DESCRIPTION" isRunning isAlive=$? if [ "${isAlive}" -eq $TRUE ]; then log_end_msg $SCRIPT_ERROR else start-stop-daemon --start --quiet --chuid $RUNAS --pidfile $PIDSPATH/$PIDFILE --exec $DAEMON \ -- -c $NGINX_CONF_FILE setFilePerms log_end_msg $SCRIPT_OK fi } stop() { log_daemon_msg "Stopping $DESCRIPTION" isRunning isAlive=$? if [ "${isAlive}" -eq $TRUE ]; then start-stop-daemon --stop --quiet --pidfile $PIDSPATH/$PIDFILE wait_for_pid 'removed' $PIDSPATH/$PIDFILE if [ -n "$try" ] ; then log_end_msg $SCRIPT_ERROR else removePIDFile log_end_msg $SCRIPT_OK fi else log_end_msg $SCRIPT_ERROR fi } reload() { configtest || return $? log_daemon_msg "Reloading (via HUP) $DESCRIPTION" isRunning if [ $? -eq $TRUE ]; then `killall -HUP $PS` #to be safe log_end_msg $SCRIPT_OK else log_end_msg $SCRIPT_ERROR fi } quietupgrade() { log_daemon_msg "Peforming Quiet Upgrade $DESCRIPTION" isRunning isAlive=$? if [ "${isAlive}" -eq $TRUE ]; then kill -USR2 `cat $PIDSPATH/$PIDFILE` kill -WINCH `cat $PIDSPATH/$PIDFILE.oldbin` isRunning isAlive=$? if [ "${isAlive}" -eq $TRUE ]; then kill -QUIT `cat $PIDSPATH/$PIDFILE.oldbin` wait_for_pid 'removed' $PIDSPATH/$PIDFILE.oldbin removePIDFile $PIDSPATH/$PIDFILE.oldbin log_end_msg $SCRIPT_OK else log_end_msg $SCRIPT_ERROR log_daemon_msg "ERROR! Reverting back to original $DESCRIPTION" kill -HUP `cat $PIDSPATH/$PIDFILE` kill -TERM `cat $PIDSPATH/$PIDFILE.oldbin` kill -QUIT `cat $PIDSPATH/$PIDFILE.oldbin` wait_for_pid 'removed' $PIDSPATH/$PIDFILE.oldbin removePIDFile $PIDSPATH/$PIDFILE.oldbin log_end_msg $SCRIPT_ok fi else log_end_msg $SCRIPT_ERROR fi } terminate() { log_daemon_msg "Force terminating (via KILL) $DESCRIPTION" PIDS=`pidof $PS` || true [ -e $PIDSPATH/$PIDFILE ] && PIDS2=`cat $PIDSPATH/$PIDFILE` for i in $PIDS; do if [ "$i" = "$PIDS2" ]; then kill $i wait_for_pid 'removed' $PIDSPATH/$PIDFILE removePIDFile fi done log_end_msg $SCRIPT_OK } destroy() { log_daemon_msg "Force terminating and may include self (via KILLALL) $DESCRIPTION" killall $PS -q >> /dev/null 2>&1 log_end_msg $SCRIPT_OK } pidof_daemon() { PIDS=`pidof $PS` || true [ -e $PIDSPATH/$PIDFILE ] && PIDS2=`cat $PIDSPATH/$PIDFILE` for i in $PIDS; do if [ "$i" = "$PIDS2" ]; then return 1 fi done return 0 } case "$1" in start) start ;; stop) stop ;; restart|force-reload) stop sleep 1 start ;; reload) $1 ;; status) status ;; configtest) $1 ;; quietupgrade) $1 ;; terminate) $1 ;; destroy) $1 ;; *) FULLPATH=/etc/init.d/$PS echo "Usage: $FULLPATH {start|stop|restart|force-reload|status|configtest|quietupgrade|terminate|destroy}" echo " The 'destroy' command should only be used as a last resort." exit 1 ;; esac exit 0 ```

</div> </div>

Make it executable and add it to autostart:

sudo chmod +x /etc/init.d/nginx
sudo /usr/sbin/update-rc.d -f nginx defaults

Symlink the logs folder:

ln -s /opt/nginx/logs/ /var/log/nginx

Create the nginx user:

echo `/bin/false` >> /etc/shells
useradd -d /opt/nginx -s /bin/false nginx

Edit the main config file:

vim /opt/nginx/conf/nginx.conf

Make the following changes to it:

Change the user to nginx:

```bash user nginx; ```

Improve security:

```bash client_body_buffer_size 4K; client_header_buffer_size 4k; large_client_header_buffers 4 4k; limit_conn_zone $binary_remote_addr zone=slimits:5m; ```

Uncomment the access log format and explicitly set the file paths:

```bash log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; ## # Logging Settings ## access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log; ```

The final step is setting up file compression:

```bash ## # Gzip Settings ## gzip on; gzip_disable "msie6"; gzip_vary on; # gzip_proxied any; gzip_comp_level 6; gzip_buffers 64 8k; gzip_http_version 1.1; #This is one line. gzip_types text/plain text/html text/css application/json application/x-javascript text/xml application/xml alication/xml+rss text/javascript; ```

Add the following line to the http section:

```bash include /opt/nginx/sites/*.conf; ```

Create a folder to store all the site configs:

mkdir /opt/nginx/sites

Create the site config:

vim /opt/nginx/sites/mywebsite.conf

Put the following into it:

```bash server { listen 80; server_name mywebsite.com www.mywebsite.com; root /var/www/html; index index.php; if ($host ~ !^(mywebsite.com|www.mywebsite.com)$) { rewrite ^ http://www.mywebsite.com$request_uri? permanent; } # Limit methods, allowed on server to GET, HEAD and POST if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; } location ~* \.(ico|gif|jpeg|jpg|png|eot|ttf|swf|woff)$ { root /var/www/html; expires 30d; access_log off; } location ~* \.(css|js)$ { root /var/www/html; expires 7h; access_log off; } location / { try_files $uri $uri/ /index.php; } location ~ \.(php|html)$ { root /var/www/html; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } ```

At this point everything's done. You can start nginx and check:
Screenshot from 2016-01-29 13:30:48

After a new version comes out you can repeat all the steps and have the newest NginX again.

Share Button