Using Ansible to Reset MikroTik and Apply Custom Bootstrap Script
🎯 Objective
This blog post shows you how to use Ansible to reset a MikroTik router to its factory settings and automatically apply a custom bootstrap configuration.
You’ll learn how to automate the process using Ansible and a .rsc
script file for configuration, allowing you to easily customize and extend your MikroTik setup.
📝 Introduction
When working on a new MikroTik project, it’s often helpful to start from a clean configuration. Rather than manually resetting and reconfiguring the device, this guide walks you through an automated Ansible playbook that:
- Resets the MikroTik to factory defaults
- Applies a minimal bootstrap configuration
- Retains access via the admin user
- Sets a static IP for remote management
1. Prepare and Test Bootstrap Script
Start by creating a bootstrap configuration script. According to MikroTik’s documentation1, it’s important to wait for all interfaces to be ready before applying configuration—especially when modifying or assigning settings to them.
To do this, we use the command /interface print count-only
to determine the number of network interfaces on the device.
📄 Interface Readiness Script Template
The following script is adapted from MikroTik’s Startup Delay troubleshooting wiki2:
{
:local i 0
:local x REPLACE_THIS_WITH_YOUR_NUMBER_OF_NETWORK_INTERFACES_INCLUDE_LOOPBACK
:local t 120
while ($i < $t && [:len [/interface find]] < $x) do={
:put $i
:set $i ($i + 5)
:delay 5
}
if ($i = $t) do={
:log warning message="Could not load all physical interfaces"
} else={
# BOOTSTRAP CODE HERE
}
}
🔧 How to Set x
and t
x
: This should be the total number of physical interfaces, plus one for the loopback.⚠️ Be cautious when using
/interface print count-only
— after a factory reset without default config, virtual interfaces like bridge or VLANs may not be present. To keep it simple: count all physical interfaces (e.g.,ether1
,ether2
,sfp1
, etc.) and add 1 for the loopback.t
: Timeout in seconds to wait for interfaces to be initialized. The default here is 120 seconds.
➕ Add Your Bootstrap Code
Once interfaces are ready, place your actual configuration commands in the else
block, replacing # BOOTSTRAP CODE HERE
.
✅ Test Your Bootstrap Script
Follow these steps to test your bootstrap script on a MikroTik device:
- Create Your Bootstrap Script
Write your complete bootstrap code and save it as: bootstrap_script.rsc
- Upload the Script to the MikroTik Device
Use the scp
command to copy the file to your device:
scp bootstrap_script.rsc [email protected]:/
- Verify the Uploaded File
Log into your MikroTik device (via terminal or SSH), and run:
/file print detail where name="bootstrap_script.rsc"
- Execute the Bootstrap Script Run the following command to test the script:
/import file-name="bootstrap_script.rsc"
If successful, you should see:
Script file loaded and executed successfully
2. Create an Ansible Playbook to Reset MikroTik and Apply a Custom Bootstrap Script
Now that we’ve tested the bootstrap manually, let’s automate the entire process using Ansible. This includes resetting the device and applying the configuration through a custom .rsc
script.
2.1 Create a Template for the Bootstrap Script
Start by creating a Jinja2 template named bootstrap_script.rsc.j2
under templates
directory that Ansible can render dynamically with variables with following content:
{
:local i 0
:local x {{ number_of_interfaces }}
:local t 120
while ($i < $t && [:len [/interface find]] < $x) do={
:put $i
:set $i ($i + 5)
:delay 5
}
if ($i = $t) do={
:log warning message="Could not load all physical interfaces"
} else={
# Bootstrap
# Enable SSH and Winbox
/log info message="Enable SSH and Winbox services";
/ip service enable ssh
/ip service enable winbox
# Setup IP address for an interface
/log info message="Setup temporary network interface and address";
/ip address remove [find address="{{ temporary_cidr }}"];
/ip address add address={{ temporary_cidr }} interface={{ temporary_interface }} network={{ temporary_cidr | ansible.utils.ipaddr('network') }};
# Post delay after configure
:delay 5s
}
}
🧠 Notes
number_of_interfaces
: Total physical interfaces (plus 1 for loopback).temporary_cidr
: Temporary IP address in CIDR format (e.g.,192.168.88.1/24
).temporary_interface
: The physical interface to assign the IP (e.g.,ether1
).- The template uses Ansible’s
ipaddr filter
3 to extract the network from the CIDR.
2.2 Create an Ansible Script
This section automates the full workflow using Ansible:
- Generate a bootstrap script from a Jinja2 template (on the local machine)
- Upload the script to the MikroTik router and trigger a factory reset with
run-after-reset
- Clean up the local bootstrap file
- Run the full automation workflow using an Ansible playbook
🛠️ Step 1: Generate the Bootstrap Script Locally
Create a playbook that renders the bootstrap template and saves it to /tmp
.
- name: Prepare local bootstrap script
hosts: localhost
connection: local
gather_facts: false
vars:
number_of_interface: 6 # Total physical interfaces + 1 for loopback
temporary_cidr: 192.168.88.1/24
temporary_interface: ether3
bootstrap_script_filename: bootstrap_script.rsc
bootstrap_script_local_path: /tmp/{{ bootstrap_script_filename }}
bootstrap_config_content: "{{ lookup('template', 'bootstrap_script.rsc.j2') | regex_replace('\n', '\\r\\n') }}"
tasks:
- name: Create bootstrap script file
ansible.builtin.copy:
dest: "{{ bootstrap_script_local_path }}"
mode: '0600'
content: "{{ bootstrap_config_content }}"
🚀 Step 2: Upload Script and Reset MikroTik
This playbook uploads the script and executes a reset with no default configuration, instructing MikroTik to run the script after reboot.
- name: Factory reset MikroTik (no default config)
hosts: mikrotik_routers
gather_facts: false
vars:
bootstrap_script_filename: bootstrap_script.rsc
bootstrap_script_local_path: "/tmp/{{ bootstrap_script_filename }}"
tasks:
- name: Upload bootstrap script file to MikroTik
ansible.netcommon.net_put:
src: "{{ bootstrap_script_local_path }}"
dest: "{{ bootstrap_script_filename }}"
protocol: scp
- name: Reset router with no default config (expecting disconnect)
community.routeros.command:
commands: |
:execute script="/system reset-configuration \
no-defaults=yes \
skip-backup=yes \
keep-users=yes \
run-after-reset=\"{{ bootstrap_script_filename }}\""
register: reset_result
failed_when: >
reset_result.failed and
(
reset_result.msg is not defined or
(
'timeout' not in reset_result.msg | lower and
'disconnect' not in reset_result.msg | lower
)
)
- name: Show reset command result
ansible.builtin.debug:
var: reset_result
⚠️ Important: The
:execute script=...
is necessary to bypass the interactive confirmation prompt (Dangerous! Reset anyway? [y/N]:
) that MikroTik normally requires for a system reset.
🧹 Step 3: Clean Up Local Bootstrap File
Remove the bootstrap script from the local /tmp
directory to keep your environment clean.
- name: Cleanup local bootstrap script
hosts: localhost
connection: local
gather_facts: false
vars:
bootstrap_script_filename: bootstrap_script.rsc
bootstrap_script_local_path: "/tmp/{{ bootstrap_script_filename }}"
tasks:
- name: Delete local bootstrap script file
ansible.builtin.file:
path: "{{ bootstrap_script_local_path }}"
state: absent
▶️ Step 4: Run the Automation Workflow
You can run each playbook separately or combine all steps into a single workflow using import_playbook
or by chaining tasks together.
For example:
ansible-playbook prepare_bootstrap.yaml
ansible-playbook reset_mikrotik.yaml
ansible-playbook cleanup.yaml
Or combine them in a master playbook:
# run_all.yaml
- import_playbook: prepare_bootstrap.yaml
- import_playbook: reset_mikrotik.yaml
- import_playbook: cleanup.yaml
Then run:
ansible-playbook run_all.yaml