Nginx, Fastcgi, PHP, rewrite config for Drupal

Afternoon.

So I've been getting stuck into making Drupal 4.7 (and 5.0) work with Nginx, which is a bit like Lighttpd except without the firehose-esque memory leaks you get with Lighty and actual web traffic busier than a trickle.

This has worked for me for the last several days on (! NSFW !) cliterati.co.uk, which roars through about 30 HTTP requests per second.

Credit: This page was completely invaluable, and everything Drupal-ish here is merely minor edits to that earlier work.

Why would you want to do this?

Because if you're running Apache/Apache2 with mod_php on a dedicated server with 1Gb of memory, and you have a lot of traffic, and more than about 50 of your visitors are logged in and posting to forum.module most of the time, then your dedicated server can't run Drupal. This is nuts. While people are raging against the non-existent caching for uid>0 in Drupal, you may want to cut your static memory requirement by about 85% at a stroke by showing Apache the door.

Nginx (and lighttpd) do more than just this, in performance terms, but even if they didn't I'd still need to run one of them to keep such a server afloat.

Nginx

Firstly you have to install nginx, which is not going to be covered here. I went for compile-from-source because the versions in Debian repositories are ancient. Next, here's the configuration details I've found to work with Drupal and URL aliasing. I'm posting an example of an entire http{} section from the config file. It passes everything PHP-related to one or more PHP fastcgi processes listening on port 8888, which you'll be setting up after this.

In nginx.conf:

http {
    include       conf/mime.types;
    default_type  application/octet-stream;
    server_names_hash_bucket_size  128;

    #log_format  main  '$remote_addr - $remote_user [$time_local] $request '
    #                  '"$status" $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  20;
    tcp_nodelay        on;

    #gzip  on;

    server {
        listen       192.168.0.1:80;  # Replace this IP and port with the right ones for your requirements
        server_name  example.com www.example.com;  # Multiple hostnames seperated by spaces.  Replace these as well.

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location = / {
            root   /path/to/drupal;  # Again, replace this. 
            index  index.php;
        }

        location / {
            root   /path/to/drupal;
            index  index.php index.html;

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

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

        }

        error_page  404              /index.php;

        # serve static files directly
        location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {
              access_log        off;
            expires           30d;
        }

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        location ~ .php$ {
          fastcgi_pass   127.0.0.1:8888;  # By all means use a different server for the fcgi processes if you need to
          fastcgi_index  index.php;

          fastcgi_param  SCRIPT_FILENAME  /path/to/drupal$fastcgi_script_name;   # !! <--- Another path reference for you.
          fastcgi_param  QUERY_STRING     $query_string;
          fastcgi_param  REQUEST_METHOD   $request_method;
          fastcgi_param  CONTENT_TYPE     $content_type;
          fastcgi_param  CONTENT_LENGTH   $content_length;
        }



        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}

     }
}

PHP and Fastcgi

I'm not mentioning PHP 4 or 5 because this part is exactly the same for each. I'm referring to 'php5-cgi' because that's the name of the right binary for the right PHP version on my Debian-based server. Your mileage may vary.

This shell script will launch a few fastcgi PHP processes bound to port 8888 for Nginx to talk to. I launch it as root - it starts the processes as the Debian apache user and exits.

#!/bin/bash

## ABSOLUTE path to the PHP binary
PHPFCGI="/usr/bin/php5-cgi"

## tcp-port to bind on
FCGIPORT="8888"

## IP to bind on
FCGIADDR="127.0.0.1"

## number of PHP children to spawn
PHP_FCGI_CHILDREN=5

## number of request before php-process will be restarted
PHP_FCGI_MAX_REQUESTS=1000

# allowed environment variables sperated by spaces
ALLOWED_ENV="ORACLE_HOME PATH USER"

## if this script is run as root switch to the following user
USERID=www-data

################## no config below this line

if test x$PHP_FCGI_CHILDREN = x; then
  PHP_FCGI_CHILDREN=5
fi

ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_CHILDREN"
ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_MAX_REQUESTS"
ALLOWED_ENV="$ALLOWED_ENV FCGI_WEB_SERVER_ADDRS"

if test x$UID = x0; then
  EX="/bin/su -m -c \"$PHPFCGI -q -b $FCGIADDR:$FCGIPORT\" $USERID"
else
  EX="$PHPFCGI -b $FCGIADDR:$FCGIPORT"
fi

echo $EX

# copy the allowed environment variables
E=

for i in $ALLOWED_ENV; do
  E="$E $i=${!i}"
done

# clean environment and set up a new one
nohup env - $E sh -c "$EX" &> /dev/null &

Initial results

I've moved two phpAdsNew ad servers, a fairly-busy Wordpress blog, the above-mentioned Drupal site and my own Drupal site from Apache2 into Nginx in the last week. Processor use has increased on the server, but critically the ongoing web+database memory use has come down by over 300MB. This means that the box hasn't gone into swap for a week (normally it was paging out every day), server response times are up and (because I'm also using APC to store Drupal's source files in memory) page download speeds are also up considerably.

Basically, it's saved a server.

I've tested it with Drupal 4.7 and Drupal 5.0, and with PHP4.3.3 and PHP5.2.0. All those configurations work.

Caveats

Drupal can serve static files either directly or via Drupal itself - it's a configuration option (in Drupal 4.7 it's in admin/settings - I don't yet have 5.0 seared into memory). This configuration requires that you serve those files directly. If Drupal's configured the other way your site will look incredibly odd, and image.module in particular breaks horribly. Me, I don't care. If this is an issue for you, it might be time to get into that in the comments.

Enjoy... and if you've got suggestions to improve this, I'd love to hear them.

Server Specs & Site Traffic

nixuzer - January 29, 2007 - 07:16

handelaar,

Thanks for putting this information out there. We're looking at getting our own server and consolidating all of our Drupal stuff onto it as well as some misc traffic. Would you mind providing the hardware configuration of the server (RAM, disk(s), CPU(s), etc) as well as the type of traffic you get (hits per day/week/month whatever)? We're trying to figure out if a Celeron would do us to start or do we need something higher powered and if so how much more do we need.

Your time putting this together is appreciated.

Server details

handelaar - February 1, 2007 - 17:50

It's a dedicated box at Servermatrix. Intel(R) Celeron(R) CPU 2.40GHz, 1Gb RAM, 80Gb HDD.

Like I said, it's doing 30-odd HTTP requests per second. The majority of the traffic at any given moment is coming from one of two sites, which between them serve 1.3m pages per month. A bunch of other co-hosted Drupal installs bring that total over 2m between them.

Interestingly, I found that locking MySQL down a little (using my-medium.cnf) and restricting its memory footprint works rather better than giving it my-huge.cnf and running the risk of sending the whole box into swap during peak periods. And both the high-traffic sites have had their databases converted to InnoDB to avoid the problem of one posted comment causing the site to be unable to show any pages to anyone for several seconds, because 400 SELECT queries are stalled for every 1 second spent on that INSERT (and the time spent waiting for table locks before the INSERT can begin).

"MyISAM considered harmful", indeed.

See also:

handelaar - February 2, 2007 - 00:17

Right under this page on a Google query for nginx rewrite examples, Scott Yang draws my attention to the part of the nginx docs which I couldn't see staring me in the face.

Where Apache uses !-f then !-d in sequence, I was looking for a way to ape it. Turns out I didn't need to. So above where I wrote this:

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

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

...you should instead use this...

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

...because Nginx has the "-e" directive which matches against a file, directory or symlink all at once, rendering my attempts to replicate the Apache way unnecessary.

You really want this instead...

furmans - September 1, 2007 - 02:43

Try this instead:

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

Drupal is expecting something of the form "node/1" and not "/node/1" after the "q=". There is at least one module, GlobalRedirect, that does not tolerate the leading "/". The rule above fixes the problem.

Current Drupal site: Inventor Spot

drupal in a subdirectory

vwX - February 7, 2008 - 04:26

I haven't used drupal under nginx in a subdir, until the other day. Found out the above won't work. You have to do something like:

if ($request_uri ~* ^.*/.*$) {
     rewrite ^/(\w*)/(.*)$ /$1/index.php?q=$2 last;
     break;
}

for your rewrite instead.

For example, if your subdirectory is called mysub a request of http://example.com/mysub/admin/report/status will be rewritten correctly as http://example.com/mysub/index.php?q=admin/report/status instead of http://example.com/mysub/admin/report/index.php?q=status. Remember that .* is greedy.

