{"id":16780506,"url":"https://github.com/monolithprojects/terraform-libvirt-vm","last_synced_at":"2026-03-11T13:17:53.745Z","repository":{"id":41532790,"uuid":"322939602","full_name":"MonolithProjects/terraform-libvirt-vm","owner":"MonolithProjects","description":"Terraform module for KVM/Libvirt Virtual Machine.","archived":false,"fork":false,"pushed_at":"2024-05-01T20:41:26.000Z","size":60,"stargazers_count":38,"open_issues_count":8,"forks_count":14,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-05-03T03:13:39.431Z","etag":null,"topics":["kvm","libvirt","libvirt-virtual-machine","libvirt-vm-terraform","module","terraform","terraform-module","virtual-machine","vm"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MonolithProjects.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-19T21:17:52.000Z","updated_at":"2024-05-30T00:59:48.547Z","dependencies_parsed_at":"2024-05-30T00:59:35.223Z","dependency_job_id":null,"html_url":"https://github.com/MonolithProjects/terraform-libvirt-vm","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/MonolithProjects/terraform-libvirt-vm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MonolithProjects%2Fterraform-libvirt-vm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MonolithProjects%2Fterraform-libvirt-vm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MonolithProjects%2Fterraform-libvirt-vm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MonolithProjects%2Fterraform-libvirt-vm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MonolithProjects","download_url":"https://codeload.github.com/MonolithProjects/terraform-libvirt-vm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MonolithProjects%2Fterraform-libvirt-vm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30382669,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-11T12:49:11.341Z","status":"ssl_error","status_checked_at":"2026-03-11T12:46:41.342Z","response_time":84,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kvm","libvirt","libvirt-virtual-machine","libvirt-vm-terraform","module","terraform","terraform-module","virtual-machine","vm"],"created_at":"2024-10-13T07:35:18.898Z","updated_at":"2026-03-11T13:17:53.726Z","avatar_url":"https://github.com/MonolithProjects.png","language":"HCL","readme":"# Libvirt VM Terraform module\n\n[![GitHub Actions](https://github.com/MonolithProjects/terraform-libvirt-vm/workflows/Lint/badge.svg)](https://github.com/MonolithProjects/terraform-libvirt-vm/actions)\n[![License](https://img.shields.io/github/license/MonolithProjects/terraform-libvirt-vm)](https://github.com/MonolithProjects/terraform-libvirt-vm/blob/master/LICENSE)\n[![Terraform](https://badgen.net/badge/Terraform%20Registry/yes/blue?icon=terraform)](https://registry.terraform.io/modules/MonolithProjects/vm/libvirt/latest)\n\nTerraform module for KVM/Libvirt Virtual Machine. This module will create a KVM Virtual Machine(s), configure it using Cloud Init and test the ssh connection. This module is using [dmacvicar/libvirt](https://github.com/dmacvicar/terraform-provider-libvirt) Terraform provider.\n\n## What it provides\n\n- creates one or more VMs\n- one NIC per domain, connected to the network using the **bridge interface**\n- setup network interface using DHCP or static configuration\n- cloud_init VM(s) configuration (Ubuntu+Netplan complient)\n- optionally add multiple extra disks\n- test the ssh connection\n\n## Tested on\n\n- Ubuntu 20.04 TLS Cloud Image\n- Ubuntu 22.04 TLS Cloud Image\n\n\u003c!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK --\u003e\n## Requirements\n\n| Name | Version |\n|------|---------|\n| \u003ca name=\"requirement_terraform\"\u003e\u003c/a\u003e [terraform](#requirement\\_terraform) | \u003e= 1.0 |\n| \u003ca name=\"requirement_libvirt\"\u003e\u003c/a\u003e [libvirt](#requirement\\_libvirt) | \u003e= 0.7.0 |\n\n## Modules\n\nNo modules.\n\n## Resources\n\n| Name | Type |\n|------|------|\n| [libvirt_cloudinit_disk.commoninit](https://registry.terraform.io/providers/dmacvicar/libvirt/latest/docs/resources/cloudinit_disk) | resource |\n| [libvirt_domain.virt-machine](https://registry.terraform.io/providers/dmacvicar/libvirt/latest/docs/resources/domain) | resource |\n| [libvirt_volume.base-volume-qcow2](https://registry.terraform.io/providers/dmacvicar/libvirt/latest/docs/resources/volume) | resource |\n| [libvirt_volume.volume-qcow2](https://registry.terraform.io/providers/dmacvicar/libvirt/latest/docs/resources/volume) | resource |\n\n## Inputs\n\n| Name | Description | Type | Default | Required |\n|------|-------------|------|---------|:--------:|\n| \u003ca name=\"input_additional_disk_ids\"\u003e\u003c/a\u003e [additional\\_disk\\_ids](#input\\_additional\\_disk\\_ids) | List of volume ids | `list(string)` | `[]` | no |\n| \u003ca name=\"input_autostart\"\u003e\u003c/a\u003e [autostart](#input\\_autostart) | Autostart the domain | `bool` | `true` | no |\n| \u003ca name=\"input_base_pool_name\"\u003e\u003c/a\u003e [base\\_pool\\_name](#input\\_base\\_pool\\_name) | Name of base OS image | `string` | `null` | no |\n| \u003ca name=\"input_base_volume_name\"\u003e\u003c/a\u003e [base\\_volume\\_name](#input\\_base\\_volume\\_name) | Name of base OS image | `string` | `null` | no |\n| \u003ca name=\"input_bridge\"\u003e\u003c/a\u003e [bridge](#input\\_bridge) | Bridge interface | `string` | `\"virbr0\"` | no |\n| \u003ca name=\"input_cpu_mode\"\u003e\u003c/a\u003e [cpu\\_mode](#input\\_cpu\\_mode) | CPU mode | `string` | `\"host-passthrough\"` | no |\n| \u003ca name=\"input_dhcp\"\u003e\u003c/a\u003e [dhcp](#input\\_dhcp) | Use DHCP or Static IP settings | `bool` | `false` | no |\n| \u003ca name=\"input_graphics\"\u003e\u003c/a\u003e [graphics](#input\\_graphics) | Graphics type (can be '`spice`' or '`vnc`') | `string` | `spice` | no |\n| \u003ca name=\"input_index_start\"\u003e\u003c/a\u003e [index\\_start](#input\\_index\\_start) | From where the indexig start | `number` | `1` | no |\n| \u003ca name=\"input_ip_address\"\u003e\u003c/a\u003e [ip\\_address](#input\\_ip\\_address) | List of IP addresses | `list(string)` | \u003cpre\u003e[\u003cbr\u003e  \"192.168.123.101\"\u003cbr\u003e]\u003c/pre\u003e | no |\n| \u003ca name=\"input_ip_gateway\"\u003e\u003c/a\u003e [ip\\_gateway](#input\\_ip\\_gateway) | IP addresses of a gateway | `string` | `\"192.168.123.1\"` | no |\n| \u003ca name=\"input_ip_nameserver\"\u003e\u003c/a\u003e [ip\\_nameserver](#input\\_ip\\_nameserver) | IP addresses of a nameserver | `string` | `\"192.168.123.1\"` | no |\n| \u003ca name=\"input_local_admin\"\u003e\u003c/a\u003e [local\\_admin](#input\\_local\\_admin) | Admin user without ssh access | `string` | `\"\"` | no |\n| \u003ca name=\"input_local_admin_passwd\"\u003e\u003c/a\u003e [local\\_admin\\_passwd](#input\\_local\\_admin\\_passwd) | Local admin user password | `string` | `\"password_example\"` | no |\n| \u003ca name=\"input_memory\"\u003e\u003c/a\u003e [memory](#input\\_memory) | RAM in MB | `string` | `\"1024\"` | no |\n| \u003ca name=\"input_os_img_url\"\u003e\u003c/a\u003e [os\\_img\\_url](#input\\_os\\_img\\_url) | URL to the OS image | `string` | `\"https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img\"` | no |\n| \u003ca name=\"input_pool\"\u003e\u003c/a\u003e [pool](#input\\_pool) | Storage pool name | `string` | `\"default\"` | no |\n| \u003ca name=\"input_runcmd\"\u003e\u003c/a\u003e [runcmd](#input\\_runcmd) | Extra commands to be run with cloud init | `list(string)` | \u003cpre\u003e[\u003cbr\u003e  \"[ systemctl, daemon-reload ]\",\u003cbr\u003e  \"[ systemctl, enable, qemu-guest-agent ]\",\u003cbr\u003e  \"[ systemctl, start, qemu-guest-agent ]\",\u003cbr\u003e  \"[ systemctl, restart, systemd-networkd ]\"\u003cbr\u003e]\u003c/pre\u003e | no |\n| \u003ca name=\"input_share_filesystem\"\u003e\u003c/a\u003e [share\\_filesystem](#input\\_share\\_filesystem) | n/a | \u003cpre\u003eobject({\u003cbr\u003e    source   = string\u003cbr\u003e    target   = string\u003cbr\u003e    readonly = bool\u003cbr\u003e    mode     = string\u003cbr\u003e  })\u003c/pre\u003e | \u003cpre\u003e{\u003cbr\u003e  \"mode\": null,\u003cbr\u003e  \"readonly\": false,\u003cbr\u003e  \"source\": null,\u003cbr\u003e  \"target\": null\u003cbr\u003e}\u003c/pre\u003e | no |\n| \u003ca name=\"input_ssh_admin\"\u003e\u003c/a\u003e [ssh\\_admin](#input\\_ssh\\_admin) | Admin user with ssh access | `string` | `\"ssh-admin\"` | no |\n| \u003ca name=\"input_ssh_keys\"\u003e\u003c/a\u003e [ssh\\_keys](#input\\_ssh\\_keys) | List of public ssh keys | `list(string)` | `[]` | no |\n| \u003ca name=\"input_ssh_private_key\"\u003e\u003c/a\u003e [ssh\\_private\\_key](#input\\_ssh\\_private\\_key) | Private key for SSH connection test (either path to file or key content) | `string` | `null` | no |\n| \u003ca name=\"input_system_volume\"\u003e\u003c/a\u003e [system\\_volume](#input\\_system\\_volume) | System Volume size (GB) | `number` | `10` | no |\n| \u003ca name=\"input_time_zone\"\u003e\u003c/a\u003e [time\\_zone](#input\\_time\\_zone) | Time Zone | `string` | `\"UTC\"` | no |\n| \u003ca name=\"input_vcpu\"\u003e\u003c/a\u003e [vcpu](#input\\_vcpu) | Number of vCPUs | `number` | `1` | no |\n| \u003ca name=\"input_vm_count\"\u003e\u003c/a\u003e [vm\\_count](#input\\_vm\\_count) | Number of VMs | `number` | `1` | no |\n| \u003ca name=\"input_vm_hostname_prefix\"\u003e\u003c/a\u003e [vm\\_hostname\\_prefix](#input\\_vm\\_hostname\\_prefix) | VM hostname prefix | `string` | `\"vm\"` | no |\n| \u003ca name=\"input_xml_override\"\u003e\u003c/a\u003e [xml\\_override](#input\\_xml\\_override) | With these variables you can: Enable hugepages; Set USB controllers; Attach USB devices | \u003cpre\u003eobject({\u003cbr\u003e    hugepages = bool\u003cbr\u003e    usb_controllers = list(object({\u003cbr\u003e      model = string\u003cbr\u003e    }))\u003cbr\u003e    usb_devices = list(object({\u003cbr\u003e      vendor  = string\u003cbr\u003e      product = string\u003cbr\u003e    }))\u003cbr\u003e    pci_devices_passthrough = list(object({\u003cbr\u003e      src_domain = string\u003cbr\u003e      src_bus    = string\u003cbr\u003e      src_slot   = string\u003cbr\u003e      src_func   = string\u003cbr\u003e      dst_domain = string\u003cbr\u003e      dst_bus    = string\u003cbr\u003e      dst_slot   = string\u003cbr\u003e      dst_func   = string\u003cbr\u003e    }))\u003cbr\u003e  })\u003c/pre\u003e | \u003cpre\u003e{\u003cbr\u003e  \"hugepages\": false,\u003cbr\u003e  \"usb_controllers\": [\u003cbr\u003e    {\u003cbr\u003e      \"model\": \"piix3-uhci\"\u003cbr\u003e    }\u003cbr\u003e  ],\u003cbr\u003e  \"usb_devices\": []\u003cbr\u003e  \"pci_devices_passthrough\": []\u003cbr\u003e}\u003c/pre\u003e | no |\n| \u003ca name=\"input_bastion_host\"\u003e\u003c/a\u003e [bastion\\_host](#input\\_bastion\\_host) | ssh bastion host | `string` | `null` | no |\n| \u003ca name=\"input_bastion_user\"\u003e\u003c/a\u003e [bastion\\_user](#input\\_bastion\\_user) | ssh user on bastion host | `string` | `null` | no |\n| \u003ca name=\"input_bastion_ssh_private_key\"\u003e\u003c/a\u003e [bastion\\_ssh\\_private\\_key](#input\\_bastion\\_ssh\\_private\\_key) | ssh private key for bastion host (either path to file or key content) | `string` | `null` | no |\n\n\n## Outputs\n\n| Name | Description |\n|------|-------------|\n| \u003ca name=\"output_ip_address\"\u003e\u003c/a\u003e [ip\\_address](#output\\_ip\\_address) | n/a |\n| \u003ca name=\"output_name\"\u003e\u003c/a\u003e [name](#output\\_name) | n/a |\n\u003c!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK --\u003e\n\n## Example\n\nExample with enable HugePages, Attached USB device, changed USB controller model... :\n\n```hcl\nterraform {\n  required_version = \"\u003e= 0.13\"\n    required_providers {\n      libvirt = {\n        source  = \"dmacvicar/libvirt\"\n      }\n    }\n}\n\nresource \"tls_private_key\" \"ecdsa-p384-bastion\" {\n  algorithm   = \"ECDSA\"\n  ecdsa_curve = \"P384\"\n}\n\nprovider \"libvirt\" {\n  uri = \"qemu+ssh://hero@192.168.165.100/system\"\n}\n\nmodule \"vm\" {\n  source  = \"MonolithProjects/vm/libvirt\"\n  version = \"1.8.0\"\n\n  vm_hostname_prefix = \"server\"\n  vm_count    = 3\n  memory      = \"2048\"\n  vcpu        = 1\n  pool        = \"terra_pool\"\n  system_volume = 20\n  dhcp        = true\n  local_admin = \"local-admin\"\n  ssh_admin   = \"ci-user\"\n  ssh_private_key = \"~/.ssh/id_ed25519\"\n  local_admin_passwd = \"$6$rounds=4096$xxxxxxxxHASHEDxxxPASSWORD\"\n  ssh_keys    = [\n    \"ssh-ed25519 AAAAxxxxxxxxxxxxSSHxxxKEY example\",\n    ]\n  bastion_host = \"10.0.0.1\"\n  bastion_user = \"admin\"\n  bastion_ssh_private_key = tls_private_key.ecdsa-p384-bastion.private_key_pem\n  time_zone   = \"CET\"\n  os_img_url  = \"file:///home/myuser/ubuntu-20.04-server-cloudimg-amd64.img\"\n  xml_override = {\n      hugepages = true,\n      usb_controllers = [\n        {\n          model = \"qemu-xhci\"\n        }\n      ],\n      usb_devices = [\n        {\n          vendor = \"0x0bc2\",\n          product = \"0xab28\"\n        }\n      ]\n      pci_devices_passthrough = [\n        {\n          src_domain = \"0x0000\",\n          src_bus    = \"0xc1\",\n          src_slot   = \"0x00\",\n          src_func   = \"0x0\",\n          dst_domain = \"0x0000\",\n          dst_bus    = \"0x00\",\n          dst_slot   = \"0x08\"\n          dst_func   = \"0x0\"\n        },\n        {\n          src_domain = \"0x0000\",\n          src_bus    = \"0xc1\",\n          src_slot   = \"0x00\",\n          src_func   = \"0x1\",\n          dst_domain = \"0x0000\",\n          dst_bus    = \"0x00\",\n          dst_slot   = \"0x09\"\n          dst_func   = \"0x0\"\n        }\n      ]      \n    }\n}\n\noutput \"ip_addresses\" {\n  value = module.nodes\n}\n```\n\nStatic IP settings... :\n\n```hcl\nterraform {\n  required_version = \"\u003e= 0.13\"\n    required_providers {\n      libvirt = {\n        source  = \"dmacvicar/libvirt\"\n        version = \"0.6.3\"\n      }\n    }\n}\n\nprovider \"libvirt\" {\n  uri = \"qemu+ssh://hero@192.168.165.100/system\"\n}\n\nmodule \"vm\" {\n  source  = \"MonolithProjects/vm/libvirt\"\n  version = \"1.8.0\"\n\n  vm_hostname_prefix = \"server\"\n  vm_count    = 3\n  memory      = \"2048\"\n  vcpu        = 1\n  pool        = \"terra_pool\"\n  system_volume = 20\n  share_filesystem = {\n    source = \"/tmp\"\n    target = \"tmp\"\n    readonly = false\n  }\n\n  dhcp        = false\n  ip_address  = [\n                  \"192.168.165.151\",\n                  \"192.168.165.152\",\n                  \"192.168.165.153\"\n                ]\n  ip_gateway  = \"192.168.165.254\"\n  ip_nameserver = \"192.168.165.104\"\n\n  local_admin = \"local-admin\"\n  ssh_admin   = \"ci-user\"\n  ssh_private_key = \"~/.ssh/id_ed25519\"\n  local_admin_passwd = \"$6$rounds=4096$xxxxxxxxHASHEDxxxPASSWORD\"\n  ssh_keys    = [\n    \"ssh-ed25519 AAAAxxxxxxxxxxxxSSHxxxKEY example\",\n    ]\n  time_zone   = \"CET\"\n  os_img_url  = \"file:///home/myuser/ubuntu-20.04-server-cloudimg-amd64.img\"\n}\n\noutput \"outputs\" {\n  value = module.nodes\n}\n```\n\n\u003e The shared directory from the example can be mounted inside the VM with command `sudo mount -t 9p -o trans=virtio,version=9p2000.L,rw tmp /host/tmp`\n\nCreate a VM with an extra disk\n\n```\n# Creates a 50GB extra-data-disk within vms pool\nresource \"libvirt_volume\" \"data_volume\" {\n  pool = \"vms\"\n  name  = \"extra-data-disk.qcow2\"\n  format = \"qcow2\"\n  size = 1024*1024*1024*50\n}\n\nmodule \"vm\" {\n  source  = \"MonolithProjects/vm/libvirt\"\n  version = \"1.8.0\"\n\n  vm_hostname_prefix = \"data-server\"\n  base_volume_name = \"debian-11-base.qcow2\"\n  base_pool_name = \"linked-images\"\n  vm_count    = 1\n  bridge =        \"bridge-dmz\"\n  memory      = \"4096\"\n  vcpu        = 4\n  pool        = \"vms\"\n  system_volume = 25\n  additional_disk_ids = [ libvirt_volume.data_volume.id ]\n  dhcp        = true\n  ssh_admin   = \"admin\"\n  ssh_keys    = [\n    chomp(file(\"~/.ssh/id_rsa.pub\"))\n    ]\n  time_zone   = \"America/Argentina/Buenos_Aires\"\n}\n\noutput \"ip_addresses\" {\n  value = module.vm\n}\n```\n\n## Module output example\n\n```hcl\noutput_data = {\n  \"ip_address\" = [\n    \"192.168.165.151\",\n    \"192.168.165.152\",\n    \"192.168.165.153\",\n  ]\n  \"name\" = [\n    \"server01\",\n    \"server02\",\n    \"server03\",\n  ]\n}\n```\n\n## License\n\nMIT\n\n## Author Information\n\nCreated in 2020 by Michal Muransky\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonolithprojects%2Fterraform-libvirt-vm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmonolithprojects%2Fterraform-libvirt-vm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonolithprojects%2Fterraform-libvirt-vm/lists"}