Important: Deprecation warning

Puppet master is the application that compiles configurations for any number of Puppet agent nodes, using Puppet code and various other data sources. (For more info, see Overview of Puppet’s Architecture.)

Rack is an interface for deploying Ruby web apps. The Puppet master application supports running as a Rack app.

A Rack server is one of two recommended ways to run the Puppet master service; the other is Puppet Server. Today, they’re very nearly equivalent, but we’re putting the bulk of our development effort behind Puppet Server — it’s going to keep getting better than Rack, and Rack support will eventually be removed.

Supported platforms

The Rack Puppet master will run on any *nix platform, including all Linux variants and OS X. It requires a multi-process (not threaded) Rack web server.

You cannot run a Puppet master on Windows.

Rack web servers

There are a lot of Rack web server stacks available. Puppet should work with any Rack server that spawns multiple processes to handle parallel requests.

Note that Puppet will not work with threaded Rack servers like Puma. Puppet’s code isn’t thread-safe, and it expects to be isolated in a single process.

If you don’t have any particular preference, you should start with Passenger and Apache, since it’s the most familiar and most thoroughly tested stack in the Puppet community. We have a detailed guide to configuring Passenger for Puppet. Additionally, some OSes have packages that automatically configure a Puppet master with Passenger.

The Unicorn + Nginx stack is also fairly popular, but it has more pieces that you’ll need to assemble and configure.

Controlling the service

Under Rack, the Puppet master processes are started and managed by your Rack web server. The way to start and stop the Puppet master will depend on your specific web server stack.

If your Rack stack isn’t running any other applications or sites, you can simply start and stop the whole server process; if it also provides other services, as a Passenger/Apache stack sometimes does, you may need to disable the Puppet master’s virtual host and do a graceful restart.

The Rack Puppet master’s run environment

Rack and the Puppet master application each have various expectations about their environment. To make them work together, you’ll need to make sure these expectations are met.

User

The Puppet master Ruby processes should be run as a specific non-root user, which is usually puppet. This should match the user specified by the user setting.

Note that you’ll need to manually create the puppet user account, as the puppet-agent package does not create it. To create this account, run the following commands:

The Rack web server sets the Puppet master process’s user. By default, it will use the owner of the config.ru file. (See below.)

All of the Puppet master’s files and directories must be readable and writable by this user.

Required directories

Before a Rack Puppet master can fully start up, it needs access to a confdir, codedir, and a vardir that its user has permission to write to. The locations of the directories it will use are set in the config.ru file (see below).

The Puppet master application can manage its own files inside those directories, but since Rack doesn’t start the master with root permissions, it won’t be able to create the initial directories in /etc or /var.

You can create these directories manually and set their ownership to the Puppet master’s user. Alternately, you can briefly start a WEBrick Puppet master and let it handle the initial setup. Run:

$ sudo puppet master --verbose --no-daemonize

Once the terminal says Notice: Starting Puppet master version <VERSION>, type ctrl-C to kill the process.

Ports

By default, Puppet’s HTTPS traffic uses port 8140. Your web server must be listening on this port, and the OS and firewall must allow it to accept incoming connections on this port.

A Rack Puppet master will ignore the masterport setting; instead, the web server’s configuration (for example, an Apache vhost) controls the port. You must ensure that the web server is listening on this port and is routing those requests to the Puppet master application.

If you want to switch to a non-default port, you’ll have to change your web server’s configuration, then make sure masterport is set correctly on all agents.

Keepalive timeout

This means Puppet expects the Rack web server to have a keepalive timeout of at least four seconds, preferably five. This is compatible with the default configuration of the most popular Rack stack.

If the keepalive timeout is set too low on the master, agents will occasionally fail with an “Error: Could not retrieve catalog from remote server: end of file reached” message.

Logging

When running under Rack, Puppet master’s logging is split.

Your Rack server stack is in charge of logging any information about incoming HTTPS requests and errors. It may maintain per-vhost log files, or send messages elsewhere. See your server’s documentation for details.

