FAQ

Page Discussion History

Difference between revisions of "Drupal"

m (Adds image style settings for D7)
(Use Drupal 7 by default.)
(9 intermediate revisions by 6 users not shown)
Line 1: Line 1:
= Drupal =
+
= Configuration project =
 +
 
 +
Caution: This project is NOT a drop-in configuration setup. It's designed to leverage the best of what Nginx and Drupal have to offer. The rest of this page details a more common and very easy to understand approach.
 +
 
 +
https://github.com/perusio/drupal-with-nginx
 +
 
 +
= Guide =
  
 
There seems to be a lot of controversy as to the best way to put Nginx in front of Drupal without passing to an Apache server. Rather than explain the reasons all of these configs are wrong, I'd rather explain a better way. (Followed by bad)
 
There seems to be a lot of controversy as to the best way to put Nginx in front of Drupal without passing to an Apache server. Rather than explain the reasons all of these configs are wrong, I'd rather explain a better way. (Followed by bad)
Line 9: Line 15:
 
server {
 
server {
 
         server_name domain.tld;
 
         server_name domain.tld;
         root /var/www/drupal6; ## <-- Your only path reference.
+
         root /var/www/drupal7; ## <-- Your only path reference.
 +
 
 +
        # Enable compression, this will help if you have for instance advagg‎ module
 +
        # by serving Gzip versions of the files.
 +
        gzip_static on;
  
 
         location = /favicon.ico {
 
         location = /favicon.ico {
Line 22: Line 32:
 
         }
 
         }
  
         # This matters if you use drush
+
         # This matters if you use drush prior to 5.x
         location = /backup {
+
         # After 5.x backups are stored outside the Drupal install.
                deny all;
+
        #location = /backup {
         }
+
        #        deny all;
 +
         #}
  
 
         # Very rarely should these ever be accessed outside of your lan
 
         # Very rarely should these ever be accessed outside of your lan
Line 34: Line 45:
  
 
         location ~ \..*/.*\.php$ {
 
         location ~ \..*/.*\.php$ {
 +
                return 403;
 +
        }
 +
 +
        # No no for private
 +
        location ~ ^/sites/.*/private/ {
 +
                return 403;
 +
        }
 +
 +
        # Block access to "hidden" files and directories whose names begin with a
 +
        # period. This includes directories used by version control systems such
 +
        # as Subversion or Git to store control files.
 +
        location ~ (^|/)\. {
 
                 return 403;
 
                 return 403;
 
         }
 
         }
Line 43: Line 66:
  
 
         location @rewrite {
 
         location @rewrite {
 +
                # You have 2 options here
 +
                # For D7 and above:
 +
                # Clean URLs are handled in drupal_environment_initialize().
 +
                rewrite ^ /index.php;
 +
                # For Drupal 6 and bwlow:
 
                 # Some modules enforce no slash (/) at the end of the URL
 
                 # Some modules enforce no slash (/) at the end of the URL
 
                 # Else this rewrite block wouldn't be needed (GlobalRedirect)
 
                 # Else this rewrite block wouldn't be needed (GlobalRedirect)
                 rewrite ^/(.*)$ /index.php?q=$1;
+
                 #rewrite ^/(.*)$ /index.php?q=$1;
 
         }
 
         }
  
Line 52: Line 80:
 
                 #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
 
                 #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
 
                 include fastcgi_params;
 
                 include fastcgi_params;
                 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+
                 fastcgi_param SCRIPT_FILENAME $request_filename;
 
                 fastcgi_intercept_errors on;
 
                 fastcgi_intercept_errors on;
 
                 fastcgi_pass unix:/tmp/phpfpm.sock;
 
                 fastcgi_pass unix:/tmp/phpfpm.sock;
 
         }
 
         }
  
         # Fighting with ImageCache? This little gem is amazing.
+
         # Fighting with Styles? This little gem is amazing.
         location ~ ^/sites/.*/files/imagecache/ {
+
         # This is for D6
                try_files $uri @rewrite;
+
        #location ~ ^/sites/.*/files/imagecache/ {
        }
+
         # This is for D7 and D8
         # Catch image styles for D7 too.
+
 
         location ~ ^/sites/.*/files/styles/ {
 
         location ~ ^/sites/.*/files/styles/ {
 
                 try_files $uri @rewrite;
 
                 try_files $uri @rewrite;
Line 72: Line 99:
 
}
 
}
 
</geshi>
 
</geshi>
 
== Not So Simple ==
 
 
For a while, I ran Drupal shop. I spent a lot of time tweaking and perfecting the recipe. Many things were left out of the above to keep from over complicating things. If you think I probably dealt with something already that you're fighting with then ask me (MTecknology) for some additional information.
 
 
My aim was to deliver a very functional Nginx config that can be very nearly a drop in working model.
 
  
 
== Little About The Others ==
 
== Little About The Others ==
  
I'd like to explain what some of the others do wrong.
+
What some of the others do wrong...
  
 
<strong>DO NOT DO THESE!</strong>
 
<strong>DO NOT DO THESE!</strong>
Line 148: Line 169:
 
                 # Drupal in a subdirectory
 
                 # Drupal in a subdirectory
 
                 rewrite ^/([^/]*)/(.*)(/?)$ /$1/index.php?q=$2&$args;
 
                 rewrite ^/([^/]*)/(.*)(/?)$ /$1/index.php?q=$2&$args;
 +
        }
 +
</geshi>
 +
 +
 +
<strong>Imagecache</strong>
 +
 +
In case it wasn't obvious, if you are using imagecache with a non-standard upload directory (site option or media mover) you will need to update the regex above to the proper directory.  Such as, if you move the upload directory to /uploads on your site, you will need to change the configuration as follows:
 +
<geshi lang="nginx">
 +
#  location ~ ^/sites/.*/files/imagecache/ {
 +
  location ~ ^/uploads/imagecache/ {
 +
#..... Stuff here
 +
}
 +
</geshi>
 +
 +
<strong>Trouble with .php extensions/Drupal migrations</strong>
 +
 +
Even after reading [[IfIsEvil]], there is a corner case for drupal sites that migrated from other software (forums, mediawiki, etc.).  These site migrations use url aliases or menu mappings via modules to handle old .php files.  This breaks the .php location provided above, so using HTTP error code 418 and a few conditionals, we pass on lookups or 404's to Drupal.
 +
 +
<geshi lang="nginx">
 +
 +
        location ~ \.php$ {
 +
                error_page 418 = @rewrite;
 +
                recursive_error_pages on;
 +
 +
                fastcgi_split_path_info ^[^=](.+\.php)(/.+)$;
 +
                include fastcgi_params;
 +
 +
                if ( $uri = /index.php ) {
 +
                        # not sure this conditional works, will have to check the debug logs
 +
                        break;
 +
                }
 +
 +
                if ( !-e $document_root$fastcgi_script_name) {
 +
                        return 418;
 +
                }
 +
 +
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
 +
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 +
                fastcgi_intercept_errors on;
 +
                fastcgi_read_timeout 240;
 +
                fastcgi_pass  127.0.0.1:9000;
 
         }
 
         }
 
</geshi>
 
</geshi>

Revision as of 15:47, 9 May 2013

Contents

Configuration project

Caution: This project is NOT a drop-in configuration setup. It's designed to leverage the best of what Nginx and Drupal have to offer. The rest of this page details a more common and very easy to understand approach.

https://github.com/perusio/drupal-with-nginx

Guide

There seems to be a lot of controversy as to the best way to put Nginx in front of Drupal without passing to an Apache server. Rather than explain the reasons all of these configs are wrong, I'd rather explain a better way. (Followed by bad)

Config

Here's the Nginx config:

server {
        server_name domain.tld;
        root /var/www/drupal7; ## <-- Your only path reference.
 
        # Enable compression, this will help if you have for instance advagg‎ module
        # by serving Gzip versions of the files.
        gzip_static on;
 
        location = /favicon.ico {
                log_not_found off;
                access_log off;
        }
 
        location = /robots.txt {
                allow all;
                log_not_found off;
                access_log off;
        }
 
        # This matters if you use drush prior to 5.x
        # After 5.x backups are stored outside the Drupal install.
        #location = /backup {
        #        deny all;
        #}
 
        # Very rarely should these ever be accessed outside of your lan
        location ~* \.(txt|log)$ {
                allow 192.168.0.0/16;
                deny all;
        }
 
        location ~ \..*/.*\.php$ {
                return 403;
        }
 
        # No no for private
        location ~ ^/sites/.*/private/ {
                return 403;
        }
 
        # Block access to "hidden" files and directories whose names begin with a
        # period. This includes directories used by version control systems such
        # as Subversion or Git to store control files.
        location ~ (^|/)\. {
                return 403;
        }
 
        location / {
                # This is cool because no php is touched for static content
                try_files $uri @rewrite;
        }
 
        location @rewrite {
                # You have 2 options here
                # For D7 and above:
                # Clean URLs are handled in drupal_environment_initialize().
                rewrite ^ /index.php;
                # For Drupal 6 and bwlow:
                # Some modules enforce no slash (/) at the end of the URL
                # Else this rewrite block wouldn't be needed (GlobalRedirect)
                #rewrite ^/(.*)$ /index.php?q=$1;
        }
 
        location ~ \.php$ {
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $request_filename;
                fastcgi_intercept_errors on;
                fastcgi_pass unix:/tmp/phpfpm.sock;
        }
 
        # Fighting with Styles? This little gem is amazing.
        # This is for D6
        #location ~ ^/sites/.*/files/imagecache/ {
        # This is for D7 and D8
        location ~ ^/sites/.*/files/styles/ {
                try_files $uri @rewrite;
        }
 
        location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
                expires max;
                log_not_found off;
        }
}

Little About The Others

What some of the others do wrong...

DO NOT DO THESE!

listen       192.168.0.1:80;

There's really no need to tell Nginx to listen to only a single interface. By default Nginx will listen to all interfaces. If you're reading this, then there's probably not much reason for you to have this line.

access_log  logs/host.access.log  main;

This isn't that bad. There's nothing wrong with it. However, system logs should be in /var/log/. That's what that directory exists for. Try something like /var/log/nginx/yoursite_access.log.

location = / {
        root   /path/to/drupal;
        index  index.php;
}

For the love of god, stop doing this. Not YOU. Everyone out there that does this and spreads it. The root and index directives do not belong here. Check out the Pitfalls page for an explanation of why.

if (!-f $request_filename) {
        rewrite  ^(.*)$  /index.php?q=$1  last;
        break;
}
 
if (!-d $request_filename) {
        rewrite  ^(.*)$  /index.php?q=$1  last;
        break;
}

Again, NO! See IfIsEvil. If is very rarely ever (EVER) something you should use. heck out the Pitfalls page for an explanation of why.

fastcgi_pass 127.0.0.1:8888;

This isn't 'wrong' per say. You will get better performance and more security by binding to a socket though. You're no longer exposing a point of attack. With ports you're limited to the number of ports available on the system and you can't dynamically allocate them. In the case of sockets, you can control, allocate, and utilize them much easier.

fastcgi_param  SCRIPT_FILENAME  /path/to/drupal$fastcgi_script_name;

You know how I complained about "location = / { root /path/to/drupal; }" above? Why am I bringing it up again? If you set your root properly then instead of "/path/to/drupal" you could just use "$document_root". What makes it amazing is that you then have one less line that needs to change whenever you change things. The root is just setup.

include /usr/local/nginx/fastcgi.conf;

This is minor at best. A full path is not needed if your config is inside of your nginx config directory. The better option here is to just use "include fastcgi.conf;" Better would be to leave the .conf off of a file that's not read dynamically.

Notes

Drupal in a subdirectory

If you're running Drupal in a subdirectory, you will need to tweak the rewrite directive a bit. The example above would take a URL like example.com/drupal/node/123 and ask Drupal for example.com/index.php?q=drupal/node/123 , which obviously won't work for subdirectory hosting. This alternative rewrite string handles Drupal in one level of subdirectory (ie /drupal/node/123 , but not /directory/drupal/node/123 ). For more exotic configurations, simply tweak the regular expression used for the rewrite directive.

        location @rewrite {
                # Drupal in a subdirectory
                rewrite ^/([^/]*)/(.*)(/?)$ /$1/index.php?q=$2&$args;
        }


Imagecache

In case it wasn't obvious, if you are using imagecache with a non-standard upload directory (site option or media mover) you will need to update the regex above to the proper directory. Such as, if you move the upload directory to /uploads on your site, you will need to change the configuration as follows:

#  location ~ ^/sites/.*/files/imagecache/ {
   location ~ ^/uploads/imagecache/ {
#..... Stuff here 
}

Trouble with .php extensions/Drupal migrations

Even after reading IfIsEvil, there is a corner case for drupal sites that migrated from other software (forums, mediawiki, etc.). These site migrations use url aliases or menu mappings via modules to handle old .php files. This breaks the .php location provided above, so using HTTP error code 418 and a few conditionals, we pass on lookups or 404's to Drupal.

        location ~ \.php$ {
                error_page 418 = @rewrite;
                recursive_error_pages on;
 
                fastcgi_split_path_info ^[^=](.+\.php)(/.+)$;
                include fastcgi_params;
 
                if ( $uri = /index.php ) {
                        # not sure this conditional works, will have to check the debug logs
                        break;
                }
 
                if ( !-e $document_root$fastcgi_script_name) {
                        return 418;
                }
 
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_intercept_errors on;
                fastcgi_read_timeout 240;
                fastcgi_pass  127.0.0.1:9000;
        }

Anything Else?

If you have any questions here, please ping me on IRC. I'm MTecknology on Freenode. I hang out in #nginx most of my time.