Packstack cannot install OpenStack on Rocky Linux 10. RDO never published an EL10 release package, so the first dnf install centos-release-openstack-* line fails before anything else runs. Kolla-Ansible is the working route: it deploys every OpenStack service as a container, and its support matrix lists Rocky Linux 10 as a host.
This guide installs OpenStack on Rocky Linux 10 as an all-in-one Kolla-Ansible node with Keystone, Glance, Nova, Neutron, Heat and the Horizon dashboard, then boots a test instance with a floating IP. Four things break on a stock Rocky 10 cloud image, and each one is covered with its exact error and fix. Every step was run in October 2026 on Rocky Linux 10.2 against the Kolla-Ansible 2026.1 (Gazpacho) branch, the newest Kolla release. OpenStack Hibiscus itself shipped on September 30, but Kolla trails the coordinated release and has not cut its Hibiscus branch yet.
Why Packstack fails on Rocky Linux 10
Packstack installs from RDO, and RDO reaches Rocky through the centos-release-openstack-* packages in the extras repo. Rocky 9 extras carries them from Yoga through Epoxy. Rocky 10 extras carries none, and the CentOS Stream 10 cloud SIG only publishes OKD. On a Rocky 10 host the install stops here:
sudo dnf -y install centos-release-openstack-dalmatian
There is no package to match:
No match for argument: centos-release-openstack-dalmatian
Error: Unable to find a match: centos-release-openstack-dalmatian
If you need Packstack specifically, stay on an EL9 host, where Rocky 9 extras still carries release packages up to Epoxy. Our older Packstack guide for Rocky and AlmaLinux 8 shows the general flow. Everything below uses Kolla-Ansible.
What you need
The Kolla quickstart asks for 8 GB of RAM. That isn’t enough. Our node used 12,279 MB after the deploy and the demo network setup, before a single instance existed. That was with 6 vCPUs, and Kolla runs one worker per vCPU for each API service up to five, so a smaller host uses somewhat less. Plan on 16 GB for an all-in-one lab; on a tight box, openstack_service_workers: 2 in globals.yml trims the worker count. Size beyond that by what you plan to run: every instance needs its own RAM and vCPUs on top of the roughly 12 GB the control plane holds.
- Rocky Linux 10 with 16 GB RAM, 4 or more vCPUs and 40 GB of disk (the deploy used 15 GB of it). Ours had 6 vCPUs and 100 GB.
- Hardware virtualization exposed to the host. On a VM, pass the host CPU through so
grep -cE 'vmx|svm' /proc/cpuinforeturns more than zero. Kolla sets Nova tokvmunconditionally, so without it instances fail to spawn. A host with no VT-x or AMD-V needsnova_compute_virt_type: "qemu"inglobals.ymlbefore the deploy, as the Kolla libvirt guide describes, and runs guests in slow software emulation. - Two network interfaces. The first (
eth0here) carries SSH and the OpenStack APIs. The second (ens19) is handed to Neutron for the external network and must not hold an IP address. - One unused IP address on the subnet of the first interface for the API virtual IP. This guide uses 10.0.1.50 for the host and 10.0.1.250 for the VIP.
- A user with sudo. The lab user here is
josphat.
For production, the control plane goes on three dedicated controllers and compute scales out on separate nodes. Treat the all-in-one spec as a floor for following along, not a production recommendation.
Update and reboot before anything else
Do this first, even on a fresh image. The Kolla bootstrap installs kernel-modules-extra for the newest kernel on disk, not the one that is running. If a kernel update is pending, the deploy dies fifteen minutes in.
sudo dnf -y upgrade
sudo systemctl reboot
Once the host is back, confirm the running kernel is the newest one installed:
uname -r
rpm -q kernel-core
The running kernel matches the last line:
6.12.0-211.61.1.el10_2.x86_64
kernel-core-6.12.0-211.16.1.el10_2.0.1.x86_64
kernel-core-6.12.0-211.61.1.el10_2.x86_64
Error: “modprobe: FATAL: Module br_netfilter not found in directory /lib/modules/…”
This is what the skipped reboot looks like. Our first node booted a cloud image whose first-boot cloud-init run upgraded the kernel without rebooting. Bootstrap then pulled in kernel-modules-extra for the new kernel, and the deploy failed in the module-load role (output trimmed):
failed: [localhost] (item=br_netfilter) => {"ansible_loop_var": "item", "changed": false, "item": {"name": "br_netfilter"}, "msg": "modprobe: FATAL: Module br_netfilter not found in directory /lib/modules/6.12.0-211.16.1.el10_2.0.1.x86_64\n", "name": "br_netfilter", "params": "", "rc": 1, "state": "present"}
Installing kernel-modules for the running kernel does not fix it, because br_netfilter ships in kernel-modules-extra. Reboot into the new kernel and run the deploy again. The Kolla tasks are idempotent, so the rerun skips the work that already finished.
Free the second NIC for Neutron
NetworkManager grabs a DHCP lease on any cabled interface, so the second NIC usually arrives with an address. Neutron plugs that interface into its br-ex bridge and needs it bare. Find the connection name first:
nmcli -t -f NAME,DEVICE connection show
On our node the second NIC sat under an auto-created profile:
Wired connection 1:ens19
cloud-init eth0:eth0
lo:lo
Strip IPv4 and IPv6 from that profile and bring it back up:
sudo nmcli connection modify "Wired connection 1" ipv4.method disabled ipv6.method disabled
sudo nmcli connection up "Wired connection 1"
Check the result:
ip -br address
The link stays up with no address on it, which is what Neutron wants:
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 10.0.1.50/24 fe80::be24:11ff:fe72:7c8a/64
ens19 UP
Fix the hostname entry in /etc/hosts
When the cloud-init user-data enables manage_etc_hosts (Proxmox does, as can any cloud whose user-data sets it), the hostname is mapped to 127.0.0.1. Kolla refuses that, and it gets worse: cloud-init rewrites /etc/hosts from a template on every boot. The Kolla bootstrap tries to stop this by dropping manage_etc_hosts: false into /etc/cloud/cloud.cfg.d/, but user-data that sets manage_etc_hosts: true wins over it. Ours did, and the hostname went back to 127.0.0.1 after the first reboot. The Kolla source itself notes that this breaks RabbitMQ.
Remove the loopback hostname lines now. Bootstrap adds the correct entry later:
sudo sed -i -E "/^(127\.0\.0\.1|::1)\s.*\b$(hostname -s)\b/d" /etc/hosts
Then fix the template so the next boot renders the real address. Replace 10.0.1.50 with the host IP on the API interface. The template is marked as a config file in the RPM, so cloud-init updates leave your edit alone:
sudo sed -i "/{{fqdn}} {{hostname}}/d" /etc/cloud/templates/hosts.redhat.tmpl
echo "10.0.1.50 {{fqdn}} {{hostname}}" | sudo tee -a /etc/cloud/templates/hosts.redhat.tmpl
Skip the template step on hosts installed from the ISO without cloud-init. Do not disable cloud-init entirely as a shortcut either. We tried /etc/cloud/cloud-init.disabled: the hosts file held, but eth0 came back as ens18 because cloud-init was the one renaming it, and that silently breaks network_interface in the Kolla config.
Error: “Hostname has to resolve uniquely to the IP address of api_interface”
Prechecks print this when the hostname still resolves to 127.0.0.1 next to the real address. Check what the resolver returns:
getent ahostsv4 $(hostname -s)
Any 127.0.0.1 line in the result means the loopback mapping is still there. Run the sed above and the precheck passes.
Install Kolla-Ansible
Build dependencies first. Kolla-Ansible and Ansible go into a Python virtual environment, so nothing touches the system Python:
sudo dnf -y install git python3-devel libffi-devel gcc openssl-devel python3-libselinux
Create the venv and install Kolla-Ansible from the stable branch:
python3 -m venv ~/kolla-venv
source ~/kolla-venv/bin/activate
pip install -U pip
pip install git+https://opendev.org/openstack/kolla-ansible@stable/2026.1
That took 51 seconds here. Confirm what landed:
pip list 2>/dev/null | grep -E "^(kolla-ansible|ansible-core) "
The branch build reports a dev version above the last 22.2.0 tag:
ansible-core 2.20.9
kolla-ansible 22.2.1.dev12
Copy the example config and the all-in-one inventory, pull the Ansible Galaxy dependencies, and generate random passwords for every service:
sudo mkdir -p /etc/kolla
sudo chown $USER:$USER /etc/kolla
cp -r ~/kolla-venv/share/kolla-ansible/etc_examples/kolla/* /etc/kolla
cp ~/kolla-venv/share/kolla-ansible/ansible/inventory/all-in-one .
kolla-ansible install-deps
kolla-genpwd
The passwords land in /etc/kolla/passwords.yml. The Horizon admin password is the keystone_admin_password value in that file.
Configure globals.yml
The example file is almost entirely commented out. Four settings are enough for an all-in-one node. Open it:
vim /etc/kolla/globals.yml
Append these lines at the end:
kolla_base_distro: "rocky"
network_interface: "eth0"
neutron_external_interface: "ens19"
kolla_internal_vip_address: "10.0.1.250"
network_interface carries the APIs and must hold the host IP. neutron_external_interface is the bare NIC from earlier. The VIP is managed by keepalived and fronted by HAProxy, so it has to be a free address on the same subnet. Everything else keeps the Kolla defaults, which means Docker as the container engine and Open vSwitch for Neutron.
Bootstrap the host and run prechecks
Bootstrap installs Docker CE and adjusts host settings (more on those at the end):
kolla-ansible bootstrap-servers -i ./all-in-one
It finished in 93 seconds with no failures. Now run the prechecks with the flag the quickstart leaves out:
kolla-ansible prechecks -i ./all-in-one --use-test-images
A clean run ends with zero failures:
PLAY RECAP *********************************************************************
localhost : ok=106 changed=0 unreachable=0 failed=0 skipped=149 rescued=0 ignored=0
Error: “Kolla images from quay.io/openstack.kolla namespace are meant only for testing purposes”
The quickstart deploys the pre-built images from quay.io/openstack.kolla, but the 2026.1 prechecks refuse them unless you opt in. Without the flag the run stops at the registry check:
fatal: [localhost]: FAILED! => {
"assertion": "not (docker_registry == \"quay.io\" and docker_namespace == \"openstack.kolla\")",
"changed": false,
"evaluated_to": false,
"msg": "Kolla images from quay.io/openstack.kolla namespace are meant only for testing purposes, if you want to continue using them please use --use-test-images CLI argument"
}
Add --use-test-images to the prechecks command only. The deploy command rejects it with kolla-ansible deploy: error: unrecognized arguments: --use-test-images. For production, build your own images with Kolla or mirror them into a private registry, then point docker_registry at it and the check passes on its own.
Deploy OpenStack on Rocky Linux 10
One command pulls the images and starts every service:
kolla-ansible deploy -i ./all-in-one
On our node it ran for 15 minutes 41 seconds. One task prints Timeout when waiting for search string MariaDB with ...ignoring under it. That is Kolla probing for an existing database cluster on a first deploy and is expected. The recap is what matters:
PLAY RECAP *********************************************************************
localhost : ok=431 changed=271 unreachable=0 failed=0 skipped=283 rescued=0 ignored=1
Finish with post-deploy, which writes the admin credentials to /etc/kolla/clouds.yaml and /etc/kolla/admin-openrc.sh:
kolla-ansible post-deploy -i ./all-in-one
Set up the OpenStack client
Install the client into the same venv, pinned to the upper constraints of the release so it matches the deployed APIs:
pip install python-openstackclient -c https://releases.openstack.org/constraints/upper/2026.1
The client doesn’t read /etc/kolla. Copy clouds.yaml to where it looks, then select the admin cloud for this shell:
mkdir -p ~/.config/openstack
cp /etc/kolla/clouds.yaml ~/.config/openstack/
export OS_CLOUD=kolla-admin
Without the copy, every command fails with Cloud kolla-admin was not found. The standalone OpenStack client guide covers running it from a workstation instead.
Check the compute services and network agents:
openstack compute service list -c Binary -c Host -c Status -c State
openstack network agent list -c "Agent Type" -c Host -c Alive -c State
Everything reports up on the single host, with the classic Open vSwitch agent set rather than OVN:

Nova runs with virt_type = kvm, the Kolla default for nova_compute_virt_type.
Launch a test instance
Kolla ships a script that uploads a CirrOS image, creates a demo network behind a router, an external network on 10.0.2.0/24, default flavors, and a keypair named mykey from ~/.ssh/id_ecdsa (generated if missing):
~/kolla-venv/share/kolla-ansible/init-runonce
Boot an instance on the demo network:
openstack server create --image cirros --flavor m1.tiny --key-name mykey --network demo-net demo1 --wait
It went ACTIVE in 18.5 seconds. With the demo network in place the node runs 38 containers, three of them Neutron DHCP and router sidecars that init-runonce triggered, and none reports unhealthy. Give the instance a floating IP from the external network:
FIP=$(openstack floating ip create public1 -f value -c floating_ip_address)
openstack server add floating ip demo1 "${FIP}"
echo "${FIP}"
The external network only exists inside br-ex, so the host cannot reach it yet. In this lab the 10.0.2.0/24 range is not routed anywhere else, so give br-ex the gateway address that init-runonce configured. On a real provider network, your upstream router owns that address instead:
sudo ip address add 10.0.2.1/24 dev br-ex
sudo ip link set br-ex up
Ping the instance and log in. CirrOS needs about half a minute to finish booting after the API says ACTIVE:
ping -c 3 "${FIP}"
ssh -o StrictHostKeyChecking=no cirros@"${FIP}" uptime
Both answer through the floating IP:

More on floating IP pools and port association is in the guide to assigning floating IPs to OpenStack instances. For real workloads, upload proper cloud images to Glance instead of CirrOS.
Log in to the Horizon dashboard
Kolla serves Horizon on port 80 of the VIP, at the root path rather than /dashboard. Open http://10.0.1.250/, sign in as admin with the keystone_admin_password from passwords.yml:

The instance from the CLI shows up under Project, Compute, Instances with both its fixed and floating address:

Network Topology draws what init-runonce built: the external public1 network, the demo router, and demo-net with the instance attached:

Under Admin, Compute, Hypervisors you can see what the single node offers to Nova. The type reads QEMU even with KVM acceleration because that is the libvirt driver name:

From here, carve the cloud up with projects, users and roles rather than running everything as admin.
What Kolla changed on the host
Bootstrap makes several host changes that are not obvious from its output. Know them before you put this node anywhere near a real network.
- SELinux is permissive. The baremetal role defaults to
change_selinux: trueandselinux_state: "permissive", and writes it to/etc/selinux/config. Our host went from Enforcing to Permissive during bootstrap. The Kolla security notes still say SELinux must stay off until policies exist for the containers, because it blocks the sudo calls services use to own their named volumes. - firewalld is stopped and disabled through
disable_firewall: truewhen it is installed, as on an ISO install. The GenericCloud image does not ship it, so our node had nothing to stop. Every API, the database and RabbitMQ listen on the host and VIP addresses. Put the node behind a network firewall or a security group on the hypervisor, and expose only Horizon and the public endpoints you need. - Docker CE is installed from the Docker repo and enabled at boot, together with
kernel-modules-extrafor the newest kernel. - The admin credentials are plain text in
/etc/kolla/passwords.yml,clouds.yamlandadmin-openrc.sh. The last two are mode 0600, butkolla-genpwdleavespasswords.ymlat 0640, so runchmod 600 /etc/kolla/passwords.yml.
A reboot brings all 38 containers back on their own, about two minutes after the host is up. Two things do not come back. The instance stays SHUTOFF because Nova does not resume guests by default, which the guide to autostarting OpenStack instances after boot changes. The 10.0.2.1 address on br-ex is gone too, since it was added by hand. Neither matters for a lab, but both catch people out after the first power cut.
To go multi-node later, the same globals.yml carries over and only the inventory changes: swap all-in-one for the multinode file and list your controllers and computes. Add every node to the cloud-init hosts template too, because cloud-init rewrites the whole file on boot and drops the entries Kolla wrote. The same tooling also runs on Debian, covered in the Kolla-Ansible guide for Debian, and the DevStack guide for Ubuntu is the faster option when you only need a throwaway developer cloud.
Hi Josphat,
Very nice article and very helpful.
Can you please rectify following line,
sudo dnf config-manager –enable PowerTools
Instead of PowerTools, it should be powertools (everything lower case)
Thanks this has been rectified.
Hi,
May we know the content of route-eno1 and route-br-ex?
sudo mv /etc/sysconfig/network-scripts/route-eno1 /etc/sysconfig/network-scripts/route-br-ex
Thanks,
JC
If your router info is not in route-xx file, you don’t need it.