the website of dither8

Alpine Linux: Home NAS Setup 3.0

Published on 2024-02-25

Welcome to my guide on setting up a NAS file server using the lightweight Alpine Linux distro. We will be using the highly reliable ZFS filesystem for data storage and backup. Then we'll setup Samba for network shares and file transfer.

A note on Alpine Linux

This guide assumes you've already installed Alpine Linux with the "sys" method, you've selected dhcp network setup on the installer, and you selected OpenSSH server.

Note these instructions were tested on Alpine Linux version 3.19. Sometimes package name or default software will change between releases, will require manual intervention, and this guide will need updating.

A note on disks

For this setup we are using ZFS's built-in RAID mode "raidz" this works similar to standard RAID5, requires at least 3 disks, and will tolerate 1 disk failure.

We will be using 3 disks of the same size for our main data. And a single backup drive that is double the size of a single data drive. In my case:

A note on text editors

Throughout the tutorial, you'll be prompted to edit text files from the terminal. Alpine comes with a text editor called vi. If you've never used it, you'll want an easier tool called nano. We'll install it soon.

When prompted to edit files, run something like: doas nano /etc/example-file.

To exit press Ctrl + x, and press y to save changes.

Next up, what is doas?

A note on privilleges

When we need to run something as root from our admin accounts, we'll need to elevate privileges to root. Rather than the common sudo command, we'll use Alpine Linux's preferred doas command. Keep this in mind if you ever refer to other guides, you need to change sudo to doas.

If you get a permission error after running a command, it probably wasn't run with root when it needed to.

To begin, log into the NAS directly using the root account and the password you set during the setup. Connect a keyboard and monitor to access the system. And follow along.

Essential post-install instructions

1. Add administrator accounts

Start by adding any users who will be administrating the NAS. We will add these users to the wheel group with the Capital -G option.

adduser me -G wheel
adduser sibling -G wheel

The wheel group is similar to an "admin" group insofar as it allows it's members privillege esculation.

If you already created the user, add them with: adduser <user> wheel

Verify membership with: groups <user>

You can delete users with: deluser <user>

2. Install base software

Let's get the bare essentials installed. Alpine Linux gives us the apk package manager to install software packages from the server with.

apk update
apk add doas nano

Heres a breakdown on those commands:

  1. Update our local package list, so apk knows what is available.
  2. Install both doas and nano. Packages to install are seperated by a space.

3. Set up doas

Next, using your preferred text editor, open the file /etc/doas.d/doas.conf:

nano /etc/doas.d/doas.conf

And add the following to the file:

permit persist :wheel

Save the changes and exit the text editor. Then log out of the root account using the exit command.

Next, log in to one of the accounts that you added to the wheel group.

If you can login succesfully, test doas using the following command:

doas apk update

If apk update runs with no permission error, than doas works. If not check you are part of the wheel group, and the text file, /etc/doas.d/doas.conf, has been changed according to above.

To enhance security, disallow direct login to the root account:

doas passwd -l root

From now on when we need to run something with elevated privileges, we'll need to prefix each command with doas.

4. Understanding SSH

To remotely access the NAS, we need SSH. If OpenSSH wasn't installed on the Alpine Linux setup, refer to the reference at the bottom of this document for setup instructions.

SSH let's you get a remote terminal session, which let's us manage the NAS remotely.

To determine the IP address of your NAS on the network, run the following command on the NAS:

ip a

Look for your Ethernet interface in the output (usually formatted like "eth0" or "enp3s0"). Find the IP address associated with it. For example, the output might include a line like this:

inet 192.168.1.100/24 brd 192.168.1.255 scope global eth0

The IP address in my case is 192.168.1.100. Note that the /24 part is not part of the IP address. brd 192.168.1.255 refers to the broadcast address and is not the IP address. Also ignore the loopback interface ("lo").

From another computer connected to the same local network, use the ssh command to connect to the NAS. Replace me with your username, and replace the IP address with the IP you obtained in the previous step:

