Using NGinx to serve static files and Apache for dynamic Rumi, September 6, 2019 Apache is a great web-server, but it has a pretty heavy memory footprint. It can get quite restrictive quite quickly, especially if you’re on a system will limited resources (given how many people now run on a VPS, and the poor disk IO of these systems it’s all the more important – swapping is slow). The way around it, is to configure your system to use NGinx as a reverse-proxy. Depending how many virtualhosts you have, you can make the changes almost completely transparently within about 10 minutes. Pre-Requisites First, we need to be able to install NGinx, which means setting up the EPEL repo (if you already have it enabled, skip this step) CentOS 6.x rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm Now that the repo is installed, we need to install NGinx yum install nginx Configuring NGinx Now that NGinx is installed we need to create a VirtualHost (actually NGinx calls them Server Blocks) for each site we are hosting. nano /etc/nginx/conf.d/virtual.conf #Insert one of these for each of the virtualhosts you have configured in Apache server { listen 80; root /path/to/site/root; index index.php index.html index.htm; server_name www.yourdomain.com yourdomain.com; 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; } location ~ /\.ht { deny all; } } This configuration tells NGinx to try and serve the requested file, but to pass the request onto Apache if it’s unable to do so. Requests for PHP files should be forwarded automatically. Apache will be told who requested the file in the ‘X-Forwarded-For’ header. The final section tells NGinx not to honour requests for .htaccess files as we don’t want anyone to see the contents of these. So, assuming you had the following VirtualHost directive in your Apache configuration <VirtualHost *:80> ServerAdmin webmaster@example.com DocumentRoot /home/example/public_html ServerName www.exaple.com ErrorLog logs/example.com-error_log CustomLog logs/example.com-access_log common <Directory /> AllowOverride All </Directory> </VirtualHost> You’d want to enter server { listen 80; root /path/to/site/root; index index.php index.html index.htm; server_name www.example.com example.com; 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; } location ~ /\.ht { deny all; } } Note: the second entry on server_name is essentially the equivalent of Apache’s ServerAlias – we’re telling NGinx to use that server block for both www.example.com and example.com. Configuring Apache The next step represents the point where we risk interruption to service if something goes wrong. We’re going to edit Apache’s config ready for the switch round. You really shouldn’t start this bit unless you plan to finish the rest of the steps in this documentation without interruption – if you edit the config and then leave it, the next time Apache is restarted your sites will appear to be down! Change the port Apache runs on We want users to hit our NGinx installation (otherwise this effort is wasted) but Apache is currently sat on port 80. So we’re going to move it to 8080 (given that’s the port we specified in the NGinx configuration we created). nano /etc/httpd/conf/httpd.conf # Find the following Listen (someIP) 80 # Change the port to Listen 127.0.0.1 8080 # Now at the bottom of the file, you'll find your virtualhost directives, # Change all port definitions of 80 to 8080 # Don't forget the Default virtualhost definition # <virtualhost *:80> becomes <virtualhost *:8080> We change the Listen address as we don’t want external hosts to access Apache directly, everything should go through NGinx. Ideally, we also want to forbid outside access to port 8080 at the firewall to ensure that the point of entry to our system is restricted to the authorised route – through NGinx. Start the Services We’ve now configured Apache to listen on a different port, so all we need to do know is restart Apache (so that it moves to port 8080) and start NGinx so that it can start handling requests. service httpd restart service nginx start Now if you browse to your site, nothing should have changed visibly. However, if you check the HTTP headers you should see NGinx instead of Apache, checking a phpinfo file should still show Apache as having called the PHP parser though. Additional Considerations Security By adding NGinx into the mix, we’re increasing our potential attack surface a little – we’ve now got an extra application to keep patched and up to date (which is why we installed from the repo’s and didn’t go out-of-band). Although we’ve hidden Apache away behind NGinx, don’t assume it’s automatically shielded – if a vulnerability is exploited using a valid request, NGinx will pass the request through verbatim (assuming it couldn’t handle itself). What you are protected from, though, is exploits that involve an invalid request. SSL Connections Nothing we’ve done will affect SSL connections, if Apache was configured to listen on port 443, it will continue to do so. However, this also means that all SSL requests will be handled by Apache and so the memory benefits of using NGinx as a proxy won’t be present on these connections. It’s more than possible (and not particularly hard) to set NGinx up as a reverse SSL proxy, but that’s outside the scope of this documentation (although the steps involved are almost identical). Administrations Configurations (Linux) Apachenginx