10

I'd like to configure Nginx in such way that I need minimal amount of efforts to add new sites.

I see this in the following way: when creating new site I put it in subfolder under /var/www, add new location in nginx config file which just includes config template for required site type. It can look like this:

server 
{
  listen 80;
  server_name localhost;
  root /var/www;        

  location /site1
  {
    include drupal.conf;
  }

  location /site2
  {
    include wordpress.conf;
  }
}

But, unfortunately, this doesn't work in my case. The issue is with nested locations. I have the following lines in one of included templates:

...

location  /core/ 
{
  deny all;
}

location / 
{
  try_files $uri $uri/ @rewrite;
}

....

Nginx gives me the following errors:

location "/core/" is outside location "/site1" in ...

location "/" is outside location "/site1" in ...

So I need to specify full path for each site (like /site1/core/), but then I will not be able to extract it as one reusable piece.

Previously, as alternative, I configured multiple server directives with different server_name (site1.locahost, site2.localhost ...) and edited /etc/hosts file. In this case I didn't need nested locations as long as everything was under the root of domain. But, as I said, I'm looking for a way to simplify the workflow as much as possible and editing /etc/hosts seems to me like extra action which I' like to avoid.

So the question is how to best handle this situations? How do you organize work on different sites locally?

2 Answers 2

6

At home and at work I use a combination of Bind9 and Nginx to solve this problem. It does require some setup, but once it's up you shouldn't ever need to touch your nginx config file again. I've added some limitations at the bottom.

Setup

Setup a DNS Server, (Bind9, dnsmasq)

1) Setup a local DNS server, and create a host called DEV 2) Create a A name entry in DEV for

* A 127.0.0.1

And restart your DNS server. 3) Make sure you can dig *.dev and verify that you get back 127.0.0.1.

Setup Nginx

1) In your nginx.conf or wherever you're storing your conf.d stuff, create a vHost entry that looks more or less like this: you can adapt it to your needs.

server {
    listen   80;
    server_name *.dev;
    access_log  /var/log/nginx/access.log;
    error_log   /var/log/nginx/error.log;

    if ($host ~* ^(.*).dev$) {
        set $site $1;
    }

    if (!-d /var/www/$site/) {
        return 404;
    }

     location ~ index.php$ {
        fastcgi_split_path_info ^(.+\.php)(.*)$;
        fastcgi_pass   backend;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /var/www/$site/$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;
    }

    location ~ / {
            try_files $uri $uri/ /index.php?$args;
    }
}

2) Restart nginx service.

3) Profit


Once this is setup, to create a new site all you have to do is create a new folder in /var/www/.

mkdir -p /var/www/sitename/

That site, and the PHP underneath it can be accessed via sitename.dev.

As stated earlier, there are a couple limitations with this. sitename has to be all lower case, and contain no spaces or special characters (periods included). Secondly, it really only works for sites that are bootstrapped through index.php.

If you have radically different site structures, you can modify a couple of things to give you a more robust setup. For example you could write your config out so that it looked something like this.

server {
    listen   80;
    server_name *.*.dev;

    [...]

    if ($host ~* ^(.*).(.*).dev$) {
        set $site $1;
        set $folder $2;
    }

    if (!-d /var/www/$folder/$site/) {
        return 404;
    }

    [...]
        fastcgi_param  SCRIPT_FILENAME  /var/www/$folder/$site/$fastcgi_script_name;
    [...]

}

And assuming you update your dns server to response to ..dev, then you could write our directories as follows, just to give you an idea.

/var/www/wordpress/site1
/var/www/wordpress/site2
/var/www/wordpress/site3

/var/www/zend/site1
/var/www/zend/site2
/var/www/zend/site3

Like I said earlier, I use this setup at home and at work with +15 people. Our work setup is a little more complex (shared server, everyone has their own home folder), but it works just fine there. Personally I prefer working on subdomains rather than localhost paths.

Hope this helps!

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for sharing your setup! I really like the idea of having local DNS to avoid hosts file editing on each new site addition. But there are 2 points that seem not ideal to me in this setup. First is using if statement, because If Is Evil. Can't say I 100% understand why it is bad and whether it applies in this case, but anyway... The second thing, as you said, that it will work only for sites bootstrapped through index.php. But I'd like to have some config which will allow me to customize rules inside each location independently.
0

What about using something like the alias function offered by nginx?

http://wiki.nginx.org/HttpCoreModule#alias

If that doesn't work for your workflow, does symlinking to the /core directory prevent that error?

2 Comments

Thanks for your ideas, but I think both versions solve a bit different problem then I have. alias directive, if I understand correctly, is needed to resolve differences between path in URL and on the file system. But I have absolutely identical paths. So http://localhost/site1 is mapped to /var/www/site1, http://localhost/site2 to /var/www/site2 etc... So no translation is needed.
symlinking also don't think that is what I need. Actually I do have core folder inside my site1 folder. But it seems that it doesn't matter, because nginx doesn't look at the file system in this case. It gives error only looking at config file, where I'm trying to reference /core location inside /site1 location. But I really want to reference /site1/core rather than just /core. But don't know how to do it without specifying full location, which will vary for different sites.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.