Contents

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:

  1. Create Your Bootstrap Script

Write your complete bootstrap code and save it as: bootstrap_script.rsc

  1. Upload the Script to the MikroTik Device

Use the scp command to copy the file to your device:

scp bootstrap_script.rsc [email protected]:/
  1. Verify the Uploaded File

Log into your MikroTik device (via terminal or SSH), and run:

 /file print detail where name="bootstrap_script.rsc"
  1. 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 filter3 to extract the network from the CIDR.

2.2 Create an Ansible Script

This section automates the full workflow using Ansible:

  1. Generate a bootstrap script from a Jinja2 template (on the local machine)
  2. Upload the script to the MikroTik router and trigger a factory reset with run-after-reset
  3. Clean up the local bootstrap file
  4. 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