Fix Ansible 'Failed to connect to bus: No such file or directory' When Using systemd Module in Containers

intermediate๐Ÿ”ง Ansible2026-05-16| Ansible 2.9+, Docker containers, LXC containers, systemd module, Ubuntu/Debian/CentOS guests

Error Message

Failed to connect to bus: No such file or directory
#ansible#systemd#dbus#docker#container

The Error

Your Ansible playbook uses the systemd module to start, stop, or enable a service. On real VMs or bare-metal hosts it works fine. Target a Docker or LXC container, and you hit this:

TASK [Enable and start nginx] **************************
fatal: [container-host]: FAILED! => {
    "changed": false,
    "msg": "Failed to connect to bus: No such file or directory"
}

The task dies immediately. Nothing else in the playbook runs.

Why This Happens

Ansible's systemd module talks to systemd over D-Bus. On a normal Linux host, the D-Bus daemon listens at /run/dbus/system_bus_socket and everything connects cleanly.

Containers don't have that socket. Most container images ship without systemd or D-Bus โ€” they're built to run a single process, not a full init stack. When Ansible goes looking for /run/dbus/system_bus_socket, the file simply isn't there. Hence: No such file or directory.

You'll run into this most often when:

  • You're using Docker containers as Ansible inventory targets for Molecule testing or CI pipelines
  • Your container image is a minimal distro build (e.g., ubuntu:22.04, not a purpose-built Ansible image)
  • The container was started without --privileged or without the cgroup filesystem mounted
  • You're running Molecule with the Docker driver against a stock base image

Fix 1: Use service Instead of systemd

No systemd-specific features? Just switch modules. The service module probes whatever init system is actually running and delegates to it:

# Before โ€” breaks in containers
- name: Enable and start nginx
  ansible.builtin.systemd:
    name: nginx
    state: started
    enabled: true

# After โ€” works in containers and on VMs
- name: Enable and start nginx
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: true

Inside a container with no init system, service falls back to calling the service binary directly or SysV init scripts. No D-Bus needed. This is the one-line fix for most cases.

Fix 2: Silence the Error with ignore_errors (Stopgap Only)

Sometimes you just need the playbook to not explode during a daemon_reload step that doesn't actually matter in a container. Slapping ignore_errors: true on it buys time:

- name: Reload systemd daemon
  ansible.builtin.systemd:
    daemon_reload: true
  ignore_errors: true

- name: Start nginx
  ansible.builtin.service:
    name: nginx
    state: started

Don't use this in production playbooks. It masks real failures. It's only useful when you're iterating on a role locally and you know the daemon_reload is irrelevant in your test environment.

Fix 3: Detect Containers and Skip Systemd Tasks Conditionally

For roles that run against both VMs and containers, the right move is to detect the environment at runtime and gate your systemd tasks behind a when: condition.

- name: Check if running inside a container
  ansible.builtin.stat:
    path: /.dockerenv
  register: dockerenv_file

- name: Set container fact
  ansible.builtin.set_fact:
    is_container: "{{ dockerenv_file.stat.exists or ansible_virtualization_type in ['docker', 'lxc', 'container'] }}"

- name: Enable and start nginx (skip in containers)
  ansible.builtin.systemd:
    name: nginx
    state: started
    enabled: true
    daemon_reload: true
  when: not is_container

LXC containers won't have /.dockerenv, so check ansible_virtualization_type as well. Gather the virtual subset first if you haven't already:

- name: Gather virtualization facts
  ansible.builtin.setup:
    gather_subset:
      - virtual

- name: Set is_container fact
  ansible.builtin.set_fact:
    is_container: "{{ ansible_virtualization_type in ['docker', 'lxc', 'podman', 'container', 'VirtualPC'] }}"

This approach keeps your role portable without forking it into separate container and VM versions.

Fix 4: Run a Systemd-Capable Container (Molecule / CI Testing)

Writing a role that genuinely manages services? Test it against a container that actually runs systemd. Jeff Geerling's geerlingguy/docker-ubuntu2204-ansible image is the standard choice here โ€” it ships with systemd configured and ready.

# docker run with systemd support
docker run -d \
  --name test-container \
  --privileged \
  --volume /sys/fs/cgroup:/sys/fs/cgroup:rw \
  --cgroupns host \
  geerlingguy/docker-ubuntu2204-ansible \
  /lib/systemd/systemd

For Molecule, wire this up in molecule/default/molecule.yml:

driver:
  name: docker

platforms:
  - name: instance
    image: geerlingguy/docker-ubuntu2204-ansible
    command: /lib/systemd/systemd
    privileged: true
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:rw
    cgroupns_mode: host
    pre_build_image: true

With systemd running as PID 1, D-Bus starts automatically. The Ansible systemd module connects normally โ€” no workarounds needed.

Fix 5: Override Service Manager Per Inventory Group

Mixed inventory โ€” some VMs, some containers โ€” and you don't want to scatter when: conditions through your roles? Set ansible_service_mgr at the group level:

# inventory/hosts
[containers]
container-01 ansible_connection=docker

[containers:vars]
ansible_service_mgr=sysvinit

Then branch on it in your role tasks:

- name: Manage nginx service (systemd hosts)
  ansible.builtin.systemd:
    name: nginx
    state: started
    enabled: true
  when: ansible_service_mgr == 'systemd'

- name: Manage nginx service (non-systemd hosts)
  ansible.builtin.service:
    name: nginx
    state: started
  when: ansible_service_mgr != 'systemd'

Verify the Fix

Re-run with -v and limit to the container host to confirm the bus error is gone:

ansible-playbook -i inventory site.yml -v --limit container-01

Clean output looks like this:

TASK [Enable and start nginx] **************************
ok: [container-01]

PLAY RECAP *********************************************
container-01  : ok=5  changed=1  unreachable=0  failed=0

If you went with Fix 3 (container detection), add a quick debug task to confirm the fact resolved correctly:

- name: Debug container detection
  ansible.builtin.debug:
    msg: "is_container={{ is_container }}, service_mgr={{ ansible_service_mgr }}"

Quick Reference

  • Fastest fix: swap ansible.builtin.systemd โ†’ ansible.builtin.service
  • CI/Molecule: use geerlingguy/docker-ubuntu2204-ansible with --privileged + cgroup mount
  • Mixed inventory: detect container via /.dockerenv or ansible_virtualization_type, gate with when:
  • Root cause: D-Bus socket /run/dbus/system_bus_socket doesn't exist in containers that don't run an init system

Related Error Notes