Home » Internet » Web Server » Setting Up Full Web Server with Nginx – From Start to Finish

Setting Up Full Web Server with Nginx – From Start to Finish

I’ve bought a new VPS Server in the past for hosting some of my site, setting up new VPS is not easy as you think, but if you need tutorial step by steps for help on setting up a VPS or dedicated server, so I thought I would go ahead and make a guide on how to set one up from start to finish to cover all of the bases. That being said, I obviously can’t go into detail how to get things up and running for every possible setup, operating system, or distribution. Here is a list of assumptions/requirements I am making for this guide:

  1. You are running Ubuntu >= 10.10 (Maverick), although any Debian Linux distribution is probably fine
  2. You have at least some basic command-line knowledge (mostly meaning you’ve used SSH before and know how to edit files in the Terminal)
  3. You want to use Nginx as a web server and not Apache (trust me, you won’t regret it)
  4. You know DNS well enough to get that side of things setup. This guide is going to stick to installing and configuring software.
  5. You are running these commands as root. If that scares you, then make sure you put ‘sudo’ in front of the apt-get commands and the ‘make install’ command.
  6. Oh and just to be clear, if there is a # in front of a Terminal line, that is just the bash prompt. Don’t enter it with the command after it.

So, assuming you have a fresh server ready to go (sorry, not going to cover OS install as that’s pretty trivial), lets go!

Preliminary Steps
First, there are a few things that we need to do because they will become useful or needed later in the setup process. They’re pretty basic, but they are easy to forget.

# apt-get update
# apt-get upgrade
# apt-get install build-essential

Installing PHP

Now that that’s out of the way, the first thing we’re going to need to do is install PHP. Luckily, Ubuntu keeps the version in the repository up to date (unlike CentOS) so this is very simple to do. If you are using Ubuntu 10.10 (Maverick), then you will get the benefit of PHP 5.3.5. Otherwise you will get PHP 5.3.2.

# apt-get install php5-cli php5-cgi php5-dev php-pear php5-xcache php5-mysql php5-mcrypt

You may notice that we didn’t install the base php5 package. This is because this package is intended for Apache web servers, and thus we will not need it. You may also have noticed that we installed XCache. This is optional, but I recommend it as it will help speed things up.

Double checking to make sure everything installed ok, we can run:

# php -v
PHP 5.3.2-1ubuntu4.5 with Suhosin-Patch (cli) (built: Sep 17 2010 13:49:46)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
with XCache v1.3.0, Copyright (c) 2005-2009, by mOo

Installing MySQL

Next up we need to install MySQL. Luckily this is also very straightforward:

# apt-get install mysql-server mysql-client

This will install MySQL and all of its dependencies. You will be prompted to enter and confirm a new password for the root MySQL user, so make sure you don’t forget it! To test that MySQL is up and running, run:

# mysql -uroot -p

and enter the root password you just specified during the install at the prompt. You should be presented with something along the lines of:

# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 39
Server version: 5.1.41-3ubuntu12.6 (Ubuntu)

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

mysql>

This means your MySQL server is up and running! If you are unable to connect, try running:

# service mysql start

Installing Nginx

Now it’s time to install our web server: Nginx. I won’t go into detail about how cool Nginx is in this guide, but if you’re unfamiliar with it: it’s pretty damn cool.

Up until now, we’ve been cruising through software installation. Unfortunately, the version of Nginx in the Ubuntu repository is very out of date. At the time of this writing, the version in the repository is 0.9.5 while the latest stable version is 0.9.7.

However, never fear! Nginx provides their own repository for the latest stable versions for Ubuntu. To add this repository, run:

# echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu lucid main" >> /etc/apt/sources.list
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C
# apt-get update

Now that we have access to the Nginx repository, we can run:

# apt-get install nginx

To verify Nginx is installed and working:

# nginx -v
# nginx version: nginx/0.9.7

Configuring Nginx

Now this guide gets a little trickier and a little bit rougher in this section. Website organization and folder structure is often a matter of personal preference. Keep in mind there is no right or wrong way of organizing your website folders (ok well, maybe putting your site in /root isn’t a good idea but you get the gist of it), so feel free to change the paths around. What follows is how I setup my own server.

The main Nginx configuration is in /etc/nginx/nginx.conf, so lets make a few tweaks to that first:

user www-data;
worker_processes  4;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
worker_connections  1024;
# multi_accept on;
}

http {
include       /etc/nginx/mime.types;
access_log  /var/log/nginx/access.log;

sendfile        on;
#tcp_nopush     on;

#keepalive_timeout  0;
keepalive_timeout  2;
tcp_nodelay        on;

gzip  on;
gzip_disable  msie6;

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

The main thing we changed was increasing worker_processes from 1 to 4, but I thought I would paste the file in its entirety just in case. If you look closely, you’ll see that Nginx includes all files in /etc/nginx/sites-enabled/, so lets take advantage of this to improve our configuration file organization.

Create a file with a descriptive name, one for each of your domains (not subdomains, unless you really want to), and put it in something along the lines of:

server {

 listen   80; ## listen for ipv4
 server_name  meltingice.net; ## change this to your own domain name

 # I find it really useful for each domain & subdomain to have
 # its own error and access log
 error_log /var/log/nginx/meltingice.net.error.log;
 access_log  /var/log/nginx/meltingice.net.access.log;

 location / {
 # Change this to the folder where you want to store your website
 root   /home/meltingice_net/public_html;
 index  index.html index.htm index.php;
 }

 # redirect server error pages to the static page /50x.html
 #
 error_page   500 502 503 504  /50x.html;
 location = /50x.html {
 root   /var/www/nginx-default;
 }

 # We haven't setup FastCGI yet, but lets configure this now anyways
 #
 # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
 location ~ .php$ {
 fastcgi_pass   127.0.0.1:9000;
 fastcgi_index  index.php;
 # again, change the directory here to your website's root directory
 # make sure to leave $fastcgi_script_name; on the end!
 fastcgi_param  SCRIPT_FILENAME  /home/meltingice_net/public_html$fastcgi_script_name;
 include /etc/nginx/fastcgi_params;
 }
}

Repeat this server block for every subdomain you wish to use, replacing the domain with the subdomain. Don’t bother restarting Nginx at this point in time because it will fail due to the fastcgi_params file missing. That comes next!

Configuring and Running FastCGI

There are many different ways to work with FastCGI, but we’re going to do what should be the easiest. Remember the php5-cgi that we installed earlier? It has a built-in spawning system that will start up our php-cgi instances for us and listen for connections. First though, we need to create a simple file that defines all of the FastCGI params for us. Create the file /etc/nginx/fastcgi_params and paste into it:

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

Now what we need to do is create an init.d script that will make starting and stopping these php-cgi instances much easier. Create the file /etc/init.d/php-fastcgi and open it for editing and copy and paste into it:

#!/bin/bash
RETVAL=0
export PHP_FCGI_MAX_REQUESTS=20
export PHP_FCGI_CH

BIND=127.0.0.1:9000
USER=www-data
PHP_FCGI_CHILDREN=5

PHP_CGI=/usr/bin/php5-cgi
PHP_CGI_NAME=`basename $PHP_CGI`
PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS $PHP_CGI -b $BIND"

case "$1" in
 start)
 echo "Starting PHP FastCGI..."
 start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
 RETVAL=$?
 echo "$PHP_CGI_NAME."
 ;;
 stop)
 killall -9 php5-cgi
 RETVAL=$?
 ;;
 restart)
 killall -9 php5-cgi
 start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS
 RETVAL=$?
 ;;
 *)
 echo "Usage: php-fastcgi {start|stop|restart}"
 exit 1
 ;;
esac
exit $RETVAL

There are a lot of options to configure in this file, but their values depend on the power and size of your server. If you have a small VPS, for instance, you want PHP_FCGI_MAX_REQUESTS and PHP_FCGI_CHILDREN to be small in order to prevent your RAM from filling up and enabling disk swap. Play with these values until you find a sweet spot. The values included in the file above are intended for a small VPS.

Now we can run:

1	chmod +x /etc/init.d/php-fastcgi
2	/etc/init.d/php-fastcgi start
3
4	update-rc.d php-fastcgi defaults

which will start our php-cgi instances. The last command will make sure that the php-cgi instances are started at boot time as well, in case you ever need to reboot the server.

Nginx and PHP Testing

Now that all of the basic pieces are done for setting up a web server, you can check to see if it’s working properly or not. Make sure the root directory for your website that you specified in the Nginx config file is created, and put an index.php file in that directory. Put some simple code in this file for testing… something along the lines of:

