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
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Name of the service |
state | string | No* | started, stopped, restarted, reloaded |
enabled | bool | No* | Whether the service starts on boot |
sleep | int | No | Seconds to sleep between stop and start during restart |
arguments | string | No | Extra arguments passed to the service command |
pattern | string | No | Substring to match in ps output if service status is unavailable |
use | string | No | Force a specific service manager (systemd, sysvinit, etc.) |
*At least one of state or enabled must be specified.
State Values Explained
| State | Behavior |
|---|---|
started | Start service if not running; no action if already running |
stopped | Stop service if running; no action if already stopped |
restarted | Always stop and start (triggers changed every time) |
reloaded | Reload 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
| Feature | service | systemd |
|---|---|---|
| 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
Related Articles
- Install Software on RHEL: dnf Module
- Install Software on Debian: apt Module
- Reboot Remote Hosts
- Ansible Handlers Guide
- Ansible Best Practices Guide
- Ansible Privilege Escalation
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.