Many think IaC (Infrastructure as Code) is only for AWS, Azure, or other cloud platforms.
But what if you donβt have access to public or private cloud resources?
I built a solution that lets you start with Terraform + Ansible using only VirtualBox locally:
πΉ Terraform β provisions the environment
πΉ Vagrant β manages VM lifecycle
πΉ VirtualBox β runs the virtual machine
πΉ Ansible (inside WSL) β configures the VM (installs & starts Nginx)
πΉ GitHub Actions β orchestrates the entire workflow (CI/CD style)
π The outcome:
β
A fully automated VM setup (Ubuntu on VirtualBox)
β
Nginx web server running & accessible
β
Same IaC workflow as in the cloud β but on your local machine
This approach is perfect for learning, testing, and practicing DevOps pipelines without spending on cloud resources.
π― Project Objective
The goal is to automate the deployment of a local infrastructure (a VirtualBox VM) and configure it with Ansible to run Nginx β all orchestrated via IaC tools and CI/CD.
π Tools Used
- VirtualBox β virtualization software to host the VM
- Vagrant β manages VM lifecycle in a simple workflow
- Terraform β declaratively provisions infrastructure
- Windows Subsystem for Linux (WSL) β runs Linux tools on Windows (needed for Ansible)
- Ansible β configuration management & app deployment
- GitHub Actions β CI/CD automation
βοΈ Setup & Installation
1. Install VirtualBox
- Enable virtualization (Intel VT-x / AMD-V) in BIOS/UEFI.
- Download VirtualBox and install it.
- (Optional but recommended) Install the VirtualBox Extension Pack.
- Verify by launching VirtualBox Manager.
2. Install Terraform
- Download Terraform.
- Extract
terraform.exe
toC:\terraform
. - Add it to PATH.
- Verify:
terraform version
3. Install Vagrant
- Download Vagrant.
- Install via the
.msi
file. - Restart your system.
- Verify:
vagrant --version
4. Install WSL & Ansible
- Enable WSL:
wsl --install
- Install Ubuntu.
- Inside Ubuntu:
sudo apt update
sudo apt install -y ansible
Or via pip:
sudo apt install -y python3-pip
pip3 install ansible
- Verify:
ansible --version
π Architecture & Workflow
The workflow is:
- Terraform β triggers Vagrant
- Vagrant β defines & creates the VM (on VirtualBox)
- Ansible β configures the VM (installs Nginx)
- GitHub Actions β automates the entire pipeline
π¦ Step-by-Step Execution
Phase 1: Create VM with Terraform + Vagrant
main.tf
:
terraform {
required_providers {
vagrant = {
source = "bmatcuk/vagrant"
version = ">= 4.0.0"
}
}
required_version = ">= 1.5.0"
}
provider "vagrant" {}
resource "null_resource" "ubuntu_vm" {
provisioner "local-exec" {
command = "vagrant up"
working_dir = "C:/Users/HOUSSAM/Desktop/terraform-ansible-vbox"
}
}
output "vagrant_info" {
value = "Alles gut"
}
Vagrantfile
:
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/focal64"
config.vm.network "private_network", ip: "192.168.56.10"
config.vm.boot_timeout = 1200
end
Phase 2: Prepare Ansible Inventory
inventory.ini
:
[ubuntu]
127.0.0.1 ansible_user=vagrant ansible_ssh_private_key_file=/mnt/c/Users/HOUSSAM/Desktop/terraform-ansible-vbox/.vagrant/machines/default/virtualbox/private_key ansible_ssh_extra_args='-o StrictHostKeyChecking=no'
Phase 3: Configure VM with Ansible
playbook.yml
:
- hosts: ubuntu
become: yes
tasks:
- name: Update apt cache
apt: update_cache: yes
- name: Install nginx
apt: name=nginx state=present
- name: Ensure nginx is running
service: name=nginx state=started
Phase 4: Automate with GitHub Actions
Example workflow (.github/workflows/main.yml
):
name: Terraform-Vagrant-Ansible
on:
push:
branches:
- main
workflow_dispatch:
jobs:
terraform:
name: Terraform & Vagrant
runs-on: self-hosted
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.7
- name: Terraform Init
run: C:\Terraform\terraform.exe init
- name: Terraform Apply (run Vagrant)
run: C:\Terraform\terraform.exe apply -auto-approve
- name: Save inventory file
run: |
echo "[ubuntu]" > inventory.ini
echo "127.0.0.1 ansible_user=vagrant ansible_ssh_private_key_file=$HOME/.vagrant.d/insecure_private_key" >> inventory.ini
shell: pwsh
- name: Upload inventory artifact
uses: actions/upload-artifact@v4
with:
name: inventory
path: inventory.ini
ansible:
name: Run Ansible
runs-on: self-hosted
needs: terraform
steps:
- uses: actions/checkout@v3
- name: Download inventory
uses: actions/download-artifact@v4
with:
name: inventory
- name: Fix private key permissions
shell: pwsh
run: |
wsl --user root chmod 600 /mnt/c/Users/HOUSSAM/Desktop/terraform-ansible-vbox/.vagrant/machines/default/virtualbox/private_key
- name: Remove old SSH host key
shell: pwsh
run: |
wsl --user root ssh-keygen -f "/root/.ssh/known_hosts" -R "[127.0.0.1]:2222"
- name: Run Playbook
shell: pwsh
run: |
wsl --user root ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i /mnt/c/Users/HOUSSAM/Desktop/terraform-ansible-vbox/inventory.ini /mnt/c/Users/HOUSSAM/Desktop/terraform-ansible-vbox/playbook.yml
β Results
- Ubuntu VM provisioned in VirtualBox
-
Nginx installed & running β accessible at
http://192.168.56.10
- End-to-end workflow fully automated via GitHub Actions
- Reproducible setup β no cloud required π
π Conclusion
This project shows how IaC concepts can be applied to local infrastructure with the same rigor used in cloud environments.
Itβs a great way for DevOps engineers and learners to practice Terraform, Ansible, CI/CD, and automation pipelines without spending on cloud providers.
So , Thank you and I am here to answer your questions.
Houssam Naji
Top comments (0)