Creating a Virtual NAS in Proxmox
Introduction
What is a NAS, and why would you want one? A Network Attached Storage appliance (NAS) actually does a bunch of stuff, but it usually boils down to a friendly web interface overlay on some raw Linux based server functionality. The core functionality of a NAS remains the same though: The ability to attach multiple hard-disks and and share them over the network.
In this guide we will do that, with a twist: we'll do it from a virtual machine inside Proxmox!
Pre-Requisites
To follow this guide, you need:
- An x86 device (not ARM) running Proxmox, installed as a ZFS Filesystem
- A dedicated hard-drive (or drives) to share media
- That's it!
Choosing a NAS Operating System
There are lots of options for a keys-included virtual NAS operating system, like:
- TrueNAS Scale
- OpenMediaVault
- Rockstor
- Unraid (commercial)
The list goes on. However we are building a relatively simple, single purpose NAS. We just want something that can manage our drives, and share them out over the Samba and/or NFS protocols. If we want to do things like virtualisation, docker containers, etc. etc… well... we have proxmox for that! We don't need it in our NAS. So with that in mind we are building a raw debian virtual machine and leveraging the 45-drives cockpit plugins for our NAS interface.
Don't panic, we aren't going full Do-It-Yourself here. By the time we're done we will have a friendly user interface to manage our NAS and simple abilities to attach and share drives.
Installing Debian
To start off with, let's look at our installed proxmox system
Info
You can see the docker container from my other guide in there as well.
Now we have two options to install Debian:
- The manual way: downloading the debian stable net installer into proxmox and installing the operating system.
- The cool kids way: using a script and cloud init to quickly bring up a new debian instance.
Well obviously we are choosing the cool kids way (though the manual way works perfectly fine). Here is a modified script from the excellent blog post over here.
Info
You will notice that, unlike the docker container guide, we are using a virtual machine instead of an lxc container. This is because the NAS will require very little resources (2gb of ram!) and hard-drives in particular pass through more easily to VMs compared to containers.
#!/bin/bash
#Create template
#args:
# vm_id
# vm_name
# file name in the current directory
function create_template() {
#Print all of the configuration
echo "Creating template $2 ($1)"
#Create new VM
#Feel free to change any of these to your liking
qm create $1 --name $2 --ostype l26
#Set networking to default bridge
qm set $1 --net0 virtio,bridge=vmbr0
#Set display to serial
qm set $1 --serial0 socket --vga serial0
#Set memory, cpu, type defaults
#If you are in a cluster, you might need to change cpu type
qm set $1 --memory 2048 --cores 2 --cpu host
#Set boot device to new file
qm set $1 --scsi0 ${storage}:0,import-from="$(pwd)/$3",discard=on
#Set scsi hardware as default boot disk using virtio scsi single
qm set $1 --boot order=scsi0 --scsihw virtio-scsi-single
#Enable Qemu guest agent in case the guest has it available
qm set $1 --agent enabled=1,fstrim_cloned_disks=1
#Add cloud-init device
qm set $1 --ide2 ${storage}:cloudinit
#Set CI ip config
#IP6 = auto means SLAAC (a reliable default with no bad effects on non-IPv6 networks)
#IP = DHCP means what it says, so leave that out entirely on non-IPv4 networks to avoid DHCP delays
qm set $1 --ipconfig0 "ip6=auto,ip=dhcp"
#Import the ssh keyfile
# qm set $1 --sshkeys ${ssh_keyfile}
#If you want to do password-based auth instaed
#Then use this option and comment out the line above
#qm set $1 --cipassword password
#Add the user
qm set $1 --ciuser ${username}
#Resize the disk to 80G, a reasonable minimum. You can expand it more later.
#If the disk is already bigger than 80G, this will fail, and that is okay.
qm disk resize $1 scsi0 80G
#Make it a template
qm template $1
#Remove file when done
rm $3
}
#Path to your ssh authorized_keys file
#Alternatively, use /etc/pve/priv/authorized_keys if you are already authorized
#on the Proxmox system
export ssh_keyfile=/root/id_rsa.pub
#Username to create on VM template
export username=local-admin
#Name of your storage
export storage=local-zfs
#The images that I've found premade
#Feel free to add your own
#Bookworm (12) (stable)
wget "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2"
create_template 902 "temp-debian-12" "debian-12-genericcloud-amd64.qcow2"
- Run the script on the proxmox node, and it should generate a VM Template.
Info
if you have a non-standard proxmox install (like using BTRFS instead of ZFS) you may have to change the storage name.
- clone the template and give it a name
- Under cloud-init, set a password, upload your public SSH key, or both (so you can, you know, log in)
- Start up the template, and log into the local console.
Install the Web Interface
- Install cockpit so we can have a friendlier terminal:
Info
We are installing cockpit "without recommends" because some of the default recommended cockpit plugins (like networking and updates) is incompatible with cloud-init.
- typing
logout
(or simplyip a
) should prompt where to log into the new web interface. Log into the new web interface.
- Since we're here, set the timezone to your local timezone
Pass through the hard-drive
Alright, we're getting there! We have a functional linux server VM and a basic web interface including terminal. Now a NAS isn't particularly useful without disks to manage, so let's pass through what we plan to share on our network.
There are two mechanisms we can use to pass through a disk to a VM
- Passing through the disk directly (this is what we will do)
- Passing through a whole SATA/SAS/SCSI controller (only if you have a dedicated PCI-E device for the disks)
With that in mind, let's pass through at least one disk.
- Shutdown the VM for now and return to the proxmox interface
- Under the proxmox host, find the disk (or disks) that you want to passthrough under disks
- Under the Proxmox Host Shell, run the following and find the disk you wish to pass through
Info
If your hard-drive is attached via USB, you may be better off doing a USB Passthrough instead of a Drive Passthrough. Note that USB hard-drive controllers vary wildly in quality and are often instable.
- Set your VM to use the new drive.
- Verify that the VM now has an entry under hardware for the new disk. Repeat for any additional disks you want to attach
- Start up the VM and verify the disk now appears under storage
- Mount and/or format the disk as required.
Warning
Cockpit only supports formatting in the GUI using traditional linux RAID (mdadm) and ext4. If you want to use more advanced filesystem formats (like btrfs or ZFS), you will likely need to format in the terminal (using command line) and then mount with cockpit.
Finally have your disk(s) mounted at an accessible location in your NAS. I typically will mount additional storage within /mnt/storage
, but the location chosen is largely arbitrary.
Setting up the NAS web interface
Now what protocols do we actually use to share stuff that's in the drive over the network. There are two primary protocols:
- NFS (this is native linux but can have some complexity in configuration)
- CIFS/Samba (this is windows compatible and what we will use)
To do so easily we will want to install a cockpit plugin to do the hard work for us.
Warning
The following snippet will automatically execute code from the 45 drives repo. for the paranoid it is always useful to check the code being downloaded first.
# pre-requisites
sudo apt-get install -y gpg
# 45 drives plugin installation
curl -sSL https://repo.45drives.com/setup | sudo bash
sudo apt-get update
sudo apt install -y cockpit-file-sharing cockpit-navigator cockpit-identities
- Refresh the cockpit window and you should have some brand new options!
- Under File Sharing (as seen above) the plugin will complain about the initial samba config. Just hit "fix now".
Creating a user for the shared folder
- Under identities create a new user that will be your user to access new shares. This guide will use the username media-user
- Do not create a password for the user (really!) We aren't logging into this user interactively for the time being.
- Once the user is created, create a Samba Password for the user
Info
A Samba Password is not a local linux password, it is the password that is associated with the user for shared folders (and domains if we were doing domain logins)
Creating and Testing the Shared Folder
Alright, home stretch! Let's get that shared folder made and working.
- Create a subfolder under your newly mounted storage to be your new shared folder (if it doesn't exist now). Also give ownership to the newly created user we just made.
Info
You can also do the below in the Navigator GUI of cockpit!
- under File Sharing, create the new shared folder
Test
Let's test! If all has gone well, we can actually log into the shared folder from windows and add/delete files!
We should also be able to see that file that just got created in the cockpit navigator section, with the media user's credentials
Conclusion
We now have a virtual machine that we've:
- Provisioned using a largely automated process
- Attached a hard-drive to virtually
- Added a web interface to create shares, users, and navigate files
- Tested a share and opened it up on a windows machine
And the best part is, it's all just a regular debian server! This NAS will be completely unopinionated for the types of drives we use (we can make btrfs shares, zfs shares, regular mdadm raid shares, use existing storage and mix and match as much as we like), and can be maintained just like any other debian server.
Also, insanely small resource usage. Here's it's (admittedly, idle) load!
with this, we have a place to set up and share our storage to be used all over our homelab.
Some next steps to consider:
- Enable unattended software updates with https://wiki.debian.org/UnattendedUpgrades
- (if using btrfs based storage) setting up btrbk backup/replication to another VM
- Setting up a docker host in proxmox
- Patting yourself on the back!