ssh me@192.168.1.100

Type your password, noting that you won't get any feedback while typing your password. You should be able to connect to the NAS.

Once you're able to connect remotely, you no longer need to be directly tethered to the NAS physically. So follow the rest of the guide from another computer. Windows, Mac and Linux OS's provide a built-in ssh command.

Reserve DHCP

It is highly recommended to reserve an IP address in your network router for the NAS. This will simpify managment, and eleminate issues resulting from change of IP. Not all routers are the same, so you will need to either explore the management interface of your router, otherwise refer to the documentation provided (or search online).

On the NAS use the command ip a to view network interfaces. As mentioned before the interface will be called something like "eth0" or "enp3s0" Although if you have two network cards installed, this might be different. You will most probably have a "loopback" interface beginning with "lo", don't use that one.

In the output from ip a, find the MAC address for the network interface it looks something like:

link/ether ee:5b:86:4b:a6:a7 brd ff:ff:ff:ff:ff:ff

The MAC Address is right after link/ether, ignore brd ff:ff:ff:ff:ff:ff as this is just the broadcast address, and not what we need.

In your router use the MAC Address you found, and then allocate it an IP address within the same subnet as your router. Most home equipment uses a subnet of 255.255.255.0 (or /24). This means that you only change the forth number when assigning the IP address to the devices.

In this arrangement forth number can be anything between 1 and 254. In my case my router is 192.168.1.1 so I give my NAS 192.168.1.100. Once set, your NAS will get the same IP address.

In the next step we'll install a subnet calculator called sipcalc. If you need help, you can use sipcalc to show the usable IP address range based on the IP address and subnet mask from your router. Otherwise plenty of subnet calculator exist online.

More is said on using sipcalc further down in the reference section.

Further software install

We'll start by installing packages we'll need throught the guide:

doas apk update
doas apk add mandoc man-pages tmux samba rsync parted lsblk avahi dbus sipcalc ncurses-terminfo
doas apk add doas-doc nano-doc tmux-doc samba-doc rsync-doc parted-doc util-linux-doc avahi-doc dbus-doc sipcalc-doc

First command will update our local package list, and should be run each time you want to install, or upgrade the system. In the second command we install a variety of packages that will be useful.

You'll notice, in the third command, packages ending with -doc. These will provide documentation for you to read if you ever get stuck. These are called man pages and are useful, if a little dry to read as a newbie.

To get help type man followed by the command, e.g. man samba. Press q to quit.

Add users

Now it is time to add more users to our NAS. We need to create a group to use for access control to the NAS data:

doas addgroup nas

This group is simply called nas.

Next, you add yourself and any other user's you already created to this group:

doas adduser me nas
doas adduser sibling nas

A script for making normal users

To easily add NAS users, I've made a script. It will add system and Samba accounts if they don't exist, then ask you to set passwords for both. Let's get the script installed.

Create a new file with your preferred text editor:

doas nano /usr/local/bin/nas-user

Once opened, copy and paste the following:

#!/bin/sh
user=$1

# Fail script if not root
if [ "$(id -u)" != "0" ]; then
    printf "ERROR: nas-user must be run as root\n"
    return 2
fi

if [ "$user" == "" ]
then
    printf "ERROR: Username not provided\nExpected: 'nas-user [username]'\n"
    return 1
else
    # Try to add a Unix user with no password and part of nas group
    # Then set password with passwd command.
    adduser $user -D -G nas 1&> /dev/null || true && \
    passwd $user && \

    # Do the same with Samba
    smbpasswd -a $user && \
    return 0
fi

Then give it execute permissions:

doas chmod +x /usr/local/bin/nas-user

Add more users

Let's add some more users:

doas nas-user mother
doas nas-user father

Re-run this script for any new users that need creation.

ZFS File system

Start by installing the ZFS filesystem for the Linux LTS release:

doas apk install linux-lts zfs-lts zfs-doc

Then enable zfs service scripts to start on boot:

doas rc-update add zfs-import sysinit
doas rc-update add zfs-mount sysinit

Then Reboot.

Once rebooted, list out the physical hard drives. We'll use the lsblk tool we installed above to list these.

Remember this guide makes use of x3 HDD's of the same size for live data. 3 drives is the minimum to use the RAID level. Backup drive should be at least double the size of a single drive.

List storage devices:

doas lsblk

Sample Output:

# Sample only
sda      8:0    0   3.6T  0 disk 
sdb      8:16   0 119.2G  0 disk 
├─sdb1   8:17   0   512M  0 part /boot/efi
├─sdb2   8:18   0     4G  0 part [SWAP]
└─sdb3   8:19   0 114.7G  0 part /
sdc      8:32   0   3.6T  0 disk 
sdd      8:48   0   3.6T  0 disk 

Here we can see 4 devices with 3 partitions belonging to sdb. So for my case, sda, sdc, and sdd are the drives I'm after. Since sdb is only 120GB and is already partitioned, it's very clearly my OS drive, and we should absoulutly avoid formatting it.

We will now create a ZFS zpool called "nas" using the raidz array (raidz is the ZFS version of RAID5). Simply prefix /dev/ before the device name:

# Careful to get the right drives!
doas zpool create nas raidz /dev/sda /dev/sdc /dev/sdd

Next we will create a ZFS dataset simply called "data":

doas zfs create nas/data

The backup drive will be a larger single drive, we will call the zpool backup, and the dataset borg, named after the backup program:

doas zpool create backup /dev/sdX
doas zfs create backup/borg

We now have a place to put our data in a way that is high volume (total 8TB), and redundent (RAID5/raidz can handle 1 drive failure).

A few more zfs related command for you to get information about the array:

What you do next depends if this is the first time setup, or if you are transferring data from a previous NAS install.

Path 1 will be for first time set up, whereas path 2 will cover transferring data over from another drive.

Path 1: New file structure

You need to come up with a few top-level folder. I have Documents, Media, Photos, and Projects. My advice is that you should not add or remove these top-level folders very often.

doas mkdir -p /nas/data/Documents
doas mkdir -p /nas/data/Media
doas mkdir -p /nas/data/Photos
doas mkdir -p /nas/data/Projects

Next let's set correct file permissions on these folders. /nas/data should be have root as it's owner and group:

doas chown root:root /nas/data

Then, make sure the permissions on /nas/data give the owner (the root user) full access but gives the group and others read and execute permissions only:

doas chmod 755 /nas/data

Now we will set the nas group onto all of the sub-folders:

doas chgrp -R nas /nas/data/*
doas chmod -R 770 /nas/data/*

The first command recursivly sets the group on all sub-folders of /nas/data, that's what the capital -R options does. And the asterisk *, is a wildcard which pattern matches. In this case: anything after /nas/data. Second command changes the scope of those permissions to give owner and group (root and nas respectivly) full access but anyone else no permission

To view files permissions change directory to the location is questions and type ls -l

cd /nas/data
ls -l

I will not elaborate on file permissions, instead read the manual pages, or look online:

Path 2: Transfer exisiting structure:

Plug the old HDD in either with SATA directly, or a USB caddy. We will create a place to mount the old disk:

doas mkdir /mnt/nas-temp

Next you would use a command like doas df -h or doas parted -l to see what the old disk is. With df you will be able to view disk usage stats, which will help in figuring out what's used in the past. Otherwise work out what is mounted with doas mount, and by a process of elimination figure out what's not yet mounted.

Make sure to mount the first partiton, or whatever other partition has data on it:

doas mount /dev/sde1 /mnt/nas-temp/    # sde1 is only an example!

Depending on skill level you might want to use a tool like tmux, so you can detach from your SSH session without interupting the file transfer. Check the reference section further below to see how it's used.

File transfer command will look like:

doas rsync -a --progress /mnt/nas-temp/data /nas/data

Once done, go back to Path 1, and re-run the file permissions commands to make sure you're set!

Set the hostname

To make it easier to access your NAS, we will set a hostname and a domain: nas.local. The first part is the hostname, second part the domain. You can change the hostname, but you should keep the domain as "local" since that is convention for local network devices.

To change the hostname edit the /etc/hostname file with a text editor using doas. Clear whatever name in that file and replace it with the new hostname.domainname scheme.

Use the command hostname to print the current hostname of your NAS.

Hostname: Zeroconf with avahi

In order for other computers to discover your NAS through Zeroconf you should setup avahi

Open /etc/init.d/avahi-daemon in a text editor and ensure that under depend(), hostname is listed next to `need'. E.g:

depend() {
        before netmount nfsmount
        use net
        need dbus hostname
}

If hostname isn't listed as a needed dependency, then upon boot, the system will advertise the hostname none instead of the desired name.

Add avahi-daemon to boot:

doas rc-update add avahi-daemon boot

Samba

Microsoft's SMB is a well supported protocol for network shares. Samba is an open-source implementation of SMB for Unix-like systems.

We now need to edit the Samba config file, located at /etc/samba/smb.conf. The file is very large and shows many example settings. We will backup this file and create a new one with just the options we want:

cd /etc/samba
doas mv smb.conf smb.conf.bak
doas nano smb.conf

Defining a share is simple, just put the name you want (anything except for "global") between two square brackets. Underneath it is where you add configuration options for that share.

For the purposes of a simple home NAS, here is the config that I use:

[global]
        server string = nas
        server role = standalone server
        force group = nas
        inherit permissions = yes
        force create mode = 0750
        force directory mode = 0770
        client min protocol = SMB3
        map to guest = Bad User

[Share]
        comment = Files shared will all users.
        path = /nas/data/files
        valid users = @nas
        guest ok = no
        read only = no

[Public]
        comment = Read-only access to media without an account.
        path = /nas/data/Media
        read only = yes
        guest ok = yes

The various "force" options will enforce permissions on any new file uploaded. Refer to the "File Permissions" section for more details.

The minimum protocol will prevent clients from using an older version of SMB. You might want to change this to SMB2 if you still have Windows 7 PCs.

I have added "@nas" to the valid users, the @ symbol tells Samba to allow any user from that group. This is why it's essential to have the same SMB and UNIX usernames.

I have also made a read-only group for guests that will allow access to anything in the "Media" folder. This is useful for setting up things like Kodi, without having to store a password.

For detailed information on any samba option, refer to the man page man smb.conf, or the web.

Finally, set the samba service to start on boot and then start for current session:

doas rc-update add samba
doas rc-service samba start

Backup Tool

In the next step we will install an incremental backup tool and set it to run daily.

1. Enable Community repo

This command will enable community repo (-c) and check for the fastest mirror (-f):

doas setup-apkrepos -cf

2. Borg Backup Install

For our backups we will be using the incredible Borg Backup. We can use this to take daily snapshots of the NAS. Borg is deduplicating, so it won't store two copies of files from different days.

Borg also won't immediately delete files just because they were deleted on the NAS.

We start by installing:

doas apk update
doas apk add borgbackup borgbackup-docs

Borg must be run as root, so we must prepend doas to all borg commands. Each function of borg is broken down into different sub-commands. To initialise a repo we type doas borg init, to create a new backup state doas borg create, and so on. Then after call the sub-command, you give any options, and then the location of the backup repo.

Borg has very good documentation, which I suggest you read here

We will create a new backup repository on the backup drive:

doas borg init --encryption none /backup/borg

Create the first backup called "First":

doas borg create --list --stats /backup/borg::First /nas/data

I recommend using tmux so you can detach from SSH without interupting the backup process. Refer to the reference section further below to see how to use it.

3. Cronjobs

We need a backup task to run automatically. Cron is perfect for this. We specify a time for a script to be run, and cron will run it at the specified time.

First make sure crond is running, and set has been set to startup on boot:

doas rc-update add crond
doas rc-service crond start

By default scripts in the folder /etc/periodic/daily will run everyday at 2am. If you are not planning on having the NAS on 24/7, you can change this to a better time by running doas crontab -e. By default Alpine Linux gives you hourly, daily, weekly etc. folders, all the scripts in these folders will be run at the set time each hour/day/week. In our entry for the daily period, you can see that it is set to run at the 2nd hour (2am in the morning):

# min   hour    day     month   weekday command
0       2       *       *       *       run-parts /etc/periodic/daily

Using 24hour time we can change this to be (for example) 6:30PM in the evening:

# min   hour    day     month   weekday command
30      18      *       *       *       run-parts /etc/periodic/daily

Save and quit once you are happy.

Backup script

Let's setup automatic backups. First create a script using any text editor you want:

doas nano /etc/periodic/daily/borgbackup.sh

Paste the following script:

#!/bin/sh
export TIME=$(date '+%Y-%m-%d_%H:%M')
export BORG_REPO="/backup/borg"

/usr/bin/borg create ::"Auto_$TIME" /nas/data
/usr/bin/borg prune -v --list --keep-daily=14 --keep-monthly=12
/usr/bin/borg compact

In the pruning stage, I have set it to keep the last 14 days of backups, and the last 12 months. In other words you'll be able to get back to a state from any day within two weeks, or the last backup for each month of the last year.

Set permissions to allow execute using chmod, and check that the script will run:

doas chmod a+x /etc/periodic/daily/borgbackup.sh
doas run-parts --test /etc/periodic/daily

View info about backups

It is a very good idea to frequently check that backups are successfully being ran.

Get a list of all current backup states in the repository:

doas borg list /backup/borg

View all the files of a particular backup state:

doas borg list /backup/borg::"Auto_2022-05-07_18:30"

Make sure to replace "Auto_2022-05-07_18:30" with the relevant backup name.

View info about the backup repository:

doas borg info /backup/borg

View info about particular backup:

doas borg info /backup/borg::"Auto_2022-05-07_18:30"

More info can simply be viewed by running borg. you can also get help in regards to a single command (e.g. create) by running borg help create. The Borg backup website is also very helpful.

Checking backups

Please reference the documentation on borgbackup website:

Please note it takes a long time to check the backups.

Restore backup

First list all the archives:

doas borg list /backup/borg

You'll likely want to restore from the latest backup.

To extract to a new drive. You'll want to use a command like this:

doas borg extract /backup/borg::"Auto_2022-07-08_18:30"

BE WARNED: borg extract will always extract to your current directory. Make sure you mount the new drive and then use the cd command to change to the new drive.

Watch out for permissions. Use doas su to change to a root shell, if you are getting permissions issues when navigating the extracted backup.

The full path including /nas will be restored, so use the following to fix it:

doas mv nas/* .

This will move all subfolders back to where it was before you can now safely delete the nas folder. But DON'T delete: /nas that's the real full path to your NAS hard drive!

Make sure to reread the guide checking permissions, and file paths in Samba etc.

There are some other things you can do, like only doing a partial restore. Please read the documentation for more info:

Access NAS file share from another computer

Now that we have our SMB share setup, it is time to access it from a different computer.

On Windows, head to file explorer and add a Network location from "My PC". The address will look like:

\\nas.local\share

On Linux, most file managers will allow access through an address bar, or an option titled "other locations" or "connect to server" or "network". Once connected, there should be a way to bookmark to the sidebar. The address to connect will look like:

smb://nas.local/share

Notes

If you cannot get the nas.local name working from one or all of your systems, you can use IP instead. E.g. \\192.168.1.100\share

Some Linux distros won't pre-install gvfs-smb, which is required to connect. KDE users should make sure kio-extras is installed.

Type username and password, set the workgroup to "WORKGROUP" if needed. You can also choose to save the credentials for faster login.

Further Reference and Misc. Tasks

1. Updating system

You should update the packages from time to time. Make sure you always reboot after the updates!

doas apk update
doas apk upgrade
doas reboot

This is enought to upgrade to minor versions, e.g. v3.19.0 to v3.19.1. But to upgrade, for example, to v3.20 more effort is required.

2. Upgrading to next stable version of Alpine Linux

News about Alpine versions are published on the website.

Edit the /etc/apk/repositories changing the version number to the latest release, then:

doas apk update
doas apk upgrade --available
doas sync
doas reboot

More detailed instructions on the wiki

3. Install Microcode

To keep the processor's microcode up-to-date, I suggested to install microcode for your CPU:

Intel:

doas add intel-ucode

AMD:

doas add amd-ucode

4. Note about IP Addresses

In this tutorial I have been using IP addresses in the 192.168.1.0 range. When setting IP addresses, make sure to follow the subnet of the router. Your router could be using any of the following in these ranges:

10.0.0.0 - 10.255.255.255
172.16.0.0 - 172.31.255.255
192.168.0.0 - 192.168.255.255

Most home networks should have the subnets at /24 (can also be represented as 255.255.255.0), so working out the network address is a simple as replacing the last character with a 0.

Login to your router and view the Network or LAN settings. Take note of the IP address and subnet mask. The math behind subnets can be tricky so use a subnet calculator, plenty online, and Alpine Linux has one called sipcalc installed with apk. Simply give it the IP and subnet mask from your routers management page, e.g. sipcalc 192.168.1.1 255.255.255.0 and it will provide information about the subnet.

Now is a good time to try and simplify your home network (if need be) to prevent confusion. You really only need one device functioning as a router. Most new gear gives you a setting to put the device in "Bridge mode" (whereby the router functions are disabled and the device acts like a dumb access point). I would suggest enabling bridge mode on any other router or managed switch that isn't your main.

5. How to use Tmux

When you run commands over SSH, you must keep the terminal open on the PC you ran them from. Using tmux allows us to execute a long running command on the remote NAS, and then disconnect the SSH session.

Start new tmux session called backup:

tmux new -s "backup"

To detach from the tmux session press Ctrl + b to put it into command mode, then press d. You can then close your SSH session, with the backup still running on the NAS.

To attach again type:

tmux attach -t "backup"

6. Backup to an external NTFS drive

In cases where Windows users might need access to data in-case of emergency. It's a good idea to store a backup on external hard-drives with the Microsoft NTFS file system.

We won't discuss formatting the drive on the NAS. That should be done in Windows, since it's best at doing that. Instead we will plug the drive directly into the NAS, mount it, and do a backup on the NAS.

First get a list of attached hard drives:

doas parted -l

Find your external drive making note of it's location (e.g. /dev/sd*), and partition number in the list.

Next create a mount point in /mnt:

doas mkdir /mnt/external1

Install NTFS driver:

doas apk add ntfs-3g

Mount the drive, in this example we mount the 1st partition of whatever /dev/ device is your external drive:

doas mount.ntfs-3g /dev/sd*1 /mnt/external1/

Confirm by viewing all mounts:

df -h

Run the following rsync command:

doas rsync -a --progress "/nas/data/" "/mnt/external1" --delete

Make sure you are inside tmux if you want to close the remote session on your PC.

Note how /nas/data/ has a leading slash, but /mnt/external1 doesn't. The leading slash means copy anything after /data/, but not the data folder itself. Slashes in rsync are significant, so make sure to follow above.

The --delete option will delete any files in the backup that were deleted on the NAS.

7. Installing OpenSSH

Alpine Linux should ask to install an SSH server, this guide uses OpenSSH. If you didn't install OpenSSH, run the following:

doas apk add openssh openssh-doc
doas rc-update add sshd
doas rc-service sshd start

Changelog

Notes for future versions of this guide

Previous versions of this guide