CHR: Cloud-Init and First-Boot Configuration
CHR: Cloud-Init and First-Boot Configuration
Section titled “CHR: Cloud-Init and First-Boot Configuration”RouterOS CHR supports automated first-boot configuration on cloud platforms through each provider’s metadata service. When CHR starts for the first time, it reads configuration data passed via the cloud provider’s user-data or startup-script mechanism and executes it as a RouterOS script.
This allows automated provisioning without manual console access: setting passwords, assigning IP addresses, configuring firewall rules, and more.
How CHR Processes User Data
Section titled “How CHR Processes User Data”CHR reads user-data from the cloud platform’s metadata service (typically at 169.254.169.254) during first boot. The content is treated as a RouterOS CLI script and executed once.
Key behavior:
- Executed once on first boot only
- Content is interpreted as RouterOS CLI commands, not standard cloud-init YAML
- Script execution errors appear in
/log print - No output is written back to the cloud platform — verify results by connecting to the router
CHR does not support standard cloud-init YAML format (e.g., #cloud-config with users:, packages:, runcmd: keys). Use RouterOS CLI syntax only.
User Data Format
Section titled “User Data Format”User data must be plain RouterOS CLI commands, one per line:
/user set admin password=SecurePassword123!/ip service disable telnet,ftp,www/system identity set name=my-routerMulti-line commands using RouterOS braces are supported:
/ip firewall filteradd chain=input action=accept connection-state=established,related comment="Accept established"add chain=input action=accept protocol=tcp dst-port=22,8291 src-address=10.0.0.0/8 comment="Management"add chain=input action=drop comment="Drop all other input"Configuring User Data by Platform
Section titled “Configuring User Data by Platform”AWS EC2
Section titled “AWS EC2”Pass user data in the EC2 launch wizard under Advanced Details → User data, or via the CLI:
aws ec2 run-instances \ --image-id ami-xxxxx \ --instance-type t3.small \ --user-data file://chr-init.rsc \ --key-name my-key \ --security-group-ids sg-xxxxx \ --subnet-id subnet-xxxxxGoogle Cloud Platform
Section titled “Google Cloud Platform”Use the startup-script metadata key:
gcloud compute instances create chr-router \ --image mikrotik-chr-7x \ --machine-type e2-small \ --can-ip-forward \ --metadata-from-file startup-script=chr-init.rsc \ --zone us-central1-aMicrosoft Azure
Section titled “Microsoft Azure”Azure passes custom data to the VM via the --custom-data parameter:
az vm create \ --resource-group chr-resources \ --name chr-router \ --attach-os-disk chr-os-disk \ --os-type Linux \ --size Standard_B2s \ --nics chr-nic \ --custom-data chr-init.rscVultr / Hetzner / Generic Providers
Section titled “Vultr / Hetzner / Generic Providers”Most cloud providers that support user-data pass it via the standard cloud metadata endpoint at http://169.254.169.254/latest/user-data or provider-specific equivalents. CHR reads from this endpoint automatically on first boot.
Example Configuration Scripts
Section titled “Example Configuration Scripts”Basic Hardening
Section titled “Basic Hardening”# chr-hardening.rsc — minimum security configuration/user set admin password=StrongPassword123!/ip service disable telnet,ftp,www,api,api-ssl/ip service set ssh port=22 address=10.0.0.0/8/ip service set winbox port=8291 address=10.0.0.0/8/tool bandwidth-server set enabled=no/ip neighbor discovery-settings set discover-interface-list=none/system identity set name=chr-prod-01IP Address and Routing
Section titled “IP Address and Routing”# chr-network.rsc — initial IP configuration/ip address add address=10.10.1.1/24 interface=ether1 comment="WAN"/ip address add address=192.168.100.1/24 interface=ether2 comment="LAN"/ip route add dst-address=0.0.0.0/0 gateway=10.10.1.254 comment="Default route"/ip dns set servers=1.1.1.1,8.8.8.8 allow-remote-requests=noFirewall Rules
Section titled “Firewall Rules”# chr-firewall.rsc — basic input protection/ip firewall filteradd chain=input action=accept connection-state=established,related comment="Accept established/related"add chain=input action=accept connection-state=untracked comment="Accept untracked"add chain=input action=drop connection-state=invalid comment="Drop invalid"add chain=input action=accept protocol=icmp comment="Accept ICMP"add chain=input action=accept protocol=tcp dst-port=22,8291 src-address=10.0.0.0/8 comment="Management"add chain=input action=drop comment="Drop all other input"
/ip firewall filteradd chain=forward action=accept connection-state=established,related comment="Accept established/related"add chain=forward action=drop connection-state=invalid comment="Drop invalid"add chain=forward action=accept out-interface=ether1 comment="Allow LAN to WAN"NAT Gateway Configuration
Section titled “NAT Gateway Configuration”# chr-nat.rsc — source NAT for LAN-to-WAN traffic/ip firewall natadd chain=srcnat out-interface=ether1 action=masquerade comment="Masquerade LAN traffic"SSH Key Authentication
Section titled “SSH Key Authentication”# chr-ssh-keys.rsc — add SSH public key for admin user/user ssh-keys import public-key-file=sftp://admin@192.168.88.1/id_rsa.pub user=adminAlternatively, pre-stage the key using RouterOS script syntax:
/file add name=admin.pub contents="ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB... user@host"/user ssh-keys import public-key-file=admin.pub user=adminLicense Activation
Section titled “License Activation”# chr-license.rsc — activate CHR license (run after first boot)/system license generate-new-id/system/license renew account=your-mikrotik-account password=your-password level=p1Run /system license generate-new-id before requesting a license if your instance was cloned or launched from a shared AMI/image. Multiple instances from the same image may share a system ID.
Complete First-Boot Script Example
Section titled “Complete First-Boot Script Example”# Complete first-boot initialization for cloud CHR deployment
# 1. Identity/system identity set name=cloud-chr-01
# 2. Security — change default password immediately/user set admin password=SecurePassword123!
# 3. Disable unused management services/ip service disable telnet,ftp,www,api,api-ssl/ip service set ssh address=10.0.0.0/8/ip service set winbox address=10.0.0.0/8
# 4. Disable bandwidth server and neighbor discovery/tool bandwidth-server set enabled=no/ip neighbor discovery-settings set discover-interface-list=none
# 5. Network configuration/ip address add address=10.10.1.1/24 interface=ether1 comment="WAN"/ip address add address=192.168.100.1/24 interface=ether2 comment="LAN"/ip route add dst-address=0.0.0.0/0 gateway=10.10.1.254
# 6. DNS/ip dns set servers=1.1.1.1,8.8.8.8
# 7. Firewall — input chain/ip firewall filteradd chain=input action=accept connection-state=established,relatedadd chain=input action=drop connection-state=invalidadd chain=input action=accept protocol=icmpadd chain=input action=accept protocol=tcp dst-port=22,8291 src-address=10.0.0.0/8add chain=input action=dropWarning — management lockout risk: The rule above only permits SSH and Winbox access from
10.0.0.0/8. If your management workstation has a public IP address (common in cloud environments), thedrop allrule will block your access immediately after the script runs. Before executing this script, replacesrc-address=10.0.0.0/8with your actual management IP or subnet — for example,src-address=203.0.113.10/32. If you need to permit access on a specific interface regardless of source IP, addin-interface=ether1to the accept rule instead of (or in addition to) thesrc-addressrestriction.
# 8. Firewall — forward chain/ip firewall filteradd chain=forward action=accept connection-state=established,relatedadd chain=forward action=drop connection-state=invalid
# 9. NAT/ip firewall nat add chain=srcnat out-interface=ether1 action=masquerade
# 10. Generate new system ID (important when launching from a shared image)/system license generate-new-id
# 11. Log completion/log info "CHR first-boot initialization complete"Verifying Script Execution
Section titled “Verifying Script Execution”After boot, verify the script ran correctly:
# Check system log for script output and errors/log print where topics~"script"
# Verify identity was set/system identity print
# Verify interfaces and IPs/ip address print
# Check firewall rules applied/ip firewall filter printTroubleshooting
Section titled “Troubleshooting”Script Not Applied
Section titled “Script Not Applied”- Verify the script was passed correctly (check cloud provider console for user-data)
- Check
/log printfor any error messages - User data executes only on first boot — rebooting will not re-execute it
- Ensure the script uses RouterOS CLI syntax, not bash or YAML
Locked Out After Firewall Rules Applied
Section titled “Locked Out After Firewall Rules Applied”If the first-boot script included a drop all input rule and you can no longer reach the router, the
management source address did not match the permitted subnet. To recover:
- Use the cloud provider’s serial console or out-of-band access (AWS EC2 Instance Connect, GCP Serial Port, Azure Serial Console) — these bypass firewall rules.
- Once connected, remove or relax the offending rule:
# Identify the rule number/ip firewall filter print
# Remove the drop rule (adjust number to match your output)/ip firewall filter remove [find chain=input action=drop]
# Re-add with your actual management IP/ip firewall filter add chain=input action=accept protocol=tcp dst-port=22,8291 src-address=<YOUR-IP>/32/ip firewall filter add chain=input action=drop- To prevent recurrence, update the
src-addressin your cloud-init script before the next deployment.
Commands Partially Applied
Section titled “Commands Partially Applied”RouterOS scripts execute line-by-line. If a command fails, execution continues with the next line. Check the log for specific errors:
/log print where message~"error"Password Not Changed
Section titled “Password Not Changed”If the password script ran but the password did not change, verify there are no quoting issues in the user-data string. Test the command manually in the CLI:
/user set admin password=TestPassword123