Let's start by creating some folders for our Puppet modules and manifests by executing the following commands:
mkdir provision cd provision mkdir modules mkdir manifests
For each of the modules we want to create, we need to create a folder within the provision/modules
folder for the module. Within this folder, we need to create a manifests
folder, and within this, our Puppet manifest file, init.pp
. Structurally, this looks something like the following:
|-- provision | |-- manifests | | `-- vagrant.pp | `-- modules | |-- our module | |-- manifests | `-- init.pp `-- Vagrantfile
Let's take a look at what is involved to install Nginx through a module and manifest file provision/modules/nginx/manifests/init.pp
. First, we define our class, passing in a variable so that we can change the configuration file we use for Nginx (useful for using the same module for different projects or different environments such as staging and production environments), then we need to ensure that the nginx
package is installed:
class nginx ($file = 'default') { package {"nginx": ensure => present }
Tip
Note that we have not closed the curly bracket for the nginx
class. That is because this is just the first snippet of the file; we will close it at the end.
Because we want to change our default Nginx configuration file, we should update the contents of the Nginx configuration file with one of our own (this will need to be placed in the provision/modules/nginx/files
folder; unless the file
parameter is passed to the class, the file
default
will be used):
file { '/etc/nginx/sites-available/default': source => "puppet:///modules/nginx/${file}", owner => 'root', group => 'root', notify => Service['nginx'], require => Package['nginx'] }
Finally, we need to ensure that the nginx
service is actually running once it has been installed:
service { "nginx": ensure => running, require => Package["nginx"] } }
This completes the manifest. We do still, however, need to create a default configuration file for Nginx, which is saved as provision/modules/nginx/files/default
. This will be used unless we pass a file
parameter to the nginx
class when using the module. The sample file here is a basic configuration file, pointing to the public
folder within our synced
folder. The server name of lemp-stack.local
means that Nginx will listen for requests on that hostname and will serve content from our projects folder:
server { listen 80; root /var/www/project/public; index index.php index.html index.htm; server_name lemp-stack.local; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; #fastcgi_pass 127.0.0.1:9000; fastcgi_param SERVER_NAME $host; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; fastcgi_intercept_errors on; include fastcgi_params; } location ~ /\.ht { deny all; } location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ { access_log off; expires max; } location ~* \.svgz { add_header Content-Encoding "gzip"; } }
To install PHP, we need to install a range of related packages, including the Nginx PHP module. This would be in the file provision/modules/php/manifests/init.pp
.
On more recent (within the past few years) Linux and PHP installations, PHP uses a handler called php-fpm
as a bridge between PHP and the web server being used. This means that when new PHP modules are installed or PHP configurations are changed, we need to restart the php-fpm
service for these changes to take effect, whereas in the past, it was often the web servers that needed to be restarted or reloaded.
To make our simple PHP Puppet module flexible, we need to install the php5-fpm
package and restart it when other modules are installed, but only when we use Nginx on our server. To achieve this, we can use a class
parameter, which defaults to true
. This lets us use the same module in servers that don't have a web server, and where we don't want to have the overhead of the FPM service, such as a server that runs background jobs or processing:
class php ($nginx = true) {
If the nginx
parameter is true
, then we need to install php5-fpm
. Since this package is only installed when the flag is set to true
, we cannot have PHP and its modules requiring or notifying the php-fpm
package, as it may not be installed; so instead we need to have the php5-fpm
package subscribe to these packages:
if ($nginx) { package { "php5-fpm": ensure => present, subscribe => [Package['php5-dev'], Package['php5-curl'], Package['php5-gd'], Package['php5-imagick'], Package['php5-mcrypt'], Package['php5-mhash'], Package['php5-pspell'], Package['php5-json'], Package['php5-xmlrpc'], Package['php5-xsl'], Package['php5-mysql']] } }
The rest of the manifest can then simply be the installation of the various PHP modules that are required for a typical LEMP setup:
package { "php5-dev": ensure => present } package { "php5-curl": ensure => present } package { "php5-gd": ensure => present } package { "php5-imagick": ensure => present } package { "php5-mcrypt": ensure => present } package { "php5-mhash": ensure => present } package { "php5-pspell": ensure => present } package { "php5-xmlrpc": ensure => present } package { "php5-xsl": ensure => present } package { "php5-cli": ensure => present } package { "php5-json": ensure => present } }