Skip to content

Instantly share code, notes, and snippets.

@stroebs
Last active March 16, 2024 06:13
Show Gist options
  • Star 61 You must be signed in to star a gist
  • Fork 37 You must be signed in to fork a gist
  • Save stroebs/54fc09734a3911e91eeeb43434f117df to your computer and use it in GitHub Desktop.
Save stroebs/54fc09734a3911e91eeeb43434f117df to your computer and use it in GitHub Desktop.
Install Mikrotik CHR on a Digital Ocean droplet (Ubuntu 20.04 tested working 29/03/2022)
#!/bin/bash
#
# Digital Ocean Ubuntu 18.04 x64 Droplet with "Regular Intel" CPU.
# Running:
# git clone https://gist.github.com/54fc09734a3911e91eeeb43434f117df.git
# cd 54fc09734a3911e91eeeb43434f117df/
# chmod +x make-chr.sh
# ./make-chr.sh
#
# Once the reboot is done, login with root/CHANGEME and change the password!
# You might get a "Segmentation fault" on line 56 while the image is being written.
# Most of the time this is absolutely fine. Reboot the droplet and attempt to login using Winbox.
# If it didn't work, just trash the droplet and try it again.
#
wget http://download2.mikrotik.com/routeros/6.37/chr-6.37.img.zip -O chr.img.zip && \
gunzip -c chr.img.zip > chr.img && \
apt-get update && \
apt install -y qemu-utils pv && \
qemu-img convert chr.img -O qcow2 chr.qcow2 && \
qemu-img resize chr.qcow2 1073741824 && \
modprobe nbd && \
qemu-nbd -c /dev/nbd0 chr.qcow2 && \
echo "Give some time for qemu-nbd to be ready" && \
sleep 2 && \
partprobe /dev/nbd0 && \
sleep 5 && \
mount /dev/nbd0p2 /mnt && \
ADDRESS=`ip addr show eth0 | grep global | cut -d' ' -f 6 | head -n 1` && \
GATEWAY=`ip route list | grep default | cut -d' ' -f 3` && \
PASSWORD="CHANGEME" && \
echo "/ip address add address=$ADDRESS interface=[/interface ethernet find where name=ether1]
/ip route add gateway=$GATEWAY
/ip service disable telnet
/user set 0 name=root password=$PASSWORD
/ip dns set servers=1.1.1.1,1.0.0.1
/system package update install
" > /mnt/rw/autorun.scr && \
umount /mnt && \
echo "Magic constant is 65537 (second partition address). You can check it with fdisk before appliyng this" && \
echo "This scary sequence removes seconds partition on nbd0 and creates new, but bigger one" && \
echo -e 'd\n2\nn\np\n2\n65537\n\nw\n' | fdisk /dev/nbd0 && \
e2fsck -f -y /dev/nbd0p2 || true && \
resize2fs /dev/nbd0p2 && \
sleep 1 && \
echo "Compressing to gzip, this can take several minutes" && \
mount -t tmpfs tmpfs /mnt && \
pv /dev/nbd0 | gzip > /mnt/chr-extended.gz && \
sleep 1 && \
killall qemu-nbd && \
sleep 1 && \
echo u > /proc/sysrq-trigger && \
echo "Warming up sleep" && \
sleep 1 && \
echo "Writing raw image, this will take time" && \
zcat /mnt/chr-extended.gz | pv > /dev/vda && \
echo "Don't forget your password: $PASSWORD" && \
echo "Sleep 5 seconds (if lucky)" && \
sleep 5 || true && \
echo "sync disk" && \
echo s > /proc/sysrq-trigger && \
echo "Ok, reboot" && \
echo b > /proc/sysrq-trigger
@lzcykevin
Copy link

lzcykevin commented Jun 15, 2019

Debian 9.6
Give some time for qemu-nbd to be ready

partx: /dev/nbd0: error adding partition 1
resize2fs 1.43.4 (31-Jan-2017)
open: No such file or directory while opening /dev/nbd0p2

@stroebs
Copy link
Author

stroebs commented Jun 18, 2019

I've noticed that this script only works in certain situations, very temperamental. I will look into the issues mentioned here at some stage in the next few weeks... Travelling is a killer

@vfedyay
Copy link

vfedyay commented Jul 22, 2019

Yes, after partx -a /dev/nbd0 we have only /dev/nbd0p1 on device
so resizing with "echo -e 'd\n2\nn\np\n2\n65537\n\nw\n' | fdisk /dev/nbd0" doesn't work.
I've tried to delete manualy p1 partition and create new one (bigger) and meet another problem.
p1 starts at sector 1, but fdisk allows to create primary partition only from 2048 starting.

