AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible Start & Enable Service on Boot: systemd Module Guide

By Luca Berton · Published 2024-01-01 · Category: installation

How to start and enable services on boot with Ansible systemd and service modules. Ensure services auto-start, check status with service_facts.

Ansible Start & Enable Service on Boot: systemd Module Guide

How to enable services on boot on remote hosts with Ansible?

I'm going to show you a live Playbook with some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible Pilot.

See also: Ansible Stop & Disable Service: systemd Module Guide (with Examples)

Ansible enable services on boot on remote hosts

• ansible.builtin.service_facts • Return service state information as fact data • ansible.builtin.service • Manage services

Today we're talking about Ansible modules service_facts and service. First, you need to acquire the information of the services on the target machine. This task is performed by the Ansible module service_facts. You can't enable a service that doesn't exist, can you? The effective actions are performed by the Ansible module service. The full name is ansible.builtin.service which means that both these modules are part of the collection of modules "builtin" with Ansible and shipped with it. This module is pretty stable and out for years and its purpose is to manage services on remote hosts. For Windows targets, use the ansible.windows.win_service module instead.

Parameters

• name path - name of the service • state string - started / stopped / restarted / reloaded • enabled boolean - no/yes • arguments/args string - extra args

The parameter list is pretty wide but I'll summarize the most useful. The only required parameter is "name" that specifies the name of the service. At least one between the "state" and "enabled" parameters is mandatory. The "state" parameter defines the action that we are going to take. It has four alternative options: "started" and "stopped" options allow you to run or stop the service. "restarted" is a combination of stop and start - you could also customize the number of seconds between using the "sleep" parameter The "reloaded" option is useful if the service needs to reload the configuration file. The "enable" parameter allows you to decide if the service should start on boot or not. The "arguments or args" parameter allows you to specify some additional arguments provided on the command line.

## Playbook

Enable services on boot and start on remote hosts with Ansible Playbook. Included code and Playbook with chronyd.service NTP server on a RedHat Enterprise Linux 8.

code

• service_enable_on_boot.yml
---
- name: service module Playbook
  hosts: all
  become: true
  vars:
    services_on_boot:
      - "chronyd.service"
  tasks:
    - name: populate service facts
      ansible.builtin.service_facts:
    - name: enable services on boot
      ansible.builtin.service:
        name: "{{ item }}"
        enabled: true
        state: started
      when: "item in services"
      with_items: '{{ services_on_boot }}'

execution

$ ansible-playbook -i virtualmachines/demo/inventory enable\ services\ on\ boot/service.yml
PLAY [service module Playbook] ************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [populate service facts] *********************************************************************
ok: [demo.example.com]
TASK [enable services on boot] ************************************************************************
changed: [demo.example.com] => (item=chronyd.service)
PLAY RECAP ****************************************************************************************
demo.example.com           : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

before execution

$ ssh devops@demo.example.com
[devops@demo ~]$ sudo su
[root@demo devops]# cat /etc/redhat-release 
Red Hat Enterprise Linux release 8.4 (Ootpa)
[root@demo devops]# rpm -qa | grep chrony
chrony-3.5-2.el8.x86_64
[root@demo devops]# systemctl status chronyd.service
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:chronyd(8)
           man:chrony.conf(5)
[root@demo devops]#

after execution

$ ssh devops@demo.example.com
[devops@demo ~]$ sudo su
[root@demo devops]# systemctl status chronyd.service
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2021-11-29 11:29:53 UTC; 49s ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
  Process: 1729 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCC>
  Process: 1725 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)
 Main PID: 1727 (chronyd)
    Tasks: 1 (limit: 4943)
   Memory: 844.0K
   CGroup: /system.slice/chronyd.service
           └─1727 /usr/sbin/chronyd
Nov 29 11:29:53 demo.example.com systemd[1]: Starting NTP client/server...
Nov 29 11:29:53 demo.example.com chronyd[1727]: chronyd version 3.5 starting (+CMDMON +NTP +REFCLO>
Nov 29 11:29:53 demo.example.com chronyd[1727]: Frequency -491.773 +/- 29.501 ppm read from /var/l>
Nov 29 11:29:53 demo.example.com chronyd[1727]: Using right/UTC timezone to obtain leap second data
Nov 29 11:29:53 demo.example.com systemd[1]: Started NTP client/server.
Nov 29 11:29:59 demo.example.com chronyd[1727]: Selected source 81.25.28.124
Nov 29 11:29:59 demo.example.com chronyd[1727]: System clock TAI offset set to 37 seconds
Nov 29 11:29:59 demo.example.com chronyd[1727]: System clock wrong by 1.840437 seconds, adjustment>
Nov 29 11:30:00 demo.example.com chronyd[1727]: System clock was stepped by 1.840437 seconds
[root@demo devops]# reboot
Connection to demo.example.com closed by remote host.
Connection to demo.example.com closed.
ansible-pilot $ ssh devops@demo.example.com
[devops@demo ~]$ sudo su
[root@demo devops]# systemctl status chronyd.service
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2021-11-29 11:31:32 UTC; 28s ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
  Process: 825 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCE>
  Process: 811 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)
 Main PID: 820 (chronyd)
    Tasks: 1 (limit: 4943)
   Memory: 1.5M
   CGroup: /system.slice/chronyd.service
           └─820 /usr/sbin/chronyd
Nov 29 11:31:32 demo.example.com systemd[1]: Starting NTP client/server...
Nov 29 11:31:32 demo.example.com chronyd[820]: chronyd version 3.5 starting (+CMDMON +NTP +REFCLOC>
Nov 29 11:31:32 demo.example.com chronyd[820]: Frequency -389.145 +/- 224.519 ppm read from /var/l>
Nov 29 11:31:32 demo.example.com chronyd[820]: Using right/UTC timezone to obtain leap second data
Nov 29 11:31:32 demo.example.com systemd[1]: Started NTP client/server.
Nov 29 11:31:39 demo.example.com chronyd[820]: Selected source 81.25.28.124
Nov 29 11:31:39 demo.example.com chronyd[820]: System clock TAI offset set to 37 seconds
Nov 29 11:31:39 demo.example.com chronyd[820]: System clock wrong by 2.026567 seconds, adjustment >
Nov 29 11:31:41 demo.example.com chronyd[820]: System clock was stepped by 2.026567 seconds
Nov 29 11:31:43 demo.example.com chronyd[820]: Selected source 89.221.210.188
[root@demo devops]#

code with ❤️ in GitHub

See also: ansible.builtin.service: Manage Services with Ansible (Complete Guide)

Conclusion

Now you know how to start and enable services on boot on Linux remote hosts with Ansible.

Start and Enable

- ansible.builtin.service:
    name: nginx
    state: started
    enabled: true
  become: true

See also: Deploy Squid Proxy on RedHat Systems with Ansible

Using systemd

- ansible.builtin.systemd:
    name: nginx
    state: started
    enabled: true
    daemon_reload: true  # If unit file changed
  become: true

Multiple Services

- service:
    name: "{{ item }}"
    state: started
    enabled: true
  loop:
    - nginx
    - redis-server
    - postgresql
  become: true

Check Before Starting

- service_facts:

- service: name: nginx state: started when: "'nginx.service' in ansible_facts.services" become: true

- debug: msg: "nginx is not installed" when: "'nginx.service' not in ansible_facts.services"

Start After Install

- apt:
    name: nginx
    state: present
  become: true

- service: name: nginx state: started enabled: true become: true

Restart vs Reload

# Restart — full stop/start (brief downtime)
- service: { name: nginx, state: restarted }

# Reload — graceful config reload (no downtime) - service: { name: nginx, state: reloaded }

Service State Reference

| State | Description | |-------|-------------| | started | Ensure running (start if stopped) | | stopped | Ensure stopped | | restarted | Stop then start | | reloaded | Reload configuration |

FAQ

service vs systemd module?

service is cross-platform (SysV, Upstart, systemd). systemd adds daemon_reload, masked, and scope options. Use systemd when you need those features.

How to check if a service is running?

- service_facts:
- debug: msg="{{ ansible_facts.services['nginx.service'].state }}"

enabled: true doesn't work?

Some services require systemd: daemon_reload=true first if the unit file was recently created or modified.

Start a Service

- ansible.builtin.service:
    name: nginx
    state: started
  become: true

Stop a Service

- service:
    name: nginx
    state: stopped
  become: true

Restart a Service

- service:
    name: nginx
    state: restarted
  become: true

Enable on Boot

- service:
    name: nginx
    state: started
    enabled: true
  become: true

Disable and Stop

- service:
    name: nginx
    state: stopped
    enabled: false
  become: true

systemd Module (More Options)

- ansible.builtin.systemd:
    name: nginx
    state: restarted
    daemon_reload: true  # Reload systemd after unit file changes
  become: true

Gather Service Facts

- service_facts:

- debug: msg: "nginx is {{ ansible_facts.services['nginx.service'].state }}"

# List all running services - debug: msg: "{{ item.key }}" loop: "{{ ansible_facts.services | dict2items }}" when: item.value.state == 'running'

Manage Multiple Services

- service:
    name: "{{ item }}"
    state: started
    enabled: true
  loop:
    - nginx
    - redis-server
    - postgresql
  become: true

Conditional Service Management

- service_facts:

- service: name: apache2 state: stopped when: "'apache2.service' in ansible_facts.services" become: true

Handler Pattern

tasks:
  - template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify: reload nginx
    become: true

handlers: - name: reload nginx service: name: nginx state: reloaded become: true

Wait for Service to Start

- service:
    name: myapp
    state: started
  become: true

- wait_for: port: 8080 delay: 5 timeout: 30

FAQ

service vs systemd module?

service is cross-platform (systemd, SysV, Upstart). systemd adds systemd-specific features like daemon_reload, scope, and masked units. Use systemd when you need those features.

How to mask a service?

- systemd:
    name: bluetooth
    masked: true
  become: true

reloaded vs restarted?

reloaded sends SIGHUP (re-reads config, no downtime). restarted fully stops and starts (brief downtime). Use reloaded when the service supports it.

Related Articles

Ansible Windows administration walkthroughmulti-condition Ansible when clausesAnsible inventory best practicesdocker_container module walkthroughbecome directives in Ansible

Category: installation

Watch the video: Ansible Start & Enable Service on Boot: systemd Module Guide — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home