Configure a VM with Ansible
Configure a VM with Ansible
This pattern composes Compute and Network.
A ready-to-use Ansible playbook that takes a freshly provisioned Quake AI VM and configures it for production use: package baseline, non-root sudo user, SSH hardening, host firewall, and a placeholder web service. The playbook is idempotent; rerun it to converge a host that has drifted.
This template handles the Day 1 configure step. Provision the VM with OpenTofu first, or use the combined provision-and-configure template when you want both steps in one workflow.
Monthly cost estimate
Pricing calculator ↗Sized as a custom package on shared vCPU.
Monthly total for the required template above. Use the configurator below to add optional pieces and see the total update.
What each resource is for
Vm
s1a.small · 2 shared vCPU, 2 GiB RAM, 0.5 Gbps
Compute shown per role at custom-package rates ($29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM). The headline above is the billed total: the cheaper of a named plan and the custom package, plus add-ons.
Included in baseline
s1a.small
2 shared vCPU, 2 GiB RAM, 0.5 Gbps
Compute + RAM rate basis
2 vCPU + 2 GiB RAM at $29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM (regular). Totals apply the flat −$5/mo package promotion.
Block storage (20 GiB)
20 GiB at $0.08/GiB/mo
Public IP (included)
1 included with the custom package
Package promotional discount
Flat −$5.00/mo on the custom package (same promotion as named plans).
Included at no charge
These line items are zero on Quake AI. Many other providers meter them separately.
Data transfer (inbound and outbound)
Unlimited data transfer on every plan; Quake AI does not meter per-GB egress.
AWS, GCP, and Azure meter outbound transfer per GB. DigitalOcean and Hetzner include an allowance on compute plans, then charge overage.
Learn morePrivate networking
Private networks, subnets, Neutron routers, and security groups are included with the plan.
VPC objects are usually free to create elsewhere, but NAT gateways bill hourly plus per-GB processed. Quake AI uses router SNAT with no separate NAT line item.
Control-plane API requests
OpenStack API calls for provisioning and management are included.
Some managed services on other clouds meter API calls or charge for premium control-plane features.
Pricing data last validated: . For current rates, check quake.ai/pricing.
How to use this template#
Prerequisites#
- Ansible 6+ installed: see Get started with Ansible on Quake AI.
- The
openstack.cloud,ansible.posix, andcommunity.generalcollections installed (see Required collections below). - A Quake AI VM running
Ubuntu-24.04with a public floating IP and an SSH keypair you can use to log in asubuntu. - Your operator SSH public key on disk at
~/.ssh/id_ed25519.pub.
Required collections#
The playbook uses ansible.posix.authorized_key for the operator key and community.general.ufw for the host firewall. Declare both alongside openstack.cloud in a requirements.yml at the project root:
collections:
- name: openstack.cloud
- name: ansible.posix
version: ">=1.5.4"
- name: community.general
version: ">=8.0.0"Install them once before the first run:
ansible-galaxy collection install -r requirements.ymlFile layout#
configure-vm/
inventory.ini
playbooks/
site.yml
group_vars/
all.ymlRun command#
cd configure-vm
ansible-playbook -i inventory.ini playbooks/site.ymlWhat this template produces#
- A non-root user
deploywith sudo and your SSH public key - SSH daemon hardened: root login disabled, password authentication disabled,
MaxAuthTries 3 - Baseline packages installed:
curl,git,vim,fail2ban,ufw,nginx ufwenabled with default-deny inbound, allow rules for SSH, HTTP, and HTTPSnginxserving a placeholder index page on port 80, verified withansible.builtin.uri
How to extend#
- Replace the placeholder index page by templating your own
index.htmlfromtemplates/index.html.j2. - Add application deployment tasks under a new
roles/app/and import the role fromsite.yml. - Move secrets such as the operator email or API tokens into Ansible Vault and reference them with
vars_files. - Swap
nginxforcaddyif you want automatic TLS; installcaddyfrom its apt repo and replace the firewall rule for port 80 with port 443.
Inventory#
inventory.ini points Ansible at the host you provisioned. Replace 203.0.113.10 with your VM's floating IP.
[web]
web-01 ansible_host=203.0.113.10 ansible_user=ubuntu
[web:vars]
ansible_ssh_private_key_file=~/.ssh/id_ed25519
ansible_python_interpreter=/usr/bin/python3Group variables#
group_vars/all.yml centralizes the values the playbook references. Edit operator_email and operator_ssh_key to match your operator account.
operator_email: [email protected]
operator_user: deploy
operator_ssh_key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
baseline_packages:
- curl
- git
- vim
- fail2ban
- ufw
- nginx
firewall_allowed_ports:
- 22
- 80
- 443Playbook#
playbooks/site.yml is the entry point. Run it with ansible-playbook -i inventory.ini playbooks/site.yml.
---
- name: Configure Quake AI VM
hosts: web
become: true
gather_facts: true
tasks:
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: Upgrade installed packages
ansible.builtin.apt:
upgrade: dist
autoremove: true
- name: Install baseline packages
ansible.builtin.apt:
name: "{{ baseline_packages }}"
state: present
- name: Create non-root sudo user
ansible.builtin.user:
name: "{{ operator_user }}"
groups: sudo
shell: /bin/bash
create_home: true
append: true
- name: Authorize operator SSH key
ansible.posix.authorized_key:
user: "{{ operator_user }}"
key: "{{ operator_ssh_key }}"
state: present
- name: Allow operator passwordless sudo
ansible.builtin.copy:
dest: "/etc/sudoers.d/90-{{ operator_user }}"
content: "{{ operator_user }} ALL=(ALL) NOPASSWD:ALL\n"
mode: "0440"
owner: root
group: root
validate: visudo -cf %s
- name: Ensure /run/sshd exists for sshd validate
ansible.builtin.file:
path: /run/sshd
state: directory
mode: "0755"
- name: Harden sshd_config
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
validate: sshd -t -f %s
loop:
- { regexp: "^#?PermitRootLogin", line: "PermitRootLogin no" }
- { regexp: "^#?PasswordAuthentication", line: "PasswordAuthentication no" }
- { regexp: "^#?MaxAuthTries", line: "MaxAuthTries 3" }
notify: Restart sshd
- name: Set ufw default-deny inbound
community.general.ufw:
direction: incoming
policy: deny
- name: Allow firewall ports
community.general.ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop: "{{ firewall_allowed_ports }}"
- name: Enable ufw
community.general.ufw:
state: enabled
- name: Render placeholder index page
ansible.builtin.copy:
dest: /var/www/html/index.html
mode: "0644"
content: |
<!doctype html>
<html>
<head><title>Configured by Ansible</title></head>
<body>
<h1>Hello from Quake AI</h1>
<p>This host was configured by Ansible.</p>
</body>
</html>
- name: Ensure nginx is running
ansible.builtin.service:
name: nginx
state: started
enabled: true
- name: Verify nginx responds
ansible.builtin.uri:
url: http://127.0.0.1/
status_code: 200
return_content: false
handlers:
- name: Restart sshd
ansible.builtin.service:
name: ssh
state: restartedVerify#
After the playbook converges, confirm from your workstation:
curl http://203.0.113.10/
# expect: <h1>Hello from Quake AI</h1> ...
ssh -i ~/.ssh/id_ed25519 [email protected] -- sudo systemctl status nginx
# expect: active (running)A second run should report ok=N changed=0 against every task: idempotency is the contract.
When to use this pattern#
Configure an existing VM with Ansible after OpenTofu provisioning. Provision the host with Simple VM with Floating IP or use Provision and configure with OpenTofu plus Ansible for both steps in one workflow.
Customize this pattern#
Provision and size the underlying VM with the OpenTofu customize how-tos on Simple VM with Floating IP:
- Customize a template's image and flavor
- Add a block volume to a template
- Parameterize a template with a tfvars file
Resources, parameters, and variables
See also#
- Get started with Ansible on Quake AI: installation and first playbook
- Provision and configure with OpenTofu plus Ansible: combined-tool workflow that runs this same configuration after provisioning
- Ansible openstack.cloud module reference: catalog of provisioning modules used by the combined template
- Ansible CI/CD on Quake AI: run this playbook from GitHub Actions or GitLab CI
Usage Guidelines
The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.
For the full policy, see Usage Guidelines.
Last validated: 23.05.2026
Quick answers
See Also
Ansible on Quake AI
Shares: Ansible, Configuration Management
Automation concepts
Shares: Ansible, Configuration Management
Automation / IaC FAQ
Shares: Ansible, Configuration Management
Automation how-to guides
Shares: Ansible, Configuration Management
Automation
Shares: Ansible, Configuration Management