Puppet, Nginx, and Reverse Proxies
So after fighting with Puppet, their dated nginx module and a cranky Atlassian instance tonight, I thought I'd post my findings so that future questions to The Oracle might be a little more fruitful for some people.
So the Puppet config for my node (consolidate for the purposes of this sample) ended up looking like this:
node "host.domain.tld" inherits atlassian-production { include atlassian::crucible } class atlassian::crucible { package { "git": ensure => latest, } package { "mercurial": ensure => latest, } package { "subversion": ensure => latest, } require firewall include ::nginx::config include ::nginx::service include ::nginx::package nginx::resource::vhost { "host.domain.tld": ensure => present, server_name => ['host.domain.tld'], listen_port => 443, proxy => 'https://127.0.0.1:8443', ssl => true, ssl_cert => 'puppet:///modules/atlassian/ssl/host.domain.tld.crt', ssl_key => 'puppet:///modules/atlassian/ssl/host.domain.tld.key', location_cfg_append => { 'proxy_set_header' => 'X-Real-IP $remote_addr', 'proxy_set_header ' => 'X-Forwarded-For $proxy_add_x_forwarded_for', 'proxy_set_header ' => 'Host $http_host', 'proxy_set_header ' => 'X-Forwarded-Proto $scheme' } } }
To anybody familiar with Puppet configs, that probably won't look like anything too unusual. Except for the location_cfg_append hash, that is.
There were two issues here:
1) The way jfryman's and PuppetLabs' nginx modules are set up, using hashes, each directive has to be unique. That conflicts with Nginx's penchant for using multiple directives to layer functionality, as is the case with proxy_set_header.
2) You have to be careful to use single quotes around the hash values, so they aren't subject to Puppet's variable substitution.
(2) is easy enough to work around. (1) was a little more difficult, but the solution ended up being simple enough: wrap each hash key in single quotes like its paired value. For each duplicate key, add a space to make it unique. The spaces are harmless to the nginx config, if a little off-putting for whitespace Nazi's out there. The puppet config above ends up spitting out this Nginx Config:
server { listen *:443 ssl; server_name host.domain.tld; ssl on; ssl_certificate /etc/nginx/host.domain.tld.crt; ssl_certificate_key /etc/nginx/host.domain.tld.key; ssl_session_cache shared:SSL:10m; ssl_session_timeout 5m; ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; index index.html index.htm index.php; access_log /var/log/nginx/host.domain.tld.access.log; error_log /var/log/nginx/host.domain.tld.error.log; location / { proxy_pass https://127.0.0.1:8443; proxy_read_timeout 90; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; } }
So overall, I can't complain, except that it took me far longer than it should have to come up with this and make it happy, given the lack of example configs that were this simple. Most involved multiple locations, www_path's, and other nightmares that ended up being wholly unnecessary.