Tutorial

How To Migrate from an Apache Web Server to Nginx on an Ubuntu VPS

Published on December 17, 2013
How To Migrate from an Apache Web Server to Nginx on an Ubuntu VPS

Introduction


There are a number of choices you have to make when getting a website or application up and running. Sometimes, your requirements change, new technology becomes viable, or your user-base balloons unexpectedly. Regardless of your reasons, one of the components of your application stack that you might consider changing is the web server.

Although the Apache web server is currently the most popular web server in the world, Nginx is gaining ground at a rapid rate. This is unsurprising, considering that Nginx performs excellent while using few resources. For many websites, a migration to Nginx would improve performance.

In this guide, we will discuss how to migrate a website from Apache to Nginx on an Ubuntu 12.04 VPS. We will attempt to remain general in our suggestions, but will give you hints on some areas that you might need to tweak for your own purposes.

This guide assumes that you have installed a LAMP (Linux, Apache, MySQL, and PHP) stack using this tutorial. If you simply selected the one-click LAMP image when creating your droplet, your server will have this configuration as well.

Install Nginx


The first thing that we will do to begin migrating our websites is to install our new server software. This will allow us to configure our new server by looking at our current Apache configuration files for guidance.

Luckily, Nginx is present in the Ubuntu repositories by default. Let’s install it now:

sudo apt-get update
sudo apt-get install nginx

One implementation detail that becomes very important in our use-case is that Nginx offloads any dynamic handling to a separate process. This allows Nginx to remain lean and fast. It can focus on its core functionality without having to try to add PHP support through modules. Instead, it just offloads that to an application that is built for that purpose.

This is all being mentioned at this point to say that we also need to install a PHP handler in order to process PHP scripts. The standard choice is php5-fpm, which performs well with Nginx:

sudo apt-get install php5-fpm

You should have all of the software you need to change your site over to Nginx. We still need to configure our software to emulate the configuration that Apache was running under.

Set Up Test Nginx Configuration


Since we have Apache running currently, if we can avoid it, we would like to configure our Nginx server independently of Apache so that our site will still be operational during the transition.

This is as simple as testing Nginx on an alternative port until we are ready to solidify our changes. This way, we can run the two servers concurrently.

Begin by opening the configuration file for the default Nginx site:

sudo nano /etc/nginx/sites-available/default

