diff --git a/test_vm/README.MD b/test_vm/README.MD
new file mode 100644
index 000000000..9a69f91e1
--- /dev/null
+++ b/test_vm/README.MD
@@ -0,0 +1,83 @@
+# Complete Step-by-Step Guide: Vagrant + libvirt + Manual DHCP
+
+This guide will help you set up a Vagrant VM with two network interfaces:
+- **First interface:** NAT (default, for SSH access)
+- **Second interface:** Directly connected to the host via an isolated bridge (e.g., enbr99), does not get an IP automatically, and will only receive an IP from your custom DHCP server running in Docker on the host.
+
+---
+
+## 1. Install Required Packages and Dependencies
+
+```bash
+sudo apt-get update
+sudo apt-get install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager \
+ ruby ruby-dev libvirt-dev zlib1g-dev ebtables dnsmasq-base vagrant
+
+```
+
+## 2. Add Your User to the libvirt Group
+
+```bash
+sudo usermod -aG libvirt $(whoami)
+newgrp libvirt
+```
+
+Note: After adding yourself to the libvirt group, restart your session or use newgrp libvirt for the permissions to take effect.
+
+
+## 3. Check and Start libvirt Service
+
+```bash
+systemctl status libvirtd
+sudo systemctl start libvirtd
+```
+
+## 4. Install the vagrant-libvirt Plugin
+
+```bash
+vagrant plugin install vagrant-libvirt
+```
+
+## 5. Remove Old Bridge (enbr99) If It Exists
+
+```bash
+ip link show enbr99
+sudo ip link delete enbr99 type bridge
+```
+
+## 6. Create an Isolated libvirt Network Without IP and DHCP
+
+### Create the file /tmp/hostonly-noip.xml:
+
+```xml
+
+ hostonly-noip
+
+
+
+```
+
+### Create and start the network:
+
+```bash
+sudo virsh net-define /tmp/hostonly-noip.xml
+sudo virsh net-start hostonly-noip
+sudo virsh net-autostart hostonly-noip
+```
+
+## 7. Verify the Network is Active
+
+```bash
+sudo virsh net-list --all
+```
+
+You should see hostonly-noip with status active.
+
+
+## 8. Start the Virtual Machine
+
+
+```bash
+vagrant up --provider=libvirt
+```
+If you see "Permission denied to /var/run/libvirt/libvirt-sock", check your libvirt group membership and restart your session.
\ No newline at end of file
diff --git a/test_vm/Vagrantfile b/test_vm/Vagrantfile
new file mode 100644
index 000000000..da820d783
--- /dev/null
+++ b/test_vm/Vagrantfile
@@ -0,0 +1,18 @@
+Vagrant.configure("2") do |config|
+ config.vm.box = "bento/ubuntu-24.04"
+ config.vm.hostname = "ubuntu-vm"
+ config.vm.network "private_network",
+ libvirt__network_name: "hostonly-noip",
+ auto_config: false,
+ mac: "52:54:00:12:34:56"
+ config.vm.provider :libvirt do |libvirt|
+ libvirt.memory = 2048
+ libvirt.cpus = 2
+ libvirt.graphics_type = "none"
+ end
+ if ENV['USE_ANSIBLE'] == '1'
+ config.vm.provision "ansible" do |ansible|
+ ansible.playbook = "provision.yml"
+ end
+ end
+end
diff --git a/test_vm/delete_vm.sh b/test_vm/delete_vm.sh
new file mode 100755
index 000000000..3fa9e62ff
--- /dev/null
+++ b/test_vm/delete_vm.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+echo "Stopping and removing all Vagrant machines..."
+# Destroy all Vagrant VMs found in global status
+vagrant global-status --prune | awk '/libvirt|virtualbox/ {print $1}' | while read id; do
+ vagrant destroy -f "$id"
+done
+
+echo "Removing all Vagrant boxes..."
+# Remove all Vagrant boxes
+vagrant box list | awk '{print $1}' | while read box; do
+ vagrant box remove -f "$box"
+done
+
+echo "Removing all Vagrant plugins..."
+# Uninstall all Vagrant plugins
+vagrant plugin list | awk '{print $1}' | while read plugin; do
+ vagrant plugin uninstall "$plugin"
+done
+
+echo "Deleting Vagrant settings and cache..."
+# Remove Vagrant configuration and cache directory
+rm -rf ~/.vagrant.d
+
+echo "Uninstalling Vagrant..."
+# Remove Vagrant package
+sudo apt-get remove --purge -y vagrant || sudo dpkg -r vagrant
+
+echo "Removing all libvirt virtual machines..."
+# Destroy and undefine all libvirt VMs
+sudo virsh list --all | awk 'NR>2 {print $2}' | while read vm; do
+ sudo virsh destroy "$vm"
+ sudo virsh undefine "$vm" --remove-all-storage
+done
+
+echo "Removing all libvirt networks..."
+# Destroy and undefine all libvirt networks
+sudo virsh net-list --all | awk 'NR>2 {print $1}' | while read net; do
+ sudo virsh net-destroy "$net"
+ sudo virsh net-undefine "$net"
+done
+
+echo "Removing all libvirt storage volumes..."
+# Delete all storage volumes in the default pool
+sudo virsh vol-list default | awk 'NR>2 {print $1}' | while read vol; do
+ sudo virsh vol-delete "$vol" default
+done
+
+echo "Uninstalling libvirt and related packages..."
+# Remove libvirt and related packages
+sudo apt-get remove --purge -y libvirt-daemon-system libvirt-clients libvirt-dev qemu qemu-kvm bridge-utils virt-manager
+sudo apt-get autoremove --purge -y
+
+echo "Deleting libvirt configs and storage directories..."
+# Remove libvirt configuration and storage directories
+sudo rm -rf /etc/libvirt
+sudo rm -rf /var/lib/libvirt
+sudo rm -rf /var/run/libvirt
+
+echo "Done! It is recommended to reboot your system."
diff --git a/test_vm/how_to_create_local_ca.md b/test_vm/how_to_create_local_ca.md
new file mode 100644
index 000000000..ff0684070
--- /dev/null
+++ b/test_vm/how_to_create_local_ca.md
@@ -0,0 +1,123 @@
+## 1. On the Host: Create Your Own CA
+
+```bash
+mkdir ~/myCA
+cd ~/myCA
+openssl genrsa -out myorgca.key 4096
+openssl req -x509 -new -nodes -key myorgca.key -sha256 -days 1825 -out myorgca.pem -subj "/C=RU/O=MyOrganization/CN=MyOrgCA"
+```
+
+Here, O=MyOrganization is the Organization Name for your CA.
+
+## 2. On the VM: Create a Key, CSR, and Config with SAN and Organization Name
+
+### On the VM:
+
+Create a file named openssl_ip.cnf:
+
+```ini
+[ req ]
+default_bits = 2048
+prompt = no
+default_md = sha256
+req_extensions = req_ext
+distinguished_name = dn
+
+[ dn ]
+C = RU
+O = MyOrganization
+CN = 10.10.10.14
+
+[ req_ext ]
+subjectAltName = @alt_names
+
+[ alt_names ]
+IP.1 = 10.10.10.14
+```
+
+Generate the key and CSR:
+
+```bash
+openssl req -new -nodes -out nginx_ip.csr -newkey rsa:2048 -keyout nginx_ip.key -config openssl_ip.cnf
+```
+
+## 3. Copy the CSR and Config from the VM to the Host
+
+### On the host:
+
+```bash
+scp vagrant@/home/vagrant/nginx_ip.csr ~/myCA/
+scp vagrant@:/home/vagrant/openssl_ip.cnf ~/myCA/
+```
+
+## 4. On the Host: Sign the Certificate with Your CA
+
+```bash
+cd ~/myCA
+openssl x509 -req -in nginx_ip.csr -CA myorgca.pem -CAkey myorgca.key -CAcreateserial -out nginx_ip.crt -days 365 -sha256 -extfile openssl_ip.cnf -extensions req_ext
+```
+
+## 5. Copy the Certificate and CA Back to the VM
+
+### On the host:
+
+```bash
+scp ~/myCA/nginx_ip.crt vagrant@:/home/vagrant/
+scp ~/myCA/nginx_ip.key vagrant@:/home/vagrant/
+scp ~/myCA/myorgca.pem vagrant@:/home/vagrant/
+```
+
+## 6. On the VM: Install nginx and Configure the Certificate
+
+```bash
+sudo apt update
+sudo apt install nginx
+sudo mv nginx_ip.crt /etc/ssl/certs/
+sudo mv nginx_ip.key /etc/ssl/private/
+sudo mv myorgca.pem /etc/ssl/certs/
+```
+
+### Edit /etc/nginx/sites-available/default and add/replace the server block:
+
+```nginx
+
+server {
+ listen 443 ssl;
+ server_name 192.168.121.234;
+
+ ssl_certificate /etc/ssl/certs/nginx_ip.crt;
+ ssl_certificate_key /etc/ssl/private/nginx_ip.key;
+ ssl_trusted_certificate /etc/ssl/certs/myorgca.pem;
+
+ location / {
+ root /var/www/html;
+ index index.html index.htm;
+ }
+}
+```
+
+### Test the config:
+
+```bash
+sudo nginx -t
+Restart nginx:
+```
+
+```bash
+sudo systemctl restart nginx
+```
+
+## 7. On the host: Add the CA to the Trusted Store
+
+### On the host:
+
+```bash
+cp ~/myCA/myorgca.pem ~/myCA/myorgca.crt
+sudo cp ~/myCA/myorgca.crt /usr/local/share/ca-certificates/
+sudo update-ca-certificates
+```
+
+You should see:
+
+
+Adding debian:myorgca.crt
diff --git a/test_vm/provision.yml b/test_vm/provision.yml
new file mode 100644
index 000000000..ed666c0f1
--- /dev/null
+++ b/test_vm/provision.yml
@@ -0,0 +1,113 @@
+---
+- hosts: all
+ become: true
+ tasks:
+ - name: Install DHCP client
+ apt:
+ name: isc-dhcp-client
+ state: present
+ update_cache: yes
+
+ - name: Run dhclient on eth1 (in background)
+ shell: nohup dhclient eth1 &
+ async: 0
+ poll: 0
+
+ - name: Install netstat for network troubleshooting
+ apt:
+ name: net-tools
+ state: present
+ update_cache: yes
+
+ - name: Install BACnet dependencies
+ apt:
+ name:
+ - git
+ - gcc
+ - make
+ - bison
+ - flex
+ - libpcap-dev
+ state: present
+ update_cache: yes
+ tags: bacnet
+
+ - name: Clone BACnet stack repository
+ git:
+ repo: https://github.com/bacnet-stack/bacnet-stack.git
+ dest: /opt/bacnet-stack
+ version: master
+ tags: bacnet
+
+ - name: Build BACnet stack
+ make:
+ chdir: /opt/bacnet-stack
+ target: all
+ tags: bacnet
+
+ - name: Copy bacserv-wrapper.sh
+ copy:
+ dest: /usr/local/bin/bacserv-wrapper.sh
+ mode: '0755'
+ content: |
+ #!/bin/bash
+ IFACE=eth1
+ while true; do
+ IP=$(ip -4 addr show $IFACE | awk '/inet / {print $2}' | cut -d/ -f1)
+ if [ -n "$IP" ]; then
+ export BACNET_IP=$IP
+ exec /opt/bacnet-stack/bin/bacserv
+ fi
+ sleep 2
+ done
+ tags: bacnet
+
+ - name: Create systemd unit for bacserv
+ copy:
+ dest: /etc/systemd/system/bacserv.service
+ mode: '0644'
+ content: |
+ [Unit]
+ Description=BACnet Server (auto-restart on IP change)
+ After=network-online.target
+ Wants=network-online.target
+
+ [Service]
+ Type=simple
+ ExecStart=/usr/local/bin/bacserv-wrapper.sh
+ Restart=always
+ RestartSec=5
+
+ [Install]
+ WantedBy=multi-user.target
+ tags: bacnet
+
+ - name: Reload systemd and enable bacserv service
+ systemd:
+ name: bacserv
+ enabled: yes
+ state: restarted
+ daemon_reload: yes
+ tags: bacnet
+
+ - name: Check if bacserv process is running
+ shell: pgrep -fl bacserv
+ register: bacserv_process
+ changed_when: false
+ tags: bacnet
+
+ - name: Show information about bacserv process
+ debug:
+ var: bacserv_process.stdout_lines
+ tags: bacnet
+
+ - name: Show last lines of bacserv log
+ shell: tail -n 20 /opt/bacnet-stack/bacserv.log
+ register: bacserv_log
+ changed_when: false
+ ignore_errors: true
+
+ - name: Display bacserv log
+ debug:
+ var: bacserv_log.stdout_lines
+ tags: bacnet
\ No newline at end of file