0

After a bit back and forth with configuring Drupal and nginx to work together, I've come up with the below configuration for a site. It works well, both with private and public file systems. However, as I am fairly new to nginx I'd like to hear if there is something with this configuration that I should change (for

Please note! I'm aiming towards getting feedback on a general purpose Drupal configuration. That is, a configuration which others who are trying out Drupal + nginx can "copy paste" to get up and running.

Update 1: I've (hopefully) improved the configuration file slightly, and I've added descriptive comments to explain what the various parts of the file are doing. I've also, according to input, enabled the 'open_file_cache' directive.

/etc/nginx/nginx.conf (partly)

# Cache information about local files.
open_file_cache max=1000 inactive=3600s;
open_file_cache_errors on;
open_file_cache_min_uses 3;
open_file_cache_valid 1800s;

/etc/nginx/sites-available/example.conf

server {
  listen 80;
  server_name ~^(www\.)?((example|example-web).+)$;
  access_log /home/example/www/logs/access.log;
  error_log /home/example/www/logs/error.log;
  root /home/example/www/public_html;

  # Do not log events related to 'favicon.ico'.
  location = /favicon.ico {
    log_not_found off;
    access_log off;
  }

  # Do not log events related to 'robots.txt'.
  location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
  }

  # Do not allow access to certain file types from outside the
  # network, regardless of their location in the file system.
  location ~* \.(txt|log|htaccess|htpassword)$ {
    allow 10.0.0.0/8;
    allow 172.16.0.0/12;
    allow 192.168.0.0/16;
    deny all;
  }

  # Requests are by default rewritten as defined in the @rewrite
  # location
  location / {
    try_files $uri @rewrite;
  }

  # The path '/system/files' is a virtual path managed by Drupal,
  # and thus needs to be handled by Drupal. Logging is disabled
  # for these requests, and server response is set to expire
  # after 7 days.
  location ~* /system/files/ {
    try_files $uri @rewrite;
    expires 7d;
    access_log off;
  }

  # Images and static content, which is defined as specific file
  # types, will be served directly by Nginx. These requests will
  # not be logged, and is set to expire after 30 days.
  location ~* \.(jpg|jpeg|gif|css|png|js|ico|xml)$ {
    access_log off;
    expires 30d;
  }

  # All requests are handled by index.php, and we need to make
  # sure that this still happens even if the site runs with clean
  # urls enabled.
  location @rewrite {
    rewrite_log on;
    rewrite ^/(.*)$ /index.php?q=$1;
  }

  # Delegate handling of '.php' files to PHP.
  location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(.*)$;
    fastcgi_pass unix:/var/run/example.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param CONTENT_TYPE $content_type;
    fastcgi_param CONTENT_LENGTH $content_length;
    fastcgi_intercept_errors on;
    fastcgi_ignore_client_abort off;
    fastcgi_connect_timeout 60;
    fastcgi_send_timeout 180;
    fastcgi_read_timeout 180;
    fastcgi_buffer_size 128k;
    fastcgi_buffers 4 256k;
    fastcgi_busy_buffers_size 256k;
    fastcgi_temp_file_write_size 256k;
  }
}
sbrattla
  • 1,456
  • 3
  • 26
  • 48

1 Answers1

1

This configuration should work. But why should you be satisfied with humming, when you can scream with nginx! You should consider adding the following directives for 'improved performance' Here is a comprehensive Nginx.conf, you can pick and chose directives, and see which work for you. Most should work, as this configuration is for serving static html files. You might want to put the server block and its directives in you default.conf and the nginx directives in nginx.conf separately as this is both into one nginx.conf unlike your present configuration above:

worker_processes  3;
#worker_rlimit_nofile 1024;

events {
worker_connections  64;
}

http {

## Size Limits
#client_body_buffer_size   8k;
#client_header_buffer_size 1k;
#client_max_body_size      1m;
#large_client_header_buffers 4 4k/8k;

## Timeouts 
#client_body_timeout     60;
#client_header_timeout   60;
keepalive_timeout       300 300;
#send_timeout            60;

## General Options
charset                 utf-8;
default_type            application/octet-stream;
ignore_invalid_headers  on;
include                 /etc/mime.types;
keepalive_requests      20;
#keepalive_disable       msie6;
max_ranges              0;
#open_file_cache         max=1000 inactive=1h;
#open_file_cache_errors  on;
#open_file_cache_min_uses 3;
#open_file_cache_valid   1m;
postpone_output       1460;
recursive_error_pages   on;
reset_timedout_connection on;
sendfile                on;
server_tokens           off;
#server_name_in_redirect on;
source_charset          utf-8;
#tcp_nodelay             on;
#tcp_nopush              off;

## Request limits
limit_req_zone  $binary_remote_addr  zone=gulag:1m   rate=60r/m;

## Compression
gzip              on;
gzip_static       on;
#gzip_buffers      16 8k;
#gzip_comp_level   1;
#gzip_http_version 1.0;
#gzip_min_length   0;
#gzip_types        text/plain text/html text/css image/x-icon image/bmp;
gzip_vary         on;

## Log Format
log_format  main  '$remote_addr $host $remote_user [$time_local] "$request" $status     $body_bytes_sent "$http_referer" "$http_user_agent" $ssl_cipher $request_time';

## Deny access to any host other than (www.)mydomain.com. Only use this
## option is you want to lock down the name in the Host header the client sends. 
# server {
#      server_name  _;  #default
#      return 444;
#  }

## Server (www.)mydomain.com
server {
add_header  Cache-Control public;
  access_log  /var/log/nginx/access.log main buffer=32k;
  error_log   /var/log/nginx/error.log error;
  expires     max;
  limit_req   zone=gulag burst=200 nodelay;
  listen      127.0.0.1:80;
  root        /htdocs;
  server_name mydomain.com www.mydomain;

 ## Note: if{} sections are expensive to process. Please only use them if you need them
 ## and take a look lower down on the page for our discussion of if{} statements.

 ## Only allow GET and HEAD request methods. By default Nginx blocks
 ## all requests type other then GET and HEAD for static content.
 # if ($request_method !~ ^(GET|HEAD)$ ) {
 #   return 405;
 # }

 ## Deny illegal Host headers. 
 # if ($host !~* ^(mydomain.com|www.mydomain.com)$ ) {
 #  return 405;
 # }

 ## Deny certain User-Agents (case insensitive)
 ## The ~* makes it case insensitive as opposed to just a ~
 # if ($http_user_agent ~* (Baiduspider|Jullo) ) {
 #  return 405;
 # }

 ## Deny certain Referers (case insensitive)
 ## The ~* makes it case insensitive as opposed to just a ~
 # if ($http_referer ~* (babes|click|diamond|forsale|girl|jewelry|love|nudit|organic|poker|porn|poweroversoftware|sex|teen|video|webcam|zippo) ) {
 #  return 405;
 # }

 ## Redirect from www to non-www
 # if ($host = 'www.mydomain.com' ) {
 #  rewrite  ^/(.*)$  http://mydomain.com/$1  permanent;
 # }

 ## Stop Image and Document Hijacking
  location ~* (\.jpg|\.png|\.css)$ {
    if ($http_referer !~ ^(http://mydomain.com) ) {
      return 405;
    }
  }

 ## Restricted Access directory by password in the access_list file.
  location ^~ /secure/ {
        allow 127.0.0.1/32;
        allow 10.10.10.0/24;
        deny all;
        auth_basic "RESTRICTED ACCESS";
        auth_basic_user_file /var/www/htdocs/secure/access_list;
    }

 ## Only allow these full URI paths relative to document root. If you only want
 ## to reference the file name use $request_filename instead of $request_uri. By default
 ## nginx will only serve out files in "root /htdocs;" defined above so this block is not needed, just an example.
 #  if ($request_uri ~* (^\/|\.html|\.jpg|\.org|\.png|\.css|favicon\.ico|robots\.txt)$ ) {
 #    break;
 #  }
 #  return 405;

 ## Serve an empty 1x1 gif _OR_ an error 204 (No Content) for favicon.ico
  location = /favicon.ico {
   #empty_gif;
    return 204;
  }

  ## System Maintenance (Service Unavailable) 
  if (-f $document_root/system_maintenance.html ) {
    error_page 503 /system_maintenance.html;
    return 503;
  }

 ## All other errors get the generic error page
  error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 495 496 497
             500 501 502 503 504 505 506 507 /error_page.html;
  location  /error_page.html {
      internal;
   }
  }
}

You should generally validate your results with Yslow or Page speed to track your progress. And use load testing if optimization is what you are trying to achieve. Best of luck!

  • Thanks! I'll look into your configuration file and see which ones fits the needs of a generic Drupal installation - and update above! – sbrattla Nov 12 '12 at 19:15
  • I've updated my configuration slightly...however, a few questions: (1) Do you know what the location "location ~ \..*/.*\.php$" will match? (2) Why set worker_processes to more than 1? (3) Why set worker_connections to 64 (and not, say 340) to match the default 1024 which works together with worker_processes = 1. (4) I'm curious about the 'gzip' directive, but uncertain about how much gain users will actually notice. I'm assuming most people have OK broadband connections and I'm worried that the gain received from less bandwith needed is overshadowed by the extra CPU required? – sbrattla Nov 13 '12 at 07:28
  • The number of worker processes should be same as the number of available cpu cores, or one less if the server is not dedicated. you need to adjust your worker connections in this manner: max_clients = worker_processes * worker_connections The default vaule of 1024 works good, I have mine set up to 2048. You can Gzip from a scale of 1-7. Seven being most cpu intensive and smallest gzipped file size. If you use caching then you should set gzip to anywhere between 4-7 as pages will be generated only once and cached, you can serve the smallest filesize. If no caching is used, then test and see. – Apurva Sukant Nov 14 '12 at 14:37