View on GitHub

onash2

3D Printed Home/Server NAS based on the ODroid H2+

O-NAS-H2+

Introduction

Image of ONASH2

Welcome, My recent Reddit post exploded with overwhelming postive comments and requests for documentation on my 3D printed NAS project, so here it is!

This document is in no means fully exhaustive, but hopefully give some idea/pointers of what’s required to recreate. I will point out links of useful guides rather than reinvent the wheel wherever i can. If you have any further questions please feel free to send me issues via the github repo. I will do my best to answer :)

If anyone does print the parts and make there own ONASH2, you can thank me by sending a photo of it! :)

Oh and why ONASH2…. ODroid - NAS - H2

Index

Specifications

ONASH2 is designed to use:

Case

3D Printed Parts List

All parts pictured were printed in Galaxy Black Prusament PLA on a PRUSA Mini using the 0.2 Quality Presets. ( I did increase my bed temp to 63C to help with bed adhesion). All parts can be found here

Part Number Print time (@ Above settings) Required
onash2_case_bottom.stl 1 ~15 hrs Yes
onash2_case_top.stl 1 ~15 hrs Yes
onash2_lag_0.stl 1 ~5 hrs* Yes
onash2_lag_1.stl 1 * Yes
onash2_lag_2.stl 1 * Yes
onash2_lag_3.stl 1 * Yes
onash2_2.5_3.5_hdd_adapter.stl 2 ~30 mins No

*Print Time is the total applied to all legs printed on the same plate

Other Parts List

Part Number Comment
40mm M3 Hex Cap Bolts/Nuts 2 For attaching the rear of the case top to bottom. (You will need a hex driver/key longer than 70mm)
20mm M3 Hex Cap Bolts/Nuts 2 For attaching the front of the case top to bottom (40mm might also work)
12mm M3 Hex Cap Bolts/Nuts 12 8 - for the case legs, 4 - holding the board to the legs
Dust Filters 2 The case was designed specifically for these, although any 120x120 dust filter which is no thicker than 2mm should be fine
9mm Diameter Rubber Feet 4 Reduce any vibrations / noise

Electronics

Parts List

Part Number Comment
ODroid H2+ 1 None
60W 15V Power Supply 1 None
ODroid H2+ SATA Power/Data Cables 2 The power cables are pretty proprietry as far as i can tell.
NVME 1 For your OS Drive, you could use a hardkernel EMMC instead.
DDR4 RAM 1/2 The maximum the ODroid supports is 32GB, use case dependant how much to get.
SATA 2.5”/3.5” HDD 1/2 If you want to create a RAID you will need two (you dont need identical drivers but it helps)
5V PWM Noctua 120x120 Fan 1 Make sure its 5V!
JST 1.25mm 4 Pin 1 Required to connect the System Fan
1.5” I2C OLED 1 Case is designed for exactly this OLED dimensions.
4k7 Resistor 2 Used to pull High the I2C SDA/SCLK lines.
USB A Socket 1 Only required if you want the internal USB Port

Fan wiring

Using the JST Connector, and the Noctua fan extension cable that came in the box I soldered together an adapter to allow connecting it to the H2+. Beware your JST Connector may have different coloured wires!

Signal JST Wire Colour Noctua Wire Colour
GND #f03c15 RED #000000 BLACK
+5V #000000 BLACK #ffff00 YELLOW
TACH #ffff00 YELLOW #c5f015 GREEN
PWM #c5f015 GREEN #1589F0BLUE

OLED/USB Wiring

I believe the USB port is only brought to the GPIO expansion header on the H2+ (Not the H2).

Wiring

Software Setup

I’d advise doing all the software setup before you construct the server case.

Auto Start on applying power

Follow the instructions here

Fan Control

Follow the instructions here

Tip: If you’ve printed the case in PLA, i would suggest that you set the low temperature to 40C - RPM 1000, medium to 47C - 1500 and high to 47C - 1500, then set thermal shutdown at 55C. This is to stop thermal runaway if the fan stops working, which could(would) cause the PLA to soften and possible damage

