/* steve jansen */

// another day in paradise hacking code and more

Chef'ing Custom Nginx Configs With the Nginx Cookbook

| Comments

The nginx cookbook has been super helpful Chef’ing some web apps recently. One thing I struggled to understand was how to use my own custom conf, like /etc/nginx/nginx.conf, that is optimized for how I use nginx.

One solution I tried, which is probably a Chef anti-pattern, is to only include the nginx cookbook on the initial converge:

The Wrong Way

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# the nginx community cookbook will relentlessly revert conf files,
# so avoid running it unless nginx isn't installed,
# or we explicitly reset/delete the node attribute
include_recipe 'nginx' unless node['nginx']['installed']
node.set['nginx']['installed'] = true

# our custom nginx.conf
template '/etc/nginx/nginx.conf' do
   source 'nginx.conf.erb'
   owner 'root'
   group 'root'
   mode  '0644'
   notifies :reload, "service[nginx]", :delayed
end

I knew this was wrong when I wrote it. Chef is all about idempotency. But, I couldn’t figure out a way to keep the nginx cookbook from reverting my custom conf during subsequent converges, only to have my template restore my custom conf a few seconds later.

The Better Way

The OpsCode blog Doing Wrapper Cookbooks Right shows the right way, and really opened my eyes on the power of Chef’s two phase model (compile, then converge).

1
2
3
4
5
6
include_recipe 'nginx'

# use our custom nginx.conf, rather than the one that ships in the nginx cookbook
# this avoids the nginx and my-app cookbooks from fighting for control of
# the same target file
resources('template[nginx.conf]').cookbook 'my-app'

Comments