intercity / chef-repo

Set up your server to host Ruby on Rails apps. - Follow us on Twitter: @intercityup
MIT License
416 stars 82 forks source link

Allow customization of nginx files #97

Open michiels opened 10 years ago

michiels commented 10 years ago

On some servers I have some custom configuration for nginx that cannot be handled abstractly by chef-repo or any other automated piece of software.

I think it would be a good idea to add include (http://nginx.org/en/docs/ngx_core_module.html#include) directives to each virtual host in the nginx config so people can customize their own domain name setups with custom rewrites, PHP sites, redirects or directory indexes. I currently use this for:

Implementation would be pretty simple at first hand. We provide something like /etc/nginx/custom/<domain_name>.custom.confthat people can then edit themselves.

michiels commented 10 years ago

Here's a Gist illustrating this with a sample from our server: https://gist.github.com/michiels/56e64dad9ecb21150de2

berkes commented 10 years ago

The way I had this solved was to include all files from a few directories. This does slow down nginx-booting but not so much nginx after that (other than nginx having more rules, directives and whatnot to cover, slowing it down anyway; I guess that nginx simply keeps a compiled version of the file with all included files).

There's two things that might need to be covered:

  1. Including config files at particular places in the file.
  2. Reloading nginx on placement or changing of one of the included file (causing potentially a lot of reloads)

By placing all includes under the /u/apps/examplecom/shared/nginx directory, you can keep the application nicely contained. It is immediately clear that confs placed there will be included only in that applications vhost.

By adding a few subdirectories there, you can make sure that a certain files gets included only in certain parts of the vhost:

Problem is that after placing a file there, you need to give nginx a kick in order to reload and take your new/edited file. An alternative would be to manage these files with chef too, but that could potentially become a quite complex set of mirrored directory-trees in the local chef-repo.

See an example, edited from your sample: https://gist.github.com/berkes/a6ec56af9a3714453248

berkes commented 10 years ago

I've just implemented a somewhat modified version, and sent that in as PR. Please let met know what you think of this direction. If this is the right direction, I'll create some tests and add some documentation in the wiki about when to use what custom-categories.

case at hand: I am moving a webshop from a dutch environment to become an english shop: a lot of paths will change. They need redirects, so I've got to add a bunch of lines with these redirects into the http and https server block.

This PR does a little more, since it allows users to place custom config before and after the template, and in several places inside the template.

I've chosen to follow the default that chef-repo already has: to include the contents in the json (rather than pointing to files and/or including these files). I had that implemented first, but that is somewhat awkward especially when you have multiple node configuration files and several apps in there; it then becomes a gigantic spagetti of files and includes of these files. Just to include a few redirects on the correct place.

Here's an example of what I'd have in the node-configuration:

    "nginx_custom": {
      "server_main": "rewrite ^/t/accessoires$ http://shop.example.com/t/small-leather-goods;\n"
    }

Other configs that are possible:

    "nginx_custom" => {
      "before" => "",
      "server_main" => "",
      "server_app" => "",
      "server_ssl"  => "",
      "server_ssl_app" => "",
      "upstream" => "",
      "after" => "",
    }
michiels commented 9 years ago

@berkes Thanks for the awesome work and research so far.

I liked your approach in providing default file locations for putting custom nginx configuration files that could be app-specific. Putting the text in the chef-repo allows you to make it versioned and create custom callbacks (like reloading nginx). If you create custom files in the app directories, you would have to copy them over to new servers if you want to migrate or scale.

Since you've tried both approaches so far. Would your opinion be to take your last approach like you mention in the last sample of the nginx_custom key?

berkes commented 9 years ago

Since you've tried both approaches so far. Would your opinion be to take your last approach like you mention in the last sample of the nginx_custom key?

Untill the moment that chef-repo has a more generic way to deal with files, I'd say the best option is to include the contents of a file in the node.json.

In my current approach, I went for the simplest solution that works: include content in the config.json, and have it write out that content in the template. So no new files and such.

I've tried with new files, and the result is theoretically nicer, but for all my cases way too complex. Debugging becomes really hard, since you have to hunt all over the disk on a server to find a broken file.

One case, where I needed about 30 rewrite rules would have been nicer with a file-based approach. But in this case I made a workaround: one custom recipe that uploads my rewrites.conf into a directory (/u/apps/example.com/shared/conf/rewrites.conf) and then in the nodes.json:

"nginx_custom": {
  "server_main": "include /u/apps/example.com/shared/conf/rewrites.conf;"
}

I think I like this approach most: because it is so simple, it is very predictable. Having chef-create all sorts of tiny files and when created, including these in the vhost file, makes it a lot more complex and harder to understand.