In the server { section, add a listen directive to tell Nginx to listen on a port other than port 80 (which Apache is still using to serve requests). For our tutorial, we’ll use port 8000.

server {

    listen 8000;
    . . .
    . . .

Save and close the file. This is a good time to do a spot check to see that we can access our Nginx server. Start Nginx to test this:

sudo service nginx start

Use the port number we configured to access the default Nginx configuration. Type this into your browser:

http://your_ip_or_domain:8000

DigitalOcean Nginx default page

Your Apache instance should still be running on the default port 80. You can check this as well by visiting your site without the :8000 at the end (our example is just serving the default Apache page. If you had configured your website, that would be here instead):

http://your_ip_or_domain

DigitalOcean Apache default page

Translate Your Apache Configuration


Now that you have both servers up and running, you can begin migrating and translating your Apache configuration for use with Nginx. This must be done manually, so it is important that you understand how Nginx is configured.

This task will mainly come down to writing Nginx server blocks, which are analogous to Apache virtual servers. Apache keeps these files in /etc/apache2/sites-available/ and Nginx follow suit and keeps its server block declarations in /etc/nginx/sites-available/ on Ubuntu.

For each virtual server declaration, you’ll be creating a server block. If you go through your Apache files, you will probably find virtual hosts that look like this:

<VirtualHost *:80>
    ServerAdmin webmaster@your_site.com
    ServerName your_site.com
    ServerAlias www.your_site.com

    DocumentRoot /var/www

    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>

    <Directory /var/www/>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        allow from all
    </Directory>

    ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
    <Directory "/usr/lib/cgi-bin">
        AllowOverride None
        Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
        Order allow,deny
        Allow from all
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>
</VirtualHost>

We can begin to build our Nginx server block using this configuration.

In your /etc/nginx/sites-available/ directory, open the file we edited before to declare the Nginx port:

sudo nano /etc/nginx/sites-available/default

Disregarding the commented lines for the moment, it should look something like this:

server {
    listen 8000;

    root /usr/share/nginx/www;
    index index.html index.htm;

    server_name localhost;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /doc/ {
        alias /usr/share/doc/;
        autoindex on;
        allow 127.0.0.1;
        deny all;
    }
}

You should already begin to see some of the items that seem to correspond to our Apache configuration. Generally speaking, the main directives translate like this:

Apache                                 Nginx
------                                 ------

<VirtualHost *:80>                     server {
                                            listen 80;

ServerName yoursite.com
ServerAlias www.yoursite.com           server_name yoursite.com www.yoursite.com;

DocumentRoot /path/to/root             root /path/to/root;

AllowOverride All                      (No Available Alternative)

DirectoryIndex index.php               index index.php;

ErrorLog /path/to/log                  error_log /path/to/log error;

CustomLog /path/to/log combined        access_log /path/to/log main;

Alias /url/ "/path/to/files"           location /url/ {
<Directory "/path/to/files">                 alias /path/to/files;

If we were going to create a server block that emulates the functionality of the virtual host file from above, it might look something like this:

server {
    listen 8000;   # We're deliberately leaving this as-is to avoid conflict at the moment

    root /var/www;
    server_name your_site.com www.your_site.com;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location /doc/ {
        alias /usr/share/doc/;
        autoindex on;
        allow 127.0.0.1;
        deny all;
    }

    location ~/\.ht {
        deny all;
    }

}

We have eliminated some items and also added a few extra lines that we should explain.

Firstly, the error log lines have been eliminated from the configuration. This is because they are already defined in the /etc/nginx/nginx.conf file. This provides us with a default that we will use.

We have also eliminated the ServerAdmin directive because Nginx does not embed that information in its error pages.

The PHP handling has changed a bit as well. Due to the fact that PHP is handled separately in Nginx, we pass these files off to the php-fpm program we installed earlier. This is implemented through a socket (which we will need to configure momentarily).

The documentation section is changed to reflect the Nginx documentation. It otherwise functions fairly similarly.

Lastly, we configure Nginx to deny access to any .htaccess or other files that begin with .ht in our directory. These are Apache-specific configuration files, and they do not work with Nginx. It is safer to not expose these configuration files.

Save and close the file when you are finished.

We must restart our Nginx server for these changes to be recognized:

sudo service nginx restart

Configure PHP-FPM


Now that we have most of the Nginx configuration out of the way, we need to modify the php-fpm configuration to communicate using the channels we specified.

To begin with, we should modify the php.ini file so that it doesn’t serve files insecurely.

sudo nano /etc/php5/fpm/php.ini

The line that we need to modify will require PHP to serve the exact file requested instead of guessing if there is an incomplete match. This prevents PHP from possibly serving or exposing sensitive data to someone who is probing the PHP handler for weaknesses.

Find the line that specifies the cgi.fix_pathinfo directive and modify it so that it looks like:

cgi.fix_pathinfo=0

Save and exit out of this file.

Next, we will change the way that php-fpm connects to our server. Open this file in your editor:

sudo nano /etc/php5/fpm/pool.d/www.conf

Find and modify the listen directive to match the value that we put in the server block configuration file:

listen = /var/run/php5-fpm.sock

If you end up running into problems with handling a lot of PHP requests, you might want to come back here and increase the number of child processes that can be spawned at once. The line you want to change is:

pm.max_children = Num_of_children

Save and close this file.

Now, our php-fpm program should be configured correctly. We need to restart it for our changes to propagate.

sudo service php5-fpm restart

It won’t hurt to restart Nginx again as well:

sudo service nginx restart

Test that any PHP files that you have in your root directory function correctly. You should be able to get PHP files to execute just as they were in Apache.

If we access the info.php file that we created in the Ubuntu LAMP tutorial, it should render like this:

http://your_ip_or_domain:8000/info.php

DigitalOcean Nginx PHP files

In the PHP Variables section, you should see Nginx listed as the “SERVER_SOFTWARE” variable:

DigitalOcean Nginx server software

Transition Your Nginx Site Live


After you have done extensive testing, you can try to seamlessly transition your site from Apache to Nginx.

This is possible due to the fact that neither of these servers implement changes until they are restarted. This allows us to set everything up, and then flip the switch in one instant.

Really, the only thing we need to do is modify the port in the Nginx server block. Open the file now:

sudo nano /etc/nginx/sites-available/default

Change the port back to the default port 80. This will allow it to start accepting regular HTTP traffic as soon as it is restarted.

server {
    # listen 8000;
    listen 80;
    . . .

Save and close the file.

If you are only transitioning some of your sites to Nginx and continuing to serve some content from Apache, you need to disable the Apache virtual servers that serve requests on port 80. This is necessary to avoid conflicts. If this is not done correctly, Nginx will fail to start because the port will already be taken.

If you’re planning on continuing to run Apache, check these files and locations for port 80 usage:

/etc/apache2/ports.conf
/etc/apache2/apache2.conf
/etc/apache2/httpd.conf
/etc/apache2/sites-enabled/  ## Search all sites in this directory

After you are satisfied that you have changed all of the necessary ports, you can restart both services like this:

sudo service apache2 reload && sudo service nginx reload

Apache should reload, releasing port 80. Immediately afterward, Nginx should reload and start accepting connections on that port. If all went smoothly, your site should now be served by Nginx.

If you are not going to be using Apache anymore to serve any portion of your sites, you can completely stop its web process instead:

sudo service apache2 stop && sudo service nginx reload

If you are not using Apache anymore, you can uninstall the Apache files at this point. You can easily find the Apache-related files by typing:

dpkg --get-selections | grep apache

apache2						    install
apache2-mpm-prefork				install
apache2-utils					install
apache2.2-bin					install
apache2.2-common				install
libapache2-mod-auth-mysql		install
libapache2-mod-php5				install

You can then uninstall them with apt-get. For example:

sudo apt-get remove apache2 apache2-mpm-prefork apache2-utils apache2.2-bin apache2.2-common libapache2-mod-auth-mysql libapache2-mod-php5

You can also remove all of the dependency packages that are no longer needed:

sudo apt-get autoremove

Migration Complications


There are a few things that are common in the Apache world that may cause you some confusion when trying to switch to Nginx.

Rewrite Translations and .htaccess Files


One of the most fundamental differences is that Nginx does not respect directory overrides.

Apache uses .htaccess files, together with an AllowOverride All directive in a location block. This allows you to put directory-specific configurations in the directory that houses the files.

Nginx does not allow these files. Housing the configuration with the files being served is potentially a security problem if misconfigured, and it is easy to look at the centralized configuration files and not realize that a setting is being overwritten through an .htaccess file.

As a result, all configuration that you have listed in an active .htaccess file must be placed within the location block in the server block configuration for that host. This is not generally any more complicated, but you must translate these rules just as you did with the virtual host definitions.

A common thing to keep in .htaccess files are rules for Apache’s mod_rewrite module, which alters the access URLs of content to be more user-friendly. Nginx has a rewrite module that is similar, but uses different syntax. Unfortunately, rewriting URLs in Nginx is outside of the scope of this guide.

Module and Outside Configuration Complications


Another thing to keep in mind is that you need to be conscious of what functionality the Apache modules that you have enabled are providing.

A simple example is the dir module. When enabled, you can specify the order of the files that Apache will attempt to serve as a directory index by placing a line like this in your virtual host file:

DirectoryIndex index.html index.htm

This line will determine the handling that will happen for this virtual host. However, if this line is not present, and the dir module is enabled, the order of files being served will be determined by this file:

sudo nano /etc/apache2/mods-enabled/dir.conf

<IfModule mod_dir.c>

          DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm

</IfModule>

The point of bringing this up is that you have to be aware of the possibility that a module, or an externally sourced configuration of any kind, for that matter, might be doing something behind-the-scenes that you will have to do explicitly in Nginx.

In this example, you can specify the directory index order in Nginx by adding this to a server block:

server {
    . . .
    index index.php index.html index.htm;
    . . .

It is important to keep this in mind.

One thing that might be helpful if you are transitioning a complex site configuration is to copy and paste all of the separately sourced configuration files into one monolithic file and systematically go through and translate each line.

This might be a headache, but for a production server, it could save you a lot of time tracking down what is causing strange behavior that you cannot quite pin down.

Conclusion


The complexity of transitioning from Apache to Nginx is almost completely dependent on the complexity of your specific configurations. Nginx can handle pretty much anything that Apache can, with the benefit of doing so with less resources. This means that your site can smoothly serve a larger pool of users.

While migrating does not make sense for all sites, and while Apache is a wonderful server that adequately serves the needs of many projects, you may see performance gains or increases in scalability with Nginx. If you still require Apache, another alternative is using Nginx as a reverse-proxy for your Apache server. This approach can leverage the strengths of both servers in a powerful way.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
10 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Hi mwsmedia,

I´ve had the same problem… in my case was the firewall that was blocking…

try:

sudo iptables -I INPUT 1 -p tcp --dport 8000 -j ACCEPT

I had trouble with 502 bad gateway errors when enabling PHP. I found that the issue was that root owned the socket which was created, so the webserver couldn’t access it. The following worked for me:

sudo chown www-data:www-data /var/run/php5-fpm.sock

I know this guide is for ubuntu, however if you are on debian note that configuring nginx will fail if the Apache service is running when you install nginx because it can’t bind to port 80.

:/ got stuck with it can’t even look at nginx command anymore. It looks like there’s something missing in this tutorial … I’ve gone through 403, 502, blank and not available pages and some really slow 400sec. loading pages. I have two websites on one IP. I couldn’t get that 8000 port working tried it all and even stoped Apache on live sites … This is the first tutorial Im really dissapointed with, Digital Ocean … I have serched internet for other nginx tutorials and all of them are different from each other … Got really confused now I only hope this will be worth a while

For query strings ``` location / { try_files $uri $uri/ /index.php?$query_string; }

“Unfortunately, rewriting URLs in Nginx is outside of the scope of this guide.” - A simple converter is available: http://winginx.com/en/htaccess and might be worth providing a link to, for further research.

I figured it out:

1: Open /etc/php5/fpm/pool.d/www.conf

2: Uncomment all permission lines, like:

listen.owner = www-data listen.group = www-data listen.mode = 0660

3:Restart fpm - sudo service php5-fpm restart

Then it all worked fine afterwards!

Now I’m trying to make phpmyadmin work, it was working with apache. Any pointers will be appreciated

Hi,

I do everything but at the end of the day I get a 403 error, and looking at the error log, it says [ directory index of “directory path” is forbidden]

Kindly assist on what I may be doing wrong here

Kamal Nasser
DigitalOcean Employee
DigitalOcean Employee badge
May 12, 2014

@jmmountz: Try stopping Apache first: <pre>sudo service apache2 stop</pre>Then start nginx: <pre>sudo service nginx start</pre>You can stop Apache from starting on startup by running: <pre>sudo update-rc.d apache2 remove</pre>

Got stuck trying to get the default page to come up.

Going here: sudo nano /etc/nginx/sites-available/default

And making it look like this:

server {

listen 8000;

}

Doesn’t seem to register. Nginx still listens on 80 and says it fails (98:Address already in use).

Am I typing something wrong?

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel