In this article, users will learn how to add an external storage device to the hardware NVR manufactured by Ubiquiti.  I took this information straight out of the Ubiquiti knowledge base, used it to install a few drives and was looking for an easy way to refer to it each time I do this so here it is where I can find it and you can benefit too!

You can add any USB external storage device.  However, for best peformance and longevity, I recommend using a USB 3.0 mechanical hard drive.  UniFi-Video involves high bit rate transfers and as such, involves a lot of read/write cycles. With flash based memory, such as USB flash drives, Solid State Drives (SSDs), SD cards, microSD cards, etc, performance and longevity is reduced over time with a high number of read/write cycles and therefore may not be the best use case for a security system storage method.

Also, make note of the type of USB drive you’re using.  I do not recommend using a USB 1.1 drive as it is too slow.  USB 2.0 is OK for a couple of cameras.  USB 3.0 is the fastest.  The UVC-NVR/airVision-C comes equipped with 6 total USB ports; 2 USB 3.0 drives on the front of the unit and 4 USB 2.0 ports on the rear of the unit.  If you’re using a USB 3.0 drive, please make sure that you have it plugged in to the front of the unit, otherwise you will not be getting the full potential of the unit.

To complete this process, you will need:

  1. A UVC-NVR/airVision-C powered up and plugged in to the network (In the rest of this article, I’ll simply rerfer to this as “NVR”)
  2. The IP address of the NVR
  3. Your USB external storage device
  4. An SSH client.  For Linux and Mac users, this is built in natively in to your Terminal application.  For Windows users, you’ll need to download an SSH client such as PuTTy.
  5. About 15 minutes of time

A few warnings before we begin

You will lose everything on your external USB storage drive following this guide, please make sure everything is backed up.

One of these steps involves rebooting the NVR to ensure that the external storage drive mounts properly upon reboot.  If your system is mission critical, it is recommended that you perform these steps during off hours.

I will be showing examples from my system which is using a 16GB USB flash drive for demonstration purposes only so that you have a visual idea of what you’re looking for on your own system.