All this made on droplet with Ubuntu 16.04.6 x64 and router OS chr-6.45.2.img.zip (RAW image download).
Will try on latest Ubuntu available for droplet.

@nick1543
Copy link

nick1543 commented Aug 28, 2019

All this made on droplet with Ubuntu 16.04.6 x64 and router OS chr-6.45.2.img.zip (RAW image download).
Will try on latest Ubuntu available for droplet.

Any success with the latest Ubuntu version?

I've just tried this script (a bit modified) on Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-159-generic x86_64).
No success, but I understand where the problem is:

echo "Magic constant is 65537 (second partition address). You can check it with fdisk before appliyng this" && \
echo "This scary sequence removes seconds partition on vda and creates new, but bigger one" && \
echo -e 'd\n2\nn\np\n2\n227328\n\nw\n' | fdisk /dev/vda && \

I changed 65537 to 227328, but in fact that wasn't correct.

Could anyone advise me, how to modify the script correctly?

Here is my fdisk -l result

Disk /dev/vda: 25 GiB, 26843545600 bytes, 52428800 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 68AB7630-F3A6-4BD2-B264-F6121E676127

Device      Start      End  Sectors  Size Type
/dev/vda1  **227328** 52428766 52201439 24.9G Linux filesystem
/dev/vda14   2048    10239     8192    4M BIOS boot
/dev/vda15  10240   227327   217088  106M Microsoft basic data

And here is the modified script by me (but still not correct at all)

wget https://download.mikrotik.com/routeros/6.44.5/chr-6.44.5.img.zip -O chr.img.zip && \
gunzip -c chr.img.zip > chr.img && \
apt-get update && \
apt install -y qemu-utils pv && \
qemu-img convert chr.img -O qcow2 chr.qcow2 && \
qemu-img resize chr.qcow2 `fdisk /dev/vda -l | head -n 1 | cut -d',' -f 2 | cut -d' ' -f 2` && \
modprobe nbd && \
qemu-nbd -c /dev/vda chr.qcow2 && \
echo "Give some time for qemu-nbd to be ready" && \
sleep 2 && \
partx -a /dev/vda && \
mount /dev/vda1 /mnt && \
ADDRESS=`ip addr show eth0 | grep global | cut -d' ' -f 6 | head -n 1` && \
GATEWAY=`ip route list | grep default | cut -d' ' -f 3` && \
echo "/ip address add address=$ADDRESS interface=[/interface ethernet find where name=ether1]
/ip route add gateway=$GATEWAY
/ip service disable telnet
/user set 0 name=XXXXXXXX password=XXXXXXXX
 " > /mnt/rw/autorun.scr && \
umount /mnt && \
echo "Magic constant is 65537 (second partition address). You can check it with fdisk before appliyng this" && \
echo "This scary sequence removes seconds partition on vda and creates new, but bigger one" && \
echo -e 'd\n2\nn\np\n2\n227328\n\nw\n' | fdisk /dev/vda && \
e2fsck -f -y /dev/vda1 || true && \
resize2fs /dev/vda1 && \
sleep 1 && \
echo "Compressing to gzip, this can take several minutes" && \
mount -t tmpfs tmpfs /mnt && \
pv /dev/vda | gzip > /mnt/chr-extended.gz && \
sleep 1 && \
killall qemu-nbd && \
sleep 1 && \
echo u > /proc/sysrq-trigger && \
echo "Warming up sleep" && \
sleep 1 && \
echo "Writing raw image, this will take time" && \
zcat /mnt/chr-extended.gz | pv > /dev/vda && \
echo "Sleep 5 seconds (if lucky)" && \
sleep 5 || true && \
echo "sync disk" && \
echo s > /proc/sysrq-trigger && \
echo "Ok, reboot" && \
echo b > /proc/sysrq-trigger

And here is the end of stdout after starting the script:

...
Setting up qemu-utils (1:2.11+dfsg-1ubuntu7.17) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...
Image resized.
Failed to set NBD socket
resize2fs 1.44.1 (24-Mar-2018)
The filesystem is already 6525179 (4k) blocks long.  Nothing to do!

Compressing to gzip, this can take several minutes
1.63GiB 0:01:24 [18.9MiB/s] [======>                                                                                                                              ]  6% ETA 0:20:05
gzip: stdout: No space left on device
1.64GiB 0:01:24 [19.8MiB/s] [======>                                                                                                                              ]  6%
sync disk
Ok, reboot