1    <? echo "test"; ?>

If you setup your DNS and domain name ahead of time, try visiting your domain. If not, you should be able to go directly to your server’s IP address and see it because Nginx defaults to the last server block that was defined (if I remember correctly).

Additional (Optional) Setup Steps

From here on, all of these steps are optional. All of the steps described here are things that I have installed/used in the past, so I thought I would include them in this guide.

Configuring XCache

Since we have XCache running, lets take a moment to configure it instead of relying on its defaults. We will also setup the XCache admin pages in this section.

Since we will want to password protect the XCache admin pages, we will need to get the md5 hash of your preferred password. You can do it on a site like MD5 Encrypter, or you can run a quick PHP script do to it for you. Either works. Once you get the MD5 hash of your password, hold on to it because we’ll need it for the configuration.

In your php.ini file, which should be located in /etc/php5/cgi/php.ini, check to see if any XCache settings are listed. If not, add this to the end of the file but replace xcache.admin.user and xcache.admin.pass with your desired username and MD5 password hash:

; XCACHE SETTINGS
[xcache-common]
extension = xcache.so
[xcache.admin]
xcache.admin.user = "your_username"
; xcache.admin.pass = md5($your_password)
xcache.admin.pass = "md5 hash of your password"
[xcache]
; ini only settings, all the values here is default unless explained
; select low level shm/allocator scheme implemenation
xcache.shm_scheme =        "mmap"
; to disable: xcache.size=0
; to enable : xcache.size=64M etc (any size > 0) and your system mmap allows
xcache.size  =                48M
; set to cpu count (cat /proc/cpuinfo |grep -c processor)
xcache.count =                 1
; just a hash hints, you can always store count(items) > slots
xcache.slots =                8K
; ttl of the cache item, 0=forever
xcache.ttl   =                 0
; interval of gc scanning expired items, 0=no scan, other values is in seconds
xcache.gc_interval =           0
; same as aboves but for variable cache
xcache.var_size  =            48M
xcache.var_count =             1
xcache.var_slots =            8K
; default ttl
xcache.var_ttl   =             0
xcache.var_maxttl   =          0
xcache.var_gc_interval =     300
xcache.test =                Off
; N/A for /dev/zero
xcache.readonly_protection = Off
; for *nix, xcache.mmap_path is a file path, not directory.
; Use something like "/tmp/xcache" if you want to turn on ReadonlyProtection
; 2 group of php won't share the same /tmp/xcache
; for win32, xcache.mmap_path=anonymous map name, not file path
xcache.mmap_path =    "/dev/zero"

; leave it blank(disabled) or "/tmp/phpcore/"
; make sure it's writable by php (without checking open_basedir)
xcache.coredump_directory =   ""
; per request settings
xcache.cacher =               On
xcache.stat   =               On
xcache.optimizer =            On
[xcache.coverager]
; per request settings
; enable coverage data collecting for xcache.coveragedump_directory and xcache_coverager_start/stop/get/clean() functions (will hurt executing performance)
xcache.coverager =          Off
; ini only settings
; make sure it's readable (care open_basedir) by coverage viewer script
; requires xcache.coverager=On
xcache.coveragedump_directory = ""

This configuration is, again, for a small VPS. If you have a beefier server, increase the cache size.

Now, to enable the admin pages, we need to make a symbolic link. Go to the folder in your web root where you want to host the XCache pages from. Personally, I went to /home/meltingice_net/public_html/ which is my root web directory. Once you’re there, run:

1    ln -s /usr/share/xcache/admin xcache

This will create a symbolic link to the XCache admin files in a folder named “xcache”. Now if you go to the corresponding url, such as http://meltingice.net/xcache, you should be asked for your username and password.

Setting up Memcached

Memcached has been a life safer for me for awhile now. I highly recommend using it if you are running a website that gets a decent amount of traffic, or if you are running WordPress (used in conjunction with W3 Total Cache). Unfortunately, the version in the Lucid Ubuntu repository is very out of date, so we are going to need to compile some code. If you are running Ubuntu 10.10 (Meerkat), you can run:

1    apt-get install memcached

to get the latest stable version. I’m going to cover installation on Lucid for now since Meerkat just came out and Lucid is a long-term release.

First, we need to download, compile and install libevent. At the time of this writing, the latest stable release is 1.4.14b, but I would check the website and make sure you get the latest version. Libevent shouldn’t have any more dependencies, so lets go ahead and make this happen:

# wget http://monkey.org/~provos/libevent-1.4.14b-stable.tar.gz
# tar xvf libevent-1.4.14b-stable.tar.gz
# cd libevent-1.4.14b-stable
# ./configure
# make
# make install

Now that libevent is installed, we can do the same for Memcached. Again, make sure you grab the latest version from the website.

# wget http://memcached.googlecode.com/files/memcached-1.4.5.tar.gz
# tar xvf memcached-1.4.5.tar.gz
# cd memcached-1.4.5
# ./configure --with-libevent=/usr/local/lib
# make
# make install

This will compile and install Memcached in /usr/local/bin by default. Unfortunately, you will probably run into this problem when you try to run Memcached:

memcached: error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory

Luckily, the fix is simple although it is not obvious at first and is not trivial unless you really know what you’re doing. First, we need to create /etc/ld.so.conf.d/libevent-i386.conf then open it for editing and paste into it:

1    /usr/local/lib/

Now run:

1    ldconfig

And that should fix it! We had to do this because, when libevent was installed, it didn’t register itself with Linux, so we had to do it manually. Now, to start Memcached as a daemon with a maximum of 128MB of RAM, we run:

1    memcached -u nobody -d -m 128 -l localhost -p 11211

To check to make sure its running, you can run:

1    ps aux | grep memcached

and you should see Memcached listed with the command-line arguments you specified when starting it.

Installing Redis

Ubuntu also did a great job of updating Redis for 10.10 (Meerkat), but if your ubuntu machine use version in the Lucid repository is very out of date. If you are running Meerkat, simply do:

1    apt-get install redis-server

If you are running Lucid, then you will need to compile Redis to get the latest version. Luckily, its very easy to compile (notice there is no configure step):

1	wget http://redis.googlecode.com/files/redis-2.0.2.tar.gz
2	tar xvf redis-2.0.2.tar.gz
3	cd redis-2.0.2
4	make
5	cp redis-server /usr/local/bin/
6	cp redis-cli /usr/local/bin/
7	cp redis.conf /etc/

This will compile Redis and move it into a directory that is in our PATH so that we can run it easily. To make life even easier, lets create an init.d script to start and stop it. Create the file /etc/init.d/redis-server and open it for editing:

01	#!/bin/bash
02	REDIS_SERVER=/usr/local/bin/redis-server
03	RETVAL=0
04
05	case "$1" in
06	    start)
07	      echo "Starting Redis Server..."
08	      $REDIS_SERVER /etc/redis.conf
09	      RETVAL=$?
10	  ;;
11	    stop)
12	      killall -9 redis-server
13	      RETVAL=$?
14	  ;;
15	    restart)
16	      killall -9 redis-server
17	      $REDIS_SERVER /etc/redis.conf
18	      RETVAL=$?
19	  ;;
20	    *)
21	      echo "Usage: redis-server {start|stop|restart}"
22	      exit 1
23	  ;;
24	esac
25	exit $RETVAL

Now, in order to force Redis to daemonize instead of opening in the foreground and stealing the Terminal, we need to change one small thing in /etc/redis.conf. Look for “daemonize no” and change it to:

1    daemonize yes

Now you should have a fully working Redis server! Feel free to read through the redis.conf file and tweak more settings as you see fit. It’s pretty well documented.

More Guides?

Lets face it, this blog post is pretty massive so far. I may even consider turning this into its own static page its become so big. If you have any more suggestions for guides I should add, or if you notice a mistake in any of my guides, please let me know! I appreciate all feedback!

 

About Azam

Azam is a professional blogger, SEO and a web developer. He loves to play with free and open source software and works with it as a part of his hobby. Don't forget to FOLLOW me on my twitter or add My Google+ to your circle. "Please leave your comment, vote my site, rate post, or share it. Like our Facebook page to get the most recent updates.

Check Also

Network Solutions Review, Easily Create an Online Store Using nsCommerceSpace™

Currently, developing your business especially in selling stuffs through online (e-commerce solution) is one way …

Leave a Reply

Your email address will not be published. Required fields are marked *

*