Installing and Utilizing CFEngine Community Edition on Ubuntu 20.04

CFEngine is an adaptable configuration management solution designed for your IT infrastructure. It empowers you to effortlessly manage all aspects of your infrastructure, including Linux, Mac, Windows, BSD, Solaris, IBM AIX, HP-UX, and various other platforms, using a single tool and policy language. Simply installing a C-written agent on each machine grants you the ability to control and monitor diverse environments. Whether you have a resource-intensive infrastructure or limited Internet of Things (IoT) devices, CFEngine is the ideal choice as it supports numerous platforms and is tailor-made for such scenarios.

You will be guided through the process of installing CFEngine Community Edition 3.21 on Ubuntu 20.04, creating example policy files, and automating your policy executions in this tutorial.


In order to finish this tutorial, you will require:

  • One Ubuntu 20.04 server with a non-root sudo user. To set this up, follow our guide Initial Server Setup with Ubuntu 20.04.
  • A way of running shell commands (including sudo), such as ssh.
  • A text editor. This tutorial uses nano.

First Step — CFEngine Installation

In this stage, you will be able to install CFEngine by utilizing apt along with the package repositories. The key benefit of employing apt for installation purposes is that it allows you to conveniently update CFEngine in the future.

There are alternative methods of installing CFEngine that can cater to various scenarios.

  • cf-remote is a flexible choice that handles installing on multiple machines, different versions of CFEngine, and nightly builds.
  • The quick-install shell script is a good choice for a single machine. You can install by copying a single command into the terminal.
  • You can also download the packages directly from the website.

If you choose to use any of these options to install CFEngine Community or Enterprise, you can either proceed to Step 2 and start CFEngine after installing, or go directly to Step 3 and create your first policy after bootstrapping.

Including the public key of CFEngine

In order to install CFEngine through apt, apt must have access to the repository. The initial action is to include the CFEngine public GPG key in the apt key collection, ensuring that apt can trust the packages obtained from the repository.

Obtain the key by using this command.

  1. wget -O ~/cfengine-gpg.key


After that, utilize apt-key to include it.

  1. sudo apt-key add ~/cfengine-gpg.key


Including the Package Repositories offered by CFEngine

Afterwards, you have to include the CFEngine repository as an apt source by executing the subsequent command:

  1. sudo sh -c “echo ‘deb stable main’ > /etc/apt/sources.list.d/cfengine-community.list”


This instruction appends the CFEngine repository to a file located in the directory for apt sources list.

If the sh argument and -c option are not included, executing this command would result in a Permission denied error since sudo does not handle the output redirection. To overcome this problem, you can employ sh to run a shell with sudo and pass the command using the -c option.

Go ahead and use the update command which will allow apt to recognize the fresh packages available in the CFEngine repository.

  1. sudo apt update


Installing the Package using apt

Now that the CFEngine package has been added to the apt registry, you have the option of installing CFEngine using apt.

  1. sudo apt install cfengine-community


You may disregard any warnings regarding the package being developed on an older operating system. It is still functional.

Confirming the Installation

After the installation is finished, you can find the CFEngine components in /var/cfengine/bin. Among them, the agent (cf-agent) is the primary one with which you will mainly interact. This executable assesses the policy you create, modifies the system accordingly, and keeps a record of its actions. By default, the agent will activate every five minutes, retrieve any updated policy if needed, and apply it.

Make use of the given command to ensure that the agent has been installed successfully.

  1. sudo cf-agent –version


The screen will display the printed version number.


CFEngine Core 3.21.0


Please note that the current version is 3.21.0 as of now. Your version number might be different.

If you are unable to run the cf-agent command, make sure to verify if /var/cfengine/bin/ is included in your PATH variable and if cf-agent exists in that specific directory. Additionally, you can examine the installation log file located at /var/log/CFEngine-Install.log to get some insights into any potential issues that occurred during the installation process.

Step 2 involves commencing CFEngine.

To initiate CFEngine, you must bootstrap the agent by executing the provided command.

  1. sudo cf-agent –bootstrap


The specified instruction instructs the agent to initiate the CFEngine elements and obtain the policy from this particular device with the IP address

In the coming days, you may need multiple machines to retrieve policy from a shared server. At that time, you will replace the IP address with the actual IP address of the server. However, for now, while you are getting started with CFEngine and learning, you will use just one machine and the IP address as described in this tutorial.

After successfully setting up CFEngine on your server, it’s time to begin creating your policy.

Step 3 involves the creation of your initial policy.

To automate a task in system administration with CFEngine, you’ll need to generate a policy file. This file is specifically written in CFEngine’s own Domain Specific Language (DSL). If you want to understand the capabilities and structure of this policy language, refer to the CFEngine reference documentation.

Policy files are different from scripts because they work in a declarative manner. By describing the desired state for the system, CFEngine will evaluate if it is already fulfilled and will only make alterations if required. Instances of what you might want to express in policy include:

  • Ensure the user sammy exists.
  • Keep the curl package updated (and installed).
  • Ensure telnet is not installed.
  • Render a script file from a template and some data.
  • Stop a process, like httpd, if it’s running.
  • Enforce strict permissions on the /usr/bin folder.