@stroebs
Copy link
Author

stroebs commented Aug 31, 2019

@nick1543 @vfedyay @lzcykevin @devstudios @fyrstyk @hklkf

FYI this script has been updated and confirmed working 100% with an Ubuntu 16.04.6 droplet on DigitalOcean.
CAVEAT: The disk is only 1GB - You can change this by changing the number "1073741824" and test for yourself.
There were some issues, which I've found, researched about and fixed.

  • Newer ROS images do not have two partitions, so I've gone back to 6.37
  • Trying to use autorun.scr on newer images no longer works, so I've gone back to 6.37
  • Partition syncing on DO droplets causes a kernel panic while the image is being written to disk, so the disk had to be shrunk to a reasonable size to be written, so reduced image size to 1GB (1073741824). I don't know why this happens but this method works and having a MikroTik with more than 1GB disk is a rare edge case.
  • DNS servers set to Cloudflare (1.1.1.1, 1.0.0.1) by default
  • Added an upgrade to the latest stable ROS on startup

Mileage may vary - I simply copied the script and pasted it into a terminal and executed it. The droplet reboots just fine, takes a few seconds to download the latest ROS, reboots and it's good to go!

@imperio2k
Copy link

I ran the scrip ./make-chr.sh on my VPS Ubuntu 16.04.6 x84_64 and it gets stuck in the next part:

Warming up sleep
Writing raw image, this will take time
744MiB 0:00:06 [ 142MiB/s] [=> ] 2% ETA 0:03:20

In the VPS screen connection this shows me.

image

What could be happening? What other code can I try?

Thank you in advance for your reply.

@stroebs
Copy link
Author

stroebs commented Sep 1, 2019

@imperio2k Try it a second time. It looks like there’s some disk synchronization that occurs which causes a kernel panic when the image is being written to disk, before the image can be completely written. I’ve tried this many times using Ubuntu 16.04 and 18.04 and I can assure you that it does work if you are not unlucky enough to get a Kernel panic.

@electropolis
Copy link

I would add psmisc because without that killall will not work as this is included in that package or use instead pkill

@devstudios
Copy link

devstudios commented Jun 12, 2020 via email

@stroebs
Copy link
Author

stroebs commented Jun 12, 2020

No workaround for that @devstudios. For AWS instances, use the marketplace CHR instead as MikroTik has specifically provided a method of provisioning CHR's on newer software, which they will not provide to consumers.

Response from MikroTik support on the matter:

For security reasons this method of file modification was disabled.

Please see our wiki article about CHR Provisioning depending on Your Hypervisor:
https://wiki.mikrotik.com/wiki/Manual:CHR#Provisioning

@devstudios
Copy link

devstudios commented Jun 12, 2020 via email

@saied45
Copy link

saied45 commented Jan 4, 2021

Is this working for anyone else? I can't get this to work anymore. It used to work maybe one month ago but now I can't make it work at all.

@stroebs
Copy link
Author

stroebs commented Jan 4, 2021

I'll take a look at it @saied45

@stroebs
Copy link
Author

stroebs commented Jan 4, 2021

@saied45 Just tried this myself on an Ubuntu 18.04 box in London and it worked fine. It got a Segmentation Fault while writing the image but ROS is only a few MB so the OS is copied to the disk just fine.

@ivazin
Copy link

ivazin commented Jan 29, 2021

I'm trying to install chr-7.1beta3.img.zip:
wget https://download.mikrotik.com/routeros/7.1beta3/chr-7.1beta3.img.zip -O chr.img.zip — the one one change in this code

But something does wrong:
mount: /mnt: special device /dev/nbd0p2 does not exist.

Could you please help to understand what's wrong? 👇) Why /dev/nbd0p2 does not exist?

@stroebs
Copy link
Author

stroebs commented Jan 29, 2021

@ivazin Unfortunately this method does NOT work for any CHR newer than 6.37. The reason for this is because MikroTik has removed the second partition and now disallows customisation of raw images that this gist makes use of. In this script there is an auto-upgrade to the latest CHR on startup but that will only get you to the latest v6 image.
See my comment here: https://gist.github.com/stroebs/54fc09734a3911e91eeeb43434f117df#gistcomment-3339533

Once v7 is released, I'm sure you'll be able to use this gist to upgrade from v6 to v7.

@ivazin
Copy link

ivazin commented Jan 29, 2021

Thanks a lot for the explanation! 🙏 we'll wait for the final v7 then)

@AlbertoCabral32
Copy link

