Setting up ReadyNAS Duo for home lab
I have an old ReadyNAS Duo 2120 (confusingly it says 2120v2 on the bottom, although it is RND2000v1 generation hardware) which I have turned into a webserver to provide a mirror service for my new air gapped home lab network. This is a precursor to setting up Proxmox VE, with both read-only package mirrors and ISO repository on the NAS. It is updated via a USB hard disk which I sync on my home network then physically move to the lab environment, mount read-only to update the mirrors from.
Reset, create share and enable anonymous http access
I started with a factory reset of the NAS by holding paper clip in reset hole for 30s while powering on until all Disk LEDs flash twice. Wait 15 minutes for the reset to happen (“The system performs the disk test, which takes about five minutes, waits 10 minutes, and then restores the system to its factory settings.”).
Next I had a fight to find a web-browser to access the NAS’ admin interface, which must be accessed over https (http redirects to https) but uses a version of TLS disabled by all modern web-browsers. When connected (I managed it by going to about:config
and setting security.tls.version.min
to 1 in Firefox which brought back the option to by-pass the security error, I had a complete failure to find a way to by-pass with Chrome and Safari), I was able to login with the default username and password (admin/netgear1) and started going through the setup wizard.
In the fileshare protocols, I disabled everything except HTTP and Rsync. I deleted both of the default shares and created one new one, mirrors
(“Software mirrors” as the description). Once setup, in the mirrors
share I enabled HTTP/S with read-only
default access and Rsync with read/write
default access but restricted access to the host I will use to update the mirrors from. I then went back into Services
and Standard File Protocols
and set Redirect default web access to this share:
to mirrors
(leaving Login authentication on this share:
set to Disabled
) so the NAS will be accessible as a source for Linux package managers.
Later I went back and enabled NFS for the ISOs share that I added at the end of this post - so if you are following along to replicate something similar to my setup you might want to do that now.
Disable https
Once setup, I downloaded and install the Enable Root SSH Access add-on. After rebooting, which the update will ask you to do, I used SSH to login to the device and disabled https - a downgrade in security but since this is in my air-gapped home lab network (where there is nothing of value or consequence) it is an acceptable risk and removes the inability to manage the device due to the version of TLS being blocked.
Note that in order to SSH I had to add a defunct (and presumably insecure) key-exchange algorithm at the client end:
ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -l root 192.168.100.200
The edits to disable https are:
- In
/etc/frontview/apache/Virtual.conf
comment these two lines:
RewriteRule ^/admin/(.*)$ https://%{SERVER_NAME}/admin/$1 [R,L]
RewriteRule ^/admin$ https://%{SERVER_NAME}/admin
- In
/etc/frontview/apache/httpd.conf
comment these lines:
Listen 443
SSLEngine On
SSLSessionCache dbm:/ramfs/gcache.db
SSLSessionCacheTimeout 600
SSLCACertificatePath /etc/frontview/apache
SSLCertificateFile /etc/frontview/apache/apache.pem
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384Smiley Very HappyHE-RSA-AES128-GCM-SHA256Smiley Very HappyHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHASmiley Very HappyHE-RSA-AES128-SHA256Smiley Very HappyHE-RSA-AES128-SHASmiley Very HappyHE-DSS-AES128-SHA256Smiley Very HappyHE-RSA-AES256-SHA256Smiley Very HappyHE-DSS-AES256-SHASmiley Very HappyHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:AES:CAMELLIASmiley Very HappyES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
SSLHonorCipherOrder on
Restart the webserver with (I tried /etc/init.d/frontview restart
but it failed to start it up again):
/etc/init.d/frontview stop
/etc/init.d/frontview start
Do not forget to set Firefox’s minimum TLS version back to default, now we can connect.
Creating the mirrors
Syncing from internet to USB drive
On a Debian Linux system with an internet connection, I installed the tools to create Debian and EL repositories:
apt-get install debmirror yum-utils
I then synced the mirrors I needed for ProxMox as well as CentOS and Rocky Linux to an ext4 formatted USB hard disk - to help make this painless in future, I created a little script called mirrors-fetch.bash
on the USB disk:
#!/bin/bash
# Basic scripting safety
set -euo pipefail
# Make sure to include Proxmox's base suite
DEBIAN_SUITES=bullseye,bullseye-updates
DEBIAN_SECURITY_SUITES=bullseye-security
CENTOS_VERSIONS=7
CENTOS_VAULT_VERSIONS=6.10
ROCKY_VERSIONS=8
PROXMOX_SUITES=bullseye
PROXMOX_CEPH_VERSION=pacific
# Taken from https://pve.proxmox.com/pve-docs/pve-admin-guide.html#repos_secure_apt
PROXMOX_KEYRING_SOURCE="https://enterprise.proxmox.com/debian/proxmox-release-bullseye.gpg"
PROXMOX_KEYRING_SHA512="7fb03ec8a1675723d2853b84aa4fdb49a46a3bb72b9951361488bfd19b29aab0a789a4f8c7406e71a69aabbc727c936d3549731c4659ffa1a08f44db8fdcebfa"
# Find where to sync to
my_path="$( dirname "$( realpath "$0" )" )"
if ! [ -d "$my_path/mirrors" ]
then
echo "$my_path/mirrors does not exist - are you running this script from the location with the mirrors directory?" >&2
echo "(N.B. mirrors directory needs to be pre-created manually)" >&2
exit 1
else
TARGET="$my_path/mirrors"
fi
# Local keyring filename for Proxmox
PROXMOX_KEYRING="$TARGET/$( basename "$PROXMOX_KEYRING_SOURCE" )"
# Check pre-requisite commands exist (fail early)
if ! command -v debmirror &>/dev/null || ! command -v reposync &>/dev/null
then
echo "Unable to locate both debmirror and reposync commands." >&2
echo "(on Debian, are debmirror and yum-utils packages installed?)" >&2
exit 1
fi
# Create Debian mirrors
# ...main mirror
debmirror -v -p -d $DEBIAN_SUITES -s main,contrib,non-free -a amd64 --keyring=/usr/share/keyrings/debian-archive-keyring.gpg --method=rsync -h rsync.mirrorservice.org -r ftp.debian.org/debian "$TARGET"/debian
# ...security mirror
debmirror -v -p -d $DEBIAN_SECURITY_SUITES -s main,contrib,non-free -a amd64 --keyring=/usr/share/keyrings/debian-archive-keyring.gpg --method=http -h security.debian.org -r debian-security "$TARGET"/debian-security
# Create Proxmox mirrors
if ! [ -e "$PROXMOX_KEYRING" ]
then
curl -o "$PROXMOX_KEYRING" "$PROXMOX_KEYRING_SOURCE"
fi
if [ "$( sha512sum "$PROXMOX_KEYRING" | awk '{print $1}' )" != "$PROXMOX_KEYRING_SHA512" ]
then
echo "ERROR: Proxmox keyring on disk ($PROXMOX_KEYRING) sha512sum does not match configured value ($PROXMOX_KEYRING_SHA512):" >&2
sha512sum "$PROXMOX_KEYRING" >&2
rm -f "$PROXMOX_KEYRING"
exit 1
fi
# ...main Proxmox repository
debmirror -v -p -d $PROXMOX_SUITES -s pve-no-subscription -a amd64 --keyring="$PROXMOX_KEYRING" --rsync-extra=none --method=http -h download.proxmox.com -r debian/pve "$TARGET"/pve-no-subscription
# ...Proxmox Ceph repository
debmirror -v -p -d $PROXMOX_SUITES -s main -a amd64 --keyring="$PROXMOX_KEYRING" --rsync-extra=none --method=http -h download.proxmox.com -r debian/ceph-$PROXMOX_CEPH_VERSION "$TARGET"/ceph-$PROXMOX_CEPH_VERSION
# Create yum repository config for reposync
[ -e "$TARGET/yum.conf" ] && rm -f "$TARGET/yum.conf" # Remove old config, if it exists
for centos_version in $( echo "$CENTOS_VERSIONS" | sed -e 's/,/ /g' )
do
cat - >> "$TARGET/yum.conf" <<EOF
[centos-$centos_version-os]
name=CentOS $centos_version OS
baseurl=http://mirror.centos.org/centos/$centos_version/os/x86_64/
enabled=1
gpgcheck=1
gpgkey=https://www.centos.org/keys/RPM-GPG-KEY-CentOS-$centos_version
[centos-$centos_version-updates]
name=CentOS $centos_version updates
baseurl=http://mirror.centos.org/centos/$centos_version/updates/x86_64/
enabled=1
gpgcheck=1
gpgkey=https://www.centos.org/keys/RPM-GPG-KEY-CentOS-$centos_version
[centos-$centos_version-extras]
name=CentOS $centos_version extras
baseurl=http://mirror.centos.org/centos/$centos_version/extras/x86_64/
enabled=1
gpgcheck=1
gpgkey=https://www.centos.org/keys/RPM-GPG-KEY-CentOS-$centos_version
EOF
done
for centos_vault_version in $( echo "$CENTOS_VAULT_VERSIONS" | sed -e 's/,/ /g' )
do
cat - >> "$TARGET/yum.conf" <<EOF
[centos-vault-$centos_vault_version-os]
name=CentOS $centos_vault_version OS
baseurl=http://vault.centos.org/$centos_vault_version/os/x86_64/
enabled=1
gpgcheck=1
gpgkey=https://www.centos.org/keys/RPM-GPG-KEY-CentOS-$( echo $centos_vault_version | sed 's/\.[0-9]*$//' )
[centos-vault-$centos_vault_version-updates]
name=CentOS $centos_vault_version updates
baseurl=http://vault.centos.org/$centos_vault_version/updates/x86_64/
enabled=1
gpgcheck=1
gpgkey=https://www.centos.org/keys/RPM-GPG-KEY-CentOS-$( echo $centos_vault_version | sed 's/\.[0-9]*$//' )
[centos-vault-$centos_vault_version-extras]
name=CentOS $centos_vault_version extras
baseurl=http://vault.centos.org/$centos_vault_version/extras/x86_64/
enabled=1
gpgcheck=1
gpgkey=https://www.centos.org/keys/RPM-GPG-KEY-CentOS-$( echo $centos_vault_version | sed 's/\.[0-9]*$//' )
EOF
done
for rocky_version in $( echo "$ROCKY_VERSIONS" | sed -e 's/,/ /g' )
do
cat - >> "$TARGET/yum.conf" <<EOF
[rocky-$rocky_version-baseos]
name=Rocky Linux $rocky_version BaseOS
baseurl=http://rockylinux.mirrorservice.org/$rocky_version/BaseOS/x86_64/os/
enabled=1
gpgcheck=1
gpgkey=https://dl.rockylinux.org/pub/rocky/RPM-GPG-KEY-rockyofficial
[rocky-$rocky_version-appstream]
name=Rocky Linux $centos_version AppStream
baseurl=http://rockylinux.mirrorservice.org/$rocky_version/AppStream/x86_64/os/
enabled=1
gpgcheck=1
gpgkey=https://dl.rockylinux.org/pub/rocky/RPM-GPG-KEY-rockyofficial
[rocky-$rocky_version-extras]
name=Rocky Linux $centos_version extras
baseurl=http://rockylinux.mirrorservice.org/$rocky_version/extras/x86_64/os/
enabled=1
gpgcheck=1
gpgkey=https://dl.rockylinux.org/pub/rocky/RPM-GPG-KEY-rockyofficial
EOF
done
reposync -a x86_64 -c "$TARGET/yum.conf" -p "$TARGET" --delete --newest-only --downloadcomps --download-metadata
# Run createrepo on RPM repositories
for file in "$TARGET"/*
do
if [ -d "$file/Packages" ]
then
pushd "$file"
CREATE_REPO_OPTS="--update -v"
if [ -e comps.xml ]
then
CREATE_REPO_OPTS="$CREATE_REPO_OPTS -g comps.xml"
fi
createrepo $CREATE_REPO_OPTS "$file"
popd
fi
done
Syncing from USB drive to NAS
To get the data into the air-gapped lab environment, I took the USB disk and plugged it into the host I had configured the NAS to allow write access via Rsync. I then mounted it and used Rsync to upload the mirrors to the NAS (which is configured to receive the IP address 192.168.100.200
on the switch):
mkdir /media/usb
mount -o ro /dev/sdb1 /media/usb
rsync -avP --delete /media/usb/mirrors/ 192.168.100.200::mirrors
umount /mnt
The same process and commands can be used to efficiently update the mirrors in future.
Using the mirrors
Once synced, the mirrors are accessible below /mirrors
on the NAS (navigating to the device now redirects to that path anyway). Helpfully folder listings are on by default so it is easy to see what is going on with it. Apt/Yum etc. can now be configured to use the NAS as a source.
Install images - a new share called isos
To make life easy with setting up VMs I added a new share, isos
, with network install iso files (since I now have local mirrors, network install makes sense) for Debian, CentOS, Rocky, Windows Server 2019 180 day evaluation(the latter to create a Domain Controller for testing Active Directory integrations) and enabled read-only NFS access (and the same read/write
access via Rsync to update).
In order to make this work with Proxmox, I had to put the files into the path template/iso
within the share (or Proxmox will complain that it cannot create them as the NFS share is read-only). Presuming the iso files are in the folder isos
on the USB drive and the drive mounted as above for syncing the mirrors, I synced them with this command:
# ReadyNAS rsync daemon does not support --mkpath, so have to pre-create parent directory by syncing an empty directory to it
mkdir /tmp/empty && rsync -r /tmp/empty/ 192.168.100.200::isos/template && rmdir /tmp/empty
rsync -avP --delete --mkpath /media/usb/isos/ 192.168.100.200::isos/template/iso