The Steps:

  1. Plug your external drive in to an appropriate USB port
  2. SSH in to the NVR. For Linux and Mac users using Terminal. For Windows users using PuTTy.  The default credentials are Username: root  Password: ubnt
  3. Find out what your drive designator is.  You can do this by issuing the following command:
    fdisk -l

    Sample Output:

    root@UniFi-NVR:~# fdisk -l
    Disk /dev/sda: 500.1 GB, 500107862016 bytes
    255 heads, 63 sectors/track, 60801 cylinders, total 976773168 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes
    Disk identifier: 0x0008ce59
       Device Boot      Start         End      Blocks   Id  System
    /dev/sda1   *        4096     1957887      976896   83  Linux
    /dev/sda2         1957888   976773119   487407616    f  W95 Ext'd (LBA)
    /dev/sda5         1959936     9771007     3905536   82  Linux swap / Solaris
    /dev/sda6         9773056    15624191     2925568   83  Linux
    /dev/sda7        15626240   976773119   480573440   8e  Linux LVM
    Disk /dev/mapper/lvm-data0: 492.1 GB, 492105105408 bytes
    255 heads, 63 sectors/track, 59828 cylinders, total 961142784 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes
    Disk identifier: 0x00000000
    Disk /dev/mapper/lvm-data0 doesn't contain a valid partition table
    Disk /dev/sdb: 15.8 GB, 15846080512 bytes
    255 heads, 63 sectors/track, 1926 cylinders, total 30949376 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
    Disk identifier: 0x2f08ac3c
       Device Boot      Start         End      Blocks   Id  System
    /dev/sdb1           16065    30941189    15462562+   f  W95 Ext'd (LBA)
    /dev/sdb5           16128    30941189    15462531    7  HPFS/NTFS/exFAT

    Note that Linux drive designators always start with “/dev/sd” and usually go in alphabetical order. The first drive plugged in is /dev/sda, the second drive plugged in is /dev/sdb. Note that you never want to do anything with /dev/sda. That is where the operating system is stored. Messing with /dev/sda may result in an unusable system!. After /dev/sdb, you see a number, this designates the partition number. Again, these are assigned in order; in this case, numerical. This doesn’t matter much because we’re going to remove all partitions on the external drive and create only one.
    In the above output, my target drive is /dev/sdb, which is most likely the same for your system.  I have bolded the sections of output that you should be looking for.  Since I am using a 16GB external drive, 15.8GB is pretty close, so that’s how I know that’s my drive.

  4. Now, we need to edit the partitions of the drive, we can do so by:
    parted /dev/sdb
  5. Next, we set the partition table to GPT, like so:
    (parted) mklabel gpt

    and type “yes” to accept the following warning

  6. Now, we create the new partition, which we do so by first establishing the units that we’re working with either GB or TB, then establishing the beginning and end of the partition. Take care that the second size here should be the max size of your drive, 16GB is the size of my drive and is only shown as sample output.  As such:
    (parted) unit GB
    (parted) mkpart primary 0.00GB 16.00GB
  7. Then confirm everything looks correct by printing the partition table with print:
    (parted) print
    Model: Patriot Memory (scsi)
    Disk /dev/sdb: 15.8GB
    Sector size (logical/physical): 512B/512B
    Partition Table: gpt
    Number Start End Size File system Name Flags
     1 0.00GB 15.8GB 15.8GB ext4 primary
  8. Finally, we write these changes with quit, hich should then drop you back to the regular shell
  9. Now we make the filesystem:
    mkfs.ext4 /dev/sdb1
    • Optional and somewhat risky: All filesystems have a reserved amount of space for overhead. In this case, it’s 5%. For 16GB, this isn’t much and is probably very much so necessary. But if you’re using a 1TB+ drive, it’s probably not all that necessary to keep 51GB+ reserved. If you like, you can reduce this reservation. Note that we do not recommend going below 2%. If you choose to do this, you’re doing so at your own risk and can do so by:
      tune2fs -m 2 /dev/sdb1

      Where the number following the -m is the percentage to keep reserved

  10. Now, create a mount point where we will be mounting our partition. For simplicity and to avoid confusion, we recommend naming it something indicative that it’s an external storage device and putting it somewhere where it’s not confusing. For demonstration purposes, we’re going with /exthd. So:
    mkdir /exthd
  11. Mount the parition:
    mount -t ext4 /dev/sdb1 /exthd
  12. Make the mount occur at boot time. If you’re familiar with Linux, you can use vi which is installed already, but we’re going to install nano for a simple, more notepad like editor:
    apt-get update; apt-get install nano


    nano /etc/rc.local

    And insert your mount command from step 11, your whole file should look like this:

    #!/bin/sh -e
    # rc.local
    # This script is executed at the end of each multiuser runlevel.
    # Make sure that the script will "exit 0" on success or any other
    # value on error.
    # In order to enable or disable this script just change the execution
    # bits.
    # By default this script does nothing.
    mount -t ext4 /dev/sdb1 /exthd
    exit 0

    Ctrl+x to exit, you’ll be prompted to save, press y on your keyboard followed by enter on your keyboard.

  13. Reboot the NVR:
  14. When the system comes back up, SSH back in. Issue the mount command:

    You should see something like this:

    root@UniFi-NVR:~# mount
    sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
    proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
    udev on /dev type devtmpfs (rw,relatime,size=10240k,nr_inodes=503334,mode=755)
    devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
    tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=403736k,mode=755)
    /dev/disk/by-label/boot on /boot type ext2 (ro,noatime,errors=continue,user_xattr,acl)
    /dev/loop0 on /mnt/.rofs type squashfs (ro,relatime)
    /dev/disk/by-label/user.0 on /mnt/.rwfs type ext4 (rw,noatime,data=ordered)
    aufs-root on / type aufs (rw,relatime,si=8458a27b1bc70b71)
    tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
    tmpfs on /run/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=1588560k)
    tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noatime,nodiratime,size=807468k)
    /dev/mapper/lvm-data0 on /srv type ext4 (rw,noatime,nodiratime,data=ordered)
    /dev/mapper/lvm-data0 on /var/lib/unifi type ext4 (rw,noatime,nodiratime,data=ordered)
    /dev/mapper/lvm-data0 on /var/lib/mfi type ext4 (rw,noatime,nodiratime,data=ordered)
    tmpfs on /var/cache/unifi-video type tmpfs (rw,noexec,noatime,nodiratime,size=524288k,mode=777,uid=104)
    /dev/sdb1 on /exthd type ext4 (rw,relatime,data=ordered)

    That means that the partition mounts on boot, we’re in the home stretch.

  15. Now change the permissions of the mount point of /exthd:
    chown unifi-video:unifi-video /exthd
  16. Log in to your UniFi-Video web interface
  17. Go to Settings in the lower left hand corner
  18. Click the NVR SETTINGS button in the upper left hand corner
  19. Expand the CONFIGURE tab if it isn’t already
  20. Change your Recording Path to “/exthd” (without quotations)
  21. Change your Space To Keep Free to about 5% of your overall drive space
  22. Save these settings
  23. Keep an eye on your records in the web interface and/or the /exthd directory with the ls command:
    ls /exthd

    to ensure that there’s data being stored there.

  24. You’re all done!