Introduction

Managing services — starting, stopping, restarting, and enabling them at boot — is one of the most common tasks in system automation. The ansible.builtin.service module provides a cross-platform interface that works with systemd, SysV init, OpenRC, Solaris SMF, upstart, and BSD init systems.

For Windows targets, use ansible.windows.win_service instead.

Module Parameters

ParameterTypeRequiredDescription
namestringYesName of the service
statestringNo*started, stopped, restarted, reloaded
enabledboolNo*Whether the service starts on boot
sleepintNoSeconds to sleep between stop and start during restart
argumentsstringNoExtra arguments passed to the service command
patternstringNoSubstring to match in ps output if service status is unavailable
usestringNoForce a specific service manager (systemd, sysvinit, etc.)

*At least one of state or enabled must be specified.

State Values Explained

StateBehavior
startedStart service if not running; no action if already running
stoppedStop service if running; no action if already stopped
restartedAlways stop and start (triggers changed every time)
reloadedReload configuration without full restart

Basic Examples

Restart a Service

- name: Restart sshd
  ansible.builtin.service:
    name: sshd
    state: restarted

Start and Enable at Boot

- name: Ensure nginx is running and enabled
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: true

Stop and Disable a Service

- name: Stop and disable firewalld
  ansible.builtin.service:
    name: firewalld
    state: stopped
    enabled: false

Reload Configuration

- name: Reload nginx config
  ansible.builtin.service:
    name: nginx
    state: reloaded

Using Handlers (Best Practice)

Handlers restart services only when changes actually occur — much better than unconditional restarts:

- name: Configure web servers
  hosts: web_servers
  become: true
  tasks:
    - name: Deploy nginx config
      ansible.builtin.template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: restart nginx

    - name: Deploy SSL certificate
      ansible.builtin.copy:
        src: files/server.crt
        dest: /etc/nginx/ssl/server.crt
      notify: reload nginx

  handlers:
    - name: restart nginx
      ansible.builtin.service:
        name: nginx
        state: restarted

    - name: reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded

Flush Handlers Immediately

By default, handlers run at the end of the play. Force them to run mid-play:

- name: Deploy config
  ansible.builtin.template:
    src: app.conf.j2
    dest: /etc/myapp/app.conf
  notify: restart myapp

- name: Force restart now (before next task needs the service)
  ansible.builtin.meta: flush_handlers

- name: Verify app is responding
  ansible.builtin.uri:
    url: http://localhost:8080/health
    status_code: 200

Rolling Restarts

Restart services across a fleet without downtime:

- name: Rolling restart of web servers
  hosts: web_servers
  serial: 1  # One host at a time
  become: true
  tasks:
    - name: Remove from load balancer
      ansible.builtin.uri:
        url: "http://lb.example.com/api/remove/{{ inventory_hostname }}"
        method: POST
      delegate_to: localhost

    - name: Restart application
      ansible.builtin.service:
        name: myapp
        state: restarted

    - name: Wait for application to be ready
      ansible.builtin.uri:
        url: "http://{{ inventory_hostname }}:8080/health"
        status_code: 200
      retries: 30
      delay: 5
      register: health
      until: health.status == 200

    - name: Add back to load balancer
      ansible.builtin.uri:
        url: "http://lb.example.com/api/add/{{ inventory_hostname }}"
        method: POST
      delegate_to: localhost

service vs systemd Module

For systemd-specific features, use ansible.builtin.systemd:

# Daemon reload (required after changing unit files)
- name: Reload systemd daemon
  ansible.builtin.systemd:
    daemon_reload: true

# Restart with systemd-specific options
- name: Restart and enable service
  ansible.builtin.systemd:
    name: myapp
    state: restarted
    enabled: true
    daemon_reload: true

# Manage user services (systemd --user)
- name: Restart user service
  ansible.builtin.systemd:
    name: myapp
    state: restarted
    scope: user
Featureservicesystemd
Cross-platform✅ All init systems❌ systemd only
daemon_reload❌✅
User scope❌✅
Masked units❌✅
Force stop❌✅

Rule of thumb: Use service for cross-platform playbooks; use systemd when you need daemon-reload or systemd-specific features.

Managing Multiple Services

- name: Ensure core services are running
  ansible.builtin.service:
    name: "{{ item }}"
    state: started
    enabled: true
  loop:
    - sshd
    - chronyd
    - rsyslog
    - crond

Conditional Restarts

# Restart only if config changed
- name: Deploy sshd config
  ansible.builtin.template:
    src: sshd_config.j2
    dest: /etc/ssh/sshd_config
    validate: '/usr/sbin/sshd -t -f %s'
  register: sshd_config

- name: Restart sshd if config changed
  ansible.builtin.service:
    name: sshd
    state: restarted
  when: sshd_config.changed

Troubleshooting

Service Not Found

FAILED! => {"msg": "Could not find the requested service sshd: ..."}

Check the actual service name:

- name: List all services
  ansible.builtin.shell: systemctl list-unit-files --type=service | grep ssh
  register: service_list

- name: Show results
  ansible.builtin.debug:
    var: service_list.stdout_lines

Common name differences: sshd vs ssh, httpd vs apache2, crond vs cron.

Service Fails to Start

- name: Restart with error details
  ansible.builtin.service:
    name: myapp
    state: restarted
  register: restart_result
  ignore_errors: true

- name: Get service logs on failure
  ansible.builtin.shell: journalctl -u myapp --no-pager -n 50
  register: logs
  when: restart_result is failed

- name: Show logs
  ansible.builtin.debug:
    var: logs.stdout_lines
  when: restart_result is failed

Permission Denied

Always use become: true for service management:

- name: Manage services
  hosts: all
  become: true  # Required for service management
  tasks:
    - name: Restart service
      ansible.builtin.service:
        name: nginx
        state: restarted

Conclusion

The ansible.builtin.service module is your go-to tool for managing services across Linux distributions and init systems. Use handlers instead of unconditional restarts, implement rolling restarts for zero-downtime deployments, and switch to the systemd module when you need daemon-reload or user-scope services. Always use become: true and validate config files before restarting critical services like sshd.