Chef is a powerful infrastructure-as-code tool for configuration management. Because it offers so many potential configuration options, ops engineers can struggle to know where to begin. This tutorial walks through a minimal but functional Chef setup — installing the Chef Development Kit (Chef DK), writing a simple recipe, and running it using Chef Zero in local mode, all on a single CentOS 7 machine.
Note: This tutorial is based on a TechTarget walkthrough originally published in 2017, using Chef client version 12.18.31 on CentOS Linux 7. Some tooling details (such as Chef DK packaging and commands) may differ in newer Chef versions. Always consult the official Chef documentation for current installation instructions.
Architecture Overview
A complete Chef environment typically consists of three components:
- Chef Server — the central repository for cookbooks, node data, and policy
- Workstation — the machine where you write and upload cookbooks using the
knifeCLI - Managed Nodes — target machines where the Chef client applies configuration
To keep this tutorial self-contained, all three roles run on a single machine. Chef Zero, a lightweight in-memory Chef server included with Chef DK, replaces a full Chef Server for local development and testing.
Step 1: Install Chef Development Kit
Chef DK is a cross-platform package available from the Chef website. It bundles the Chef client, Chef Zero, the knife CLI, and supporting tools such as Test Kitchen and Berkshelf.
- macOS and Windows: Chef DK ships with a graphical installer.
- Linux (CentOS/RHEL): Download the RPM package, install it with
rpmoryum, then verify the installation.
After installation, confirm that Chef is available by checking the version:
chef -v
Configure the Shell Environment
Chef DK installs its own Ruby runtime and tools into an isolated directory. To make them visible in your shell session, initialise the Chef shell environment:
eval "$(chef shell-init bash)"Code language: JavaScript (javascript)
On RHEL/CentOS 7 with Bash, the command above sets the correct PATH and environment variables for the duration of your session. Add it to your ~/.bashrc to make it persistent.
Install Git
Chef repositories are typically managed with Git. Install it with:
yum install git-all -y
No additional Git configuration is required for this tutorial.
Step 2: Generate a Chef Repository and Cookbook
Chef organises configuration instructions into cookbooks, which contain recipes. The chef generate command scaffolds the directory structure for you.
chef generate app myapp --email "yourmail@example.com"Code language: JavaScript (javascript)
This creates a myapp/ directory tree. The default recipe is located at:
myapp/cookbooks/myapp/recipes/default.rbCode language: JavaScript (javascript)
Listing 1: Initial default.rb Content
After generation, the file contains only a header comment block:
#
# Cookbook:: myapp
# Recipe:: default
#
# Copyright:: 2017, The Authors, All Rights Reserved.Code language: PHP (php)
Step 3: Write Your First Recipe
Chef recipes use a Ruby-based DSL built around resources — declarative descriptions of the desired state of a system component. Add the following resource declaration to the end of default.rb:
file '/tmp/cheffile.txt' do
action :create
content 'Chef example file'
endCode language: JavaScript (javascript)
This tells Chef to ensure that the file /tmp/cheffile.txt exists and contains the text Chef example file. If the file does not exist, Chef creates it. If it exists with different content, Chef updates it. This idempotent behaviour is a core principle of Chef configuration management.
Step 4: Run the Recipe with chef-client in Local Mode
From the directory containing default.rb, run:
chef-client --local-mode $(pwd)/default.rbCode language: JavaScript (javascript)
The --local-mode flag tells the Chef client to use Chef Zero as an in-process server rather than connecting to a remote Chef Server. This is ideal for development and testing.
Listing 2: chef-client Output
The output is verbose by design — Chef logs each action it takes. A successful run on CentOS 7 with Chef 12.18.31 produces output similar to the following:
[root@sander recipes]# chef-client --local-mode $(pwd)/default.rb
[2017-04-05T12:47:57+02:00] WARN: No config file found or specified on command line, using command line options.
[2017-04-05T12:47:57+02:00] INFO: Forking chef instance to converge...
Starting Chef Client, version 12.18.31
[2017-04-05T12:47:57+02:00] INFO: *** Chef 12.18.31 ***
[2017-04-05T12:47:57+02:00] INFO: Platform: x86_64-linux
[2017-04-05T12:47:57+02:00] INFO: Chef-client pid: 24793
[2017-04-05T12:48:15+02:00] INFO: Run List is []
[2017-04-05T12:48:15+02:00] INFO: Run List expands to []
[2017-04-05T12:48:15+02:00] INFO: Starting Chef Run for sander.example.com
...
Converging 1 resources
Recipe: @recipe_files::/home/user/Downloads/myapp/cookbooks/myapp/recipes/default.rb
* file[/tmp/cheffile.txt] action create
- create new file /tmp/cheffile.txt
- update content in file /tmp/cheffile.txt from none to 2ccbda
--- /tmp/cheffile.txt 2017-04-05 12:48:15.657202657 +0200
+++ /tmp/.chef-cheffile20170405-24793-wufglh.txt 2017-04-05 12:48:15.655202665 +0200
@@ -1 +1,2 @@
+Chef example file
- restore selinux security context
[2017-04-05T12:48:15+02:00] INFO: Chef Run complete in 0.194898281 seconds
Chef Client finished, 1/1 resources updated in 18 secondsCode language: PHP (php)
Key lines to note:
- “Converging 1 resources” — Chef found one resource to evaluate (the
fileresource). - “create new file /tmp/cheffile.txt” — Chef created the file because it did not previously exist.
- “restore selinux security context” — On SELinux-enabled systems (like CentOS 7), Chef automatically restores the correct SELinux context after creating or modifying files.
- “1/1 resources updated” — All resources were successfully converged.
Step 5: Extend the Recipe — Installing and Starting a Service
Once you are comfortable with the basic workflow, you can manage packages and services. The following recipe snippet installs NGINX and ensures it is enabled and running:
package 'nginx' do
action :install
end
service 'nginx' do
action [:enable, :start]
endCode language: JavaScript (javascript)
Add these blocks to default.rb after the file resource and re-run chef-client --local-mode. Chef will install NGINX via yum on CentOS 7, enable the systemd unit, and start the service — in a single idempotent run.
Moving to a Production Chef Environment
Local mode with Chef Zero is intended for development and learning. A production Chef environment requires a Chef Server to manage multiple nodes, store cookbooks centrally, and handle authentication via SSL certificates. You have two primary options:
- Self-hosted Chef Server: Install and operate a Chef Server on your own infrastructure (on-premises or in a private cloud).
- Chef SaaS / Hosted Chef: Use Progress Chef’s hosted offering, where you create an account, upload cookbooks with
knife cookbook upload, and register nodes against the hosted endpoint.
Major public cloud providers, including AWS and Microsoft Azure, also offer marketplace integrations and managed Chef Server options to simplify infrastructure management at scale.
Summary
This tutorial covered the essential steps to get started with Chef configuration management on a single CentOS 7 machine:
- Install Chef DK and configure the shell environment.
- Install Git and generate a Chef repository with
chef generate app. - Write a simple
fileresource in a recipe’sdefault.rb. - Execute the recipe with
chef-client --local-modeand validate the output. - Extend the recipe to manage packages and services (NGINX example).
From here, explore attributes, templates, data bags, and roles to build production-grade cookbooks. The Chef documentation is the authoritative reference for all these concepts.