Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

 

Nginx for fun and performance

Are you already using nginx ("engine-x")? If the answer is no, why not?!

Read post

Are you already using nginx ("engine-x")? If the answer is no, why not?!

Why nginx

It is the cool little brother of Apache httpd. Launched in 2004 from Russia, its popularity has been ever growing and depending on whose statistics you trust, it is now the second most popular webserver of all active sites and leading for the most popular ones. Many well known sites are using it, such as GitHubWordPress.com, or NASA.

And while nginx's performance is impressive, I find its overall handling much more pleasing than Apache's. Do you still remember the days when we were using Subversion? While it didn't suck, there was always this feeling that this just isn't perfect — especially for interactions with thirdparty code. Once we had switched to Git and got used to it, we realized that Subversion actually did suck. And the switch from Apache to nginx is much the same.

nginx and SilverStripe

If you are interested in the inner details of nginx, why concurrency is important, and how to achieve this with an event-based architecture, I can highly recommend the nginx chapter of "The Architecture of Open Source Applications". But we will skip to the SilverStripe specific parts right away. There are two main changes you need to get used to:

  • Firstly, there are no .htaccess files. While it is very convenient to add configurations as you go along, it requires a lot of redundant work from the webserver. For every request it needs to check every directory for an .htaccess file and if one is found, it needs to parse it. nginx keeps all configurations in a central file and you need to reload it whenever you want to apply a change. Slightly more work for you, but it allows nginx to cut a lot of corners.
  • Secondly, PHP must always run as a standalone process. PHP-FPM is the way to go, which you might (and should) already be using with Apache.

Now we are ready to go. Just as in every cooking show I have already prepared some important pieces: A Vagrant box, so you can easily give it a try; you will only need VirtualBox and Vagrant to run it. Clone the repository and run vagrant up. We are using a plain Ubuntu image and install MySQL, nginx, PHP-FPM, and Composer with a shell script. Then Composer does the hard work and installs SilverStripe. After a little while you should be able to connect to a working SilverStripe site athttp://127.0.0.1:8888 running on nginx and PHP-FPM. Magic, isn't it?

So let us take a look at the configuration and go over some of the important points, the full configuration file is located in nginx/custom:

server {
        root /var/www/silverstripe-nginx;
        server_name localhost;


        error_page 404 /assets/error-404.html;
        error_page 500 /assets/error-500.html;

server_name defines the domain name the configuration block is setting up — in our local example it is just localhost, but this would be yourdomain.comroot defines the location of the SilverStripe installation in the file system and error_page sets up our 404 and 500 pages.

        location / {
            try_files $uri @silverstripe;
        }

Everything that is calling the root directory (localhost or 127.0.0.1 in our example) is being redirected to the @silverstripe block, which is just a name I chose.

        location @silverstripe {
            fastcgi_keep_conn on;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_read_timeout 120;
            fastcgi_connect_timeout 60;
            fastcgi_send_timeout 120;
            fastcgi_buffer_size 64k;
            fastcgi_buffers 4 65k;
            fastcgi_busy_buffers_size 128k;

            fastcgi_param SCRIPT_FILENAME $document_root/framework/main.php;
            fastcgi_param SCRIPT_NAME /framework/main.php;
            fastcgi_param QUERY_STRING url=$uri&$args;
        }

        location ~* \.php$ {
            fastcgi_keep_conn on;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_read_timeout 120;
            fastcgi_connect_timeout 60;
            fastcgi_send_timeout 120;
            fastcgi_buffer_size 64k;
            fastcgi_buffers 4 65k;
            fastcgi_busy_buffers_size 128k;
        }

Next we have our @silverstripe block and the configuration for any PHP file. Both need to talk to the PHP-FPM process and we have chosen a Unix socket for the communication, which is the default. This must match your PHP-FPM settings (the alternative would be TCP). If in doubt, check the official documentation.

Additionally, the @silverstripe block defines which PHP file to call for the request and how to pass on any arguments.

        # Deny access to silverstripe-cache
        location ~ ^/silverstripe-cache {
            deny all;
        }

        # Deny access to logs
        location ~ ^/logs {
            deny all;
        }

        # Don't execute scripts in the assets folder
        location ^~ /assets/ {
            sendfile on;
            try_files $uri $uri/ =404;
        }

        # Deny access to composer
        location ~ ^/(vendor|composer.json|composer.lock) {
            deny all;
        }

        # Deny access to yaml files
        location ~ \.yml$ {
            deny all;
        }

        # Deny access to template files
        location ~ \.ss$ {
            satisfy any;
            allow 127.0.0.1;
            deny all;
        }

        # CMS & Framework .htaccess rules
        location ~ ^/(cms|framework|mysite)/.*\.(php|php[345]|phtml|inc)$ {
            deny all;
        }
        location ~ ^/(cms|framework)/silverstripe_version$ {
            deny all;
        }
        location ~ ^/framework/.*(main|static-main|rpc|tiny_mce_gzip)\.php$ {
            allow all;
        }

        # Deny access to all dot files
        location ~ /\. {
            deny all;
        }
}