For each of these instances, you need to create a policy and save it in the appropriate location on your server (/var/cfengine/masterfiles). Afterward, CFEngine will execute the policy.

  • Automate distribution of the policy file by transferring it to your other bootstrapped hosts.
  • Enforce your requirements regularly (running the policy every five minutes by default). For example, if someone deleted the user sammy, or changed the permissions on /usr/bin, these changes would be restored automatically within five minutes.
  • Only make changes, such as writing to a file, if it’s necessary (that is, if the state is not already as desired).
  • Handle many platform differences for you (for example, the commands used to install packages, create users, and other operations vary depending on the operating system).

In this stage, you will generate a policy called “Hello World” that will display the text “Hello!” on the terminal.

Create a new file named “” in your home directory using either nano or your preferred text editor.

  1. nano ~/


To the document, include the subsequent information.

“” file in the home directory.
bundle agent main

CFEngine policy is not evaluated from top to bottom; rather, it is declarative in nature.

In CFEngine policy language, a promise refers to each statement made about the managed aspect. Organized into bundles, promises offer the flexibility to selectively run different parts of the policy and determine their order of execution.

In this policy, “reports” is a type of commitment that is in charge of displaying the message on the terminal. When “agent” is mentioned after “bundle,” it indicates that this bundle is intended for the cf-agent component. The bundle is named “main.” The bundle sequence determines the order in which bundles are assessed. By default, it already includes the main bundle, so there is no need to make any modifications.

To save and exit the file, employ nano and press CTRL+X to exit. Then, press Y to save and ENTER to confirm the filename, ultimately closing the file.

Because CFEngine usually operates as the root user, it aims to prevent unauthorized system alterations by enforcing strict permissions on policy files. Allowing other users to modify the policies that CFEngine uses would grant them the ability to make privileged changes to the system. To prevent this, you can utilize chmod to modify the file permissions and ensure that only specific users are able to edit this file.

  1. chmod 600


To execute the policy, employ the subsequent command.

  1. sudo cf-agent ~/


The CFEngine agent locates your bundle by recognizing its main name. Subsequently, the agent examines the promises within the bundle and assesses them. During the evaluation of promises, the agent verifies if any system modifications are required. In this scenario, there was only one promise, and the agent concluded that it should display a message on the terminal to fulfill it.

You will get the output as stated below.


R: Hello!

CFEngine has a default setting where it maintains a record of actions performed and avoids reassessing promises that were evaluated recently (within the past minute). If you attempt to execute the policy again, no output will be displayed. To deactivate this locking mechanism, you can utilize the –no-lock command line option.

  1. sudo cf-agent –no-lock


After successfully creating and implementing your initial policy, it appears that it only facilitates console output without modifying the system itself. However, the upcoming phase will involve making those necessary changes.

Step 4 involves creating a policy to effectively handle the content within a text file.

In the previous phase, you developed a policy which involved displaying a message on the terminal. Nonetheless, if we consider a more practical scenario, it would be to guarantee the existence of a file with certain content on every host within your infrastructure. In this stage, you will generate a policy that generates a text file (/tmp/my_file.txt) containing the words Hello, CFEngine!.

Please create a new policy file at the location ~/

  1. nano ~/


Include the provided information.

The cf file for managing files in the specified directory.
bundle agent manage_my_file
      content => "Hello, CFEngine!$(const.n)";

Instead of naming the bundle as “main”, it should be called “manage_my_file”. It is advisable to assign distinct and meaningful names to each bundle as you continue to write policies. Remember, there can only be a single main bundle.

Since this policy deals with files, it has a promise type of files. For file promises, the attribute content specifies the expected content of the file. The final section of the string, $(const.n), expands the special variable const.n, resulting in the addition of a new line at the file’s end.

Please save and exit the file.

Just like before, establish the policy file’s stringent permissions.

  1. chmod 600


Please execute the file while including some extra command line options.

  1. sudo cf-agent –no-lock –info ~/ –bundle manage_my_file


In order to manage my file, it is essential to specify the bundle using –bundle manage_my_file as there is no longer a primary bundle.

When using the –info option, CFEngine will provide informational notifications regarding the modifications it is implementing on the system.

The changes will be described in the output of this command.


info: Using command line specified bundlesequence info: Created file ‘/tmp/my_file.txt’, mode 0600 info: Updated file ‘/tmp/my_file.txt’ with content ‘Hello, CFEngine!

CFEngine successfully generated my_file.txt in the /tmp folder, containing the message Hello, CFEngine!.

If you execute the same command once more, you will no longer see any notifications regarding the file creation or update. CFEngine understands that the file’s contents are already accurate and doesn’t make any alterations.


Note: When creating and testing policy files, it is common to use –no-lock and –info together. To simplify the process, shortcuts are available, such as -KI, which is the same as using –no-lock –info.

