Ansible service Module: Start, Stop & Restart Services (ansible.builtin.service)
By Luca Berton · Published 2024-01-01 · Category: installation
How to manage services with Ansible service module (ansible.builtin.service). Start, stop, restart, enable, disable systemd and init services.
The ansible.builtin.service module manages services across any init system — systemd, SysVinit, OpenRC, Upstart. It abstracts the differences so the same playbook works on any Linux distribution.
Basic Operations
# 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
See also: Ansible service Module: Start, Stop, Restart Services (Complete Guide)
Enable on Boot
# Start now AND enable on boot
- ansible.builtin.service:
name: nginx
state: started
enabled: true
# Enable without starting
- ansible.builtin.service:
name: nginx
enabled: true
# Disable and stop
- ansible.builtin.service:
name: nginx
state: stopped
enabled: false
service vs systemd Module
# ansible.builtin.service — works on any init system
- ansible.builtin.service:
name: nginx
state: started
# ansible.builtin.systemd — systemd-specific features
- ansible.builtin.systemd:
name: nginx
state: started
daemon_reload: true # Only available in systemd module
scope: system # system, user, or global
masked: false # Unmask a service
| Feature | service | systemd | |---------|---------|---------| | Start/stop/restart | ✅ | ✅ | | Enable/disable | ✅ | ✅ | | daemon-reload | ❌ | ✅ | | Mask/unmask | ❌ | ✅ | | User services | ❌ | ✅ | | Cross-platform | ✅ | ❌ (systemd only) |
Rule of thumb: Use service for portability. Use systemd when you need daemon_reload or masking.
See also: ansible.builtin.service: Manage Services with Ansible (Complete Guide)
Common Patterns
Install and Start
- name: Install and enable Nginx
ansible.builtin.apt:
name: nginx
state: present
- name: Start and enable Nginx
ansible.builtin.service:
name: nginx
state: started
enabled: true
Handler Pattern (Restart on Config Change)
tasks:
- name: Deploy nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart nginx
- name: Deploy site config
ansible.builtin.template:
src: site.conf.j2
dest: /etc/nginx/conf.d/mysite.conf
notify: reload nginx
handlers:
- name: restart nginx
ansible.builtin.service:
name: nginx
state: restarted
- name: reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
Validate Config Before Restart
- name: Deploy nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
validate: nginx -t -c %s
notify: restart nginx
Conditional Service Name
- name: Restart web server
ansible.builtin.service:
name: "{{ (ansible_facts['os_family'] == 'Debian') | ternary('apache2', 'httpd') }}"
state: restarted
Wait for Service Readiness
- name: Start application
ansible.builtin.service:
name: myapp
state: started
- name: Wait for port to be ready
ansible.builtin.wait_for:
port: 8080
timeout: 30
delay: 5
- name: Verify health endpoint
ansible.builtin.uri:
url: http://localhost:8080/health
status_code: 200
retries: 5
delay: 5
Multiple Services
- name: Start all required services
ansible.builtin.service:
name: "{{ item }}"
state: started
enabled: true
loop:
- nginx
- postgresql
- redis
- myapp
Stop and Disable Unwanted Services
- name: Disable unnecessary services (CIS hardening)
ansible.builtin.service:
name: "{{ item }}"
state: stopped
enabled: false
loop:
- cups
- avahi-daemon
- rpcbind
- bluetooth
ignore_errors: true # Some may not be installed
systemd-Specific Features
Daemon Reload
# After creating/modifying a .service unit file
- name: Deploy custom service unit
ansible.builtin.template:
src: myapp.service.j2
dest: /etc/systemd/system/myapp.service
notify: restart myapp
- name: Reload systemd daemon
ansible.builtin.systemd:
daemon_reload: true
- name: Start custom service
ansible.builtin.systemd:
name: myapp
state: started
enabled: true
Mask a Service
# Prevent a service from being started (even manually)
- name: Mask unnecessary service
ansible.builtin.systemd:
name: cups
masked: true
state: stopped
Create a systemd Service File
- name: Create service unit
ansible.builtin.copy:
dest: /etc/systemd/system/myapp.service
content: |
[Unit]
Description=My Application
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/start
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
mode: '0644'
notify:
- reload systemd
- restart myapp
handlers:
- name: reload systemd
ansible.builtin.systemd:
daemon_reload: true
- name: restart myapp
ansible.builtin.systemd:
name: myapp
state: restarted
See also: Ansible Start & Enable Service on Boot: systemd Module Guide
Service State Checking
- name: Check if service is running
ansible.builtin.service_facts:
- name: Show nginx status
ansible.builtin.debug:
msg: "Nginx is {{ ansible_facts.services['nginx.service'].state }}"
when: "'nginx.service' in ansible_facts.services"
- name: Fail if critical service not running
ansible.builtin.fail:
msg: "PostgreSQL is not running!"
when: >
'postgresql.service' not in ansible_facts.services or
ansible_facts.services['postgresql.service'].state != 'running'
FAQ
What's the difference between restarted and reloaded?
restarted stops and starts the service (brief downtime). reloaded sends a signal (usually SIGHUP) to re-read configuration without stopping — zero downtime. Not all services support reload; use restart as fallback.
Should I use service or systemd module?
Use ansible.builtin.service for cross-platform playbooks. Use ansible.builtin.systemd only when you need systemd-specific features like daemon_reload, masked, or user scope services. Most playbooks should use service.
How do I restart a service only when a config file changes?
Use the handler pattern: add notify: restart myservice to your template/copy task, and define a handler that restarts the service. Handlers only run when notified by a changed task.
Why does my service start but immediately stop?
Check the service logs with journalctl -u myservice -n 50. Common causes: wrong ExecStart path, missing dependencies, permission errors, port already in use. Test manually with systemctl start myservice && systemctl status myservice.
Conclusion
Use ansible.builtin.service for starting, stopping, and enabling services across any Linux distribution. Pair it with handlers for config-driven restarts, wait_for for readiness checks, and service_facts for state verification. Switch to the systemd module only when you need daemon-reload or masking.
Related Articles
• flush_handlers in Ansible • Ansible template Module Guide • Ansible ignore_errors Guide • Ansible for Linux System AdministrationCategory: installation