Introduction: OrangeBOX: OrangePI Based Secure Backup Storage Device

About: Never stops thinking.

The OrangeBOX is an all-in-one remote storage backup box for any servers.

Your server can be infected, corrupted, wiped and all your data is still secure on the OrangeBOX and who wouldn't like a mission impossible like backup device what you just plug in and see a progress indicator without doing anything more (just hope the magic smoke will not come out at the end:)).

The OrangeBOX is my first project which is mostly a software, not a hardware hack. It is basically a custom built NAS with an LCD attached.

Step 1: Hardware Parts

The Orange PI zero is an open-source single-board computer. It can run Android 4.4, Ubuntu, Debian. It uses the AllWinner H2 SoC, and has 256MB/512MB DDR3 SDRAM(256MB version is Standard version. Orange Pi Zero is for anyone who wants to start creating with technology – not just consuming it. It's a simple, fun, useful tool that you can use to start taking control of the world around you ( So it is exactly for us lets get on with it :)

  • Metal/plastic/wood box (I have used an old Yamaha external cd-rw box)
  • Orange PI Zero or better (GPIO pinout might changes if you use another model)
  • 2x20 RGB LCD screens
  • Any SFF 3.5/ LFF 2.55 usb drive
  • Sata -> usb adapter. Keep in mind that while the OrangePI does not imposes an upper limit on the maximum drive capacity however a lot of USB-to-SATA bridges do (2TB max). The orange PI Zero I use only has a single USB 2.0 port with effective transfer rate of 28 MB/s max. I have chosen a USB3.0 (prepared for future upgrades) -> SATA bridge (brand will not be mentioned) and it caps the limit so it is better to chose a bridge proven to be supporting larger drives such as JMicron JMS567 chip based bridges. Do your own research before buying one. I can live with the speed and hard drive limit by using a 2TB sata drive in this project (if you put in bigger drives, it will be recognized but the OS will only see the first 2TB of it so the rest of the capacity will be lost).
  • 12V 2.5 A or higher amp adapter. Calculate about 500mA normal usage for the OPI Zero and 1.5A peak for a standard LFF SATA drive. Oversizing never hurts. In my setup the Yamaha psu (what could've supply more than enough current on both 12+5V rails) unfortunately blown up :( due to sorting the main switch to GND for a second so I had to glue in a regular adapter, at least it made the box a couple of grams lighter.
  • Buck converter DC-DC 12V->5V. I used the same adjustable mini buck as with IronForge, works perfectly.


If you are willing to spend + 10$ then you can get the Orange Pi Plus ( which is similar form factor and gets you Gbe and SATA3. For this the Libra PI wiring library can be used: but since the GPIO pinout is different it is out of the scope of this writing.

You can also do this build with the new Orange PI Plus2 which have SATA connector and you can skip the use of sata->usb converters all together with their limitations. If you planning to use FreeBSD or other BSDs the Orange PI series might not be the best choice since their hardware support is limited (for example you need to use USB stick to boot). For BSDs it's the best advice to use Raspberry PI. Both the C code for the LCD and all the shell scripts are portable to any other UNIX systems.

Step 2: Hardware Design

The Yamaha box was just enough to store all this, it would not have enough space for an Orange PI PC or regular Raspi form-factor board.

The Ethernet was brought out with an extender to the back of the box. Remember that the Orange PI zero only have 100mbit/s Ethernet interface if you want faster you will need to use another board such as Asus Tinkerboard/RPI3B+/Other Orange PI models.

Wrong PIN Out is the one and only mistake you can make in this project therefore it worth applying some rule of the thumb principles:

1, Always try to use the same colored cable from END to END. I myself commit the same "mistake" in some projects where I don't, simply because I don't have long enough male-male/male-female/female-female cables on hand and I patch 2 together just to get on with the circuit. If you don't properly document your work this can lead to headaches years later where you have to do a repair, upgrade.

2, Apply some hotglue to the connectors. In case of using these arduino-starter kit style mm/mf/ff cables which are not top of the line quality it is quite common (especially if you move around/transport the device) that the connectors slip out. If you know it will be a long term use device (possibly use until it breaks?!) then it is better to apply a bit of hotglue both on the OrangePI and LCD side of connectors to keep them together. This can be easily melted/scratched off later on if needed.

3, The OrangePI zero wiring The bad news is that the Orange PI pinout is NOT the same as the Raspberry PI 0/1/2/3 and there is even difference between other Orange PI models. The best way to go is get the wiring library (Orange PI Zero version). The image might be a bit confusing but these were the best I could find. One is a 180 degree mirror of the other one. Although the CLI non graphical image might be more difficult to comprehend it is the most straight forward.

You can always differ the 2 end of the sockets by considering one end as the POSITIVE end with the (+3.3/+5V) and other as the NEGATIVE end (one GND) -> this is the end of the connector facing the ETHERNET port.

From the Wiring PI Zero table you will only need one column the wPI forget about the others like they would not be there.

So for example to connect the LCD_E 15 (that is wPI 15!) and LCD_RS 16 (that is wPI 16!) count the pins from the POSITIVE end of the connector (easy to do with a pen or small screwdriver). That will be physically going down 4 pins and 5 pins.

4, Group up. If there is a possibility to put used pins next to each other (grouping them up) always chose that, it makes them to have a hold by each other even without hotglue and also in other projects when you have 2x 4x 6x molex connectors you can just take advantage the pins being next to each other. Here the best you can do is group of 2-3s (ideal when using salvaged jumper cables from old PCs).

Pins used for OrangePI <> LCD Screen connection:

#define LCD_E   15              //Enable Pin
#define LCD_RS  16              //Register select pin

#define LCD_D4  5               //Data pin 4
#define LCD_D5  6               //Data pin 5
#define LCD_D6  10              //Data pin 6
#define LCD_D7  11              //Data pin 7

Pins used for RGB backlight control

        $G write 1 0
        $G write 4 1
        $G write 7 1

Orange PI zero wPI pins 1, 4, 7. The only magic this LCD can do compared to the standard fix blue or fix green backlight LCD where you have a single cathode which needs to be pulled down to GND that it has 3 for the 3 colors. Red, green and blue. By changing the combination of which one is turned ON you can mix out different colors from these base colors but only the high ends no shades because you cannot control the brightness of a color (it's either on or off).

Additive color mixing: adding red to green yields yellow; adding red to blue yields magenta; adding green to blue yields cyan; adding all three primary colors together yields white.

Step 3: Operating System

The OrangeBOX boots up and Armbian linux (based on Debian Stretch) 4.14.18-sunxi kernel with a secure firewalled environment, connects to a VPN and waits for remote backup commands from the server.

Design principles:

-Full luks based disk encryption (the device itself does not contains the key for opening the backup drive. It will be temporarily copied from the remote server to the ram /dev/shm, the drive opened and the key erased. After the backup finished the drive closed and the OrangeBox is automatically shuts down in 1 minute.)

-All the commands and keys are sent from the remote server (the device itself only contains a vpn cert) it does not have ANY access to the remote server even ssh from this device is firewalled out

-The local filesystems un-encrypted to be able to boot up but does not contain anything useful and since the VPN uplink is highly restricted on the other end even with the complete loss of the device an attacker cannot do anything

Download the Armbian Stretch from

Get the system up and running:

  apt-get update && apt-get upgrade
  apt-get install sysvinit-core sysvinit-utils

Edit the /etc/inittab, all the console can be disabled as the box will be used as headless. Comment out the following section:

#1:2345:respawn:/sbin/getty 38400 tty1
#2:23:respawn:/sbin/getty 38400 tty2
#3:23:respawn:/sbin/getty 38400 tty3
#4:23:respawn:/sbin/getty 38400 tty4
#5:23:respawn:/sbin/getty 38400 tty5
#6:23:respawn:/sbin/getty 38400 tty6

Reboot your box and remove systemd to have a real open source bloatware free system.

  apt-get remove --purge --auto-remove systemd

Install some packages

  apt-get install cryptsetup vim htop rsync screen gcc make git

Install the wiringpi library

  cd /usr/src
  git clone
  cd WiringOP-Zero
  chmod +x ./build

Create orange user for the lcd display

  groupadd -g 1000 orange
  useradd -m -d /home/orange -s /bin/bash -u 1000 -g orange orange

The watchdog which does not watch over you

apt-get install watchdog
Looking at /etc/default/watchdog<br>
# Start watchdog at boot time? 0 or 1
# Start wd_keepalive after stopping watchdog? 0 or 1
# Load module before starting watchdog
# Specify additional watchdog options here (see manpage).
Looking at /etc/watchdog.conf
# At least enable these
max-load-1              = 24
max-load-5              = 18
max-load-15             = 12
/etc/init.d/watchdog start 
There should be at least 1 kernel thread and 1 process:
root        42  0.0  0.0      0     0 ?        I<   10:50   0:00 [watchdogd]
root     14613  0.0  0.2   1432  1080 ?        SLs  13:31   0:00 /usr/sbin/watchdog


Make sure you stop everything and do a sync && sync && sync to write the rest of the data to the disk. Then as root issue:

echo 1 > /dev/watchdog

After some seconds the machine should reboot.

As the manual states:

       o  Is the process table full?

       o  Is there enough free memory?

       o  Is there enough allocatable memory?

       o  Are some files accessible?

       o  Have some files changed within a given interval?

       o  Is the average work load too high?

       o  Has a file table overflow occurred?

       o  Is a process still running? The process is specified by a pid file.

       o  Do some IP addresses answer to ping?

       o  Do network interfaces receive traffic?

       o  Is the temperature too high? (Temperature data not always available.)

       o  Execute a user defined command to do arbitrary tests.

       o  Execute one or more test/repair commands found in /etc/watchdog.d.  These commands are called with the argument test or repair.

       If any of these checks fail watchdog will cause a shutdown. Should any of these tests except the user defined binary last longer than one minute  the
       machine will be rebooted, too.

This watchdog might worked OK on the regular x86 architectures but on ARM based boards such as Raspberry PIs, Orange PIs it failed me countless times. The system can go into hang states where even the watchdog is hanging. Let's just configure it anyway maybe it will get improved with an apt-get upgrade over the years :(

Step 4: Software Design

The backup process itself is rsync based (best backup tool ever invented) data gets pushed from the SERVER->OrangeBOX.

Extracting the data from rsync was the only challenging part of the project to have a progress bar about the backup printed out on the LCD.

There were 3 possible ways to calculate the backup progress:

1, Using formulas such as to determine the approx time the transfer can take

 Transfer Time (d:h:m:s):  0:02:44:00
 For comparison:
 Estimated time to transfer 123 GB file over different network links (d:h:m:s):
 T1/DS1 line (1.544 Mbps) - 7:09:01:46
 Ethernet (10 Mbps) - 1:03:20:00
 Fast Ethernet (100 Mbps) - 0:02:44:00
 Gigabit Ethernet (1000 Mbps) - 0:00:16:24
 10 Gigabit Ethernet (10 Gbps) - 0:00:01:38 

If the rsync finishes it signals the script to stop the calculation. This method is just an approximate and not reliable, also the link speed is not fix, it can slow down, speed up again. This is just a theoretical calculation.

2, Doing size checks on the directory to determine how much data did we sync already. Can get very slow with hundreds of GBs small files (although du -s in Linux does some caching if you rerun it)

Host A -> Server data to be backed up                    Data dir: 235GB
Host B -> Orange box client data we have right now       Data dir: 112GB

The delta is 123 GB.

3, If the filesystem is dedicated like in our case /dev/mapper/backup is we can take advantage of the overall filesystem usage indicator to determine how is our backup progressing and this is really damn fast. In this case we don't even need to pipe the rsync stdout anywhere, just run a dry rsync, wait until it completes, calculate the delta in bytes and crosscheck this with the free space what we have on the backup drive and voila we can now make a nice bar graph. This was the method I chose and here is my script for it:

# Backup Progress Calculator for OrangeBOX by NLD
# Version: 0.2 (2018/03/05)
# Run it as unprivileged user from cron
# * * * * * /home/orange/ &> /dev/null
# This script is responsible only for displaying data on the LCD, it communicates
# with the main program indirectly through position and lock files.

VFILE="$HOME/start.pos"  # disk usage at the beginning of the backup
TFILE="$HOME/trans.size" # overall precalculated transfer size
BFILE="$HOME/backup.lck" # determines started state
FFILE="$HOME/backup.fin" # determines finished state
LFILE1="$HOME/"  # LCD progress indicator data
LFILE2="$HOME/"  # LCD progress indicator data
SHUTDOWN="1"             # If 1 it will initiate another script which shuts down the box at the end of backup
BACKUP_CURRENT="0"       # Has to be initialized but will be calculated
DRIVE_SIZE="<YOUR DRIVES SIZE IN BYTES>" # Drive size in bytes (secondary check)
LCD="sudo /bin/lcd"
function is_mount() {
                grep -q "$1" /proc/mounts

function red() {
 sudo /bin/lcdcolor red
function green() {
 sudo /bin/lcdcolor green
function blue() {
 sudo /bin/lcdcolor blue

# Clear state (set on boot by No backup is in progress, do NOT mess up the
# status LCD. Only display progress in case of there is an ongoing backup => No start file AND No fin file = quit
if [ ! -f $BFILE ] && [ ! -f $FFILE  ]; then
  exit 1

# If the backup finished this script will display that and remove the locks
# not to be able to run again until the next initiation.
if [ -f $FFILE ]; then
   $LCD "   Backup   " "** Completed **"
   echo "Backup Completed"
   rm -rf $BFILE $TFILE $FFILE $LFILE1 $LFILE2 $VFILE # Backup finished clean up

   if [ $SHUTDOWN == "1" ]; then
        echo "Executing shutdown script..."
        /home/orange/ &
   exit 0

# From this point the script ONLY executes if there is an ONGOING backup
# therefore all errors will be printed out to the LCD and cause the script
# to abort however it will not remove the backup.lck file so will go in here
# over and over again and evaulate the conditions.

is_mount $BACKUP_DRIVE
  if [ $status -ne 0 ]; then
          $LCD "ERR: Backup drive" "is not mounted!"
          echo "Backup drive is not mounted"
          exit 1

if [ ! -s $TFILE ]; then
          $LCD "ERR: transfile" "is empty"
          echo "Transport size calculation file is empty."
          exit 1

BACKUP_OVERALL=$(head -1 $TFILE |tr -d '\n')

if [ -z $BACKUP_OVERALL ]; then
          $LCD "ERR: Size readback" "from server invalid"
          echo "Backup overall size readback is invalid 1"
          exit 1

if ! [[ $BACKUP_OVERALL =~ ^-?[0-9]+$ ]] ; then
          $LCD "ERR: Size readback" "from server invalid"
          echo "Backup overall size readback is invalid 2"
          exit 1

if [ $BACKUP_OVERALL -le 0 ]; then
          $LCD "ERR: Size readback" "Size is too small"
          echo "Overall backup size is too small"
          exit 1

# Query filesystem information in bytes
SPACE_ALL=$(df -B1 | grep $BACKUP_DRIVE | awk '{ print $2 }')
SPACE_USED=$(df -B1 | grep $BACKUP_DRIVE | awk '{ print $3 }')
SPACE_FREE=$(df -B1 | grep $BACKUP_DRIVE | awk '{ print $4 }')

if [ $SPACE_ALL -ne $DRIVE_SIZE ]; then
          $LCD "ERR: drive size" "Space mismatch"
          echo "The mounted hard drive is not identical with the hardcoded value."
          exit 1

if [ ! -f $VFILE ]; then
        echo "START_POS=$SPACE_USED" > $VFILE

        source $VFILE

if [ $BACKUP_OVERALL -ge $SPACE_FREE ]; then
        $LCD "ERR: Backup size" "exceeds disk space!"
        echo "Backup exceeds free space, not performing backup"
        exit 1

#Blue light from here


if [ $BACKUP_OVERALL_GB -gt 1 ]; then

if [ $BACKUP_CURRENT_GB -gt 1 ]; then

# Maps the percentage on a scale of 20 COL LCD
  LCD_BAR=$(expr $PROGRESS \* 20 / 100)
  rm -rf $LFILE1 $LFILE2

# LCD Display

  echo "$LCD_CURRENT / $LCD_OVERALL" | cut -b -19 > $LFILE1
  for ((i=0;i<=$LCD_BAR;i++))
          echo -n "#" >> $LFILE2

 sudo /bin/lcd "$(head -1 $LFILE1)"  $(head -1 $LFILE2 | cut -b -19)

# Console Display
echo "-------------------------------------------------------"
echo "Space all: $SPACE_ALL bytes => $(expr $SPACE_ALL / 1024 / 1024) MB => $(expr $SPACE_ALL / 1024 / 1024 / 1024) GB"
echo "Space used: $START_POS bytes => $(expr $START_POS / 1024 / 1024) MB => $(expr $SPACE_ALL / 1024 / 1024 / 1024) GB"
echo "Space free: $SPACE_FREE bytes => $(expr $SPACE_FREE / 1024 / 1024) MB => $(expr $SPACE_ALL / 1024 / 1024 / 1024) GB"
echo "-------------------------------------------------------"
echo "Backup completed: $BACKUP_CURRENT bytes => $BACKUP_CURRENT_MB MB => $BACKUP_CURRENT_GB GB"
echo "Progress: $PROGRESS %"

Although the code is simple here is some description what it does:

1, If the BFILE or FFILE does not exist (which is the state after a clear startup) that indicates there is no backup process so do NOT do anything just quit. This way you can graph whatever nice information you want regarding the bootup like the hostname, ip, uptime etc and it won't be messed up.

2, Let's jump to the is_mount $BACKUP_DRIVE section. Just a reminder the only way we got here is that a backup was started so the BFILE exist. Now the code just does various error checks like is the backup drive mounted?, is the overall size of what we about to back up exceed the drive? or other errors. Remember this is a DISPLAY only program even if the size would exceed the backups it will not abort anything.

3, OK all error checks cleared time to calculate the percentage graph. First the script takes a "snapshot" of the space used in bytes on the backup filesystem right now and stores it down in VFILE. What is the purpose of this: a bash script is stateless, it loses data between executions, so if you want to "remember" some data from the previous execution you need to store it down somewhere. In our case this is just a simple text file. To make it simple let's say our START_POS is 1GB (data we have), what we want to backup is +2GB and the overall drive capacity is 10GB.

4, Next time when the script runs the VFILE exist and this will be read back (so we know what was the start position in case the drive was not empty) in to calculate the BACKUP_CURRENT which is essentially a delta of the space used right now on the backup drive minus the start position what we have saved in the VFILE in the last round (again this is the data we had on the drive when the backup started). The script internally works with bytes but to make it simple after half an hour we backed up 500MB data then the formula would be BACKUP_CURRENT=1.5GB - 1GB (initial state) => which gives us back exactly the real data 500 MB, that is what we backed up so far. You can see that without keeping track of what the original data was at the beginning of the backup this size calculation would fail because it would see that the space used right now is 1.5GB without knowing that 1 gig data was there on the disk all along coming from a previous backup so it would assume that the server has sent us 1.5GB data instead of 500MB.

5, BACKUP_OVERALL will be read in, this data was calculated by the server when it did the initial dry rsync (so this is an external data source containing the amount of bytes what will be backed up from Server->OrangeBOX). This value will be checked against the overall FREE space on the disk at the moment and if it exceeds it then an error message will be displayed on the lcd and the script stops execution. Remember again that all this script does is display ONLY, it does not interfere with the backup process. If you clean up files on the disk or the amount of files changes remotely and therefore the BACKUP_OVERALL changes at one point it will proceed.

6, Finally we are done with the second level checks it's time to display something. The script both displays the data on the console and on the lcd using a simple C app. The background is switched to BLUE indicating that the backup finally began and the progress calculated by the following formula PROGRESS=$(( ($BACKUP_CURRENT * 100) / $BACKUP_OVERALL )). This is a basic percentage calculation we take the current amount, in our example 0.5GB*100/2GB = 25%.

7, The numbers are also converted from byte to Mega/Giga bytes and the screen automatically displays in MB if it is lower than 1GB.

8,One thing left to map this in our case is the 25% on a 20 column LCD. That would be 25 * 20 / 100 = 5 in our example. Currently the refresh with the LCD program is implemented that every time you call the program it will redraw the whole screen. So in this case it would run a for loop 5 times to draw 5 hashmarks # on the screen this would show up as ugly flickering in each round so instead I writing out the calculated progress bar data to LFILE1 and 2, which in this case after the 5 rounds would contain ##### and this is read back and displayed on the LCD. You might put LFILE1 and 2 on ramdisk as well to save the sdcard from extra write operations, it did not cause any issues for me, the script runs once in every minute from cron.

9, When the backup finished the other script from the server which runs rsync will touch the FFILE (Finish File). At the next loop will then display that the backup is completed and optionally calls another script to shut down the OrangeBOX. It deletes its lock files at this point making further executions impossible so even if you don't enable shutdown the next minute when this script runs it will quit right away because the BFILE is not there and the FFILE is not there. Therefore it will display the backup completed message indefinitely unless the backup is restarted again.

Remote backup script (

You will need to generate an ssh key for the backup and a key for the luks encryption for the drive. When you run the remote backup manually for the first time it will save the orange boxes host fingerprint to the hosts file (from this point it can run automatically by cron).


To find out your hard disk identifier run uuid, blkid or just look up the corresponding /dev/disk/ directories.

A directory include exclude can be setup if you don't want to back everything up. This is quite annoying process because for rsync if you want to exclude a single sub-directory deep in the structure you have to do:

+ /a
+ /a/b
+ /a/b/c
+ /a/b/c/d
- /a/b/c/d/e
+ /dir2

Since this script is executing commands on the OrangeBOX remotely it have no oversight of the return variables from that side, therefore I use some clever tricks such as it will output the message of opening the remote drive to /tmp/contmsg.txt, then parse it to see if it was successful, if not then it changes the rsync binary to non-executable so the rsync will not try to upload data to the OrangePIs rootfs filling the SDcard up. Also a good practice to set the immutable bit on chattr +i /mnt/backup to make this impossible.

The size precalculation takes place locally on the Server therefore this file has to be sent to the OrangeBOX in next step.

The main backup is initiated as a loop for ((i=0;i<100;i++)); do because in case of low quality DSL/Cable internet connections rsync can often break, timeout. If it completes successfully then the loop will break without trying more iterations. This works flawlessly with good operating systems, however if for some reason the remote box would be windows and there would be access denied like regularly on NTUSER.DAT then rsync would return an error code and this loop would execute 100 times and then still fail.

Step 5: Closure & ToDo List

My instructable demonstrates once again how can your create something better, more customisable device from a 10$ computer on your own which beats the hell out of Buffalo with it's proprietary locked down NAS devices, weird internal partitioning, busybox crippled linux with segfaulting tools, managed by their windows software, closed firmware, bad documentation and support and no matter how much money you will spend you will never get a progress indicator showing your backup not to mention how cool the OrangeBox looks (I even using orange CAT5 cable with it :D).

With mini computers becoming more and more powerful while maintaining the same < 100$ price line we can use them for more and more tasks. As Gbe Ethernet ports are quite common these days in 1-2 years the memory on these boards will dramatically increase and they can be used for ZFS based backup systems as well.

-Fine grain progress indicator by the C program (see WasserStation one of my other project). Right now just # hashmark # characters used in character mode with lcdPuts(lcd, line1), this could be improved even when using character LCDs to divide 1 column to 5 parts and the main C program could just take an integer like 25 and draw out the progress bar properly or further improved by using a graphical LCD

-Possibility to have a removable hdd for creating new and new backups and moving them to different locations (if the box detects an empty drive then it should auto-format it with the encryption key once it has been received).

-If you want to print your own case with makerbot the OrangeNAS might be interesting for you: