Debian on ASUS Router

Asus makes pretty impressive hardware and I've been their fan for quite some time. Recently purchased router lives up to the task - their GT-AC5300 variant features a quad core CPU and 1GB of on-board RAM. Toss in a small SD card and you've got yourself a pretty neat server.

It turns out the firmware on this router is pretty custom even by Asus standards. The features and the look of UI is full of not entirely important stuff for an average user. This means Merlin firmware does support these routers - nobody has time for that.

Luckily, the router's impressive specs are good enough to start a debian chroot. Here's a post explaining how to land Debian on GT-AC5300 or other Asus routers that don't run a custom firmware for whatever reason.

Set up SSH access

Create SSH key

If you don't have an SSH key, open terminal window on your OS X or Linux box and type in:


This will start SSH key generation process, which will, at the end, create two files:

  • ~/.ssh/id_rsa - this is your private key. You don't want to share this key with anyone. Works as a physical door key,
  • ~/.ssh/id_rsa.pub - this is your public key. Works as a physical door lock: systems that list this key as authorized_key will accept your private key as a login credential.

Add your SSH key to router's authorized keys

Open your Asus' web UI (most of the routers running recent firmware will respond to http://router.asus.com) and scroll down to Administration. Click the System tab and paste in your public ssh key to a field named Authorized keys.

Set up SD card

Now that your ssh is authorized, it's time to initialize your SD card. You do want to make sure that:
  • you have a decently fast SD card (cards marked U3 with speeds ~60-100MBps should be perfect)
  • you have a USB3.0 SD card reader. While sd card readers for USB 2.0 will work, too, they won't be anywhere that fast.
SSH to your router and initialize your SD card:

ssh admin@
umount /dev/sda1
mkfs.ext3 /dev/sda1
mount /dev/sda1 /tmp/mnt/sda1

Install software

Get Optware / ipkg

That part is fairly simple and depends solely on software supplied by Asus. Simply navigate to USB Application, scroll down to Download Master and hit Install. This process will take a short while, but once it's complete, the next time you ssh to your router, a new command will be accessible: ipkg.

ssh admin@

Get basic debian image

There is a good instruction on https://www.hqt.ro/how-to-install-debian-jessie-arm/ explaining how to install Debian Jessie on Arm. It's good for the most part, but lacks a few important steps, so i dared put my updates here:

ssh admin@
ipkg install nano findutils
cd /opt
wget --no-check-certificate -c https://files.hqt.ro/debian/arm/debian_jessie8.9-arm_clean.tgz
tar -xvzf ./debian_jessie8.9-arm_clean.tgz

Next, create the debian script:

cat > /opt/etc/init.d/S99debian << 'EOF'

if [ ! -e "$CHROOT_SERVICES_LIST" ]; then
echo "Please, define Debian services to start in $CHROOT_SERVICES_LIST first!"
echo "One service per line. Hint: this is a script names from Debian's /etc/init.d/"
exit 1

MountedDirCount="$(mount | grep $CHROOT_DIR | wc -l)"

start() {
if [ $MountedDirCount -gt 0 ]; then
echo "Chroot'ed services seems to be already started,
exit 1

echo "Starting chroot'ed Debian services..."
for dir in dev dev/pts proc sys; do
mount -o bind /$dir $CHROOT_DIR/$dir

[ -d "$EXT_DIR" ] && mount -o bind $EXT_DIR $CHROOT_DIR/mnt
for item in $(cat $CHROOT_SERVICES_LIST); do
chroot $CHROOT_DIR /etc/init.d/$item start

stop() {
if [ $MountedDirCount -eq 0 ]; then
echo "Chroot'ed services seems to be already stopped,
exit 1
echo "Stopping chroot'ed Debian services..."
for item in $(cat $CHROOT_SERVICES_LIST); do
chroot $CHROOT_DIR /etc/init.d/$item stop
sleep 2

for dir in sys proc dev/pts dev; do
umount $CHROOT_DIR/$dir
[ -d "$EXT_DIR" ] && umount $CHROOT_DIR/mnt

restart() {
if [ $MountedDirCount -eq 0 ]; then

enter() {
if [ $MountedDirCount -eq 0 ]; then
echo "Not started."
chroot /opt/debian /bin/bash

status() {
if [ $MountedDirCount -gt 0 ]; then
echo "Chroot'ed services running..."
echo "Chroot'ed services not running!"

case "$1" in
echo "Usage: (start|stop|restart|enter|status)"
exit 1
echo Done.
exit 0
chmod 755 /opt/etc/init.d/S99debian

Create a control file telling Asus to start debian for you upon each reboot:

cat > /opt/lib/ipkg/info/debian.control <
Package: debian
Architecture: arm
Priority: optional
Section: misc
Version: 8.0.0
Maintainer: debian
Source: debian.org
Description: Debian chroot
Enabled: yes

The most important part up there is to make sure that 'Enabled: yes' is present. This is how Asus' optware decides what is to be started at boot.

touch /opt/etc/chroot-services.list
ln -s /opt/etc/init.d/S99debian /opt/bin/debian
ln -s /opt/debian/usr/sbin/chroot /opt/bin/chroot

This step will ensure you have a 'debian' script and 'chroot' commands available. Finally, you probably want to execute:

debian start
debian enter

and edit the /etc/apt/sources.list file, replacing all references to jessie with buster, which will put you on current (as of the time of writing this post) debian testing head. At the end, simply execute:

apt-get update
apt-get dist-upgrade

and reboot your router. The moment it comes up, it should be running debian chroot already, so after you ssh in to your router, type in debian enter


Getting started with ESP8266 12E (AI Thinker IoT WIFI module)

I decided to write this down for multiple reasons, but mainly because I have spent a bit of time to dig through this and get started.

First of all, this will only work if you are using this module in particular:

If you're working on a different module - you probably want to read, but do a bit more research yourself. The above is the ESP8266 12E module i've been trying to get to work for past few days.

The module itself comes with a flashed image that works sort of like an old AT modem. Once it boots up, it will start talking over UART (top left two yellow cables on the image) at 115200bps, 8n1. You can use this default image to do the basic programming with arduino etc, but - let's face it: this module is fine working all by itself, and having an arduino controlling it is in most cases pointless; there are GPIO pins available on this baby, there is I2C interface, it draws very little power etc etc.

OK, to the point.

This tool requires 3.3V supply and if you supply 5V well it might work for a while, but no promises. I used 5V with mine for a while and it still works, but I suspect only because i never got it running at this higher voltage for too long.

Wiring is important here. Typically you will want to connect it like this:

VCC = 3.3V
GPIO2 (~LED), RST - Pull up,
GPIO15 - Pull down,
RXD, TXD - to TXD and RXD of your UART endpoint.

Finally, there's GPIO0 (~FLASH), which is used to either boot flash bootrom (GND) or user code (VCC). You will likely want to have a look at datasheet; table 4 is particularly useful.

First and foremost: the bootrom of this baby talks at 74880bps. Yes, you read this right: 74880bps. Most of the tools I tried failed to set the /dev/ttyS0 to this, well, unusual speed. All except for miniterm.py command, that was delivered with python-serial (or pyserial) debian package. This tool is capable of talking 74880bps even on Rasberry Pi, so it's quite good. Why is this important? Well, each time you need to reflash your card or diagnose a (likely) reboot cycle, you need to be able to switch your serial port to 74880bps.


Install this SDK: https://github.com/pfalcon/esp-open-sdk
It comes with everything you would need to get started. There's even a 'blinky' example code that you will want to deploy to your ESP8266. It shows how to write and compile C code for that unit.

Installation takes about 90 minutes on Raspberry Pi. The installer there builds compiler, libraries and tools, and, well, it takes time, but it's worth it. If you haven't already, go get it.


Once you have the toolchain (compiler, linker, ...) available, let's try to build and deploy blinker. It sounds like it's a simple job, but it isn't necessarily.

Inside the esp-open-sdk folder there's 'examples/blinky' project that builds and installs with makefile.
You will want to make a few modifications there:

1. modify 'flash:' target and add parameter --baud 460800 to esptool. You may also want to specify --port /dev/tty## or the like

2. modify 'flash:' target to flash one image extra: append '0x3fc000 esp_init_data_default.bin' at the end. Get the binary file from here. Now this is important to get you past RF calibration. If you're seeing reboot cycle with error:

rf_cal[0] !=0x05,is 0xFF

it is for that exact reason, that your init data file cannot be found by the boot rom. This question explains it in greater detail.

Done? Connect GPIO0 to GND and execute: make clean && make flash.  Finally, connect the GPIO0 to VCC and power-cycle your unit. The led should start blinking.


When building your usercode you may end up seeing a weird flash error that tells you your binary is too large to be flashed to the card. The error indicating this is:

region `iram1_0_seg' overflowed by ...

I hit that after adding maybe 5LOC that were essentially debug prints. Soon after I read I may need to add a compiler flag: -DICACHE_FLASH to get past this error.


If you are stuck and you think you bricked your unit don't fret. I thought I killed mine several times already and it still works. You just need to revert all your changes. You can download the necessary files from github and flash them back to your module. Just bind the GPIO0 to GND and use esptool.py to reflash it:

esptool.py --port /dev/ttyS0 --baud 460800 write_flash 0 boot_v1.1.bin 0x1000 user1.bin 0x7c000 esp_init_data_default.bin 0x7e000 blank.bin

I am not fully confident if the 0x7c000 is the right address for init_data.bin and whether 0x7e000 is the right address for blank.bin. If you are stuck in boot loop despite the above, chances are you should use a different address as explained here: that would be

esptool.py --port /dev/ttyS0 --baud 460800 write_flash 0 boot_v1.1.bin 0x1000 user1.bin 0x3fc000 esp_init_data_default.bin 0x3fe000 blank.bin

When the above works, you will see your unit talk at 115200 over serial port again, and serving your AT commands. More details about this are on NodeMCU website.


You may be tempted to write C++ code now that there's a C++ compiler bundled in, too. It's not going to be simple: the SDK does not include most of the library calls. These calls exist, of course, and can be easily linked by the C compiler, but C++ emits and looks up a bit different symbols and needs to know what it's after. This will all certainly be possible once we have the proper header files - or, if you want, you can create one yourself. Sadly, this means creating an extern for every single call that you want to use.

The API Reference for ESP8266 is here.


Tuning Dual LAN Synology

Having really excellent experience with Synology NAS I recently acquired a dual LAN Synology DS412+ disk station. This NAS is very quiet, supports up to 4 drives, features 1GB of RAM and 2 gigabit LAN interfaces, which I got particularly excited about.

Unfortunately, to my surprise, it turned out that both LAN interfaces are entirely isolated. This is great if you run a small home company and want to use the same disk station for both your business and personal needs, but fails to address typical home use cases, like mine:

  • LAN1 is used to access internet and provide access to media files to all electronic devices (Audio station streams music directly to my amplifier; Media station provides excellent UPnP access for my TV and other electronic devices; my phone and tablets regularly synchronize etc.)
  • LAN2 is used to work with large files on my laptop (processing RAW photos, working with virtual machines etc.)
The problem was, I had to decide whether I want to work with the files on my laptop or use the internet (unfortunately the masquerading is not configurable with UI). After some poking around I came up with the boot script, that does all that I need: I can connect my laptop directly to LAN2 and use internet access (shared by the Synology DS).

Part 1: Sharing internet access on LAN2.

If you, like me, would like your disk station to enable internet access (this includes network bridging, so you will also see all the devices visible from LAN1 on LAN2 interface), log in to your Synology station as root and try to execute the following commands (note: this is important you try it first):

insmod /lib/modules/nf_nat.ko
insmod /lib/modules/iptable_nat.ko
insmod /lib/modules/ipt_MASQUERADE.ko

echo 1 > /proc/sys/net/ipv4/ip_forward
/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
/sbin/iptables -A FORWARD -i eth0 -o eth1 -m state \
/sbin/iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT

If everything worked (read: none of the above commands has failed), then you should be able to connect your laptop directly to LAN2 interface of your Synology and be able to use the internet (please check!). If the above did not work for any reason, well, you can skip to second part of this post.

If all the above has worked well for you, you can leave your disk station as is (no need to reboot!), but you still want to be able to use network sharing after DS reboots. To preserve this functionality, still logged in as root, edit following files and add suggested lines at the end (note: you need to know Vi basics to do this)

  • vi /etc/rc.local

    insmod /lib/modules/nf_nat.ko
    insmod /lib/modules/iptable_nat.ko
    insmod /lib/modules/ipt_MASQUERADE.ko
    /sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

    /sbin/iptables -A FORWARD -i eth0 -o eth1 -m state \
            --state RELATED,ESTABLISHED -j ACCEPT
    /sbin/iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
  • vi /etc/sysctl.conf


So far so good: these modifications will enable sharing internet access from LAN1 to LAN2, but that's not quite enough just yet, so stick with me.

Part 2: tuning performance.

Some disk stations have enough RAM they could really use it to boost LAN transfer speeds. Not much is needed, really, but the defaults are rather.. low (total of 128kB memory of read and write buffers etc.). I'm not saying the DS will be slow or anything - actually it performs really good with these defaults (I have frequently seen throughputs temporarily reaching 100MBps, that is, nearing full 800Mbps on uplink and around 60MBps = 480Mbps on dowlink). That is pretty cool already, but.. this can get a whole lot better if you add some more buffers and enable TCP window scaling; in other words, edit the /etc/sysctl.conf file and add the following lines:

net.core.wmem_max = 12582912
net.core.rmem_max = 12582912
net.ipv4.tcp_rmem = 10240 87380 12582912
net.ipv4.tcp_wmem = 10240 87380 12582912
net.ipv4.tcp_window_scaling = 1

once done, save file, close the editor and execute

sysctl -p

this command should print what has been applied to the system (pretty much everything that it can find in the /etc/sysctl.conf file). Buffers should range from 10kB to 12MB per connection (depending on needs!), and the window scaling will be enabled. Window scaling is a feature, that allows peers to send larger and larger chunks of data by negotiating their size beforehand; the effect is that despite Max Transfer Unit (MTU) is low on ethernet interfaces (usually 1500 bytes), the chunk can contain tens, hundreds or thousands of packets and will be sent without any interruptions from the receiving side (bonus: the whole window is followed by a simple acknowledge from the receiving side).


time dd if=largefile of=/dev/null bs=1048576
4294967296 bytes transferred in 45.106328 secs (95218731 bytes/sec)

time dd if=/dev/zero of=largefile bs=1048576
4294967296 bytes transferred in 55.481166 secs (77413068 bytes/sec)

Average (rather than temporary) transfer speeds of 95MBps and 77MBps are pretty cool! And best yet: it won't get much better with larger MTU sizes.


Clipboard manager

If anything, clipboard managers are among the most underestimated and neglected tools these days.

The problem with these is not that they are useless. Actually they serve a great deal of very cool features. Just nobody knows.

There are multiple different clipboard managers available and most of them have more or less comparable functionality. I decided to give xfce4-clipman a try, since I'm a great fan of Xfce. What did I get?
  • paste anything I copied earlier (the length of history is adjustable), available at hand upon pressing keyboard combination; the menu looks somewhat like this:

  • synchronization between primary and secondary clipboards (Ctrl-C and mouse-select, Ctrl-V and middle mouse button work on same content)
  • actions available immediately after selecting the text.
While first two elements are not that important and everyone could live without them, the last one is something absolutely worth trying. What it does is: once you select text to copy, the text is matched against a regular expression, and, if a match is found, a popup menu with possible actions is presented to the user.

Imagine you work with buganizer and code review tools, for example. In your case, people oftentimes refer to these as: Bug:12345 and Change:67890. What you do then is open the web browser, navigate to the appropriate tool and paste the number in the search field. That takes time and discourages you from looking into the change or bug almost instantly.

Now imagine you could simply select (highlight) the text with your mouse and with one more click simply open the bug or change.

Here's what it'd look like:

Clicking on the Open Bug option will open a new browser tab that will get you directly to Ubuntu's bug 12345. Here's what you need to do to get things rolling:

  • Install the xfce4-clipman tool. It comes with xfce4-goodies package:

    sudo apt-get install xfce4-clipman
  • Attach the Clipman to any of your panels: right-click on panel and select Add New Items:

  • Open Clipman's properties and navigate to actions:

  • Click the plus sign and create new element. There will be some elements already provided for you to see how that works anyway. Now fill the new element like this:
    • Provide a name for your pattern (in my example it's going to be Ubuntu Bug)
    • Provide a regular expression pattern that will trigger the match. you can use playground if you need by clicking the pen icon next to the pattern field
    • Create a custom command: Open Bug and
    • provide Command to be executed as:

      google-chrome "https://bugs.launchpad.net/ubuntu/+source/isdnutils/+bug/\1" --new-tab

  • Click OK.
Now, the second you select anything that matches the pattern, say: Bug:12345, a new context menu will immediately pop up suggesting, that you may want to open the Ubuntu Bug number 12345. Try it yourself!

The Regular Expression editor comes with a playground window, where you can try how your regular expression works in action. To open it, simply click the pen icon next to the pattern field. You will be provided with a new window, where you'll see the regular expression itself and a field to paste examples for matching:

Good luck!


Forking GIT project to Gerrit

Going through your own changes before you decide to carry on is a pretty good idea. I treat it myself as a form of checkpoint: I can approve my changes at any time, but the more important thing is: I can find all the hacks I made along the way.

It turns out to be a pretty good idea to use Gerrit even when you contribute your changes to other repositories, or even when you want to keep your custom changes to yourself and at the same time be able to stay up to date with remote changes.

So how does that work, in short?

  1. Open up Gerrit website and navigate to Projects. Create a new project, that will be a fork of another repository. Create initial commit, it may make things easier;
  2. Open Access configuration for this project. Create new reference refs/* and add 
    1. permission Push merge commits to project owners group (that will allow you to invoke git push);
    2. permission Forge commiter identity - this will be required by Gerrit to accept the changes you are not an author of.
  3. Clone this repository;
  4. Branch off the master branch;
  5. Add new upstream: git remote add upstream ;
  6. Merge the upstream's master branch to your local master branch
  7. Push changes to gerrit using git push origin master.

That's pretty much it. Good thing about mixture like the above is: you can - at any time in the future - recreate this exact configuration. It will work. You will also be able to push changes - once reviewed - to your upstream repository.

Good luck!

Gerrit Code Review - setup

Gerrit Code Review has given me a hard time when I first tried it out.

It wasn't such a big problem to have it installed, as it was to have it configured. Whenever I was done with initial setup, it kept failing on attempt to register first user, and the problem re-emerged some time later, when I decided to upgrade the system.

My biggest fail back then was to set things up manually. I added user to specific groups by hand, thinking that the setup script was not mature enough to handle it for me. While searching around for how i did this last time i stumbled upon a short [ticket](, which helped me realize, that it was all so much out of sync, it just couldn't handle the upgrade.

Ultimately, every time I set up the review site from scratch, the attempt to register first user ended up with the following message:

[2012-12-22 18:58:24,835] WARN / : Unexpected error during authentication
 at java.util.ArrayList$Itr.next(ArrayList.java:794)
 at com.google.gerrit.server.account.AccountManager.create(AccountManager.java:291)
 at com.google.gerrit.server.account.AccountManager.authenticate(AccountManager.java:122)
 at com.google.gerrit.httpd.auth.openid.OpenIdServiceImpl.doAuth(OpenIdServiceImpl.java:409)
 at com.google.gerrit.httpd.auth.openid.OpenIdLoginServlet.doPost(OpenIdLoginServlet.java:50)
 at com.google.gerrit.httpd.auth.openid.OpenIdLoginServlet.doGet(OpenIdLoginServlet.java:40)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)

Here's a step-by-step procedure that will help you set things up right the first time you try.


  • Linux box, 
  • Sun JAVA virtual machine - version 1.6 or later, 
  • PostgreSQL installed and running

Here's what you do:

  1. As root: Prepare Gerrit repository folder, say
    mkdir /var/repositories

  2. As root: Change permissions on this folder, allowing your gerrit2 user full access:
    chown -R gerrit2 /var/repositories
  3. As gerrit2: Initialize a new repository:
    git init --bare /var/repositories/All-Projects.git
  4. As gerrit2: Create new PostgreSQL user:
    createuser -A -D -P -E gerrit2
  5. As gerrit2: Create new PostgreSQL database:
    createdb -E UTF-8 -O gerrit2 reviewdb
  6. As gerrit2: Download the latest gerrit2 installation package and launch the setup:
    java -jar gerrit-full-2.5.1.war init \
        -d /home/gerrit2/review_site
  7. Finally, navigate to Gerrit web site and register your new user:
    xdg-open http://localhost:8080/#/admin/projects
Now, if you are facing complete reinstallation of your system, and upgrading is simply not possible (say, you did the same thing I did previously), here's what you need to do:
  1. As gerrit2: stop the review site:
    cd ~/review_site bin/gerrit.sh stop
  2. As postgres: drop the database:
    dropdb reviewdb
  3. As gerrit2: remove the All-Projects repo:
    rm -rf /var/repositories/All-Projects.git
Yes, this will purge the history of your reviews. It sucks - well, kind of. Ultimately you will get fully functional review site, which is pretty much what counts more.

Next step is usually to trim the approval categories. It feels kind-of wrong to manipulate the database directly, but then, at the same time, it feels stupid to go through verification of own changes.

Typically, one could do this by invoking:

ssh server gerrit gsql
delete from approval_categories \
    [where category_id="VRIF" or category_id="CRVW"]
delete from approval_category_values \
    [where category_id ...]

The contents of these two tables are:

gerrit> select * from approval_categories;
 name        | abbreviated_name | position | function_name | copy_min_score | category_id
 Verified    | V                | 0        | MaxWithBlock  | N              | VRIF
 Code Review | R                | 1        | MaxWithBlock  | Y              | CRVW
(2 rows; 14 ms)

gerrit> select * from approval_category_values; name                                            | category_id | value
 Verified                                        | VRIF        | 1
 No score                                        | VRIF        | 0
 Fails                                           | VRIF        | -1
 Looks good to me, approved                      | CRVW        | 2
 Looks good to me, but someone else must approve | CRVW        | 1
 No score                                        | CRVW        | 0
 I would prefer that you didn't submit this      | CRVW        | -1
 Do not submit                                   | CRVW        | -2
(8 rows; 7 ms)

so, nothing's lost - just delete the contents. Gerrit still does need an approval category. To add them, execute:

ssh server gerrit gsql

insert into approval_categories values \
    ("Approved", 'A', 0, MaxNoBlock, 'Y', "APRV");
insert into approval_category_values values \
    ('No Score', 'APRV', 0);
insert into approval_category_values values \
    ('Approved', 'APRV', 1);

and restart the server (for some, invoking flush-caches would work, too).


Import bookmarks from XMarks to Chrome

I love xmarks. I don't think there's anything even a little close to this service. I have my bookmarks everywhere and even if something goes wrong I can restore it - always.

Yet I do love android and chrome, too. Let's face it, xmarks for chrome is waay better than xmarks for android. And what happens if you accidentally enable syncing your bookmarks with chrome, while using xmarks? well, it all multiplies. In hundreds.

Here's a little trick you can do to propagate your xmarks to google chrome. It's pretty straight forward, but it requires a little bit of tweaking. That said, you can do that even if you're a total noob. Ready?

  1. Disable syncing your bookmarks with XMarks: click on the xmarks icon, open settings and select Sign Out,
  2. Navigate to your bookmarks management site,
  3. From the Tools menu select Export Bookmarks to HTML,
  4. Open text editor - any one will do - and replace all occurences of "&#58;" with a colon (":"); save modified file,
  5. Open Chrome Settings (navigate to chrome://settings) and in Advanced Sync Options enable Bookmarks
  6. Close settings, open Chrome Bookmark Manager (navigate to chrome://bookmarks),
  7. From Organize menu select Import bookmarks from HTML,
  8. Select the file.
That will push your bookmarks to google and later synchronize with your android device.

Remember to turn off chrome bookmark sync before signing back into xmarks!