What you’ll accomplish: Install Ansible on the Rundeck host, configure the Ansible plugin, import your inventory as Rundeck nodes, set up SSH key-based authentication to managed hosts, and run your first Ansible playbook through Rundeck’s web UI.
At this point you have a working Rundeck instance backed by MySQL and fronted by Apache. That’s useful on its own — you can define jobs, run scripts, schedule tasks. But the real power for a home lab comes from connecting Rundeck to Ansible. Instead of SSH-ing into your workstation and running ansible-playbook from the command line, you’ll trigger playbooks from a browser, schedule them, and see full execution history.
This chapter bridges those two worlds.
Installing Ansible on the Rundeck Host
Rundeck doesn’t invoke Ansible remotely — it runs it locally on the Rundeck server. That means Ansible needs to be installed on the same host.
sudo dnf install -y ansible-core
Verify:
ansible --version
You should see ansible [core 2.x.x] with a config file path and Python version. The exact version doesn’t matter much — anything from Rocky 9’s AppStream repository will work with the Rundeck Ansible plugin.
The Ansible Plugin
The Ansible plugin for Rundeck provides five capabilities:
- Resource Model Source — Imports hosts from your Ansible inventory into Rundeck’s node list, including facts as node attributes.
- Node Executor — Executes commands on individual nodes via Ansible (replaces Rundeck’s built-in SSH executor).
- File Copier — Copies files to nodes using Ansible.
- Playbook Workflow Step — Runs an Ansible playbook as a job step. This is the one you’ll use most.
- Module Workflow Step — Runs a single ad-hoc Ansible module.
Checking If the Plugin Is Already Installed
Recent Rundeck versions may ship with the Ansible plugin included. Check:
ls /var/lib/rundeck/libext/ | grep -i ansible
If you see a JAR file like ansible-plugin-x.x.x.jar, you’re set. If not, download it:
# Replace the version with the latest from https://github.com/rundeck-plugins/ansible-plugin/releases
sudo curl -L -o /var/lib/rundeck/libext/ansible-plugin-3.2.10.jar \
https://github.com/rundeck-plugins/ansible-plugin/releases/download/v3.2.10/ansible-plugin-3.2.10.jar
sudo chown rundeck:rundeck /var/lib/rundeck/libext/ansible-plugin-3.2.10.jar
Restart Rundeck after adding the plugin:
sudo systemctl restart rundeckd
SSH Key Setup
Before Rundeck can manage your nodes through Ansible, the rundeck system user needs passwordless SSH access to each managed host. This is non-negotiable — Ansible communicates over SSH, and you don’t want Rundeck prompting for passwords.
Generate an SSH Keypair
# Generate an ed25519 key with no passphrase
sudo -u rundeck ssh-keygen -t ed25519 -f /var/lib/rundeck/.ssh/id_ed25519 -N ""
Verify the key was created:
sudo ls -la /var/lib/rundeck/.ssh/
You should see id_ed25519 (private key, permissions 0600) and id_ed25519.pub (public key).
Prepare Managed Nodes
On each node Rundeck will manage, you need to:
- Create a
rundeckservice user. - Deploy the SSH public key.
- Configure passwordless sudo for the commands Rundeck will run.
Here’s how to do it manually for one node. The bundled playbook’s node-setup.yml automates this across all your hosts.
# On the MANAGED NODE (not the Rundeck server):
# Create the rundeck user with a locked password (no direct login)
sudo useradd -m -s /bin/bash -G wheel rundeck
sudo passwd -l rundeck
# Create .ssh directory
sudo mkdir -p /home/rundeck/.ssh
sudo chmod 700 /home/rundeck/.ssh
sudo chown rundeck:rundeck /home/rundeck/.ssh
# Add the Rundeck server's public key
# Copy the content of /var/lib/rundeck/.ssh/id_ed25519.pub from your Rundeck server
echo "ssh-ed25519 AAAA... rundeck@rundeck.example.com" | \
sudo tee /home/rundeck/.ssh/authorized_keys
sudo chmod 600 /home/rundeck/.ssh/authorized_keys
sudo chown rundeck:rundeck /home/rundeck/.ssh/authorized_keys
Configure Passwordless Sudo
Create a sudoers file that grants the rundeck user passwordless access to specific commands:
sudo visudo -f /etc/sudoers.d/rundeck
# /etc/sudoers.d/rundeck
# Allow rundeck user to run specific commands without a password
rundeck ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart *, /usr/bin/systemctl status *, /usr/bin/dnf update *
Warning: Scope the sudo permissions to what Rundeck actually needs. Granting
ALLcommands withNOPASSWDis convenient but dangerous. If Rundeck is compromised, the attacker has root on every managed node. Start narrow and widen only when a job requires it.
Test the Connection
Back on the Rundeck server, test SSH as the rundeck user:
sudo -u rundeck ssh 192.168.1.51 hostname
If this doesn’t work, nothing else in this chapter will work. Common issues:
- Wrong permissions on the private key (must be
0600, owned byrundeck) - Public key not deployed correctly on the target
- Firewall blocking SSH on the target
- Host key verification failing (first connection needs to accept the key)
For the host key issue on first connection:
# Accept the host key non-interactively
sudo -u rundeck ssh -o StrictHostKeyChecking=accept-new 192.168.1.51 hostname
Creating a Rundeck Project
Rundeck organizes everything into projects. You need at least one project to start running jobs.
Create the Project via Web UI
- Log in to Rundeck at
https://rundeck.example.com. - Click New Project (or the
+icon). - Enter a project name:
homelab(or whatever describes your environment). - Click Create.
You’ll land on the project’s dashboard, which will show zero nodes and zero jobs. That’s expected — we haven’t configured the node source yet.
Configure the Ansible Resource Model Source
This tells Rundeck to pull its node list from your Ansible inventory instead of maintaining a separate node database.
- In your project, go to Project Settings (gear icon) > Edit Configuration > Resource Model Sources.
- Click Add Source.
- Select Ansible Resource Model Source from the dropdown.
- Configure these settings:
| Setting | Value | Why |
|---|---|---|
| Ansible inventory | /var/lib/rundeck/inventory/hosts.yml | Absolute path to your inventory file |
| Ansible config file path | /var/lib/rundeck/.ansible.cfg | Ansible config for the rundeck user |
| SSH Authentication Type | privateKey | We set up key-based auth above |
| SSH User | rundeck | The service user we created on managed nodes |
| SSH Key File Path | /var/lib/rundeck/.ssh/id_ed25519 | Private key location |
- Click Save.
Set Up the Inventory File
Create an inventory file that the rundeck user can read:
sudo mkdir -p /var/lib/rundeck/inventory
sudo vi /var/lib/rundeck/inventory/hosts.yml
# /var/lib/rundeck/inventory/hosts.yml
all:
children:
rocky:
hosts:
web01.example.com:
ansible_host: 192.168.1.51
db01.example.com:
ansible_host: 192.168.1.52
dbservers:
hosts:
db02.example.com:
ansible_host: 192.168.1.61
sudo chown -R rundeck:rundeck /var/lib/rundeck/inventory/
Create an Ansible Config File
sudo vi /var/lib/rundeck/.ansible.cfg
# /var/lib/rundeck/.ansible.cfg
[defaults]
inventory = /var/lib/rundeck/inventory/hosts.yml
remote_user = rundeck
host_key_checking = False
timeout = 30
[privilege_escalation]
become = True
become_method = sudo
become_user = root
sudo chown rundeck:rundeck /var/lib/rundeck/.ansible.cfg
Setting host_key_checking = False is a pragmatic choice for a home lab. In a production environment you’d manage known_hosts properly, but in a home lab where nodes get rebuilt regularly, strict host key checking just generates noise.
Verify Node Discovery
After saving the resource model source configuration, go to the Nodes tab in your project. You should see your hosts listed with their attributes pulled from the Ansible inventory.
If the Nodes tab is empty, check:
# Can the rundeck user read the inventory?
sudo -u rundeck ansible-inventory --list -i /var/lib/rundeck/inventory/hosts.yml
This should output a JSON representation of your inventory. If it fails, the path is wrong or permissions are broken.
Node Executor vs. Workflow Step
Rundeck offers two ways to run Ansible within a job. Understanding the difference saves confusion later.
Node Step (Node Executor): Rundeck iterates over nodes one at a time and runs Ansible targeting each individual node. Useful when you want Rundeck to control the node-by-node execution flow — for example, running a command on one node, checking the result, then proceeding to the next.
Workflow Step (Playbook Step): Rundeck runs Ansible once and lets Ansible handle the full play across all target nodes. This is better for running existing Ansible playbooks because Ansible manages its own parallelism, error handling, and host grouping.
My recommendation: Use Workflow Steps for running playbooks. Use Node Steps only when you need per-node control flow within Rundeck (e.g., a canary deployment where Rundeck decides whether to continue based on each node’s result).
Your First Rundeck Job
Let’s prove the full chain works: Rundeck triggers Ansible, Ansible connects to your nodes via SSH, and the output flows back to Rundeck.
Create the Job
- In your
homelabproject, go to Jobs > Create a New Job. - Job Name:
Test - Ansible Ping - Description:
Verify Ansible connectivity to all managed nodes - Under Workflow, click Add a Step.
- Under Node Steps, expand Node Step Plugins and select Ansible Playbook Inline Workflow Node Step.
- Paste the following into the inline playbook field:
---
- name: Test connectivity
hosts: all
gather_facts: false
tasks:
- name: Ping all nodes
ansible.builtin.ping:
- name: Show hostname
ansible.builtin.command: hostname
register: result
- name: Display hostname
ansible.builtin.debug:
msg: "{{ inventory_hostname }} reports hostname: {{ result.stdout }}"
- Leave the Authentication and Privilege Escalation sections at their defaults. The SSH key and become settings are handled by Ansible’s own config (
ansible.cfgand the playbook’sbecome: true), not by Rundeck’s step-level settings. - Click Save for the step, then Create for the job.
Run the Job
Click Run Job Now. You’ll see a live execution log showing Ansible connecting to each host, running the ping module, and displaying the hostname. Green means success.
If the job fails:
- “No hosts matched” — The inventory path is wrong or unreadable. See the Ansible Resource Model Source settings.
- “Permission denied (publickey)” — SSH key setup is broken. Go back to the SSH key section above.
- “ansible-playbook: command not found” — Ansible isn’t installed or isn’t in the
rundeckuser’s PATH. Verify withsudo -u rundeck which ansible-playbook.
Verification
Run through this checklist to confirm everything is connected:
# 1. Ansible is installed and accessible by the rundeck user
sudo -u rundeck ansible --version
# 2. The rundeck user can read the inventory
sudo -u rundeck ansible-inventory --list -i /var/lib/rundeck/inventory/hosts.yml
# 3. The rundeck user can SSH to managed nodes
sudo -u rundeck ssh 192.168.1.51 hostname
# 4. Ansible can reach nodes (the real test)
sudo -u rundeck ansible all -i /var/lib/rundeck/inventory/hosts.yml -m ping
Expected output for the last command:
web01.example.com | SUCCESS => {
"changed": false,
"ping": "pong"
}
db01.example.com | SUCCESS => {
"changed": false,
"ping": "pong"
}
If all four checks pass, your Rundeck-Ansible integration is solid.
What Can Go Wrong
Rundeck Shows Zero Nodes
Symptom: The Nodes tab in your project is empty even after configuring the Ansible Resource Model Source.
Cause: Usually a file path or permission issue. The rundeck user can’t read the inventory file, the path in the resource model source is wrong, or the inventory file has a syntax error.
Fix:
# Test as the rundeck user
sudo -u rundeck ansible-inventory --list -i /var/lib/rundeck/inventory/hosts.yml
If this fails, fix the inventory path or permissions. If it succeeds but Rundeck still shows zero nodes, restart Rundeck — the resource model source caches results.
“ansible-playbook: command not found”
Symptom: Job execution fails immediately with a PATH error.
Cause: The rundeck user’s environment doesn’t include Ansible’s install path. This happens if Ansible was installed via pip into a location not in the system PATH.
Fix: If you installed via dnf, the binary is at /usr/bin/ansible-playbook and should be in PATH. If it’s elsewhere, set the ansible-playbook path explicitly in the project’s Ansible plugin settings. Or add the path to /var/lib/rundeck/.bashrc.
SSH Connections Time Out
Symptom: Jobs hang for 30 seconds per node and then fail with “Timeout” errors.
Cause: Firewall on the managed node is blocking SSH, or DNS resolution is failing for the hostname.
Fix: Test from the Rundeck host:
sudo -u rundeck ssh -v 192.168.1.51
The verbose flag will show where the connection stalls. Common culprits: firewalld on the target node doesn’t allow SSH, the IP address is wrong, or the target is offline.
Plugin Version Mismatch After Rundeck Upgrade
Symptom: After upgrading Rundeck, the Ansible plugin stops working. Error messages mention class loading failures or incompatible plugin versions.
Cause: The Ansible plugin JAR in /var/lib/rundeck/libext/ is not compatible with the new Rundeck version.
Fix: Download the latest plugin version from the GitHub releases page, replace the old JAR, and restart Rundeck. Always check plugin compatibility notes before upgrading Rundeck.