Atomic Host from Project Atomic is a lightweight, container-based OS built upon the principle of immutable infrastructure using the LDK (Linux, Docker, Kubernetes) stack. Atomic Hosts are built from standard RPM packages composed into filesystem trees using rpm-ostree.

Atomic Host comes with certain packages pre-installed. It does not allow installing packages randomly, to introduce and maintain the only-container workflow. But Atomic Host allows adding RPM packages to OSTree to build an Atomic Host which boots into its own OSTree. This guide describes the method for the automation of building an Atomic Host. At the end of this article, you’ll able to create a VM from a QCOW2 image, which will use OSTree. This VM can also be used for testing purpose (please feel free to open an issue in that case)!

One of the primary benefits to Atomic Host and OSTree is the ability to configure once, deploy many times using custom OSTree images.

The procedure and playbook below enable you to create your own Atomic Host OSTree image. This is the first step in creating your own distributions of Atomic Host to install on your cloud servers. Note that it will install a bunch of requirements on your local server, as well as using system resources heavily. As such, you may want to run it on a development machine instead of your personal laptop.

Getting started

To get started, you will need to have these requirements.

$ sudo dnf install ansible python2-dnf

Next, you need to clone the Build-Atomic-Host git repo on your working machine.

$ git clone
$ cd build-atomic-host

Create VM from the QCOW2 image

The following commands create a VM from the QCOW2 image, where username is


and password is


. Here,


is the instance name.

$ sudo sh atomic-node /path/to/fedora-atomic25.qcow2
# For example: /var/lib/libvirt/images/Fedora-Atomic-25-20170131.0.x86_64.qcow2

Install requirements and start HTTP server

The tree is made available via a web server. The following Ansible playbook installs the requirements, creates the directory structure, initializes the OSTree repository and starts the HTTP server on TCP port 35000.

$ ansible-playbook setup.yml --ask-sudo-pass


ip addr

to check IP Address of the HTTP server.

This is how it looks when you check for the IP address of the running HTTP server with the above command.
According to the output, the IP address of the running HTTP server is


Give OSTree a name and add IP address

Replace the variables given in vars/atomic.yml with the OSTree name and HTTP server IP address. For instance:

# Variables for Atomic host
atomicname: my-atomic



is the OSTree name and

is the HTTP server IP address we discovered above.

Run all-in-one playbook

The following playbook composes the OSTree, performs SSH-setup and rebases on the created tree.

$ ansible-playbook main.yml --ask-sudo-pass

Check IP and reboot

The following command returns IP Address of the running Atomic instance.

$ sudo virsh domifaddr atomic-node

Now, log in via SSH to the Atomic Host and reboot it so that it reboots into the created OSTree:

$ ssh atomic-user@<atomic-hostIP>
$ sudo systemctl reboot

Wait for a few minutes after the reboot so that you do not get “connection refused” by the host while SSH-ing.

Verify: SSH to the Atomic Host

$ ssh atomic-user@
[atomic-user@atomic-node ~]$ sudo rpm-ostree status
State: idle
● my-atomic:fedora-atomic/25/x86_64/docker-host
       Version: 25.1 (2017-02-07 05:34:46)
        Commit: 15b70198b8ec7fd54271f9672578544ff03d1f61df8d7f0fa262ff7519438eb6
        OSName: fedora-atomic

       Version: 25.51 (2017-01-30 20:09:59)
        Commit: f294635a1dc62d9ae52151a5fa897085cac8eaa601c52e9a4bc376e9ecee11dd
        OSName: fedora-atomic

Now you have the updated OSTree.

In a future post, we will see the automation of building an Atomic Host using the OSTree with customized packages (addition / deletion of packages). You can have a look at the documentation to refer to the process of composing OSTree.

Special thanks

Shout-out for the following folks: