Difference between revisions of "Backup NAS Mini"

From TheBeard Science Project Wiki
Jump to: navigation, search
 
(No difference)

Latest revision as of 00:56, 8 August 2018

Unfinished page...

I wanted to build a small Network Attached Storage (NAS) that is small, portable, cheap, and and doesn't consume a lot of power. I decided to use a Raspberry Pi 2 with a 500GB mechanical hard drive attached via USB. The purpose of this project is to have my most important files backed up on a portable device that I can grab in case of a fire.

Hardware

Parts list

  • Raspberry Pi 2 Model B (link)
  • 4GB Sandisk SD card (link)
  • 500GB 2.5 inch hard drive (link)
  • SATA-to-USB adapter (link)
  • LM2596S DC-to-DC buck converter (link)
  • CD drive enclosure (thrift store)
  • 12V DC power supply (link)
  • various parts (USB cable, nuts/bolts, etc.)

Power

The Raspberry Pi requires a little more than 5V and the USB-to-SATA adapter requires 12V, so I'm using a 12V DC power supply and a DC-to-DC buck converter (LM2596S) to convert it to 5V. Notice the placement of glue on the SATA port (second photo below) to prevent things from coming loose. I also put glue on the potentiometer on the buck converter after dialing it in to about 5.4V.

DSC00539.JPG DSC00679.JPG
Note: the hard drives are different colors because I switched hard drives half way through the project.

The whole power setup is wired like this:

[ wiring diagram ]

Another thing that I did was add a tactile button to the back as a way of shutting down and restarting the machine. I mapped it to GPIO04 on the Raspberry Pi. For software setup, see Off Button Script.

Hard Drive

The hard drive is a 500GB 2.5 inch mechanical drive, attached via USB with a SATA to USB adapter. I mounted it under the Raspberry Pi using 3D printed brackets (link).

DSC00478.JPG DSC00480.JPG

The adapter is a WEme USB 3.0 to SATA Converter Adapter (model number 4328317644) that I bought from Amazon (here's a Google link). I took the casing off of it and just used the bare PCB. The reason I chose this particular adapter is that it uses external power instead of being powered through the USB. The Raspberry Pi can only provide so much current. The adapter came with a 12V power supply, but I replaced it with higher current adapter.

Hdd-usb-adapter.jpg DSC00535.JPG

I decided to solder the USB cable to the Pi instead of plugging it into the USB port. I found that I still needed to wire up all four USB pins to the Raspberry Pi because the adapter still expects there to be power on the USB. I also soldered the cable shielding to one of the USB anchor points on the Raspberry Pi.

DSC00676.JPG
Notice that I put kapton tape under the wire as well as on top.

Here is the USB wiring diagram:

[ USB pinout diagram ]

Wiring it up this way presents the risk of accidentally plugging something into the USB port in the back that is used for the hard drive, so I 3D printed a USB cover. The port that needs to be blocked is the top right next to the Ethernet port.

DSC00747 EDIT.JPG DSC00828.JPG
Not my design (link).

LED Indicator

I put an RGB LED on the front of the case as an indicator light.

DSC00681.JPG

Here is the GPIO Pinout:

LED Pin GPIO Pin
blue GPIO23
red GPIO18
GND GND

Here are the current ways this LED indicates status:

Color Behavior Meaning
blue solid system idle
blue blink backup in progress
red blink backup error occurred

For software setup of the LED indicator, see LED Script.

Enclosure

The enclosure is simply an old external CD/DVD drive enclosure. I cut out a place in the back for the Raspberry Pi USB and Ethernet connectors. I glued on a piece of black acrylic on the front of the case as a face plate. The internals are mounted to a piece of MDF board which is bolted in from the bottom. It was really just trial and error figuring out how to mount everything. I ended up making 3D printed parts for the hard drive.

DSC00682.JPG DSC00680.JPG

Notice the stand-offs on the Raspberry Pi have segments of drinking straw on them. This was simply to ensure the nuts were put on at exactly the same height; the straw segments were all cut exactly the same length and were used as guides. I could have cut them off, but it wasn't necessary.

DSC00475.JPG DSC00827.JPG

Software

Operating System

I used a minimal install of Raspbian Jessie. You can download the latest version of Raspbian here. There are several configurations I setup for this project. I do these tasks as root.

I installed all the packages that I'm going to use in this project:

apt-get install python python-rpi.gpio python-pylibacl python-pylibattr python-pyxattr rdiff-backup ssmtp

I added the user and the group that will be performing the backup (I typically don't use the system's built-in accounts):

# Assuming your password is 'PICKLES', but you should run passwd manually and enter the password in the prompt
useradd -m backer
echo -e "PICKLES\nPICKLES" | passwd backer

I created a mount point for the backups and setup permissions:

mkdir /backups
chown backer:backer /backups
chmod 770 /backups

I setup the drive:

# Find out the drive name
# Mine was /dev/sda but for basic copy/paste safety I will use /dev/sdx in these examples
fdisk -l | grep "^Disk"

# Create the partition /dev/sdx1
echo -e "n\np\n1\n\n\n\nw\n" | fdisk /dev/sdx

# Create file system with 0% reserved blocks on sdx1
mkfs -t ext4 -m 0 -L Backups01 /dev/sdx1

# Add the mount to fstab. Importantly, I'm using the 'nofail' and 'nobootwait' options.
echo 'LABEL="Backups01" /backups   ext4    defaults,nofail,nobootwait  0  0' >>/etc/fstab
mount -a

On the source machine (the remote machine that has my files) I also create the user:

# Assuming your password is 'PICKLES'
useradd -m backer
echo -e "PICKLES\nPICKLES" | passwd backer

The tricky part is making sure that backer has read permissions on all the files that you need to backup, and read/execute permissions on folders. So if I assume your files are contained in /home/timmy/myfiles (on the source machine), you might do:

# Add group ownership to all files/folders
chown -R :backer /home/timmy/myfiles
# Add read/execute to all folders
find /home/timmy/myfiles -type d -print0 | xargs -0 chmod g+rx  
# Add read to all files
find /home/timmy/myfiles -type f -print0 | xargs -0 chmod g+r

You can set permissions on a more granular level if you need to. Don't do this on system files.

[ incomplete: source server ssh config and certificate ]

Backup Script

This is the main script that I wrote to perform the backups. Make sure you've installed the packages mentioned in Operating System.

Here's the idea:

  • The backup server has a cron job that performs the backup process on a schedule.
  • The backup process logs in remotely to the source server using rdiff-backup.
  • Rdiff-backup uses SSH. We will be able to log in without a password prompt by using certificate authentication.
  • We define included and excluded files and directories to control what get backed up incrementally.
  • Each backup process generates a log file and sends text and email notifications if an error occurs.

As root, I created the directory structure:

mkdir -p /scripts/backup-system/config /scripts/config /logs/backups

crontab

10 4    * * * root /scripts/backup-system/backup-run.sh -y

Re-upload scripts after I've fixed everything.

[ incomplete ]

LED Script

Backup Status Script

Restore Script

Text and Email Messaging

I wanted the system to send me text and email notifications.

Make sure you've installed the packages mentioned in Operating System.

crontab

00 12   * * * root /scripts/scheduled-messages.sh

[ incomplete ]

Off Button Script

I added a tactile button to GPIO4 on the Raspberry Pi to act as a power button. When held for a certain number of seconds, it executes the shutdown command. This allows my Shutdown Script to wait for a backup to complete before powering the system down.

Here is the Python script:

#!/bin/python
#
# Script to shutdown Raspberry Pi when GPIO input is held.
# Connect a button between ground (GND) and the GPIO pin
# that you specify below.
#
# If you run this script from your /etc/rc.local file, it
# will be running as root, which eliminates the need to 
# enter a password to elevate privileges. Otherwise, the
# sudo command will ask for a password before it will
# execute shutdown.

import RPi.GPIO as GPIO
import sys,os,signal,time

# GPIO pin number
btn = 4

# Button must be held for this many seconds
delay = 3.0

def sense_input(btn,delay):

  try:
    # Wait for button press
    GPIO.wait_for_edge(btn, GPIO.FALLING)

    count = 0
    while True:
      if GPIO.input(btn) == False:
        if count < delay:
          count = count + 1
          time.sleep(0.1)
          continue
        else:
         # Shutdown system
         os.system("sudo shutdown -h now")
         os._exit(-1)
      else:
          try:
            GPIO.cleanup()
          except:
            pass
          time.sleep(0.1)
          break

  except KeyboardInterrupt:
    try:
      GPIO.cleanup()
    except:
      pass
    os._exit(-1)

  except:
    pass          
        
delay = delay*10
while True:
  GPIO.setmode(GPIO.BCM)
  GPIO.setup(btn, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  sense_input(btn,delay)

Assuming you save this to /scripts/off-button.py go ahead and make it executable:

chmod a+x /scripts/off-button.py

Then add it to /etc/rc.local so it runs on startup. Enter the command above the exit 0 line so that it looks like this:

# ... existing rc.local stuff ...

python /scripts/off-button.py &
exit 0

Shutdown Script

I wanted to have the system wait for a backup to complete if the system is shutdown while a backup is in progress. I created this script called wait-for-backup. It also sends a text message on shutdown (see Text and Email Messaging):

#!/bin/bash
#
# Shutdown script for backup server.
# Waits for rdiff-backup to finish.
#

log=/logs/server-shutdown.log

mount -oremount,rw /
echo "[`date`] TEST: Shutdown issued. Waiting for rdiff-backup to stop..." >>$log

/scripts/sms.sh "backup2" "system shutdown ( `date` )"
sleep 20

echo "[`date`] TEST: Done waiting." >>$log
mount -oremount,ro /

Once you have this script located in /etc/init.d you can create a symbolic link in the appropriate rc directories. Make sure this script is run before any of the VirtualBox services are stopped. For my server, I made it K64. Make sure wait-for-backup is executable.

sudo chmod 755 /etc/init.d/wait-for-backup
sudo ln -s /etc/init.d/wait-for-backup /etc/rc0.d/K64stop-vms
sudo ln -s /etc/init.d/wait-for-backup /etc/rc6.d/K64stop-vms

If you're using Systemd you need to do this differently.

You can put a script in the Systemd system-shutdown script folder. It is located in a different place on different Linux distributions:

  • Debian: /lib/systemd/system-shutdown
  • Other: /usr/lib/systemd/system-shutdown

Put the wait-for-backup script in that folder and make sure it's executable.

[ THIS SECTION NEEDS TO BE CORRECTED ]

You actually make script /scripts/backup-system/shutdown-wait-for-backup.sh

contents

Then make file /lib/systemd/system/wait-for-backup.service with:

contents

Links