Flashing the OS

Follow the instructions on Hardkernel for this. However i picked Ubuntu Server 20.04 LTS.

I picked server edition because it doesnt start up an X server or any Window Manger, i dont want the GUI taking up any resources when I dont plan to use it.

To “Flash” the OS you will need a USB Mouse and keyboard/HDMI cable hooked up to the ODroid so that you can go through the installation steps.

Its pretty straightforward but you will get some fun messages about missing Network Interface. At the time of writing the Gigabit ethernet controller drvier is not part of the Kernel in 20.04 LTS (5.4.0-52-generic). You can sort this out after OS installation.

Gigabit Ethernet Controller Driver

Compiling the Driver

You can follow the guide on Hardkernel. The process is very much a chicken and the egg sort of situation, compiling a network driver without a network driver was tricky.

I tried USB tethering, but with an iPhone i just couldnt get it to work without installing packages, which is also tricky without a network connection.

I ended up setting up an QEMU VM running the Ubuntu Server 20.04 LTS image on another machine i have, then compiled the driver on there. It was surprisingly easy to do but probably not for a beginner.

I also see theres now steps on Hardkernel for loading packages onto a USB drive. This looks like the simpliest method.

Using Precompiled Driver

If you are using the an Ubuntu Image with the same kernel (5.4.0-52-generic) as me, i’ve also included the driver in the github repo to make it super easy. You can copy this to your board using a USB stick and then load it into your kernel using insmod, then to bring up the network interface follow the instructions on Hardkernel

Tip: If you do use my Precompiled Driver, as soon as its working i suggest you install properly using the instructions on Hardkernel

Docker

I use Docker to run all my services, being able to containerize all the dependancies allows for super easy backups and also makes things very easy to manage. I also run Portainer in a Docker container which gives a fantastic Web UI for managing all the other Docker containers.

I’m not going into how to set these up as theres plenty of information about Docker around, just have a Google :)!

MDADM

Because i want my main NAS HDDs to be redundant, i set them up in RAID 1 Mirror using MDADM.

To set up a RAID 1 Array follow this guide.

**Tip: If your drives are new you can use the follow argument to your mdadm create command –assume-clean. This stops you wasting resources copying 4TB (in my case) of 0s for 14 hours… **

Status OLED

I2C connections

I assume you have connected up your I2C Display following the wiring diagram above. I2C 6 on the GPIO header is accessible via /dev/i2c-2 from the linux terminal. The first thing you will need to do is find the address of the Display. I2C supports upto 127 addresses 0x00 - 0x7F. On my OLED there was a choice of two addresses based on a resistor soldered between two points that could be swapped (0x78 or 0x7A). However it turns out the PCB description was lying to me and the address was actaully 0x3C go figure….

Anyway, to be able to find the address/confirm you’ve got something there, you can use i2c-tools to do a “detect” of the bus. Now theres a few fun caveats here:

  1. I2C doesnt strictly support “discovery” so if you run this on an I2C bus thats used for other purposes (CPU Temperature sensors / Clock chips etc) it could potential have bad side effects.
  2. By default i2c tools runs SMBus flavour commands which is a subset of I2C commonly used for motherboard components, if you dont use the -r argument things wont work.
sudo apt-get install i2c-tools
sudo i2cdetect -a -r 2

This should give you something like:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

With this setup you are ready to use the code.

Python/Docker

You can get the Docker File/Source to build the image from here

You can build/run the image as a container using the Docker-compose YAML

This script uses the Luma Library which does all the hard work, and is based on one of the Luma examples which i modified to work for my use case. There are some hardcoded magic numbers in the python script which are specific to my setup, these must be changed before building the Docker image. These could(probably should) have been added as arguments to make it easier to reuse. Hopefully it will be pretty obvious what to change.

FAQ