After creating a functional system policy, you may wish to run it independently without needing your oversight. This will be carried out in the upcoming phase.

Step 5 involves the automation of policy runs.

Using CFEngine’s automation features can save you from the hassle of manually executing policy via the command line constantly.

You can achieve automation of policy runs by placing your policy files in the designated location and making updates to a JSON file. This JSON file will regularly instruct the CFEngine component to perform tasks in the background, eliminating the need for you to manually run commands from the command line.

To copy the policy file you made in the previous step, use the given command and move it to the suggested destination.

  1. sudo cp /var/cfengine/masterfiles/services/


It is advised to store your custom policy files in the services/ subdirectory within /var/cfengine/masterfiles/ in order to keep them distinct from the default CFEngine policy, which includes policy not authored by you.

When the CFEngine agents retrieve new policy files, they duplicate them from this directory on the hub. Even if you are only operating on one machine, the agent operates similarly: it will search for files in /var/cfengine/masterfiles and duplicate them to /var/cfengine/inputs. For beginners, it is advisable to utilize these paths. Modifying the paths or placing policy files in different locations would necessitate additional effort to guarantee that permissions, copying, and file location are all handled accurately.

Afterwards, generate a JSON file that augments the policy file’s location and specifies the bundle to be executed.

  1. sudo nano /var/cfengine/masterfiles/def.json


Include the provided information in that document.

The file def.json is located in the directory /var/cfengine/masterfiles.
  "inputs": [ "services/" ],
  "vars": {
    "control_common_bundlesequence_end": [ "manage_my_file" ]

To ensure your policy runs regularly (every five minutes), you need to ensure that the agent locates and reads the file and runs your bundle.

The def.json file’s inputs key informs the agent about which policy files to access. In this scenario, the agent will access the policy file named that you generated in the previous step.

The vars option allows for variable definition. By incorporating the control_common_bundlesequence_end variable in the default policy, any bundle names added there will be assessed after all the default bundles in the bundlesequence. Hence, cf-agent can choose the policy files to read and the bundles within them to evaluate automatically, eliminating the need to specify these details via the command line.

Once you are making changes to the policy within /var/cfengine/masterfiles/, automation will handle the remaining tasks. In particular, cf-agent will regularly check for the updated policy files that you have written. The agent will read and assess the policy, ensuring all the commitments are enforced and making necessary modifications to the machines, like editing files and creating users.

According to the policy outlined in this tutorial, whenever the agent is executed, it will confirm the existence of /tmp/my_file.txt, along with the specific content mentioned in the policy file.

Please save the file and then close it.

To verify the functionality of automation, remove the text file that was generated during the initial execution of the file management policy.

  1. sudo rm /tmp/my_file.txt


You will be able to verify if CFEngine has successfully regenerated my_file.txt in the background after a five-minute duration.

  1. cat /tmp/my_file.txt



Hello, CFEngine.

Instead, you can also choose to expedite the process of creating the file.

  1. sudo rm /tmp/my_file.txt ; sudo cf-agent -Kf ; sudo cf-agent -KI


CFEngine will identify changes required as the file gets deleted using the rm command.

The initial cf-agent command updates the policy file by duplicating it from /var/cfengine/masterfiles to /var/cfengine/inputs.

The final cf-agent command ensures implementation of your policy by searching for the /tmp/my_file.txt file and creating or modifying it when needed.

If you run the agent right after deleting the file, cf-agent will indicate that it has created the file. The likelihood of the agent running in the background between these commands is extremely low.


Please note that the command sudo cf-agent -Kf ; sudo cf-agent -KI is equivalent to the default command CFEngine executes every five minutes. Thus, running this command should yield the same outcome as waiting for five minutes, assuming CFEngine is functioning correctly. The initial agent run updates the policy, while the second one assesses the policy and implements alterations to the system.

Once you have reached this stage, you have successfully automated your initial system administration task using CFEngine. Although the current illustration demonstrates the creation and modification of a file, the procedure for any other task would be the same: formulate the policy, place it in the appropriate directory, and subsequently update the def.json file.

In summary,

Once CFEngine has been successfully installed and initiated on a solitary server, you can proceed to create your initial policy and configure it to run automatically.

To proceed further, explore the CFEngine official documentation. Take a look at this tutorial which explains how to manage files by creating, modifying, and deleting them.

If you need assistance or have any inquiries, please feel free to post them in the Q&A section of CFEngine’s GitHub Discussions.


More tutorials

Python 3 installing on Rocky Linux 9(Opens in a new browser tab)

sudo for new user with privileges on Rocky Linux 8(Opens in a new browser tab)

A guide on creating a Ruby on Rails application on Ubuntu 22.04.(Opens in a new browser tab)

Server Configurations Frequently Used for Your Web Application(Opens in a new browser tab)

Step-by-step Guide: Installing Rust on Ubuntu 20.04(Opens in a new browser tab)

Leave a Reply 0

Your email address will not be published. Required fields are marked *