Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: July 29, 2025
systemd is the modern system and service manager in Linux that initializes the user space and manages the lifecycle of services. Ansible, on the other hand, is a popular open-source automation tool for application deployment, configuration management, and infrastructure orchestration.
In this tutorial, we’ll discuss how to control a systemd service using Ansible. We’ll see how to start and stop a simple systemd service. The version of Ansible we use in the examples is 2.12.0.
In this section, we’ll discuss the service we’ll use. It’s a simple shell script. We’ll run this script as a service using systemd and Ansible in the subsequent section.
We’ll run the following script, simple_service.sh, using systemd:
$ cat simple_service.sh
#!/bin/bash
while true
do
sleep 1
done
This script calls the sleep 1 command in an infinite while loop.
We’ll use the following unit file, simple_service.service, to run simple_service.sh as a service using systemd:
$ cat simple_service.service
[Unit]
Description=Simple Service
[Service]
ExecStart=/home/baeldung/work/systemd-ansible/simple_service.sh
[Install]
WantedBy=multi-user.target
The ExecStart option in the Service section of the unit file specifies the path of the executable that systemd runs as a service. It’s the path to simple_service.sh in our case.
In this section, we’ll enable and start the script we’ve already discussed as a systemd service using Ansible.
Using Ansible while managing system services with systemd has several advantages. For example, we can avoid unnecessary operations since Ansible checks the current state of services before applying changes. If the service is already up and running, Ansible won’t attempt to start it again. This is more difficult to achieve using shell scripts. As another advantage, it’s easier to manage multiple systemd units on different hosts using a single playbook.
We’ll use the following playbook, playbook_systemd.yml:
$ cat playbook_systemd.yml
--
- name: Ansible enable service
hosts: localhost
tasks:
- name: Create unit file link
file:
state: link
src: /home/baeldung/work/systemd-ansible/simple_service.service
dest: /etc/systemd/system/simple_service.service
- name: Enable and start the service
systemd:
name: simple_service
enabled: true
state: started
The playbook consists of two tasks. The first task creates a symbolic link to the service’s unit file, whereas the second one enables and starts the service.
Testing the playbook only on localhost is sufficient for us. Therefore, we’ll use the following inventory file:
$ cat inventory
localhost ansible_connection=local
Let’s discuss each task separately in the subsequent sections.
The first task utilizes the built-in file module, which is used for managing files and their properties. The module’s FQCN (Fully Qualified Collection Name) is ansible.builtin.file. While working with Ansible playbooks using many different modules, it might be a good idea to use the FQCN to avoid name conflicts with other collections that may have the same module name.
The module’s state parameter, with the value link, specifies that we want to create a symbolic link. The module’s src parameter specifies the path of the file to link to, which is /home/baeldung/work/systemd-ansible/simple_service.service. The dest parameter, on the other hand, corresponds to the path of the symbolic link. It’s /etc/systemd/system/simple_service.service in our example. This directory contains the systemd unit files created by the systemctl enable command.
In addition to the file module’s three parameters, other parameters can be used. For example, the mode parameter sets the permissions of the symbolic link. Its default value is ‘777’. Another parameter, modification_time, indicates the file’s modification time we want to set.
The second task utilizes the built-in systemd module, which manages systemd units, such as services, timers, and sockets. Its FQCN is ansible.builtin.systemd. This module has been renamed to systemd_service in newer versions of Ansible to better reflect the module’s scope. However, systemd is still kept as an alias for backward compatibility.
The name parameter specifies the unit’s name, simple_service in our case. It refers to the unit file we use. If we don’t use any extension in the name, the .service extension is used by default. Therefore, we use the simple_service.service unit file.
The enabled parameter specifies whether the unit should start on boot. It’s a boolean variable, i.e., it’s either true or false. The value of this parameter is true in our case since we want the service to be started automatically by systemd on boot.
The state parameter with the value started implies starting the service immediately without waiting for a reboot.
In addition to the parameters discussed, the systemd module has other parameters that can be useful. For instance, if we set the daemon_reload parameter to true, we make sure that systemd reads any configuration updates. A second example might be using the masked parameter to mask or unmask a unit. It isn’t possible to start a masked unit.
Now, let’s run the playbook using the ansible-playbook command. Since the tasks within the playbook need root privileges, we use the sudo command while running the playbook:
$ sudo ansible-playbook playbook_systemd.yml -i inventory
PLAY [Ansible enable service] **************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Create unit file link] ***************************************************
changed: [localhost]
TASK [Enable and start the service] ********************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The -i option of ansible-playbook specifies the inventory file, which is inventory in our case. As is apparent from the output, we’ve successfully run the playbook. Let’s check the result of the first task, creation of the symbolic link to the unit file, using the ls command:
$ ls -l /etc/systemd/system/simple_service.service
lrwxrwxrwx 1 root root 56 Jul 18 05:51 /etc/systemd/system/simple_service.service -> /home/baeldung/work/systemd-ansible/simple_service.service
The symbolic link we create using the file module in the playbook exists, as expected.
Let’s also check the result of the second task, enabling and starting the service using the systemctl status command:
$ systemctl status simple_service
● simple_service.service - Simple Service
Loaded: loaded (/etc/systemd/system/simple_service.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2025-07-18 05:51:18 EDT; 10min ago
Main PID: 3084 (simple_service.)
Tasks: 2 (limit: 4601)
Memory: 560.0K
CPU: 2.502s
CGroup: /system.slice/simple_service.service
├─3084 /bin/bash /home/baeldung/work/systemd-ansible/simple_service.sh
└─4284 sleep 1
Jul 18 05:51:18 ubuntu-2204 systemd[1]: Started Simple Service.
The service is enabled and running as expected. We can run the playbook multiple times since it’s an idempotent action, i.e., Ansible won’t reattempt to create the existing link and start the already running service again.
We can stop the service in a similar way to how we started it. We can use the following task:
- name: Disable and stop the service
systemd:
name: simple_service
enabled: false
state: stopped
Setting the enabled parameter to false disables the service. The symbolic link to the unit file is also automatically removed when the service is disabled. Setting the state parameter to stopped stops the running service immediately.
In this article, we discussed how to control a systemd service using Ansible.
Firstly, we learned how to start a service using an Ansible playbook. We saw that we can use the built-in file module for creating a symbolic link to a service’s unit file in the /etc/systemd/system directory, and the built-in systemd module to enable and start a service. Finally, we saw that we can again use the systemd module to stop and disable a systemd service.