Using Nginx and Apache together on Ubuntu

I am beginning a new project that uses MEAN.JS (MongoDB, ExpressJS, AngularJS, Node.js). I use Apache as my webserver on my local Ubuntu VM. When I first read about using Express, I wondered how I would use Express and Apache together. Further confusion came when I learned that my host provider (webfaction uses Nginx to serve static files and Apache for PHP and other server-side technologies. So Node.js and Express will actually be running under Nginx. Because I wanted my development environment to be enulate production as much as possible, I decided to run Nginx and Apache together.

Install Apache

To install Apache, open a terminal and enter:

sudo apt-get install apache2

Note: For more details about setting up a LAMP stack, read my post: Setting up Ubuntu for Web Development.

Install Nginx

Next, I installed Nginx

sudo apt-get install nginx

Serving Static Files

Nginx serves static files much faster than Apache. One of my local domains is only used to serve static files for Django Apps (/etc/apache2/sites-enabled/media). The following is the Apache Virtual Host configuration:

<VirtualHost *:80> 
 
    ServerName media.staticfiles 
    DocumentRoot /srv/www/media 
 
    <Directory /srv/www/media> 
        Options Indexes FollowSymLinks MultiViews 
        AllowOverride All 
    </Directory> 
 
</VirtualHost>

I’m going to remove this virtual host from Apache and re-create it as a Nginx virtual host.

sudo rm /etc/apache2/sites-enabled/media
sudo vi /etc/nginx/sites-available/media
server { 
        root /srv/www/media; 
        index index.html index.htm; 
        server_name media.staticfiles; 
 
        location / { 
                try_files $uri $uri/ /index.html; 
        } 
}

Note: I could place all server configurations in a single file, but I decided to place each virtual host configuration in it’s own file (just as I did with Apache).

Next, I moved the Nginx virtual host to sites-enabled.

sudo ln -s /etc/nginx/sites-available/media /etc/nginx/sites-enabled/media

I then restarted Apache and Nginx:

sudo service apache2 restart
sudo service nginx restart

Changing Apache’s Port

Currently, Apache is listening on port 80. I want to change the port for all Apache’s virtual hosts to 8080. All of my Apache virtual hosts configurations are in separate files, so I open each file and change the port. The example below is for my local copy of DevoutGeek.com.

<VirtualHost *:8080> 
        ServerAdmin webmaster@localhost 
        ServerName devoutgeek.local 
 
        DocumentRoot /srv/www/devoutgeek 
 
        <Directory /srv/www/devoutgeek> 
                Options Indexes FollowSymLinks MultiViews 
                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}/devoutgeek-error.log 
 
        LogLevel warn 
 
        CustomLog ${APACHE_LOG_DIR}/devoutgeek-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> 
 
The only change was:
<VirtualHost *:80>
was changed to
<VirtualHost *:8080> 
 
I then restarted Apache
 
<pre lang="Bash">
sudo service apache2 restart

PHP

Next, I had to create a Nginx virtual host for each Apache virtual host for each PHP-based domain.

sudo vi /etc/nginx/sites-available/devoutgeek
 
server { 
 
        root /srv/www/devoutgeek; 
        index index.php index.html index.htm; 
 
        server_name devoutgeek.local; 
 
        location / { 
                try_files $uri $uri/ /index.php; 
        } 
 
         location ~* \.php$ { 
                proxy_set_header X-Real-IP  $remote_addr; 
                proxy_set_header X-Forwarded-For $remote_addr; 
                proxy_set_header Host $host; 
                proxy_pass http://127.0.0.1:8080; 
         } 
}

Nginx listens on Port 80. DevoutGeek is a Magento site (PHP-based). I could use Fastcgi, but Apache serves PHP better, so I use the proxy_pass directive to pass anything with a PHP extension on to Apache (port 8080).

I then created a sym link of devoutgeek to the sites-enabled folder and restarted nginx:

sudo ln -s /etc/sites-available/devoutgeek /etc/sites-enabled/devoutgeek
sudo service nginx restart

Note: Because these sites already exist on my local VM, I already have the relevant configurations in my hosts file (/etc/hosts):

127.0.0.1       devoutgeek.local

I opened my browser and navigated to my local DevoutGeek domain.

http://devoutgeek.local

The home page displayed, but when I navigated to any other page, only the home page displayed. After hours of research, I found that the Nginx configuration that I used does not account for Apache’s mod_rewrite that enabled my to create “Pretty” URLs. Also, Magento’s .htaccess file was not being read. So I had to change the Nginx’s virtual host configuration:

server {
 
        root /srv/www/devoutgeek;
        index index.php index.html index.htm;
 
        server_name devoutgeek.local;
 
        location / {
 
             proxy_set_header X-Real-IP  $remote_addr;
             proxy_set_header X-Forwarded-For $remote_addr;
             proxy_set_header Host $host;
             proxy_pass http://127.0.0.1:8080;
 
        }
 
        location ~* ^.+\.(jpg|jpeg|gif|png|css|zip|pdf|txt|js|flv|swf)$
        {
            # this will basically match any file of the above extensions
            # course if the file does not exist you'll see an Nginx error page as opposed
            # to apache's own error page.
        }
}

This configuration passes everything to Apache except static files. After restarting Nginx, I navigated back to my site and I was able to view all pages.

WordPress

The Nginx virtual host configuration for WordPress was similar to Magento. But when I viewed the site in Firefox, I received the error:

Firefox has detected that the server is redirecting the request for this address in a way that will never complete

I received a similar error in Chrome:

This webpage has a redirect loop

After a few minutes of googling, I found that I had disable the redirect_canonical plugin in Wordpres (WordPress Support Forum).

I opened the functions.php file for my selected theme and added this to the top of the file:

remove_filter('template_redirect', 'redirect_canonical');

After that, my WordPress site displayed correctly.

phpMyAdmin

phpMyAdmin is a browser based gui tool for MySql. After installing phpMyAdmin on Ubuntu, it runs on Apache without having to create a virtual host file. But I found that in order to do a proxy_pass from Nginx to Apache, I had to create a Nginx virtual host.

sudo vi /etc/nginx/sites-available/phpmyadmin
 
server {
 
        root /usr/share/phpmyadmin;
        index index.php;
 
        server_name phpadmin.local;
 
 
        location / {
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8080;
         }
 
        location ~* ^.+\.(jpg|jpeg|gif|png|css|zip|pdf|txt|js|flv|swf)$
      {
            # this will basically match any file of the above extensions
            # course if the file does not exist you'll see an Nginx error page as opposed
            # to apache's own error page.
      }
 
}
sudo ln -s /etc/sites-available/phpmyadmin /etc/sites-enabled/phpmyadmin
sudo service nginx restart

I also had to create an entry in the hosts file (/etc/host):

127.0.0.1       phpadmin.local

Now, instead of the normal url:

http://localhost/phpmyadmin

I access phpmyadmin from:

http://phpadmin.local/phpmyadmin/

Django

I also have a couple of Django sites on my Ubuntu VM. Again, I want Nginx to pass these sites onto Apache.

server { 
 
        root /srv/www/mobilepebbles/mobilepebbles; 
        index index.py index.html index.htm; 
 
        server_name mobilepebbles.local; 
 
        location / { 
 
                 proxy_set_header X-Real-IP  $remote_addr; 
                 proxy_set_header X-Forwarded-For $remote_addr; 
                 proxy_set_header Host $host; 
                 proxy_pass http://127.0.0.1:8080; 
 
        } 
}

Just as I did with Magento and WordPress, I want everything passed to Apache. I could have Nginx serve Django, but since I already have wsgi set up with Apache (See my post: Setting up Django with Apache and mod_wsgi on Ubuntu 11.10), I decided to keep it on Apache.

I then enabled the site and restarted Nginx:

sudo ln -s /etc/nginx/sites-available/mobilepebbles /etc/nginx/sites-enabled/mobilepebbles
sudo service nginx restart

I opened my browser and viewed the site. All is well. An interesting note, on my local, I never collected all of static files under the mobilepebbles folder (see collectstatic):

manage.py collectstatic

So my static files for the Django site are actually being served by Nginx (on Port 80), while the Python files are being served by Apache (Port 8080). If you recall, one of the first domains that I switched was nedia.staticfiles. In my settings.py file of mobilepebbles.local, my STATIC_URL is set to meida.staticfiles:

?View Code PYTHON
STATIC_URL = 'http://media.staticfiles/mobilespebbles/static/'

Well that’s it. Now I can use Nginx and Apache together. For more information about configuring Nginx, read the Nginx Wiki. In my next post, I will discuss how to Node.js and the Express webserver with Nginx. Enjoy.

Be Sociable, Share!

Checkout My New Site - T-shirts For Geeks