Over the course of this series of articles, I will cover the build and configuration of an Amazon EC2 Instance capable of serving Ruby on Rails applications. The series will cover the build and installation of Nginx from source, virtual host and proxy configuration within Nginx, installation of Ruby and RubyGems, installation of the Rails and Thin gems, and the deployment of a set of clustered Thin workers. I chose Nginx over Apache HTTPD as it is renowned for both performing very well as a reverse proxy as well as serving static content whilst having a very low memory footprint. Plus, I’m always interested in looking at “alternative” software solutions to common problems.
Read my article around EC2 instance management via the ec2-api-tools if you’d like to provision your instance(s) via the command line, otherwise just provision your instance(s) via the EC2 Management Console. This article presumes that you have an instance running and ready to go. I used ami-08df4961 (which is Ubuntu 12.10 i386 Server, EBS-backed). I’d use a RHEL instance but they are not eligible for the free tier due to licensing, plus the Ubuntu instances are very well supported by Canonical.
Installation of Nginx
Prior to downloading and compiling Nginx, I first installed the prerequisites via APT. I like to let package management tools take care of dependencies (so they are easily managed and updated), but install the major software components from source. This ensures that I always have the latest and greatest software release, and all functional and security patches are up-to-date. Anyway … those dependencies. First, I install dependencies I’ll need for general software build tasks:
|
1 |
# apt-get install gcc g++ make autoconf libtool flex bison |
Followed by the dependencies I need specifically for the Nginx build:
|
1 |
# apt-get install libpcre3 libpcre3-dev libssl1.0.0 libssl-dev |
Obviously, all the packages I just installed had their own dependencies too, which APT handled and installed along with the specified packages.
Next, download the latest stable version of Nginx to /usr/local/src. This was 1.2.7 at the time of writing.
|
1 2 |
# cd /usr/local/src # wget http://nginx.org/download/nginx-1.2.7.tar.gz |
Extract the source:
|
1 2 |
# tar xzf nginx-1.2.7.tar.gz # cd nginx-1.2.7 |
Next, configure Nginx:
|
1 2 |
# ./configure --prefix=/usr/local/nginx-1.2.7 --with-http_ssl_module \ > --conf-path=/etc/nginx/nginx.conf |
As you can see, I’ve defined a few things at the configure stage. I’m installing to /usr/local/nginx-1.2.7, and compiling in SSL support, whilst having Nginx look for its configuration file at /etc/nginx/nginx.conf by default.
Once configure completes successfully, compile and install the software:
|
1 2 3 |
# make # make install # ln -s /usr/local/nginx-1.2.7 /usr/local/nginx |
Add a group and user for Nginx to run as. Nginx must still be started as root, but after successfully binding to any privileged ports, Nginx will drop privileges to the user and group created here (after appropriate configuration, of course).
|
1 2 |
# groupadd -g 80 nginx # useradd -M -d /dev/null -s /bin/false -u 80 -g nginx nginx |
I’ll be placing log files under /var/log/nginx, so I’ll create that directory now with appropriate ownership and permissions:
|
1 |
# install -m 755 -o nginx -g nginx -d /var/log/nginx |
Nginx is now ready to start up - but before we do that, we need to configure it.
Configuring Nginx
Here is my /etc/nginx/nginx.conf. I’ve commented each directive so you can see what’s going on. The Nginx Documentation should be consulted if further clarity is required.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# Run nginx with UID nginx and GID nginx user nginx nginx; # We have one CPU, so 1 worker process is a good start worker_processes 1; # Set the path to the error log error_log /var/log/nginx/error.log; # Set the path to the pid file pid /var/log/nginx/nginx.pid; # Set the path to the lock file lock_file /var/log/nginx/nginx.lock; # The events block is used to define directives that affect # connection processing events { # Define the maximum number of connections that can # be opened by a worker process worker_connections 1024; } # Begin our HTTP configuration http { # Include the standard MIME type configuration include /etc/nginx/mime.types; # Set the default type default_type application/octet-stream; # Don't give away our server version server_tokens off; # Linux-specific performance tuning options sendfile on; tcp_nopush on; # Other performance tuning options # keepalive_timeout is 75 seconds by default, but # I'll still state explicitly here keepalive_timeout 75; # Enable use of TCP_NODELAY when in # keep-alive state tcp_nodelay on; # Turn on gzip compression gzip on; # Only gzip responses larger than 1024 bytes gzip_min_length 1024; # Only gzip plain text - text/html is ALWAYS compressed # if gzip is turned on gzip_types text/plain; # Include virtual host specific configuration include /etc/nginx/vhosts.d/*.conf; } |
Even though I’m referring to virtual host specific configuration files under /etc/nginx/vhosts.d/*.conf at this point, there is no configuration there yet. I will create the directory, however.
|
1 |
# mkdir /etc/nginx/vhosts.d |
Now, start Nginx:
|
1 2 3 4 |
# /usr/local/nginx/sbin/nginx # ps -ef | grep '[n]ginx' root 14133 1 0 09:33 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx nginx 14134 14133 0 09:33 ? 00:00:00 nginx: worker process |
Check for errors in /var/log/nginx/error.log (or whichever path you defined in your nginx.conf) - if there are none, the base setup is ready. Stop Nginx:
|
1 2 3 |
# /usr/local/nginx/sbin/nginx -s stop # ps -ef | grep '[n]ginx' # |
We can also have Nginx reload its configuration on the fly with the following commands:
|
1 2 3 4 |
# /usr/local/nginx/sbin/nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful # /usr/local/nginx/sbin/nginx -s reload |
As you can see, first the -t option is used to verify that the nginx.conf syntax is error-free, and then -s reload is passed to reload the configuration. Nginx even supports an upgrade of the nginx executable itself on-the-fly. See the Nginx Wiki for further information.
Conclusion
This article has walked through compiling Nginx from source, including the installation of prerequisite packages. It has also described the basic Nginx configuration in detail by way of a well-commented ngnix.conf file. Whilst the configuration is ready for the addition of virtual hosts (for example, the virtual host that will proxy back to the Thin workers), this is not yet done - at the moment Nginx is not serving anything - in fact it’s not even listening on a port yet.
Depending on your Operating System, you might want to create an init script or upstart job as appropriate so that you don’t have to start/stop Nginx manually on system reboot, for example.
Moving on from here, we need to install Ruby, RubyGems, Rails, Thin and finish the configuration of Nginx. All that is covered in the second article in this series.
Appendix - Upstart Script
Here is my well-commented upstart script for Nginx on Ubuntu. Install this to /etc/init/nginx.conf.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# nginx - Upstart job # description of job description "nginx web server" # author - that's me # start only once filesystem and network interface eth0 # are available - these will be emitted upstart events start on (filesystem and net-device-up IFACE=eth0) # stop on transition out of multi-user runlevels stop on runlevel [!2345] # define DAEMON and PID env DAEMON=/usr/local/nginx/sbin/nginx # note - this PID is for upstart use, not the same pid defined # in nginx.conf env PID=/var/run/nginx.pid # have upstart track the forked processes (i.e. the nginx # workers) expect fork # respawn if nginx fails respawn # but only for a maximum of 10 times in 5 seconds respawn limit 10 5 # fire it up exec $DAEMON |
You can now use the start/stop/status/restart/reload commands to manage Nginx.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# status nginx nginx stop/waiting # start nginx nginx start/running, process 14313 # status nginx nginx start/running, process 14313 # ps -ef | grep '[n]ginx' root 14313 1 0 10:12 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx nginx 14314 14313 0 10:12 ? 00:00:00 nginx: worker process # stop nginx nginx stop/waiting # ps -ef | grep '[n]ginx # |
You can extend this script to add a call to $DAEMON -t, for example, to check the syntax of your Nginx configuration prior to attempting to (re)start the service.