This block just sets some security restrictions; which directories or files should not be accessible and where should scripts (not) be executed.

If anything is still unclear, I am sure you can figure it out with the repository — source code does not lie!

Moar speed

Ok, so I have switched to nginx — how much faster is my site now?

Unfortunately, it is not that easy. While the webserver is an important part, your bottleneck might be the database or your old PHP version — but switching to nginx is a great chance to switch to the latest PHP version as well. And there are many other factors, like the number of concurrent connections, your specific configuration, slow CPU or network or disk, too little memory,...

Imagine an intelligence test between a squid and a cat: Both are given the same puzzle to solve and the environment is also exactly the same. But it will still make a huge difference whether both of them are in a water tank or stand high and dry. The same is true for performance tests. That is why you will always need to run your own benchmarks for your specific situation to get a meaningful result.

Wait, there is more

But nginx can also do much more for you:

I hope I could draw your interest in nginx. Or helped you make a more conscious decision for sticking with Apache. Just know what you are using and why.

Thanks and let me know if something is unclear or if there is anything I missed.

About the author
Philipp Krenn

Phillip is a developer living in Vienna, Austria. he loves tinkering with IT problems, especially in the area of databases, infrastructure, and web development. He has in depth experiences with databases, cloud computing, and web development in general and SilverStripe in specific. He's also written a book about SilverStripe and has been both a GSoC student and mentor for SilverStripe.

Post your comment

Comments

  • So there is a rule just for that:
    location ~ ^/framework/.*(main|static-main|rpc|tiny_mce_gzip)\.php$ {
    allow all;
    }

    1. is tiny_mce_gzip.php not only giving you a 200 but also being served correctly if you open it directly?
    2. Is gzipping interfering with it? See https://serverfault.com/questions/455049/nginx-wont-execute-php-page-that-returns-javascript for a similar discussion on the topic.

    Cheers,
    Philipp

    Posted by Philipp, 06/11/2015 2:10pm (4 years ago)

  • Hi,

    Thank you for this article. I've managed to get my Silverstripe site working under NGINX, but unfortunately the Tiny MCE editor does not load! Do you have any idea what that might be?

    In my console I see the error message: Uncaught ReferenceError: tinyMCE is not defined.

    Tiny_mce_gzip.php is loaded properly with a 200 status.

    Posted by Bas, 05/11/2015 9:07am (4 years ago)

  • Nginx seemed to pop-up from nowhere, having high performance, efficiency and stability.

    I guess that it has such a success because it works totally different than other web servers. It has an event-driven, asynchronous architecture, it doesn’t need to start new processes in order to handle new requests (as other web servers do)...

    Posted by Kristine, 13/07/2015 11:31pm (4 years ago)

RSS feed for comments on this page | RSS feed for all comments

Like what you have read?

Sign up for our weekly blog digest sent to your inbox.

Subscribe