Automation

Configure Chef Knife, Upload Cookbooks, and Run Recipes

Knife is the command-line tool that connects your Chef Workstation to the Chef Infra Server. It handles everything from uploading cookbooks and managing node run lists to searching indexed data and working with data bags. If you manage infrastructure with Chef, knife is the tool you use daily.

Original content from computingforgeeks.com - post 4125

This guide walks through configuring knife on your workstation, verifying server connectivity, creating and uploading cookbooks, running recipes on nodes, and managing data bags. These steps apply to any supported Linux distribution with Chef Workstation installed.

Prerequisites

Before starting, make sure you have the following in place:

  • A running Chef Infra Server (self-hosted or managed)
  • Chef Workstation installed on your local machine – this provides the knife and chef commands
  • Your user RSA private key (.pem file) downloaded from the Chef Server
  • The Chef Server organization name and URL
  • At least one target node (server) with SSH access for running recipes

Step 1: Configure knife.rb

Knife reads its configuration from a file called knife.rb inside a .chef directory. Start by generating a Chef repo and creating the configuration file.

Generate the Chef repository structure on your workstation:

chef generate repo chef-repo
cd chef-repo
mkdir -p .chef

Copy your user private key into the .chef directory:

cp ~/your-username.pem ~/chef-repo/.chef/

Create the knife configuration file:

vi ~/chef-repo/.chef/knife.rb

Add the following configuration, replacing the values to match your environment:

current_dir = File.dirname(__FILE__)

log_level                :info
log_location             STDOUT
node_name                'admin'
client_key               "#{current_dir}/admin.pem"
chef_server_url          'https://chef-server.example.com/organizations/myorg'
cookbook_path             ["#{current_dir}/../cookbooks"]

Here is what each setting does:

  • node_name – your Chef Server username
  • client_key – path to your RSA private key file
  • chef_server_url – full URL to your Chef Server organization
  • cookbook_path – local directory where knife looks for cookbooks

Prevent the .chef directory from being committed to version control by adding it to .gitignore:

echo '.chef' >> ~/chef-repo/.gitignore

Step 2: Verify Knife Connectivity to Chef Server

Before doing anything else, confirm that knife can communicate with the Chef Server. Run the SSL certificate check first:

knife ssl check

A successful check confirms the SSL certificate is valid and trusted:

Connecting to host chef-server.example.com:443
Successfully verified certificates from 'chef-server.example.com'

If you get a certificate error, fetch the server’s SSL certificate to your trusted certificates directory:

knife ssl fetch

Next, verify authentication by listing registered clients on the Chef Server:

knife client list

You should see the organization validator client and any previously registered nodes:

myorg-validator

If you get an authentication error (401), double-check that node_name in knife.rb matches your Chef Server username and the .pem file is correct.

Step 3: Create a Cookbook

Cookbooks are the fundamental unit of configuration in Chef. Each cookbook contains recipes, templates, files, and metadata that define how a piece of infrastructure should be configured. Generate a new cookbook using the chef generate command:

cd ~/chef-repo/cookbooks
chef generate cookbook my_webserver

This creates a complete cookbook directory structure:

my_webserver/
├── CHANGELOG.md
├── LICENSE
├── Policyfile.rb
├── README.md
├── chefignore
├── compliance
│   └── ...
├── kitchen.yml
├── metadata.rb
├── recipes
│   └── default.rb
└── test
    └── integration
        └── default
            └── default_test.rb

The key files are metadata.rb (cookbook name, version, dependencies) and recipes/default.rb (the default recipe that runs when the cookbook is applied). Review the metadata file to confirm the cookbook name and version:

cat ~/chef-repo/cookbooks/my_webserver/metadata.rb

The output shows the generated metadata with version 0.1.0:

name 'my_webserver'
maintainer 'The Authors'
maintainer_email '[email protected]'
license 'All Rights Reserved'
description 'Installs/Configures my_webserver'
version '0.1.0'
chef_version '>= 16.0'

Step 4: Write a Recipe

Recipes define the resources (packages, services, files, templates) that Chef manages on a node. Open the default recipe file:

vi ~/chef-repo/cookbooks/my_webserver/recipes/default.rb

Add the following recipe that installs Apache HTTP Server, creates a custom index page, and starts the service:

# Install Apache web server
package 'httpd' do
  action :install
end

# Create a custom index page
file '/var/www/html/index.html' do
  content '

Managed by Chef

' mode '0644' owner 'root' group 'root' action :create end # Enable and start Apache service 'httpd' do action [:enable, :start] end

This recipe uses three resource types: package to install software, file to manage file content and permissions, and service to control the daemon. Chef processes resources in the order they appear, so the package installs before the service starts.

For Ubuntu/Debian nodes, replace httpd with apache2 in both the package and service resources.

Step 5: Upload Cookbook to Chef Server

Once the recipe is ready, upload the cookbook to the Chef Server so it becomes available for nodes. Run the upload command from your chef-repo directory:

knife cookbook upload my_webserver

A successful upload confirms the cookbook name and version:

Uploading my_webserver [0.1.0]
Uploaded 1 cookbook.

Verify the cookbook is on the server by listing all uploaded cookbooks:

knife cookbook list

The output shows all cookbooks with their current versions:

my_webserver   0.1.0

Step 6: Add Cookbook to Node Run List

A node’s run list determines which recipes Chef applies during a converge. Before adding a cookbook to the run list, bootstrap the node if it has not been registered with the Chef Server yet:

knife bootstrap 10.0.1.50 --ssh-user root --node-name web01 --run-list 'recipe[my_webserver]'

This command installs chef-client on the target node, registers it with the Chef Server, and sets its initial run list in a single step. If the node is already bootstrapped, add the cookbook to its run list with:

knife node run_list add web01 'recipe[my_webserver]'

Confirm the run list was updated correctly:

knife node show web01

The node details include the current run list and platform information:

Node Name:   web01
Environment: _default
FQDN:        web01.example.com
IP:          10.0.1.50
Run List:    recipe[my_webserver]
Roles:
Recipes:     my_webserver, my_webserver::default
Platform:    rocky 10.0

Step 7: Run chef-client on the Node

With the run list configured, trigger a Chef converge on the node. You can run chef-client directly over SSH:

knife ssh 'name:web01' 'sudo chef-client' --ssh-user root

Chef connects to the server, downloads the cookbooks in the run list, and applies each recipe. A successful run shows the resources that were converged:

web01 Starting Chef Infra Client, version 18.5.0
web01 resolving cookbooks for run list: ["my_webserver"]
web01 Synchronizing Cookbooks:
web01   - my_webserver (0.1.0)
web01 Installing Cookbook Gems:
web01 Compiling Cookbooks...
web01 Converging 3 resources
web01 Recipe: my_webserver::default
web01   * yum_package[httpd] action install
web01     - install version 2.4.62-1.el10 of package httpd
web01   * file[/var/www/html/index.html] action create
web01     - create new file /var/www/html/index.html
web01   * service[httpd] action enable
web01     - enable service service[httpd]
web01   * service[httpd] action start
web01     - start service service[httpd]
web01
web01 Running handlers:
web01 Running handlers complete
web01 Chef Infra Client finished, 4/4 resources updated in 15 seconds

Alternatively, SSH into the node and run chef-client directly:

ssh [email protected] "chef-client"

After the run completes, verify the web server is responding:

curl -s http://10.0.1.50

You should see the custom page content confirming the recipe was applied:

<html><body><h1>Managed by Chef</h1></body></html>

Step 8: Manage Data Bags

Data bags store global JSON data that any cookbook can access. They are useful for storing configuration values like user accounts, API keys, or application settings that should not be hardcoded into recipes. Refer to the official Chef data bags documentation for advanced use cases.

Create a data bag called app_config:

knife data bag create app_config

The server confirms the data bag was created:

Created data_bag[app_config]

Create a JSON file for a data bag item. This example stores database connection details:

vi ~/chef-repo/data_bags/app_config/database.json

Add the following JSON content:

{
  "id": "database",
  "host": "db01.example.com",
  "port": 5432,
  "name": "app_production",
  "user": "app_user"
}

Upload the data bag item to the Chef Server:

knife data bag from file app_config ~/chef-repo/data_bags/app_config/database.json

The upload confirms the item was stored:

Updated data_bag_item[app_config::database]

To read a data bag item in a recipe, use the data_bag_item method:

db_config = data_bag_item('app_config', 'database')
db_host = db_config['host']
db_port = db_config['port']

List all data bags and their items to verify everything is stored correctly:

knife data bag list

This returns all data bags on the server:

app_config

View items inside a specific data bag:

knife data bag show app_config database

The output displays the stored JSON values:

host: db01.example.com
id:   database
name: app_production
port: 5432
user: app_user

For sensitive data like passwords, use encrypted data bags with knife data bag create --secret-file to protect values at rest on the Chef Server.

Step 9: Knife Commands Reference

The table below covers the most commonly used knife commands for day-to-day Chef operations.

CommandDescription
knife ssl checkVerify SSL connectivity to Chef Server
knife ssl fetchDownload and trust the Chef Server SSL certificate
knife client listList all registered API clients
knife node listList all registered nodes
knife node show NODEDisplay node details, run list, and attributes
knife node run_list add NODE 'recipe[COOKBOOK]'Add a recipe to a node’s run list
knife node run_list remove NODE 'recipe[COOKBOOK]'Remove a recipe from a node’s run list
knife cookbook upload COOKBOOKUpload a cookbook to the Chef Server
knife cookbook listList all cookbooks on the Chef Server
knife cookbook delete COOKBOOKDelete a cookbook from the Chef Server
knife bootstrap HOST --node-name NAMEInstall chef-client and register a new node
knife ssh 'name:NODE' 'sudo chef-client'Run chef-client remotely on a node
knife data bag create BAGCreate a new data bag
knife data bag from file BAG FILEUpload a data bag item from a JSON file
knife data bag show BAG ITEMDisplay a data bag item’s contents
knife search node 'platform:rocky'Search nodes by attribute
knife environment listList all Chef environments
knife role listList all defined roles
knife statusShow last check-in time for all nodes

Conclusion

You now have a working knife configuration connected to your Chef Server, a cookbook uploaded and applied to a node, and data bags set up for shared configuration. This covers the core workflow you will repeat for every piece of infrastructure managed by Chef.

For production environments, store your cookbooks in Git and use a CI/CD pipeline to test and upload them. Keep sensitive data in encrypted data bags, rotate your .pem keys periodically, and set up chef-client to run on a scheduled interval (every 15-30 minutes) so nodes stay in the desired state automatically.

Related Articles

Docker How To Install Docker on Fedora 43/42/41/40 Automation How To Setup Chef Infra Server on CentOS 8 / RHEL 8 Automation Upgrading Kubespray Kubernetes Cluster to newer release Jenkins Running Jenkins Server in Docker Container with Systemd

Leave a Comment

Press ESC to close