Introduction
The ansible.builtin.service module manages system services across all init systems — systemd, SysV init, OpenRC, and BSD rc.d. It's the universal way to start, stop, restart, and enable services on boot without worrying about the underlying init system.
Quick Reference
# Start a service
- ansible.builtin.service:
name: nginx
state: started
# Stop a service
- ansible.builtin.service:
name: nginx
state: stopped
# Restart a service
- ansible.builtin.service:
name: nginx
state: restarted
# Reload configuration (no downtime)
- ansible.builtin.service:
name: nginx
state: reloaded
# Enable on boot
- ansible.builtin.service:
name: nginx
enabled: true
# Start AND enable
- ansible.builtin.service:
name: nginx
state: started
enabled: true
Parameters
| Parameter | Values | Description |
|---|---|---|
name | string | Service name (required) |
state | started, stopped, restarted, reloaded | Desired service state |
enabled | true/false | Start on boot |
pattern | regex | Process name pattern for status check |
sleep | seconds | Wait between stop and start (for restarted) |
arguments | string | Additional arguments for the service command |
Common Patterns
Install and Start
- name: Install and start nginx
hosts: webservers
become: true
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
- name: Start and enable nginx
ansible.builtin.service:
name: nginx
state: started
enabled: true
Restart on Configuration Change
- name: Configure and restart service
hosts: webservers
become: true
tasks:
- name: Deploy nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx
handlers:
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
Reload vs Restart
# Reload: re-read config without dropping connections
- name: Reload nginx (graceful)
ansible.builtin.service:
name: nginx
state: reloaded
# Restart: full stop + start (brief downtime)
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
Multiple Services
- name: Ensure core services running
ansible.builtin.service:
name: "{{ item }}"
state: started
enabled: true
loop:
- sshd
- chronyd
- rsyslog
- firewalld
Stop and Disable
- name: Disable unnecessary services
ansible.builtin.service:
name: "{{ item }}"
state: stopped
enabled: false
loop:
- cups
- bluetooth
- avahi-daemon
ignore_errors: true # Some may not exist
service vs systemd Module
# ansible.builtin.service — universal, works everywhere
- ansible.builtin.service:
name: nginx
state: started
# ansible.builtin.systemd_service — systemd-specific features
- ansible.builtin.systemd_service:
name: nginx
state: started
daemon_reload: true # Only systemd supports this
scope: system # system or user
| Feature | service | systemd |
|---|---|---|
| Cross-platform | ✅ All init systems | ❌ systemd only |
daemon_reload | ❌ | ✅ |
scope (user units) | ❌ | ✅ |
| Masked units | ❌ | ✅ |
| Timer units | ❌ | ✅ |
Rule: Use service unless you need systemd-specific features.
Conditional Service Management
- name: Start service only if installed
ansible.builtin.service:
name: nginx
state: started
when: "'nginx' in ansible_facts.packages"
- name: Restart only if running
ansible.builtin.service:
name: myapp
state: restarted
when: ansible_facts.services['myapp.service'].state == 'running'
Check Service Status
- name: Gather service facts
ansible.builtin.service_facts:
- name: Show nginx status
ansible.builtin.debug:
msg: "nginx is {{ ansible_facts.services['nginx.service'].state }}"
- name: Fail if critical service not running
ansible.builtin.assert:
that:
- ansible_facts.services['sshd.service'].state == 'running'
fail_msg: "SSHD is not running!"
Wait for Service to Be Ready
- name: Start database
ansible.builtin.service:
name: postgresql
state: started
- name: Wait for PostgreSQL to accept connections
ansible.builtin.wait_for:
port: 5432
host: localhost
delay: 2
timeout: 30
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
Could not find the requested service | Service not installed | Install package first |
Unable to start service | Config error or port conflict | Check journalctl -u servicename |
Service is masked | Service deliberately disabled | Use systemd module with masked: false |
| Idempotency: always "changed" | Service doesn't report status correctly | Use pattern parameter |
| Service starts but crashes | Dependencies not met | Check logs, ensure deps are started first |
Best Practices
- Use handlers for restarts — only restart when config actually changes
- Always set
enabled: truealongsidestate: started— survives reboot - Use
reloadedoverrestartedwhen possible — avoids downtime - Gather service_facts before conditionals — check state before acting
- Use
wait_forafter starting — verify the service is actually ready - Use
servicemodule, not shell — idempotent and cross-platform
Conclusion
The ansible.builtin.service module manages services across all init systems. Use state: started with enabled: true for services that should always run. Use handlers to restart only on configuration changes. Check service readiness with wait_for after starting. Prefer service over systemd unless you need daemon_reload or user-scope units.