In this article, I want to guide you to install and set up a Puppet server for those who are new to Puppet. For those who don’t know what Puppet is, Puppet is a configuration management tool that helps you manage and automate the configuration of servers. The Puppet team has a very good document here, you can have a look through it.
Before setting up Puppet, I want to discuss why we need it and its use case. If you are familiar with the concept of Puppet, you can jump straight to Puppet’s documentation to see the installation instructions.
The old configuration way
When it comes to managing a large number of servers at scale, you might encounter a situation where you need to deploy a change to these servers. E.g. add a user to a machine. The manual way is to log in to each server and run the adduser command.

That’s fine if you just have a few servers, but if you have 100, 500, or 1000 servers? It becomes a nightmare and inefficient if you do it manually.
The next approach (scripting):
The next level is to use scripting, which is faster but requires us to have a deep understanding of the scripting language we use. For example, Bash or Python, etc. You can automate the commands in the script to access each server and do the job for you.

However, when you have a system with multiple OS platforms, running a script requires you to understand the command lines of each OS so that you can adjust the commands in the script to make it work on the OS you’ve run the script. That becomes inefficient and is likely to cause trouble when rolling out changes to servers.
Automate configuration management.
With that being said, we have a couple of tools to automate configuration management for servers without relying on scripting. In the market at the moment, I can find the three most popular tools, which are Ansible, Puppet, and Chef. In a nutshell, Ansible is agentless, suitable for fast deployment through SSH, while Chef and Puppet are agent-based, meaning you have to install agent on each server, and they are suitable for large-scale, ensuring the entire system is in a desired state.
Each tool has its own pros and cons. It depends on your organisation’s requirements. You can easily find information on Google. Here, I want to mention the Puppet Configuration Management Tool.
With the requirement of adding a user above, we can do this by writing infrastructure as code in Puppet’s Domain-Specific Language (DSL) – known as Puppet code. For example
user { 'binh':
ensure => present,
}With Puppet automation, you don’t need to know either the different commands according to each OS or do it manually. You just need to execute the code through puppet-agent (we will dive in deeply later) by setting up crontab to run and let it execute code for you every time you add new codes on puppet-master. There might be a case where you need to delete the created user. You just need to change the code on puppet-master to:
user { 'binh':
ensure => absent,
}At the next crontab run, it will automatically delete the created user for you.
Puppet Architecture

Execution Flow:
- Facts: is the agent’s current configuration information. Agents send “Facts” to the Puppet Master. Puppet Agent uses Facter command internally – a system inventory tool – to gather information about servers (e.g. IP address, Hostname, FQDN, networking, etc.). Facter returns a list of key-value pairs for information which are called “Facts”.
- Catalogs: Once Puppet Master receives Agents’ Facts, it uses agent’s current configuration information as built-in variables and combines with Puppet Code that we write. Next, it compiles them into a “Catalog” that specifies how the agent should be configured. Then, it compares the received Facts with the definition configuration in the Catalog. Finally, Puppet master sends Catalog back to agents (on each server) to execute the state based on Catalog to maintain idempotency – known as consistency, maintaining between the desired state and the running state.
- Reports: After receiving the Catalog from Puppet Master, Puppet Agent executes or applies the desired configuration based on the Catalog. During the whole process, the Agent reports back to the Master, indicating configuration has been applied and completed.
Puppet Terminologies

# An small example of module structure for Puppet:
.
├── data
├── environment.conf
├── hiera.yaml
├── manifests # A directory contains .pp files
│ ├── init.pp # Contain Classes And Resources
│ └── site.pp # Contain Classes And Resources
└── modules # Contains collections of Manifests and Classes, Resources
Explanations :
- Resources : are in-built functions that run at the back end to perform underlying operations in Puppet. Look at the example of creating a user above,
user {}is a resource function called “user”. Similarly, we have other types such asfile,group,package, etc. Check it out here to know more about resource types. - Class : is a combination of different resources and operations that can be grouped together into a single unit. See example below
class base::linux { # here is a class that includes multiple resources
user { 'binh': # here is a resource - called User resource
ensure => present,
}
file { '/etc/passwd': # here is another resource - called File resource
owner => 'root',
group => 'root',
mode => '0644',
}
file { '/etc/shadow': # here is another File resource again
owner => 'root',
group => 'root',
mode => '0440',
}
}- Manifest : is a directory containing puppet DSL files with a
.pp(stands for puppet program) extension. The .pp files consist of definitions or declarations of Puppet Classes. For example, we put all the Class declarationsbase::linuxabove into a file, e.g.site.pp. Like other classes, we put classes into corresponding.ppfiles, like the classuser::installinto users.pp file, so on - Modules : are a collection of files and directories, such as Manifests, Class definitions and any other dependent files that work together and follow a specific directory structure.
Puppet Installation
The Puppet installation process is straightforward and the same on all Ubuntu versions. I’m using Ubuntu 24.04 to install Puppet 8, but Puppet 8 works with previous Ubuntu versions from 18.04 onwards as well. For other Linux distros, please consult Puppet’s documentation here.
NOTE: At the time of this writing, Puppet has been acquired by Perforce. Therefore, Perforce no longer develops or supports open source Puppet, and since January of 2025, they have started launching a Puppet Core (open core), which still allows us to run up to 25 nodes for free, but will charge if we use more.
I’m the one who advocates Open Source, and fortunately, Puppet community started forking the Puppet project under a new name OpenVox – is fully Puppet compatible, all the commands and code are the same, they’re just currently installed under different packages:
- puppet-agent -> openvox-agent
- puppetserver -> openvox-server
- puppetdb -> openvoxdb
Therefore, in this article, we’ll use OpenVox instead (I’ll still call it Puppet for consistency). If you prefer to use Puppet Core, you can refer to the documentation here, it’s pretty straightforward.
Systems Requirements:
- 2 x Ubuntu 24.04 – Master & Agent
- 2-4 processor cores (for master), agent needs at least 1 core.
- 3GB RAM and above (for master), agent needs at least 512MB.
- sudo access
| Hostname | IP address | Role |
| puppet-master.srv.local | 192.168.68.117 | Puppet Server |
| web-01.srv.local | 192.168.68.116 | Puppet Agent |
Step 1: Set up hostnames on both machines
Note: if you want to have local DNS server so that you won’t have to edit each machine in this way – please check out How to Set Up a Local DNS Server with Dnsmasq in Ubuntu 24.04 (Fast & Easy) to facilitate your testing.
We need to set hostname for each server so that they can communicate through the hostname without using IP directly.
On each machine, open /etc/hosts by command sudo nano /etc/hosts and add the following content (Change the IPs according to your machine):
192.168.68.117 puppet-master.srv.local puppet-master
192.168.68.116 web-01.srv.local web-01
Press Ctrl + O and press Enter to save the content. Then press Ctrl + X to exit.
To test the connection, we ping each other. The result should look like

Step 2: Install Puppetserver on puppet-master server (master node):
Optional: If you are using old Puppet versions (before 8.10 version – inclusive), they’re still under Open Source, so we can download at https://apt.puppet.com/. I’ll recommend that we start using OpenVox instead. Please check it here to view OpenVox downloads and the installation guide for more details.
The master node, also known as the Puppet Server, manages configuration policies and distributes them to client nodes (agents). It compiles manifests into a Catalog, which defines the desired system state and ensures that agents apply the correct configurations.
1. Install and set up Puppetserver
On the puppet-master server, run the following command to install and set up Puppetserver:
# Download openvox package to enable Openvox repositories
wget https://apt.voxpupuli.org/openvox8-release-ubuntu24.04.deb
# Enabling openvox repositories
sudo dpkg -i openvox8-release-ubuntu24.04.deb
# Update new repository
sudo apt update
# Install openvox-server package (contains puppetserver), this package will lead to install openvox-agent (contain puppet-agent) as dependency as well.
sudo apt install openvox-server -y
# Start and enable puppetserver service
sudo systemctl start puppetserver.service
sudo systemctl enable puppetserver.service
If you install correctly, you will have a similar result when running sudo systemctl status puppetserver.service:

2. JVM Memory Allocation (optional)
By default, puppetserver uses 2GB of RAM. If you want to run it on a VM with lower memory for an experiment, you could adjust this setting by editing file: nano /etc/default/puppetserver. It will show content like this

Changes JAVA_ARGS="-Xms2g -Xmx2g..." to JAVA_ARGS="-Xms1g -Xmx1g..." (or to the amount you want to allocate). Press Ctrl + O and press Enter to save the content. Then press Ctrl + X to exit.
Restart puppetserver service to make the new setting take effect:
sudo systemctl restart puppetserver.service
3. Configure puppetserver
To make this demo simple, set the values for dns_alt_names, server name, and ca_server.
Run sudo nano /etc/puppetlabs/puppet/puppet.conf and add the following content
[server]
server = puppet-master.srv.local
ca_server = puppet-master.srv.local
vardir = /opt/puppetlabs/server/data/puppetserver
logdir = /var/log/puppetlabs/puppetserver
rundir = /var/run/puppetlabs/puppetserver
pidfile = /var/run/puppetlabs/puppetserver/puppetserver.pid
codedir = /etc/puppetlabs/code
dns_alt_names = puppet-master,puppet-master.srv.localPress Ctrl + O and press Enter to save the content. Then press Ctrl + X to exit. You’ll have the config look like:

Where:
- server: is the primary Puppet server to which the Puppet agent should connect.
- ca_server: The server to use for certificate authority requests, basically means that when the agent connects to the Puppet server, it sends a certificate request to the CA server, and the CA server has to sign this certificate so that the agent is authorised at the next run. It’s a separate server because it cannot and does not need to horizontally scale. In this demo, we’re using puppet-master server itself as a CA server. In reality, you could set it up separately if you need it for your own purpose.
- dns_alt_names: A comma-separated list of alternate DNS names for Puppet Server. These are extra hostnames (in addition to its
certname) that the server is allowed to use when serving agents.
For more information about the setting parameters, please view here.
Restart puppetserver service : sudo systemctl restart puppetserver.service
Noted: Before continuing to the next step, if you want to enable the Intermediate CA for Puppet, you can refer to this Enabling Puppet Intermediate CA for Enhanced Security blog for more information. By default, Puppet use a simple CA architecture to sign the requests sent from Puppet Agents. If you’re not interested in the Intermediate CA, feel free to continue setting up.
Step 3: Install Puppet Agent on web-01 server
1. Install Puppet Agent on web-01 server
On web-01 server, similar to puppet-master, we run the following command to install Puppet Agent:
# Download openvox package to enable Openvox repositories
wget https://apt.voxpupuli.org/openvox8-release-ubuntu24.04.deb
# Enabling openvox repositories
sudo dpkg -i openvox8-release-ubuntu24.04.deb
# Update new repository
sudo apt update
# Install puppet agent package
sudo apt install openvox-agent -y
2. Configure Puppet Agent to connect to Puppet Server
Run sudo nano /etc/puppetlabs/puppet/puppet.conf and add the following content
[main]
server = puppet-master.srv.local
certname = web-01.srv.localPress Ctrl + O and press Enter to save the content. Then press Ctrl + X to exit. You’ll have config file as result:

Run the following commands to generate certificates from your puppet agent(s) for the puppet master to sign:
sudo /opt/puppetlabs/bin/puppet agent -t
At this step, you just generated an agent’s certificate for web-01.srv.local. But the CA server hasn’t approved yet, we need to sign this request on the puppet-master server

On puppet-master, run this command to list all requested certificates:
sudo /opt/puppetlabs/bin/puppetserver ca list
Output:

Now, we need to sign the Puppet Agent’s hostname to approve the request. In here is web-01.srv.local
sudo /opt/puppetlabs/bin/puppetserver ca sign --certname web-01.srv.local
Output:

We go back web-01 server and run the puppet command again to verify the certificate is signed
sudo /opt/puppetlabs/bin/puppet agent -t
We will have the result below:

Optional: We can also enable basic autosigning, but I wouldn’t recommend this because it’s insecure. If your computers are in a fully trusted environment, it’s probably fine to use this autosigning or unless you know what you’re doing.
Puppet looks for autosign.conf at $confdir/autosign.conf by default, $confdir is located in /etc/puppetlabs/puppet.
We run sudo nano /etc/puppetlabs/puppet/autosign.conf and add the fully domain name that you want to allow to connect to Puppet Server, for example:
web-01.srv.local # allow an exact match of a domain name
*.srv.local # allow any domain with tail is .srv.local
*.localPress Ctrl + O and press Enter to save the content. Then press Ctrl + X to exit. Then we go back web-01 server to run sudo /opt/puppetlabs/bin/puppet agent -t as usual without performing ca signing process on puppet-master server.
Note: there’s a high secure level of autosigning by using custom policy executables – a policy-based autosigning interface provided by Puppet. It’s more complex to configure. If you’re interested, I’ve written A Guide to Policy-Based Autosigning in Puppet to walk you through a basic implementation.
Step 4: Testing package installation on web-01 server through Puppet
We need to verify whether we can configure the web-01 server with Puppet. I’ll specify Nginx installation in Puppet code to tell Puppet Agent what to install.
On puppet-master server, create a file:
sudo nano /etc/puppetlabs/code/environments/production/manifests/init.pp
Add the following content:
class nginx {
# Instruct puppet to install Nginx package
package { 'nginx':
ensure => installed,
}
# Instruct puppet to start/enable Nginx service only if nginx package is installed successfully
service { 'nginx':
ensure => true,
enable => true,
require => Package['nginx'],
}
}Press Ctrl + O and press Enter to save the content. Then press Ctrl + X to exit.
Create /etc/puppetlabs/code/environments/production/manifests/site.pp to tell which node should use class nginx {} declared above.
sudo nano /etc/puppetlabs/code/environments/production/manifests/site.pp
Add the following content:
node 'web-01.srv.local' {
include nginx
}
# If you have more than one web server nodes, can add another node like below, and so on.
node 'web-02.srv.local' {
include nginx
}Again, press Ctrl + O and press Enter to save the content. Then press Ctrl + X to exit
Go back web-01 server, and run sudo /opt/puppetlabs/bin/puppet agent -t command, we will have the result below:

Run sudo systemctl status nginx.service to check whether Nginx service is started as instructed in the Puppet code.

Access http://192.168.68.116 to verify Nginx site is working

In this way, you can include multiple classes that a web server needs. When you relaunch a web server, Puppet ensures your new web server will have all the setup and installations that the old one had.
Ok. We’ve completed the Puppet 8 setup. To learn more about Puppet, please explore Puppet’s documentation to understand how to manage servers and infrastructure configuration. I also wrote a blog Mastering Puppet: Implementing Roles and Profiles Effectively in Reality to help you design your Puppet structure effectively in a real project. Hope you enjoy using Puppet.
If you like my blog post and want to find a way to thank me, feel free to Buy me a coffee to support me in providing more quality content, or simply share it with others who may have the same issue. Thanks for reading my blog.
Discover more from Turn DevOps Easier
Subscribe to get the latest posts sent to your email.