Hi, i have a problem with the script. Can somebody help me? From already thank you very much
modprobe: FATAL: Module nbd not found in directory /lib/modules/4.15.0
resize2fs 1.44.1 (24-Mar-2018)
open: No such file or directory while opening /dev/nbd0p2
sync disk

@stroebs
Copy link
Author

stroebs commented Mar 30, 2021

@AlbertoCabral32 which base OS are you using? This works fine with Ubuntu 16.04

@AlbertoCabral32
Copy link

@stroebs Ubuntu 18.04

@AlbertoCabral32
Copy link

So for version 18 it no longer works?

@stroebs
Copy link
Author

stroebs commented Mar 31, 2021

@AlbertoCabral32 I just tested this with a "Regular Intel" droplet using Ubuntu 18.04 in London and the steps in my code comments worked perfectly, without the error you're describing.

@AlbertoCabral32
Copy link

I understand, in the case I will be verifying what happened.
Thank you

@violoelettronica
Copy link

violoelettronica commented Jun 1, 2021

ciao, l'installazione è andata correttamente ma successivamente non riesco ad accedere con winbox al chr, devo fare qualcosa in particolare?

@stroebs
Copy link
Author

stroebs commented Jun 2, 2021

devo fare qualcosa in particolare

Il nome utente predefinito è root e la password predefinita è CHANGEME

@Melkaiya
Copy link

The Script work perfectly in a clean Installation of Ubuntu Server 20 VPS on UpCloud. The Only note to consider is the CHR initialized without password instead of the CHANGEME.

@stroebs
Copy link
Author

stroebs commented Mar 29, 2022

What is the problem @eklascode? Does it work or not?

EDIT: Just tested this yet again on a Digital Ocean Ubuntu 20.04 x64 Droplet with "Regular Intel" CPU and it worked absolutely fine.

@stroebs
Copy link
Author

stroebs commented Feb 14, 2023

Digital Ocean supports custom images: https://docs.digitalocean.com/products/images/custom-images/ which should be used instead of this script where possible. MikroTik CHR disk images have been tested to work with this method. The script will remain here as historical reference.

@nhan6310
Copy link

These are my customizations and I have successfully installed them on Ubuntu 20.04
Good luck
#!/bin/bash
wget https://download.mikrotik.com/routeros/7.14.1/chr-7.14.1.img.zip -O chr.img.zip &&
gunzip -c chr.img.zip > chr.img &&
apt-get update &&
apt install -y qemu-utils pv &&
qemu-img convert chr.img -O qcow2 chr.qcow2 &&
qemu-img resize chr.qcow2 1073741824 &&
modprobe nbd &&
qemu-nbd -c /dev/nbd0 chr.qcow2 &&
echo "Give some time for qemu-nbd to be ready" &&
sleep 2 &&
partprobe /dev/nbd0 &&
sleep 5 &&
mount /dev/nbd0p2 /mnt &&
ADDRESS=ip addr show eth0 | grep global | cut -d' ' -f 6 | head -n 1 &&
GATEWAY=ip route list | grep default | cut -d' ' -f 3 &&
echo "/ip address add address=$ADDRESS interface=[/interface ethernet find where name=ether1]
/ip route add gateway=$GATEWAY
/ip service disable telnet
/ip dns set servers=1.1.1.1,1.0.0.1
" > /mnt/rw/autorun.scr &&
umount /mnt &&
echo "Magic constant is 65537 (second partition address). You can check it with fdisk before appliyng this" &&
echo "This scary sequence removes seconds partition on nbd0 and creates new, but bigger one" &&
echo -e 'd\n2\nn\np\n2\n65537\n\nw\n' | fdisk /dev/nbd0 &&
e2fsck -f -y /dev/nbd0p2 || true &&
resize2fs /dev/nbd0p2 &&
sleep 1 &&
echo "Compressing to gzip, this can take several minutes" &&
mount -t tmpfs tmpfs /mnt &&
pv /dev/nbd0 | gzip > /mnt/chr-extended.gz &&
sleep 1 &&
killall qemu-nbd &&
sleep 1 &&
echo u > /proc/sysrq-trigger &&
echo "Warming up sleep" &&
sleep 1 &&
echo "Writing raw image, this will take time" &&
zcat /mnt/chr-extended.gz | pv > /dev/vda &&
echo "Don't forget your password: $PASSWORD" &&
echo "Sleep 5 seconds (if lucky)" &&
sleep 5 || true &&
echo "sync disk" &&
echo s > /proc/sysrq-trigger &&
echo "Ok, reboot" &&
echo b > /proc/sysrq-trigger

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment