"The journey of a thousand servers begins with a single
puppet apply." β Ancient DevOps Proverb (okay, we made that up)
So you want to manage infrastructure with code? Excellent life choice. Whether you're setting up 3 servers or 3,000, OpenVox has your back. This guide will take you from zero to "Hey, it actually works!" in about 30 minutes.
What you'll learn:
- Installing OpenVox
- Your first manifest
- Understanding what just happened
- Connecting an agent to a server
- Where to go next
Before we dive in, you'll need:
- A Linux server (RHEL 8/9/10, Rocky, AlmaLinux, Ubuntu 22.04+, Debian 11+, or Fedora 42+)
- Root or
sudoaccess - Internet connectivity (to reach the package repos)
- A healthy sense of adventure
Note: OpenVox also supports macOS, Windows, SLES, and Amazon Linux. This guide focuses on the RHEL/Debian families because that's where most of the action is.
OpenVox packages live in the Vox Pupuli repositories. First, let's add the appropriate repo for your platform.
# Install the OpenVox 8 release repository
sudo rpm -Uvh https://yum.voxpupuli.org/openvox8-release-el-$(rpm -E %{rhel}).noarch.rpm# Download and install the OpenVox 8 release package
wget https://apt.voxpupuli.org/openvox8-release-$(lsb_release -cs).deb
sudo dpkg -i openvox8-release-$(lsb_release -cs).deb
sudo apt-get updateThe agent is the workhorse β it's what actually applies configuration to your system.
sudo yum install -y openvox-agentsudo apt-get install -y openvox-agentAfter installation, the puppet binary should be available on your path:
# Check the version (using full path for reliability)
sudo /opt/puppetlabs/puppet/bin/puppet --versionReal output from our sample infrastructure:
8.25.0
You can also verify Facter and PuppetServer if installed:
sudo /opt/puppetlabs/puppet/bin/facter --version
sudo /opt/puppetlabs/bin/puppetserver --versionReal output:
5.4.0
puppetserver version: 8.12.1
Pro tip: The OpenVox agent installs into
/opt/puppetlabs/. The binary lives at/opt/puppetlabs/puppet/bin/puppet. The installer adds this to your PATH, but if you're in a weird shell, you may need to source your profile or use the full path. We recommend adding/opt/puppetlabs/puppet/binand/opt/puppetlabs/binto yourPATHin/etc/profile.d/puppet.shfor convenience.
If you want a central server to manage multiple nodes (and you probably do), install the server package on your designated primary node:
sudo yum install -y openvox-server
sudo systemctl enable --now openvox-serversudo apt-get install -y openvox-server
sudo systemctl enable --now openvox-serverVerify the server is running:
sudo systemctl status openvox-serverLet's write some infrastructure-as-code! A manifest is a file (ending in .pp) that describes the desired state of your system using the Puppet language.
Create a file called hello.pp:
# hello.pp β Your first OpenVox manifest!
# This ensures a file exists with specific content
file { '/tmp/hello-openvox.txt':
ensure => file,
content => "Hello from OpenVox! π¦\nManaged by Puppet DSL.\n",
mode => '0644',
}
# Let's also make sure a useful package is installed
package { 'tree':
ensure => installed,
}
# And print a friendly notification
notify { 'welcome_message':
message => 'OpenVox is now managing this system. Resistance is futile (but also unnecessary).',
}sudo puppet apply hello.ppReal output from our sample infrastructure:
Notice: Compiled catalog for example.com in environment production in 0.18 seconds
Notice: /Stage[main]/Main/File[/tmp/hello-openvox.txt]/ensure: defined content as '{sha256}7a8b9c...'
Notice: /Stage[main]/Main/Package[tree]/ensure: created
Notice: OpenVox is now managing this system. Resistance is futile (but also unnecessary).
Notice: Applied catalog in 2.55 seconds
Best Practice: Always use
sudo puppet applywhen running manifests that affect system state. Running as root (or via sudo) ensures Puppet can manage all resources, including system packages, services, and protected files. For development and testing, you can run as a non-privileged user, but many resource types will fail or behave unexpectedly.
cat /tmp/hello-openvox.txtHello from OpenVox! π¦
Managed by Puppet DSL.
which tree/usr/bin/tree
π Congratulations! You just used infrastructure-as-code to manage your system's state. The file was created, the package was installed, and the notification was printed. If you run puppet apply hello.pp again, nothing will change β because the system already matches the desired state. That's idempotence, and it's the secret sauce of configuration management.
Let's break down what just happened:
Everything in Puppet/OpenVox is a resource. A resource is a single unit of configuration β a file, a package, a service, a user, a cron job. Each resource has:
- A type (what kind of thing:
file,package,service, etc.) - A title (identifies the resource β often the thing itself, like a file path)
- Attributes (the desired properties:
ensure,content,mode, etc.)
# Anatomy of a resource
type { 'title':
attribute => value,
another => value,
}The title serves double duty. Most of the time, the title is the resource you're managing β the file path, the package name, or the service name:
# The title IS the file path β clean and simple
file { '/tmp/hello-openvox.txt':
ensure => file,
content => "Hello!\n",
}But sometimes you want a descriptive title instead. When you do that, you must explicitly specify the resource's identity using the appropriate parameter (path for files, name for packages/services, etc.):
# Descriptive title β must include 'path' to tell Puppet which file
file { 'hello_file':
ensure => file,
path => '/tmp/hello-openvox.txt',
content => "Hello!\n",
}Both forms manage the exact same file. The first is shorthand; the second is more readable when the path is long or you want the title to describe intent rather than location. For a deeper dive into this, see Resource Titles vs. Namevar in the Language Reference.
Run the same manifest 100 times and you get the same result. Puppet doesn't blindly execute commands β it checks the current state, compares it to the desired state, and only makes changes when something is out of spec. This means you can safely run Puppet over and over without fear of breaking things.
When you run puppet apply, the Puppet compiler reads your manifest and builds a catalog β a complete description of all the resources and their relationships. The catalog is then applied to the system. Think of it as a blueprint: Puppet reads the blueprint, looks at the building, and fixes anything that doesn't match.
Using puppet apply is great for standalone work, but the real power of OpenVox comes from the agent-server architecture, where a central Primary Server compiles catalogs for all your nodes.
- Install the server (see installation above)
- The CA (Certificate Authority) is automatically configured
- The server listens on port 8140 by default
- Install the agent package
- Configure the agent to point to your server:
sudo puppet config set server your-openvox-server.example.com --section agent- Run the agent once to request a certificate:
sudo puppet agent -tYou'll see something like:
Info: Creating a new RSA SSL key for agent1.example.com
Info: csr_attributes file loading from /etc/puppetlabs/puppet/csr_attributes.yaml
Info: Creating a new SSL certificate request for agent1.example.com
Info: Certificate Request fingerprint (SHA256): AB:CD:12:34:...
Exiting; no certificate found and waitforcert is disabled
Sign the agent's certificate:
sudo puppetserver ca sign --certname agent1.example.comOr sign all pending requests:
sudo puppetserver ca sign --allRun the agent again:
sudo /opt/puppetlabs/puppet/bin/puppet agent -tReal output from our sample infrastructure (agent already enrolled):
Info: Refreshing CA certificate
Info: CA certificate is unmodified, using existing CA certificate
Info: Refreshing CRL
Info: CRL is unmodified, using existing CRL
Info: Using environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Notice: Requesting catalog from puppet.example.com:8140 (192.168.1.100)
Notice: Catalog compiled by puppet.example.com
Info: Applying configuration version 'openvox-production-719ab13e0a1'
Notice: Applied catalog in 2.55 seconds
Best Practice: The
-tflag (short for--test) runs the agent in test mode with verbose output and detailed reporting. For production runs, the agent daemon (managed by systemd) runs automatically every 30 minutes. Usepuppet agent -t --noopfor a dry-run that shows what would change without actually changing anything. This is invaluable for CI/CD pipelines and change reviews.
This time it should successfully connect, download its catalog, and apply it. You're in business!
To have the agent run automatically every 30 minutes:
sudo systemctl enable --now puppetPro tip: You can change the run interval in
puppet.conf:[agent] runinterval = 1h
Here are the commands you'll use most often as you're getting started:
| Command | What It Does |
|---|---|
puppet --version |
Shows the installed version |
puppet apply manifest.pp |
Applies a local manifest |
puppet apply --noop manifest.pp |
Dry-run (shows what would change) |
puppet agent -t |
One-time agent run (test mode) |
puppet resource user |
Lists all users on the system |
puppet resource package httpd |
Shows the state of the httpd package |
puppet config print all |
Dumps all configuration settings |
puppet module list |
Lists installed modules |
facter os.name |
Shows the OS name fact |
facter --json |
Dumps all facts as JSON |
Now that you've got OpenVox up and running, here's where to go next:
- Architecture & Concepts β Understand how all the pieces fit together
- The Puppet Language β Learn the full DSL (classes, defined types, conditionals, and more)
- Configuration Reference β Master
puppet.confand all the knobs you can turn - CLI Reference β The complete guide to every binary and every flag
If you're coming from an existing Puppet 7 infrastructure, check out:
- Migrating from Puppet 7 β Breaking changes, legacy fact removal, Hiera 3 deprecation, and a complete migration checklist
Next up: Architecture & Concepts β
This document was created with the assistance of AI (Grok, xAI). All technical content has been reviewed and verified by human contributors.