The Puppet master application itself logs its activity to syslog. This is where things like compilation errors and deprecation warnings go. Your syslog configuration dictates where these messages will be saved, but the default location is /var/log/messages on Linux, /var/log/system.log on Mac OS X, and /var/adm/messages on Solaris.

You can adjust how verbose the logs are with the log_level setting, which defaults to notice. Setting it to info is equivalent to running with the --verbose option, and setting it to debug is equivalent to --debug. You can also make logs quieter by dialing back to warning or lower.

Alternately, if you specify the --logdest <FILE> option in config.ru, Puppet master will log to the file specified by <FILE>.

The config.ru file

All Rack web servers use a config.ru file to load applications. This file is a Ruby script that loads any necessary libraries, performs any necessary configuration, and creates an application object that can handle Rack-formatted requests.

To run a Rack Puppet master, you must configure your Rack web server to load an application from this config.ru file and to route all Puppet requests to it.

The exact steps will depend on your Rack server; see the Passenger guide for an example.

Note that the config.ru file must be owned by the user puppet and the group puppet (or whatever user you want the Puppet master to run as; see “User” above). Most Rack servers use this file’s ownership to set the application’s user. Alternately, you may be able to explicitly configure your Rack server to use a specific user.

SSL termination

Your Rack web server stack must terminate SSL and verify agent certificates. The stack must also pass certain certificate data from each request to the Puppet master.

This may be done by the Rack web server itself, or by some kind of SSL terminating proxy. For general information about this, see our background reference on SSL.

You should have already initialized a CA and created the Puppet master’s credentials. To terminate SSL you will need one or more CA certificates, a Puppet master certificate, a Puppet master private key, and a certificate revocation list (CRL).

Your SSL termination must be configured as follows:

It must use a set of cyphers and protocols compatible with the version(s) of OpenSSL that your Puppet agent nodes are using.

It must trust the Puppet CA certificate as its CA. (If you are using an intermediate or split external CA, this is somewhat more complicated; see the external CA reference for details.)

It must identify itself to clients using the Puppet master’s certificate and private key.

SSL_CLIENT_CERT

Optional. Should be the entire client certificate in PEM format, if a certificate was presented.

Puppet uses this variable to enable the $trusted hash and to log warnings when agent certificates are about to expire. If the variable is absent, you will not be able to use these features.

If the Rack server is embedded in the same server that terminates SSL, this variable may be easy to fill. For example, in Apache with mod_ssl, setting SSLOptions +ExportCertData will automatically put the client certificate into SSL_CLIENT_CERT.

If the Rack server is not embedded in the SSL terminating part of your stack (for example, when running under the Nginx + Unicorn stack), you may need to embed the certificate in an HTTP header, then configure your Rack server to extract the certificate data and set the environment variable.

The name of this variable is not configurable.

Configuring a Rack Puppet master

As described elsewhere, the Puppet master application reads most of its settings from puppet.conf and can accept additional settings on the command line. When running under Rack, Puppet master gets its command line options from the config.ru file. The default config.ru file sets some common options for you.

To change the Puppet master’s settings, you should use puppet.conf. The only two options you may want to set in config.ru are --verbose or --debug, to change the amount of detail in the logs.

Aside: How a Rack Puppet master works

A Rack web server loads and executes a special part of Puppet’s Ruby code, which creates a Puppet master application object that can respond to specially formatted requests. To handle parallel requests, it can do this any number of times. (The number of workers depends on how the Rack server is configured.)

When an HTTPS request comes in, the web server passes it to Rack. Rack reformats the request, turning it into a Ruby object that contains all of the relevant information (URL, method, POST data, headers, SSL info). It then passes the formatted request to the application object.

The Puppet master application reads information from the request, then builds a response, doing whatever is necessary to construct it. This may involve returning file contents, returning certificates or other credentials, or the full process of catalog compilation (request a node object from an ENC, evaluate the main manifest, load and evaluate classes from modules, evaluate templates, collect exported resources, etc.). The Puppet master object then formats its response and passes it to Rack, which passes it on to the web server and the agent node that made the request.