phpinfo()

Here’s the next part of my basic web server administration tutorial.

At the first part, we set up the virtual machine. Now we’ll be setting up the web server itself.

Set Static IP Address and fake Domain Name

Before we could proceed with installing our web server, let’s do a couple of things to make our server behave more like a “normal” server.

First is to set our server’s IP address to a static IP address. There are a bunch of ways to do this (e.g. change the router settings), but we’ll just go with changing our server’s settings

Running ifconfig and route will give us the current IP address and gateway.

ifconfig and route

In this case, the new IP address is 192.168.1.125 and the gateway is 192.168.1.5. We can now apply these settings to /etc/network/interfaces. Open the said file via:

$ sudo vim /etc/network/interfaces

(For this tutorial, I’ll be using vim as the default text editor. If you find vim too daunting, you can replace all instances of vim with nano)

It will look something like:

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0
iface eth0 inet dhcp

Now replace the last line with the following:

iface eth0 inet static
address [address here]
netmask 255.255.255.0
gateway [gateway here]

for example:

iface eth0 inet static
address 192.168.1.125
netmask 255.255.255.0
gateway 192.168.1.5

To make sure you got the static IP settings correctly, you can restart the server via

$ sudo shutdown -r now

or you could just simply restart the network interface:

$ sudo /etc/init.d/networking restart

Here we see the /etc/init.d folder where the init scripts (like networking) are placed. Aside from being executed automatically upon boot to start services, they can also be used to stop or restart the said services just like what we just did with networking. We will see more of /etc/init.d/ later in this tutorial.

Now that we’ve set the IP address as static, it’s time to set a fake domain name.

Normally, when you’ve got a server with a static IP address, you’d have to go and buy a domain name from a registrar like Namecheap and you’d go through the steps in linking that name with the IP address and waiting for the DNS propagation.

For this tutorial, we’re going to skip all that by faking it with the hosts file.

First let’s update the server’s /etc/hosts file to add our fake domain name “mysite.dev”:

sudo vim /etc/hosts

Add the line at the end:

192.168.1.125   mysite.dev

You can verify the new setting by using the ping command.

user@ubuntu:~$ ping -c 4 mysite.dev
PING mysite.dev (192.168.1.125) 56(84) bytes of data.
64 bytes from mysite.dev (192.168.1.125): icmp_seq=1 ttl=64 time=0.172 ms
64 bytes from mysite.dev (192.168.1.125): icmp_seq=2 ttl=64 time=2.38 ms
64 bytes from mysite.dev (192.168.1.125): icmp_seq=3 ttl=64 time=3.34 ms
64 bytes from mysite.dev (192.168.1.125): icmp_seq=4 ttl=64 time=1.59 ms

--- mysite.dev ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3016ms
rtt min/avg/max/mdev = 0.172/1.874/3.342/1.161 ms
user@ubuntu:~$

Now let’s apply the fake domain name mapping to the host Windows computer. Like in Linux, the hosts file in Windows requires admin privileges so we first need to run the text editor as Administrator in order to allow us to modify it.

Run as administrator

Right-click Notepad and select “Run as administrator”. Once open, you can now add the “192.168.1.125 mysite.dev” to the end of the C:\Windows\System32\drivers\etc\hosts file.

Now you could change the PuTTy settings to use “mysite.dev” instead of the actual IP address.

The actual installation of the web server below the cut.

Installing Nginx

It’s finally time to install the web server.

We won’t be using Apache, though. Instead, we’re going to go with its leaner and faster Russian counterpart nginx. We’re also going to build it from scratch (as opposed to getting it from a repository) to show you how its done in Linux machines.

Installing dependencies

We’ll need to install a few things before we could proceed with building nginx.

$ sudo apt-get install build-essential libssl-dev libpcre3-dev

build-essential contains the essential tools for compiling programs from source while the other two are libraries that nginx needs during compilation.

Building from source

~$ wget http://nginx.org/download/nginx-1.0.11.tar.gz

Using wget we download the latest stable source as of this writing. Yes, it’s a whopping 700 KB.

