Currently viewing the tag: "Nginx"

It’s a good practice to monitor your web server logs for erroneous HTTP status codes in the requests made to your web server. There are several reasons for doing this routinely, including troubleshooting web server problems, identifying web server attacks, SEO purposes, and providing an overall improved experience for the end users.

Many system administrators and developers will monitor web server logs for issues. A lot of the time, it isn’t a routine practice and can be inadvertently neglected. This is a quick and dirty bash one-liner that will grab all of the matching 4xx & 5xx web server log entries, and send them to you in a daily email digest for further analysis, which automates the practice of proactively monitoring web server logs for issues.

Consider the following…


The web server access log format displays:

Log Location

The web server access logs are located in:

Where VHOST is your virtual host(s).

The Script

The above one-liner will effectively find all of your individual Apache virtual host access log files, and extract all of the HTTP 4xx and 5xx entries for a given date (in the format of “18/Mar/2012“).

A variation of the above script caters to server deployments that run Nginx along side of Apache, where the server is logging to two different default web server locations (/var/log/apache2/ and /var/log/nginx/), and will perform the script operations on both sets of access log files:

Adding this to cron, running it a 11:59pm daily will give you the digest. A consideration before deploying this is the possibility of having large access logs that might potentially produce thousands of lines of log entries. A better solution in those types of deployments for this script example is to use uuencode for attaching the output as a compressed attachment instead.

Depending on your tolerance for the email size, one can incorporate simple logic using wc to count the lines in the output, and send it raw via the mail utility if the lines are less than X or use uuencode if the lines are greater than Y.

For those that are fairly new to web server administration or HTTP in general, here are some of the most common HTTP server and client error codes you will encounter:


HTTP error codes beginning with 5 indicate a problem with the server. Most commonly these fire in scenarios such as:

500 Internal Server Error

  • A server misconfiguration prevents the request from being processed

502 Bad Gateway

  • Can indicate server in your load balance pool are down at the time of the request

503 Service Unavailable

  • May indicate that there isn’t enough capacity on the back-end servers or back-end server threads to handle the traffic


These HTTP codes relate problems with the client request, but the most common scenarios are:

401 Unauthorized

  • The client attempted to access a resource that requires authentication
  • Large amounts of HTTP 401′s in your server logs can indicate a brute force attempt against resources protected by HTTP authentication

403 Forbidden

  • The client attempted to access a resource that the server’s configuration denies permission to
  • Can be caused by file permissions, an htaccess directive, a client attempting to view directory indexes, and so forth

404 Not Found

  • Files no longer exist or were moved
  • Broken links or paths, best remedied with 301 or 302 redirects to the new location

444 No Response (Nginx specific)

  • This is a special Nginx HTTP response code that simply does not respond and resets the connection to the client
  • Useful for protecting web server assets and mitigating requests from known-bad user agents, and has several other advantages


This is a tutorial for setting up your own open-source anti-theft software in OSX. Upon completion of this tutorial, you will have a system daemon that will securely perform, nearly all of the core functions as many paid Macbook / Macbook Pro anti-theft applications provide.

Be advised, this guide is aimed towards those with a bit of Unix/Linux knowledge, so if there are points that are not clear to novice users, do not hesitate to contact me for clarifications.

Why are you reading this?

Some time ago, I read about an individual who had their Macbook Pro stolen from them and recovered it with the help of the police and an app called “hiddenapp”. Since I had actually had a 2008 Macbook Pro stolen from me in the past, I decided to purchase (waste my money on) the app for my current machine.

Right after I performed the installation, I immediately noticed an outbound request from a curl to hiddenapp.com, thanks to Little Snitch. Before allowing this egress traffic, I decided to fire up Wireshark to inspect the traffic leaving my machine and network, whereby I found the following unacceptable application behaviors:

  • Traffic leaves the Mac unencrypted to hiddenapp.com, to port 80
  • The outbound request for status (Stolen, Test Mode, or OK) attempted to send my Macbook Pro’s serial number in plain text in the curl (GET) request URI!

Having witnessed this, I attempted to reconstruct the request via curl over HTTPS, only to find that the domain does not offer SSL encryption whatsoever. Not being able to live with the fact this app transmits my Macbook Pro’s serial number in the clear back to the mothership, I took it upon myself to identify the core features this self proclaimed “Most advanced theft tracking software for your Mac”, and replicate the functionality securely on my own setup.


This tutorial is for the adventurous. You must have the following at your disposal to complete the setup:

  • ImageSnap
  • Web Server with shell access (I’m using Nginx for this tutorial)
  • Intermediate Unix commandline fu (or the motivation to follow some the steps in this guide)

Step #1: Install and Test ImageSnap

As stated above, you have two options for getting the imagesnap binary installed. Grab the ImageSnap source code either way, as it contains a precompiled binary that you can copy into your $PATH or desired location, or compile your own using the Xcode project file contained within.

Once you have the imagesnap binary in $PATH, run the following test to ensure that it works as expected (taking a picture with the iSight camera):

The above should produce a Jpeg image in the current directory.

Step #2: Configure Your Nginx vhost with SSL and Auth Basic

We will now setup an Nginx vhost to handle our application’s requests. Our web server will have the following attributes:

  • SSL encryption for our status requests
  • User / Password authentication for status requests
  • Custom user agent filtering with Nginx to provide an added layer of authentication
  • A single web page containing your Mac’s status code (Stolen or Not)

Generate a self signed SSL certificate:

* If you do not have htpasswd installed to create the passwd file, see this.

Test the Nginx configuration:

Create the file on the remote server with:

In this example, we will use the number “0″ as the status message indicating our machine is not stolen. Anything other than “0″ will indicate the device is in fact stolen. We’ll come back to this file later.

Step #3: Test Authentication with cURL

Now let’s ensure that we can authenticate with the web server before proceeding. Use the following curl command to test:

Confirm the status code in the server response headers is “HTTP/1.1 200 OK” and not “HTTP/1.1 401 Unauthorized“. If you get a 401, fix your configuration in Step #2.

Step #4: Generate an SSH Key and Server User Account

For this setup, we will use an SSH key for a user account on the remote server with limited privileges. If our status check indicates the machine is stolen, the machine will transfer the picture taken with the iSight camera to the remote server via the SCP protocol, so we can retrieve the photo(s) taken.

We will configure the remote user’s SSH authorized_keys file to only allow SCP access to the remote user’s /home/ folder.

ssh-keygen -t rsa -b 2048 -C "some text you can identify"

It would be a good idea to bury this key somewhere in the filesystem, but make note of the path.

Next, setup a user account on the remote server (useradd -m -s /bin/bash someusername). Create the user’s .ssh folder in it’s home account and create an authorized_keys file (a shortcut for this is to run: su – someusername , then run ssh localhost). Do not give the new user account a password (although you shouldn’t be allowing users to login with passwords from the get go).

Add the contents of the SSH .pub file to the authorized_keys file, save it then chmod 700 the file. Run a test to ensure the Mac can ssh to the server (ssh someusername@someserverip -i /path/to/ssh/private/key).

We will need to restrict what this user can do once SSH’d to the remote server. A quick way to accomplish this, is to edit the authorized_keys, preceding it with a “command=”. In our case, we will be using a basic Perl script (scp-wrapper) to ensure that this user only be allowed to copy files. Download the file here and copy this to the remote server as /usr/bin/scp-wrapper (make sure to chmod +x the file).

Edit the user’s authorized_keys file, so the beginning of the file looks like this:
command=”/usr/bin/scp-wrapper” ssh-rsa <rest of key bits>
Test that the user’s functionality is limited to scp only:
ssh someusername@someserverip -p someport -i /ssh/private/key “uptime”
Should return the following:

/usr/bin/scp-wrapper: account restricted: only scp allowed (“uptime”)

Now test scp functionality:
scp -P someport -i /ssh/private/key test.txt someusername@someserverip:
test.txt 100% 0 0.0KB/s 00:00

This is not the only method available for restricting commands for remote user accounts, so once again feel free to be creative.

Step #5: Create Script to Perform Status Checks

Next, we will create a simple bash script to perform the status checks. The below script is rather simple in form, but performs the basic functions needed for operation (let your creativity improve on this if desired).

Make this script executable (chmod +x) and note the location.

Step #6: Test Run

It’s now time to test our script. Run the file from the terminal, and ensure that it has scp’d a copy of a fresh iSight snapshot to the remote server (since our status page is set to “123″ indicating a status other than not stolen).

Congratulations, you’re almost done.

Step #7: Create a Launch Daemon

We’ll now create a launch daemon to load and run our script. Become root in a terminal and create the following file: /Library/LaunchDaemons/com.myapp.SomeName.plist.

Grab the template file here

I’ve set the integer value to 300 (seconds), edit to your taste (don’t forget to set the script path in the file). Be sure to set remote status page content to “0″, then load the plist with: launchctl load -w /Library/LaunchDaemons/com.myapp.SomeName.plist and you’re in business ;-)

Step #7: Dummy Account & Conclusion

Setup a new “dummy” user account on your Mac, require no login. If you are unlucky enough to have your Mac swiped, the perpetrator will hopefully be dumb enough to fall for the non-password protected user account and the script will do it’s job thereafter (so long as they connect to the internet).

You can check your Nginx server logs for the IP they have connencted from, and provide the information to law enforcement along with any pictures that were successfully uploaded to the server. With any luck, karma will be on your side and you will recover your machine.

Once again, creativity is at your disposal here. One could setup a custom Twitter page and change the status to something indicating the machine is stolen (if you do not prefer to have to SSH in to change the status page of the static HTML on the server).

You could even setup a custom email account on the server and use a procmail recipe to modify the status code on the file if certain regex expressions are met in the Subject and/or body of the email sent to the server. Anything is possible.

Hiddenapp should change their name to Hiddencrap.

Splunk is probably one of the greatest IT tools of all time. It is a robust monitoring and reporting tool that can index just about any type of data from several types of data inputs.

There is a free license version of the Splunk software that has a few limitations in comparison to the enterprise licensed version; one of the limitations is the inability to perform a basic method of user and password authentication (or even the full scope of PAM authentication methods). We can fix this easily with a small and lightweight installation of the freely available Nginx web server software.

For this guide, I will demonstrate the process using methods using Linux for the Splunk deployment. I will not go into the details of how to install Splunk, and will presume a prexisting installation exists.


How it Works

Below is a diagram showing the communication between the client connecting to Splunk, running on the host “splunkbox”:

Nginx Splunk Proxy

Nginx will proxy all requests on port SSL 443 for https://splunkbox/splunk to the Splunk instance (running on the same server), listening only on Any attempts to bypass the authentication mechanism we configure (by making direct requests to splunkbox:8000) will be denied.


Step #1: Getting the Required Software

Your have the options of installing Nginx through your distribution or from source. If choosing a source compile, make sure you grab it from the official Nginx download page.


Step #2: Configuring Splunk

We start this process by editing the Splunk web.conf, to add the settings we need for it to run on locahost and for proxy configuration:

Once the web.conf file looks like the above, restart Splunk with the following command:

Splunk should now bind to localhost only and be set for accepting proxy requests (it’s a good idea to confirm that it is listening only on localhost with the netstat command).


Step #3: Nginx Configuration

This step will presume that you with to use SSL for the configuration and have properly generated the needed SSL certificates (if you do not have certificates already, refer to the Openssl documentation on how to generate a self-signed certificate). In this section we will edit the nginx.conf directly, and not cover how to setup seperate virtual host configuration files for the sake of simplicity:

Next we create our password file for the authentication. From the Nginx documentation:

Passwords must be encoded by function crypt(3). You can create the password file with the htpasswd program from Apache.” If you do not have apache2-utils installed, see man 3 crypt on how to generate this. htpasswd -c /etc/nginx/nginx.passwd username; (prompted to enter password twice)

Now we can start Nginx with the command “nginx” from a terminal (and now would be a good time to read the Nginx man page).


Step #4: Testing the Proxy

Assuming that the nginx binary is running, and listening on the correct port, open up a browser and navigate to https://splunkbox/splunk. You should be prompted for the username and password as set in the above configuration. Once you are authenticated, you should see the Splunk interface.