The Puppet Labs Issue Tracker has Moved: https://tickets.puppetlabs.com

Using Thin Nginx

This example installation is on Debian Lenny with backported puppet packages version 0.24.5-3. It uses the standard nginx install 0.6.32-3+lenny3. The general idea is to run [thin][http://code.macournoyer.com/thin/] on a local unix socket and use nginx to handle SSL and static files. This setup assumes you’ve used Puppet_Best_Practice to setup your files, specifically you do not have standalone dist or files directories; they should all be under modules. I do not recommend using this setup when starting from scratch; you’ll want to make sure everything is working correctly with the default installation so you’re not debugging too many things at once. The default installation will setup SSL certificates and other artifacts correctly.

Setup thin

To setup thin, here is the puppet description of packages I installed:

  package { 
    "rubygems1.8": ensure => latest;
    puppetmaster: ensure => latest;
    librrd-ruby: ensure => latest;
    "ruby1.8-dev": ensure => latest;
    libfcgi-dev: ensure => latest;
    "libfcgi-ruby1.8": ensure => latest;
    bacon: ensure => present, provider => gem;
    rack: ensure => present, provider => gem;
    rake: ensure => present, provider => gem;
    memcache-client: ensure => present, provider => gem;
    mongrel: ensure => present, provider => gem;
    fcgi:       
      ensure => present,
      provider => gem,  
      require => Package[libfcgi-dev];
    thin:       
      ensure => present,
      provider => gem,  
      require => [
        Package[bacon],
        Package[rack],
        Package[rake],
        Package[fcgi],
        Package[memcache-client],
        Package[mongrel]];
  }

Instead of running the puppetmaster binary, we want to run thin with the puppetmaster provided rackup file, so I replaced /etc/init.d/puppetmaster with:

DAEMON=/var/lib/gems/1.8/bin/thin
SCRIPT_NAME=/usr/share/puppet/rack/puppetmasterd/config.ru
ROLE_NAME=puppetmasterd
DAEMON_OPTS="-P /var/run/puppet/$ROLE_NAME.pid -e production --servers 3 --daemonize --socket /var/run/puppet/$ROLE_NAME.sock --chdir /etc/puppet/ --user puppet --group puppet -R $SCRIPT_NAME"
    
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
  
case "$1" in
  start)
        $DAEMON start $DAEMON_OPTS
        ;;
  stop)
        $DAEMON stop $DAEMON_OPTS
        ;;
  restart|force-reload|reload)
        $DAEMON restart $DAEMON_OPTS
        ;;
  *)
        echo "Usage: $0 {start|stop|restart}" >&2
        exit 3
        ;;
esac
    
:   

Now you should be able to start thin by running /etc/init.d/puppetmaster start, presuming that your puppet configuration files and directories are setup correctly.

Setup Nginx

For this you simply can install the standard Debian nginx package. The magic is in the configuration file:

user www-data;
worker_processes  2;

events {
        worker_connections  1024;
} 

http {
        default_type  application/x-raw;
  
        # site specific settings such as access_log, proxy_buffers
        # I use
        # proxy_max_temp_file_size 0;
        # proxy_buffers 128 4k;

        upstream puppet-production {
                server   unix:/var/run/puppet/puppetmasterd.0.sock;
                server   unix:/var/run/puppet/puppetmasterd.1.sock;
                server   unix:/var/run/puppet/puppetmasterd.2.sock;
        }
        
        server {
                listen puppet:8140;
                include conf.d/ssl.conf;
                include conf.d/proxy_set_header.conf;
    
                location /production/file_content/ {
                        rewrite ^/production/file_content/([^/]+)/(.*) /$1/files/$2;
                        break;
                        root /etc/puppet/modules/;
                }
                location / {
                        proxy_pass http://puppet-production;
                }
        }
}

This uses a server name of ‘puppet’. If yours is different change the listen line. The conf.d/ssl.conf file will check the connection of incoming client requests:

ssl on; 
ssl_certificate /var/lib/puppet/ssl/certs/puppet.pem;
ssl_certificate_key /var/lib/puppet/ssl/private_keys/puppet.pem;
ssl_ciphers ALL:-ADH:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP;
ssl_client_certificate  /var/lib/puppet/ssl/ca/ca_crt.pem;
  
#ssl_crl                 /var/lib/puppet/ssl/ca/ca_crl.pem;
ssl_verify_client       on;`

The conf.d/proxy_set_header.conf file sends information to the puppetmaster process so it can verify the client’s certificate:

proxy_redirect         off; 
proxy_set_header Host              $host;
proxy_set_header X-Real-IP         $remote_addr;
proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
#proxy_set_header    X-Client-Verify  $ssl_client_verify;
proxy_set_header    X-Client-Verify  SUCCESS;
proxy_set_header    X-Client-DN $ssl_client_s_dn;
proxy_set_header    X-SSL-Subject    $ssl_client_s_dn;
proxy_set_header    X-SSL-Issuer     $ssl_client_i_dn;

This version of nginx (0.6.32-3+lenny3) doesn’t support full verification, but Using_Mongrel_Nginx indicates that this support is available in later versions. If you have a later version of nginx, I recommend checking out that page and seeing if uncommenting the X-Client-Verify line works for you. With this setup, you now should be able to /etc/init.d/nginx start and have clients connect to you with less CPU load on your server. Cheers!