~$ tar zxvf nginx-1.0.11.tar.gz

We then unpack it using tar.

~$ cd nginx-1.0.11

~/nginx-1.0.11$ ./configure --sbin-path=/usr/local/sbin --with-http_ssl_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module

~/nginx-1.0.11$ make

~/nginx-1.0.11$ sudo make install

Now we finally perform the build/installation. This three-step configure-build-install scheme is pretty much how one builds any program in Linux from scratch.

This nginx build doesn’t come with an init script so we’ll have to download one off the net.

~/nginx-1.0.11$ cd ~

~$ wget https://raw.github.com/JasonGiedymin/nginx-init-ubuntu/master/nginx

~$ sudo mv nginx /etc/init.d/nginx

We still need to set a couple of things with the script:

$ sudo chmod +x /etc/init.d/nginx

$ sudo chown root:root /etc/init.d/nginx

The first command sets the script to executable and the other command gives the ownership of the script to root. Now we can run nginx:

$ sudo /etc/init.d/nginx start

You can now open http://mysite.dev to check if it’s installed properly.

nginx

Using Firebug or Chrome Developer tools will confirm the server’s really nginx 1.0.11.

nginx response headers

Tweaking nginx

Before we proceed with installing PHP, let’s apply some tweaks to nginx to make it more Apache-ish (lol) and then some.

$ sudo ln -s /usr/local/nginx/conf /etc/nginx

This creates a symbolic link in the /etc folder to match with the convention for configuration files.

$ sudo vim /etc/nginx/nginx.conf

Now we edit the configuration file like so:

user  www-data;
worker_processes  1;

pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    gzip on;
    gzip_buffers 16 8k;
    gzip_disable "MSIE [1-6]\.";
    gzip_proxied any;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    error_log  /var/log/nginx/error.log  debug;

    sendfile        on;
    keepalive_timeout  3;
    index              index.html index.htm;

    server {
        listen       80;
        server_name *.mysite.dev;
        root /var/www;

        if ($http_host != "mysite.dev") {
                rewrite ^ http://mysite.dev$request_uri permanent;
        }

        # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
        location ~ /\. {
                deny all;
                access_log off;
                log_not_found off;
        }

    }

}

A quick summary of the changes:

  • We changed the server’s user from “nobody” to the system user “www-data”, the default user for web servers.
  • We set the file where the PID for the server would be located. This will allow our init script to stop or restart the server.
  • We enabled gzip for supported browsers to dramatically reduce the bandwidth usage.
  • We set the log to match Apache’s format.
  • We defined a handler for the *.mysite.dev domain, defining its root to be the same as Apache’s (/var/www)

Now to wrap things up:

$ sudo cp -r /usr/local/nginx/html /var/www

$ sudo chown -R www-data:www-data /var/www

We copy the html folder to /var/www and give it to www-data.

$ sudo mkdir /var/log/nginx

Just creating the log folder.

$ sudo /etc/init.d/nginx destroy

$ sudo /etc/init.d/nginx start

We force stop the server (as we haven’t defined the PID file when we started it) then start it normally.

Opening http://mysite.dev now shows us that the site is served as gzipped.

nginx response headers

Installing PHP-FPM

Unlike nginx, we won’t be building PHP from scratch. We will, however, not go with Apache’s mod_php/extension route and instead go the PHP-FPM route which, like nginx, is much leaner than the former.

Since PHP-FPM isn’t available in the official apt repositories of Ubuntu 10.04, we will have to use another repository. Nginx’s repositories may be a bit out of date (PHP v5.3.5 vs the current v5.3.8) but it should be enough for this tutorial.

$ sudo apt-get install python-software-properties

$ sudo add-apt-repository ppa:nginx/php5

$ sudo apt-get update

$ sudo apt-get install php5-fpm

The steps above will install PHP-FPM with fairly decent defaults. If you want to change some settings, you can modify the files at /etc/php5/fpm/ and restart the server via “sudo /etc/init.d/php-fpm restart“.

Now all we need to do is to tell nginx how to use PHP-FPM. Here’s our modified /etc/nginx/nginx.conf:

user  www-data;
worker_processes  1;

pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    gzip on;
    gzip_buffers 16 8k;
    gzip_disable "MSIE [1-6]\.";
    gzip_proxied any;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    error_log  /var/log/nginx/error.log  debug;

    sendfile        on;
    keepalive_timeout  3;
    index              index.php index.html index.htm;

    upstream php {
        server 127.0.0.1:9000;
    }

    server {
        listen       80;
        server_name *.mysite.dev;
        root /var/www;

        if ($http_host != "mysite.dev") {
                rewrite ^ http://mysite.dev$request_uri permanent;
        }

        # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
        location ~ /\. {
                deny all;
                access_log off;
                log_not_found off;
        }

        location ~ \.php$ {
                include fastcgi_params;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_pass php;
        }
    }
}

The main changes between the original are:

  • Adding “index.php” before “index.html index.htm” to let the server prioritize the former over the latter.
  • The addition of the upstream php block that points to PHP-FPM.
  • The addition of the location handler for PHP files.

We also need to modify /etc/nginx/fastcgi_params, adding the following lines at the end of the file:

fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

Once done we can now restart the server via sudo /etc/init.d/nginx restart.

To test PHP, create the phpinfo() index.php file:

$ sudo sh -c 'echo "<? phpinfo();" > /var/www/index.php'

Then open http://mysite.dev again:

phpinfo()

You have now installed nginx and PHP on your web server.

Benchmarking

You can use ApacheBench to see how well your site performs under load.

$ sudo apt-get install apache2-utils

Here’s 1000 requests with 100 concurrent users (10 requests each user) to our static HTML file:

user@ubuntu:~$ ab -n 1000 -c 100 http://mysite.dev/index.html
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking mysite.dev (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        nginx/1.0.11
Server Hostname:        mysite.dev
Server Port:            80

Document Path:          /index.html
Document Length:        151 bytes

Concurrency Level:      100
Time taken for tests:   1.720 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      378290 bytes
HTML transferred:       157795 bytes
Requests per second:    581.31 [#/sec] (mean)
Time per request:       172.025 [ms] (mean)
Time per request:       1.720 [ms] (mean, across all concurrent requests)
Transfer rate:          214.75 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       27   79  15.7     84     102
Processing:    39   83  16.5     86     131
Waiting:       10   61  17.5     65      98
Total:        129  161  16.5    172     184

Percentage of the requests served within a certain time (ms)
  50%    172
  66%    173
  75%    173
  80%    173
  90%    178
  95%    182
  98%    183
  99%    183
 100%    184 (longest request)

Here’s the same test against our phpinfo() page:

user@ubuntu:~$ ab -n 1000 -c 100 http://mysite.dev/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking mysite.dev (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        nginx/1.0.11
Server Hostname:        mysite.dev
Server Port:            80

Document Path:          /
Document Length:        42481 bytes

Concurrency Level:      100
Time taken for tests:   8.582 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      42649000 bytes
HTML transferred:       42481000 bytes
Requests per second:    116.52 [#/sec] (mean)
Time per request:       858.186 [ms] (mean)
Time per request:       8.582 [ms] (mean, across all concurrent requests)
Transfer rate:          4853.19 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    6  16.6      0      63
Processing:    66  810 126.3    861     875
Waiting:       59  808 127.0    858     873
Total:        125  816 113.2    861     875

Percentage of the requests served within a certain time (ms)
  50%    861
  66%    862
  75%    863
  80%    864
  90%    869
  95%    874
  98%    874
  99%    875
 100%    875 (longest request)

581 and 116 requests per second? Not bad for a “low end” server.

Proceed to part 3: Installing MySQL and WordPress

Tagged with →  
Share →

2 Responses to Learn how to setup a web server pt2: Installing Nginx and PHP

  1. […] Here’s a quick update to this mini-tutorial. Previous parts can be found here and here. […]

Leave a Reply

Google+