(For more resources on Nginx, see here.)
There are basically two main parts involved in the configuration, one relating to Apache and one relating to Nginx.
Note that while we have chosen to describe the process for Apache in particular, this method can be applied to any other HTTP server. The only point that differs is the exact configuration sections and directives that you will have to edit. Otherwise, the principle of reverse-proxy can be applied, regardless of the server software you are using.
There are two main aspects of your Apache configuration that will need to be edited in order to allow both Apache and Nginx to work together at the same time. But let us first clarify where we are coming from, and what we are going towards.
At this point, you probably have the following architecture set up on your server:
The new configuration that we are going towards will resemble the following:
As you can tell, only two main configuration changes will be applied to Apache as well as the other web server that you are running. Firstly, change the port number in order to avoid conflicts with Nginx, which will then be running as the frontend server. Secondly, (although this is optional) you may want to disallow requests coming from the outside and only allow requests forwarded by Nginx. Both configuration steps are detailed in the next sections.
Depending on how your web server was set up (manual build, automatic configuration from server panel managers such as cPanel, Plesk, and so on) you may find yourself with a lot of configuration files to edit. The main configuration file is often found in /etc/httpd/conf/ or /etc/apache2/, and there might be more depending on how your configuration is structured. Some server panel managers create extra configuration files for each virtual host.
There are three main elements you need to replace in your Apache configuration:
The virtual host sections must be transformed from the following template
<VirtualHost A.B.C.D:80>
ServerName example.com
ServerAliaswww.example.com
[...]
</VirtualHost>
to the following:
<VirtualHost A.B.C.D:8080>
ServerName example.com:8080
ServerAliaswww.example.com
[...]
</VirtualHost>
In this example, A.B.C.D is the IP address of the virtual host and example.com is the virtual host's name. The port must be edited on the first two lines.
There are many ways you can restrict Apache to accept only local requests, denying access to the outside world. But first, why would you want to do that? As an extra layer positioned between the client and Apache, Nginx provides a certain comfort in terms of security. Visitors no longer have direct access to Apache, which decreases the potential risk regarding all security issues the web server may have. Globally, it's not necessarily a bad idea to only allow access to your frontend server.
The first method consists of changing the listening network interface in the main configuration file. The Listen directive of Apache lets you specify a port, but also an IP address, although, by default, no IP address is selected resulting in communications coming from all interfaces. All you have to do is replace the Listen 8080 directive by Listen 127.0.0.1:8080; Apache should then only listen on the local IP address. If you do not host Apache on the same server, you will need to specify the IP address of the network interface that can communicate with the server hosting Nginx.
The second alternative is to establish per-virtual-host restrictions:
<VirtualHost A.B.C.D:8080>
ServerName example.com:8080
ServerAliaswww.example.com
[...]
Order deny,allow
allow from 127.0.0.1
allow from 192.168.0.1
eny all
</VirtualHost>
Using the allow and deny Apache directives, you are able to restrict the allowed IP addresses accessing your virtual hosts. This allows for a finer configuration, which can be useful in case some of your websites cannot be fully served by Nginx.
Once all your changes are done, don't forget to reload the server to make sure the new configuration is applied, such as service httpd reload or /etc/init.d/ httpd reload.
There are only a couple of simple steps to establish a working configuration of Nginx, although it can be tweaked more accurately as seen in the next section.
The first step is to enable proxying of requests from your location blocks. Since the proxy_pass directive cannot be placed at the http or server level, you need to include it in every single place that you want to be forwarded. Usually, a location / { fallback block suffices since it encompasses all requests, except those that match location blocks containing a break statement.
Here is a simple example using a single static backend hosted on the same server:
server {
server_name .example.com;
root /home/example.com/www;
[...]
location / {
proxy_passhttp://127.0.0.1:8080;
}
}
In the following example, we make use of an Upstream block allowing us to specify multiple servers:
upstream apache {
server 192.168.0.1:80;
server 192.168.0.2:80;
server 192.168.0.3:80 weight=2;
server 192.168.0.4:80 backup;
}
server {
server_name .example.com;
root /home/example.com/www;
[...]
location / {
proxy_passhttp://apache;
}
}
So far, with such a configuration, all requests are proxied to the backend server; we are now going to separate the content into two categories:
We thus have to separate the content somehow to be provided by either server.
In order to establish this separation, we can simply use two different location blocks—one that will match the dynamic file extensions and another one encompassing all the other files. This example passes requests for .php files to the proxy:
server {
server_name .example.com;
root /home/example.com/www;
[...]
location ~* .php.$ {
# Proxy all requests with an URI ending with .php*
# (includes PHP, PHP3, PHP4, PHP5...)
proxy_passhttp://127.0.0.1:8080;
}
location / {
# Your other options here for static content
# for example cache control, alias...
expires 30d;
}
}
This method, although simple, will cause trouble with websites using URL rewriting. Most Web 2.0 websites now use links that hide file extensions such as http://example.com/articles/us-economy-strengthens/; some even replace file extensions with links resembling the following: http://example.com/useconomy- strengthens.html.
When building a reverse-proxy configuration, you have two options:
Here is an implementation of this mechanism, using the error_page directive :
server {
server_name .example.com;
root /home/example.com/www;
[...]
location / {
# Your static files are served here
expires 30d;
[...]
# For 404 errors, submit the query to the @proxy
# named location block
error_page 404 @proxy;
}
location @proxy {
proxy_passhttp://127.0.0.1:8080;
}
}
Alternatively, making use of the if directive from the Rewrite module:
server {
server_name .example.com;
root /home/example.com/www;
[...]
location / {
# If the requested file extension ends with .php,
# forward the query to Apache
if ($request_filename ~* .php.$) {
break; # prevents further rewrites
proxy_passhttp://127.0.0.1:8080;
}
# If the requested file does not exist,
# forward the query to Apache
if (!-f $request_filename) {
break; # prevents further rewrites
proxy_passhttp://127.0.0.1:8080;
}
# Your static files are served here
expires 30d;
}
}
There is no real performance difference between both solutions, as they will transfer the same amount of requests to the backend server. You should work on porting your Apache rewrite rules to Nginx if you are looking to get optimal performance.