There is probably a better way to write this, but this works for me for now.

Nginx Performance & Feedback

nixuzer - February 6, 2007 - 22:37

handelaar, thanks for the information on your server. Based on the fact that most of our sites will be running semi-static content (i.e. usually updated by us and not the users) I think we'll be okay with a lower end box.

As an aside I ran some performance numbers using http_load and the difference between Apache2 and nginx was pretty dramatic. Granted this isn't completely an apples to apples comparison but I did do some tweaking with both to get the numbers more inline but nothing too drastic. This was on a fresh Debian Stable install using a 'as delivered' from Dell Precision 360 w/1GB of RAM and a 3GHz Intel P4 inside my local network where both machines were connected to a Linksys WRT54G. Also I repeated this test several times to verify the results were consistent. The Drupal install was the latest 4.7.X branch with 7 pages set up and referenced in the urls.txt file.

Server: Apache2
Apache2 caching=On
Drupal Caching=On
$ http_load.exe -parallel 50 -seconds 30 urls.txt
547 fetches, 50 max parallel, 3.62053e+06 bytes, in 30.015 seconds
6618.88 mean bytes/connection
18.2242 fetches/sec, 120624 bytes/sec
msecs/connect: 122.124 mean, 3250 max, 0 min
msecs/first-response: 2337.75 mean, 5016 max, 141 min
HTTP response codes:
code 200 -- 547

Server: nginx
PHP_FCGI_CHILDREN=6
PHP_FCGI_MAX_REQUESTS=250
eAccelerator=On
Drupal Caching=On
Browser Load Time = 1
$ http_load.exe -parallel 50 -seconds 30 urls.txt
2748 fetches, 50 max parallel, 1.83063e+07 bytes, in 30.015 seconds
6661.68 mean bytes/connection
91.5542 fetches/sec, 609905 bytes/sec
msecs/connect: 6.52766 mean, 3265 max, 0 min
msecs/first-response: 215.662 mean, 3625 max, 0 min
HTTP response codes:
code 200 -- 2748

I'm still playing around so I'm sure the numbers from nginx will only get better.

I dont think that this would

beryl - January 22, 2008 - 13:57

I dont think that this would be a fair comparison, we all know that eAccelerator makes apache 2 very much faster, yet you didnt test apache2 with it here, but tested nginx with it.

Addition to the nginx.conf

vwX - February 14, 2007 - 02:38

I added

location ~* /(modules|themes|misc|sites|profiles|scripts)/ {
                        return 404;
                }

to prevent download of the non .php extension files.

themes dir?

nixuzer - February 15, 2007 - 19:17

Are you sure about the themes directory?

To test this make sure to restart nginx and clear your browser cache.

Sorry

vwX - February 16, 2007 - 01:13

I'll blame lack of sleep. This doesn't actually work, didn't realize how many .css files are under the modules dir now. Here is the better config.

               location ~* /(modules|themes|scripts|sites)/ {
                        if (-f $request_filename) {
                                rewrite \.(module|inc|info|engine|sql|sh)$  / permanent;
                        }
                }

My /admin/build/modules page

snelson - January 26, 2008 - 04:46

My /admin/build/modules page wouldn't submit after using this bit. Why not just copy how .htaccess does it?

This worked nicely for me:

  # hide protected files
  location ~* \.(engine|inc|info|install|module|profile|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(code-style\.pl|Entries.*|Repository|Root|Tag|Template)$ {
    deny all;
  }

--
Scott Nelson
This by Them, LLC
Services Module

Debian style init script

nezroy - May 11, 2007 - 09:55

Here's a Debian-style init script for starting and stopping the PHP FCGI instances. The one thing it doesn't do is clear the environment like the original does. You could probably interleave env into this somehow to get it to do that, but I didn't go that far on this first pass. Note that, as with any use of start-stop-daemon and --background, you don't get much error checking on startup.

#!/bin/sh -e

# Start or stop PHP FastCGI handlers
#
# based on Postfix's init.d script

SSD=/sbin/start-stop-daemon
DAEMON=/usr/bin/php5-cgi
NAME=phpcgi
FCGIPORT="8080"
FCGIADDR="127.0.0.1"
export PHP_FCGI_CHILDREN=5
export PHP_FCGI_MAX_REQUESTS=1000
USERID=www-data
PIDFILE=/var/run/fastcgi.pid
TZ=
unset TZ

test -x $DAEMON || exit 0

. /lib/lsb/init-functions
DISTRO=$(lsb_release -is 2>/dev/null || echo Debian)

running() {
    if [ -f ${PIDFILE} ]; then
        pid=$(sed 's/ //g' ${PIDFILE})
        exe=$(ls -l /proc/$pid/exe 2>/dev/null | sed 's/.* //;')
        if [ "X$exe" = "X$DAEMON" ]; then
            echo y
        fi
    fi
}
case "$1" in
    start)
        log_daemon_msg "Starting PHP FastCGI Handler" ${NAME}
        RUNNING=$(running)
        if [ -n "$RUNNING" ]; then
            log_end_msg 0
        else
        if ${SSD} --start --chuid ${USERID} --background --pidfile ${PIDFILE} --make-pidfile --startas ${DAEMON} -- -q -b ${FCGIADDR}:${FCGIPORT}; then
                log_end_msg 0
            else
                log_end_msg 1
            fi
        fi
    ;;

    stop)
        RUNNING=$(running)
        log_daemon_msg "Stopping PHP FastCGI Handler" ${NAME}
        if [ -n "$RUNNING" ]; then
        if ${SSD} --stop --pidfile ${PIDFILE} --signal 15; then
                rm -f ${PIDFILE}
                log_end_msg 0
            else
                log_end_msg 1
            fi
        else
            log_end_msg 0
        fi
    ;;

    restart)
        $0 stop
        $0 start
    ;;

    force-reload|reload)
        $0 stop
        $0 start
    ;;

    *)
        log_action_msg "Usage: /etc/init.d/fastcgi {start|stop|restart|reload|force-reload}"
        exit 1
    ;;
esac

exit 0

Init script submitted to Debian

jordi - June 20, 2007 - 15:37

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=426780 has yet another init script that is being proposed for inclussion in Debian's php5-cgi.

imagecache module mods to nginx.conf

furmans - March 17, 2008 - 07:23

If you're using the imagecache module, serving static files directly like the original poster does, nginx bypasses the image rescaler. In order to make image cache work with the following,

# serve static files directly
        location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {
              access_log        off;
            expires           30d;
        }

you need to add the code below to force the imagecache images through PHP. My code assumes that your imagecache image dir is set up under /files/imagecache.

        # imagecache needs to have php read any files that it's planning to manipulate                                                 
        location ^~ /files/imagecache/ {
            index  index.php index.html;

            # assume a clean URL is requested, and rewrite to index.php                                                                
            if (!-e $request_filename) {
rewrite  ^/(.*)$  /index.php?q=$1  last;
                break;
            }
        }

Current Drupal site: Inventor Spot

Can't get rewrite to work with nginx

ldway - April 18, 2008 - 04:43

I am not able to get the rewrite working correctly...

Without the rewrite rule all works as expected. (No rewrite but the main site shows, just no links work because of no rewrite)

When I have the rewrite section in my conf file, I get no CSS, pictures, just straight text with a darn funny looking white page.

Here is what I have in my conf file:

===============================================
# serve static files directly
location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {
access_log off;
expires 30d;
break;
}

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

error_page 404 /index.php;

location ~ \.php$ {
include /usr/local/nginx/fastcgi.conf;
fastcgi_pass 127.0.0.1:57102;
fastcgi_index index.php;
}
===============================================

Very strange indeed as it seems like the above would work. When I comment out the rewrite section the home page displays fine but just not rewrite (as expected).... As soon as I put that rewrite section back in I get the page with straight text, no css formatting, no pics, etc.

ANYONE have any ideas? Spend all day on trying to figure this out and I am completely stumped.

Shell Script Modifications

mpapet - May 3, 2008 - 19:36

The shell script as shown above did not work for me. (Debian Etch circa 5/2008). I had two issues:

1. It did not spawn anything.
2. When I tweaked it some more, I got it to spawn a parent, but no chldren.
3. When I finally got it to spawn, there is another issue where the user account that started the script (not www-data) owned the process and threw permission errors.

So, I revised the punchline of the script a bit. Instead of:

if test x$UID = x0; then
EX="/bin/su -m -c \"$PHPFCGI -q -b $FCGIADDR:$FCGIPORT\" $USERID"
else
EX="$PHPFCGI -b $FCGIADDR:$FCGIPORT"
fi

I used sudo with as few modifications to /etc/sudoers as possible. If you spent some time modifying /etc/sudoers, you could probably come up with a more elegant approach:

if test x$UID = x0; then
EX="sudo -u www-data env PHP_FCGI_CHILDREN=4 $PHPFCGI -c $PHP_CONFIG_FILE -q $
else
echo "Sorry, can't start. Must start as root"
fi

Pay careful attention to the "env..." bit. This allows the php5-cgi to make children. To run multiple versions of php, I added the $PHP_CONFIG_FILE stanza as follows:

##DIRECTORY to *find* the php.ini
PHP_CONFIG_FILE="/etc/php5/cgi"

I still have a problem where the listener dies with peak loads. php5-cgi sucks all of the cpu up and then dies. I don't care about the cpu running near 100%. it seems like it can't queue very well. Does anyone have any experience with nginx instance as load balancer to multiple php5-cgi listeners?

There is pending/orphaned

westbywest - July 8, 2009 - 21:33

There is pending/orphaned Debian bug report with a more canonical implementation of the fastcgi startup script.

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=426780

Ben West

Typo in static files statement

NickSI - May 29, 2008 - 10:21

In initital configuraion:

        # serve static files directly
        location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {
              access_log        off;
            expires           30d;
        }

this statement breaks Drupal AJAX upload. You shoud add backslash to the secon "." in regular expression to fix it. Updated statement should look like
        # serve static files directly
        location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico)$ {
              access_log        off;
            expires           30d;
        }

I love you.

Setzler - August 23, 2008 - 18:07

I love you.

How to deny access to a directory

dgrant - August 6, 2008 - 17:04

How do I block access to a specific directory? like /var/www/drupal/sites/www.willmusic.ca/files/backup_migrate. There is a .htaccess file in that directory that does a "deny all"...

Create appropriate rule in your NGINX config file

NickSI - August 9, 2008 - 16:49

nginx does not use .htaccess so you have to specify access rules in nginx config file.

        # fix for backup_migrate
        location ~* ^/files/backup_migrate {
          deny all;
        }

RewriteRule in .htaccess to rewrite

Dzuma - August 12, 2008 - 00:20

I have this .htaccess, and I would like to change it to rewrite.
Can somebody please, give me an example using one of these rules below, how I would do it?
This .htaccess is located at: /var/mysql/www/www.yuwa.org/bioskop
Thank you.

RewriteRule ^category/([0-9]+)/.*\.p([0-9]+)\.(htm|html)$ listplaylists.php?cat=$1&p=$2 [QSA,L]
RewriteRule ^category/([0-9]+)/.*\.(htm|html)$ listplaylists.php?cat=$1 [QSA,L]
RewriteRule ^playlists/([0-9]+)/.*\.p([0-9]+)\.(htm|html)$ listplaylists.php?uid=$1&p=$2 [QSA,L]
RewriteRule ^playlists/([0-9]+)/.*\.(htm|html)$ listplaylists.php?uid=$1 [QSA,L]
RewriteRule ^videos/([0-9]+)/.*\.p([0-9]+)\.(htm|html)$ listvideos.php?uid=$1&p=$2 [QSA,L]
RewriteRule ^videos/([0-9]+)/.*\.(htm|html)$ listvideos.php?uid=$1 [QSA,L]
RewriteRule ^playlist/([0-9]+)/.*\.p([0-9]+)\.(htm|html)$ listvideos.php?pid=$1&p=$2 [QSA,L]
RewriteRule ^playlist/([0-9]+)/.*\.(htm|html)$ listvideos.php?pid=$1 [QSA,L]
RewriteRule ^tag/(.*)\.p([0-9]+)$ listvideos.php?tag=$1&p=$2 [QSA,L]
RewriteRule ^tag/(.*)$ listvideos.php?tag=$1 [QSA,L]
RewriteRule ^video/([0-9]+)/.*\.(htm|html)$ showvideo.php?id=$1 [QSA,L]
RewriteRule ^member/([0-9]+)/.*\.(htm|html)$ member/user.php?id=$1 [QSA,L]
RewriteRule ^playlists(\.p([0-9]+))?\.(htm|html)$ listplaylists.php?p=$2 [QSA,L]
RewriteRule ^videoslist(\.p([0-9]+))?\.(htm|html)$ listvideos.php?p=$2 [QSA,L]
RewriteRule ^memberslist(\.p([0-9]+))?\.(htm|html)$ listusers.php?p=$2 [QSA,L]
RewriteRule ^index\.(htm|html)$ index.php [QSA,L]

Best documentation is in

Cronjobs - August 25, 2008 - 07:30

Best documentation is in russian, but you can try http://wiki.codemongers.com/NginxConfiguration

Games For Girls Online

Nginx VirtualHost and Static Files

yookoala - August 22, 2008 - 06:19

The "serve static files directly" config doesn't work when you have multiple virtualhost in Nginx.
It seems you have to define "root" directive there.

After referencing some comments here I changed the configuration.
The below configuration works well on my testing server:

        # serve static files directly
        location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico)$ {
              root   /path/to/drupal;
              access_log        off;
              expires           30d;
              break;
        }

Or alternatively, you can add the "root" directive to "server" like this":

    server {
        listen       192.168.0.1:80;               # Replace this IP and port with the right ones for your requirements
        server_name  example.com www.example.com;  # Multiple hostnames seperated by spaces.  Replace these as well.
        root   /path/to/drupal;                    # ***** Replace this  *****

        #charset koi8-r;
        #access_log  logs/host.access.log  main;

        location = / {
            index  index.php;
        }

        location / {
            index  index.php index.html;

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

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

        }

        error_page  404              /index.php;

        # serve static files directly
        location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ {
            access_log        off;
            expires              30d;
            break;
        }

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        location ~ .php$ {
          fastcgi_pass   127.0.0.1:8888;  # By all means use a different server for the fcgi processes if you need to
          fastcgi_index  index.php;

          fastcgi_param  SCRIPT_FILENAME  /path/to/drupal$fastcgi_script_name;   # ***** Replace this  *****
          fastcgi_param  QUERY_STRING     $query_string;
          fastcgi_param  REQUEST_METHOD   $request_method;
          fastcgi_param  CONTENT_TYPE     $content_type;
          fastcgi_param  CONTENT_LENGTH   $content_length;
        }



        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}

     }

How to use nginx.conf file to redirect IP address to sitename

StefanScottAlexx - December 10, 2008 - 05:00

Hi -

I installed nginx + PHP-FPM, and set up multiple Drupal sites using the "more secure" directory layout following the instructions from Justin Hileman:

http://justinhileman.info/blog/2007/06/a-more-secure-drupal-multisite-in...

So far I've only configured site1.com to use Drupal, and site2.com and site3.com display "Welcome to Nginx" for now, which is fine. I configured my nginx.conf file based on the examples above, and also here:

http://www.codegobbler.com/drupal-nginx-fastcgi-setup-and-configuration

It seems to be working ok so far - I've set up a database, installed some modules and themes, and created a few pages.

Now as an additional test, I tried pointing my browser at my numeric IP address, eg:

http://208.77.188.166/ ## this is the official IP address of example.com !!

I hoped it would go by default to the first site in my nginx.conf file (site1.com) - but instead it goes to my Drupal installation page.

I should clarify that I've already set up site1.com in Drupal - so the installation page no longer appears when I go to http://site1.com - it only appears when I go to http://208.77.188.166 - because Drupal is somehow grabbing that IP address and redirecting it to an installation page.

I don't want to expose this Drupal installation page to the public. It's not a big security risk I think, because the page shows errors saying ./sites/default/default.settings.php and sites/default/files don't exist yet and need their permissions to be set. But still I'd like to prevent this Drupal installation page from being displayed in case anybody happens to point a browser at my IP address!

How do I change my ningx.conf file so that entering a numeric IP address in my browser will go to the first site in my nginx.conf file (site1.com)?

Here's my nginx.conf file:

user  www-data www-data;
worker_processes  2;

error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] $request '
    #                  '"$status" $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip on;
    gzip_comp_level 1; gzip_proxied any;
    gzip_types text/plain
               text/html
               text/css
               application/x-javascript
               text/xml
               application/xml
               application/xml+rss
               text/javascript;

    server {
        listen       80;
        server_name  .site1.com;

        location / {
            root   /usr/local/nginx/html/site1;
            index  index.php;
        }

        location / {
            root   /usr/local/nginx/html/site1;
            index  index.php index.html;

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

        # hide protected files
        location ~* \.(engine|inc|info|install|module|profile|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(code-style\.pl|Entries.*|Repository|Root|Tag|Template)$ {
            deny all;
        }

        # hide backup_migrate files
        location ~* ^/files/backup_migrate {
            deny all;
        }

        # serve static files directly
        location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico)$ {
            root /usr/local/nginx/html/site1;
            access_log        off;
            expires           30d;
            break;
        }

        error_page  404              /index.php;

        error_page   500 502 503 504  /50x.html;

        location = /50x.html {
            root   html;
        }

        location ~ \.php$ {
            root   html/site1;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            include /usr/local/nginx/conf/fastcgi_params;
        }
    }

    server {
        listen       80;
        server_name  .site2.com;

        location / {
            root   html/site2;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    server {
        listen       80;
        server_name  .site3.com;

        location / {
            root   html/site3;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

Thanks for any help!

FIXED

StefanScottAlexx - December 10, 2008 - 14:27

OK, fixed it - but 'listen ... default' wasn't working for some reason - somehow Drupal was grabbing it anyways and redirecting to the "Install Drupal" page.

Instead I followed the advice here:

https://calomel.org/nginx.html

and added this:

## Deny access to any host other than (www.)mydomain.com
server {
server_name _; #default
return 444;
}

BEFORE all the other server directives in the nginx.file - and it worked!

Thanks!

you should perhaps also make

edrex - February 1, 2009 - 11:16

you should perhaps also make sites/default a symlink to sites/site1.com

Any thoughts of

Igor K - February 27, 2009 - 16:46

Any thoughts of Nginx+Imagecache without Apache config?

I cant get it work together and havent found solution yet, if someone can help, please do it, cause the thing is crucial.

try accessing

mrfelton - April 28, 2009 - 10:22

try accessing http://your-site/som-php-page-that-doesnt-exist.php. do you get the Drupal 404? or a plaintext message saying "No input file specified" ?

If if have the php redirect in the server{} section, Drupal handles the 404 pages, but then other location directives do not work correctly. If I have it in a location / {} or location = / {} other location directives work correctly, but I get the plain text error when accessing non existent .php files.

(by 'the php redirect' I mean:)

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

--
Tom
kirkdesigns.co.uk - web design and development

Wiki config for version 0.7.x

brianmercer - June 18, 2009 - 23:00

NT

Anyone have any issues

Campsoupster - July 15, 2009 - 21:51

Anyone have any issues getting NginX working with outgoing email? Drupal's not sending out user registration emails, nor contact form submissions. The Drupal logs show that emails going out correctly, but it's not being received.

Sean Larkin
Think!Shout

Problem I'm having with my

mshaver - August 10, 2009 - 22:03

Problem I'm having with my nginx and drupal multisite setup?

The problem is with the password reset function in Drupal. Everything works as expected, until you get to the point where you are selecting the "login" button that is supposed to redirect you to your account edit page where you change your password. In my case it instead does not redirect and gives you an error for trying to use the reset url again. I read someplace that running PHP in CGI mode sometimes has issues with sessions after a redirect in the URL?

Does this sound familiar at all?

Join Nginx g.d.o.

omega8cc - September 20, 2009 - 21:58

Everyone looking for latest, working and supported configuration examples, tips and tricks, please join our Nginx group:

http://groups.drupal.org/nginx

~Grace -- Turnkey Drupal Hosting on Steroids -- http://omega8.cc

I joined the group but...

MrMac - October 29, 2009 - 13:12

...the group does not seem to have (yet) much support offered in its threads.

As this thread has quite a number of modifications / corrections / updates to the original configuration file, may I suggest somebody prepare a bit of how-to for the abovementioned group? That would be very helpful! :)

[I can't do that myself as I still did not manage to make drupal/nginx tandem to properly work...]

Thanks!

@MrMac

omega8cc - November 7, 2009 - 21:47

There is fully working example available, now with help for custom nginx + php-fpm build, and it works with any Drupal site, not only with Aegir or Boost enabled:

http://groups.drupal.org/node/26363

~Grace -- Drupal on Steroids -- http://omega8.cc

 
 

Drupal is a registered trademark of Dries Buytaert.