Secure your Nginx for Magento

Recent security patches have covered many security leaks. Some of the changes were added via .htaccess files either in Magento root or in specific directories (e.g. shell directory). These fixes will be applied automatically, if your Magento 1.x installation is running on Apache 2, but it won’t work if you prefer Nginx. In this post we will show you the proper Nginx config which provides the same result with a few additions.

Let’s start with the general content of Nginx config file. It should be found by the following path (may vary from your Nginx installation path): /etc/nginx/sites-available/your-site-name and, sometimes, it may be under /etc/nginx/sites-available/default. So the content of this file with all our modifications should look like in the example below:

server {

    listen 80;
    listen 443 default ssl;
    ssl_certificate /etc/ssl/private/ssl-certificate-name.cer;
    ssl_certificate_key /etc/ssl/private/ssl-certificate-key.key;

	#disabling SSLv3 in order to avoid poodle attack
	ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

	#Weak Diffie-Hellman and the Logjam Attack
	ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
	ssl_prefer_server_ciphers on;
	ssl_dhparam /etc/nginx/dhparams.pem;

    server_name website.com;
    root /path/to/magento/root;

    # Gzip Settings
    gzip on;
    gzip_disable "msie6";

    gzip_comp_level 6;
    gzip_min_length  1100;
    gzip_buffers 16 8k;
    gzip_proxied any;
    gzip_types       text/plain application/xml text/css text/js text/xml application/x-javascript text/javascript application/json application/xml+rss;

   location / {
        index index.html index.php; ## Allow a static html file to be shown first
        try_files $uri $uri/ @handler; ## If missing pass the URI to Magento's front handler
        expires 30d; ## Assume all files are cachable
    }

    location @handler {
        rewrite /   /index.php;
    }

    location ~ \.php(/.*)? {
        if (!-e $request_filename) {
            rewrite / /index.php break;
        }
        expires off;

        fastcgi_pass unix:/var/run/php5-fpm.sock;

        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        root /path/to/magento/root;
        fastcgi_param  SCRIPT_FILENAME  /path/to/magento/root$fastcgi_script_name;
        fastcgi_index index.php;
        fastcgi_read_timeout 18000; #set phpscript executing timeout
        include fastcgi_params;
    }

    location /api {
            rewrite ^/api/rest /api.php?type=rest;
    }

    location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|xml|txt)$ {
        root /path/to/magento/root;
        access_log        off;
        expires           max;
    }
    ##downloader directory password
    location /downloader {
            auth_basic            "Halt! Please, confirm your identity";
            auth_basic_user_file  /etc/nginx/.htpasswd;
            index index.php;
    }
	##restrict var, dev and .git directory from external access
	##restrict cron.php from external access
	location ^~ /.git/ { return 403; }
	location ^~ /cron.php { return 403; }
	location ^~ /dev/ { return 403; }
	location ^~ /var/ { return 403; }
}

Let’s check further details.

First of all, we need to restrict our store from using SSL protocols in order to avoid their vulnerabilities. We will use TLS only:

#disabling SSLv3 in order to avoid poodle attack
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

We also need to use stronger key for Diffie-Hellman encryption:

#Weak Diffie-Hellman and the Logjam Attack
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparams.pem;

For that purpose, we need to generate two-kilobytes crypt key in the specified path. That can be done from bash shell:

sudo openssl dhparam -out /etc/nginx/dhparams.pem 2048

We also should restrict downloader directory with htpassword protection:

##downloader directory password
location /downloader {
        auth_basic            "Halt! Please, confirm your identity";
        auth_basic_user_file  /etc/nginx/.htpasswd;
        index index.php;
}

For that purpose generate /etc/nginx/.htpasswd file from the bash shell:

htpasswd -c /etc/nginx/.htpasswd username

At last, restrict web access for var and dev (Magento 1.9.1.x) directories and cron.php. If you use git for version control (which is not recommended for production servers), you should also restrict .git directory:

##restrict var, dev and .git directory from external access
##restrict cron.php from external access
location ^~ /.git/ { return 403; }
location ^~ /cron.php { return 403; }
location ^~ /dev/ { return 403; }
location ^~ /var/ { return 403; }

That is all. Nginx should be restarted after all the above mentioned changes:

sudo service nginx restart

In order to check the results (and it is better to check both before and after the changes), you may use magereport.com and ssllabs.com for SSL vulnerability check.

Also, file contents provided in this post may be used for your Nginx config file if necessary (we assume that all the paths and domain names were updated properly). Thanks for reading us!