31 December 2024

ASUS ROG Charger Dock

In order to simplify connecting my chromebook to my tv, I wanted a small dock. As Best Buy has been running sales on the ASUS ROG Charger Dock for $30, I decided to snag it.


Pros

  • Price when on sale
  • Size (about the size of a deck of cards cut in half, but twice as thick)
  • 65 Watt charging capability
  • Ports:
    • USB-C to laptop
    • USB-A
    • HDMI
  • Comes with a braided USB-C cable
  • Charges chromebook and outputs to tv with a single laptop connection


Cons

  • Limited ports (no ethernet or downstream USB-C)
  • HDMI 2.0 limits output to 4K 60Hz


Other Thoughts

  • USB-C cord was packaged with sharp bends that may lead to longevity issues


Firmware

Mine came with firmware B41 and I updated it to B59 (version 1.4.1)


Appendix

Links:


23 December 2024

Replacing drives in ZFS take two

As it had been ~3 years since the last storage upgrade and there was only about 20% free space remaining, I wanted to take advantage of Black Friday prices. From WD.com, I grabbed 2 x 16TB Red Pro drives with a 5 year warranty.


Verify the drives

  • smartctl short tests
    • smartctl -t short /dev/sdX
    • smartctl -t short /dev/sdY
  • check smartctl test status after ~5 minutes
    • smartctl -a /dev/sdX
    • smartctl -a /dev/sdY
  • badblocks
    • Does 4 iterations of a write followed by a read. For my 16TB drives, each step took ~24 hours for a total of around 8 days.
    • nohup badblocks -wsv -b 4096 /dev/sdX >16TB_serial_1.log 2>&1 &
    • nohup badblocks -wsv -b 4096 /dev/sdY >16TB_serial_2.log 2>&1 &
    • The logs will continue to grow as it runs. Mine got to 5.3MiB each for my 16TB drives after ~8 days
  • Create script to check status of verification
    • echo "" > newline.log
    • echo "cat 16TB_serial_1.log newline.log 16TB_serial_2.log newline.log" > status.sh
    • sh status.sh


Add the drives to the mirror

  • Attach the drives
    • zpool attach [POOLNAME] [EXISTING_DRIVE] [NEW_DRIVE_1]
    • zpool attach [POOLNAME] [EXISTING_DRIVE] [NEW_DRIVE_2]
  • Resilver both drives at once
    • resolves: (awaiting resilver) on [NEW_DRIVE_2]
    • zpool resilver [POOLNAME]
  • Check on resilver
    • zpool status [POOLNAME]
    • resilver in progress since Wed Dec 18 17:37:48 2024
    • I had 4.35TiB to resilver with an estimated runtime of around 7 hours, it ~7 hours and 45 minutes


Remove the old drives

I am planning on waiting at least 11 days to ensure the new drives are functioning as expected, but this is the step to remove them.

  • zpool detach [POOLNAME] [DISKNAME]


Appendix

Sources


03 November 2024

Ubuntu VM add storage

Since my Ubuntu VM was running out of space, I needed to expand it.


Steps I used

  • Expand the storage in Proxmox
    • Proxmox web GUI -> Select the VM -> Hardware
    • Select the Hard Disk
    • Disk Action -> Resize
    • Type the number of GB to add -> Resize disk
  • Have the VM use the additional storage
    • Proxmox web GUI -> Select the VM -> Console
    • login
    • sudo cfdisk /dev/sda
      • sort (This should hopefully put your FreeSpace right after your Linux filesystem
      • resize
      • Write
    • Reboot
    • sudo resize2fs /dev/sda4


Appendix

Sources


Repair La-Z-Boy Office Chair Lumbar support

 Similar to https://www.reddit.com/r/fixit/comments/1btyyg3/lazboy_ergonamic_mesh_chair_lumbar_pad_came_off/ my lumbar support fell off on my La-Z-Boy Ergonomic Mesh Swivel Task Chair model 60021 (Joel). The lumbar support was always loose and had to constantly be readjusted to where I wanted it.


The problem

  • The single screw that holds the padding to the lumbar support arm backed all the way out which caused it to fall off.
  • There is no apparent way to easily reattach it


The solution

  1. remove the arm the padding attaches to by removing the 2 screws with an allen key
  2. separate the padding from the plastic backing by carefully pulling them apart until the 4 posts pulled out of the padding (one in each corner)
  3. attach the plastic backing to the arm using the plastic adjuster, locking washer, and screw
    • I screwed it in really tight, but if you have some thread lock you may want to use it
  4. snap the padding back onto the plastic backing by pressing it into place
  5. reattach the arm to the chair


The result

The lumbar support is reattached and now much better at staying in place (better than new)

Update: Since I did not use thread lock the lumbar support has loosened some

14 September 2024

Adding a USB card to Dell r730xd

As I was tired of being limited to just 2 USB ports, I picked up the Inateck RedComets U21 20Gbps on Prime Day for $31.99 plus tax.


Specs

  • 2 lanes of PCIe 2.0/3.0/4.0 (3.0 or 4.0 required for full speed)
  • Max combined throughput 16 Gbps
  • 10 Gbps dedicated port
    • USB-A
  • 10 Gbps split between
    • 2 x USB-A
    • 2 x USB-C


Add USB Card

  • Shutdown containers and VMs
  • Turn off the server
  • Install the USB card
    • I installed it above the 2.5" drive bays in the back in Riser 3 (Slot 6)
  • Turn on the server
  • Fix fan speed
    • apt-get install ipmitool
    • ipmitool -I lanplus -H 192.168.1.X -U root -P <password> raw 0x30 0xce 0x00 0x16 0x05 0x00 0x00 0x00 0x05 0x00 0x01 0x00 0x00
    • response:
      • 16 05 00 00 00
  • Shutdown the VM you want to add it to
  • Add the USB Card to a VM
    • Select your VM -> Hardware -> Add -> PCI Device
    • Select Raw Device -> Device: ASM2142/ASM3142 USB 3.1 Host Controller
    • Check All Functions
    • Add
  • Start the VM
  • Check that it is working
    • lsusb -t


Test a USB hard drive

  • plug in the USB hard drive
  • determine what drive letter it is:
    • ls -l /dev/disk/by-id
  • Mount it
    • sudo mount -m /dev/sdb1 /mnt/backup-plus
  • Error: unknown filesystem type 'exfat'
    • sudo apt-get install exfat-fuse
    • sudo mount /dev/sdb1 /mnt/backup-plus -t exfat-fuse


Appendix

Sources

Setting up a Jellyfin media server

I wanted to install a media server to help manage my growing library. The top two options that I found are Plex and Jellyfin. I have used Plex in the past, but disliked when they started requiring an account so I went with Jellyfin.


Create the container

  • bash -c "$(wget -qLO - https://github.com/tteck/Proxmox/raw/main/ct/jellyfin.sh)"


Set Static IP and hostname

  • Proxmox -> jellyfin -> Network -> net0 -> Edit
    • set static ip
  • Restart the container
  • Proxmox -> jellyfin -> Console
    • ping 192.168.1.1
      • this ensures that the container will show up on Unifi's list of clients
  • Unifi -> Clients -> Select the jellyfin -> Settings
    • give it a memorable name
    • check "Fixed IP Address"
      • it should auto-populate with current IP
    • check "Local DNS Record"
      • jellyfin.home.arpa


Setup Jellyfin

  • Self signed SSL certificate:
    • https://jellyfin.org/docs/general/networking/
    • jellyfin -> Console
      • mkdir -p /home/jellyfin
      • cd /home/jellyfin
      • openssl req -x509 -days 3650 -newkey rsa:4096 -keyout ./privkey.pem -out cert.pem -nodes -subj '/CN=jellyfin.home.arpa'
        • -subj '/' can work if you can override ssl verification on the client, but Kodi doesn't have that option
        • -subj '/CN=localhost' was causing jellyfin to crash here are some keywords from the crash:
          • Error occurred during a cryptographic operation
          • MapOpenSsl30Code
      • openssl pkcs12 -export -out jellyfin.pfx -inkey privkey.pem -in cert.pem -passout pass:
      • chown -R jellyfin /home/jellyfin
      • chgrp -R jellyfin /home/jellyfin
  • http://jellyfin.home.arpa:8096
    • create user/pass
    • hamburger menu -> Dashboard -> Networking
      • Check "Enable HTTPS"
      • Check "Require HTTPS"
      • Custom SSL certificate path -> /home/jellyfin/jellyfin.pfx
      • Save
  • Restart the jellyfin container
  • Test the self-signed certificate
    • curl --cacert cert.pem https://jellyfin.home.arpa:8920
  • https://jellyfin.home.arpa:8920
    • hamburger menu -> Dashboard -> Users
      • Add User
      • Name
      • Password
      • Check "Enable access to all libraries"
    • hamburger menu -> Dashboard -> Plugin -> Catalog -> Kodi Sync Queue
      • Install
    • Restart jellyfin


Add to Kodi on Google TV

  • Have Kodi trust the self signed certificate
  • Enable adb (Android Debug Bridge)
    • Determine IP of the Google TV
      • Settings -> System -> About -> Status
    • Enable Developer mode
      • Settings -> System -> About -> Build Number -> Click 10 times or until developer mode is unlocked
    • Enable USB debugging (also enables remote debugging)
    • install adb onto a computer to be able to modify the Google TV remotely
      • sudo apt install android-tools-adb
  • Used adb to add new certs file to existing
    • adb pull /sdcard/Android/data/org.xbmc.kodi/files/.kodi/addons/script.module.certifi/lib/certifi/cacert.pem
    • cat cacert.pem cert.pem > updatedcacert.pem
    • adb push updatedcacert.pem /sdcard/Download/
    • echo -e '<advancedsettings version="1.0">\n<network>\n<catrustfile>special://masterprofile/updatedcacert.pem</catrustfile>\n</network>\n</advancedsettings>' >advancedsettings.xml
    • adb push advancedsettings.xml /sdcard/Download/
  • Have Kodi use the new certs
    • Google TV -> Settings -> Apps -> Kodi -> Permissions -> Files and Media -> Allow management of all files
    • Kodi -> Settings -> File Manager
      • Left Side
        • Add Source -> Browse -> External Storage -> Download -> OK
        • Open Download
      • Right Side
        • Profile directory
      • Long press the files one at a time in the Left pane and select copy
    • Restart Kodi
  • Install Jellyfin on Kodi
    • Kodi -> Settings -> File Manager -> Add Source
      • https://kodi.jellyfin.org
    • Kodi -> Settings -> AddOn Browser
      • Allow install from unknown sources when prompted
      • Install from zipfile -> jellyfin -> repository.jellyfin.kodi.zip
      • Install from Repository -> Kodi Jellyfin Add-ons -> Video Add-ons
      • Select Jellyfin add-on and install
    • Cancel adding the server
    • Disable "Verifiy connection" -> OK
    • Restart Kodi
    • Select Manual server add (as auto does it by IP)
      • https://jellyfin.home.arpa:8920
      • sign in using user/pass
      • Playback -> Addon (default)
      • Choose which libraries you want to sync
        • click "All"
        • click "OK"
    • After Syncing is complete restart Kodi
    • Settings -> Add-ons -> My add-ons -> Video add-ons -> Jellyfin
      • Configure -> Sync -> Enable Kodi Sync Queue -> OK


Appendix

Sources

18 July 2024

Debugging Windows 11 crashes

Once to twice a week, I have been finding my system asleep when it should have been folding. After looking at "Event Viewer" after each of these I noticed a trend of a Kernel-Power event proceeded (but not immediately) by a volmgr one.

To view the events open up "Event Viewer", expand "Windows Logs", and click on "System"

Simplified Example:

LevelDate and TimeSourceEvent IDTask Category
Critical5/7/2024 2:13:36 AMKernel-Power41(63)

The system has rebooted without cleanly shutting down first. This error could be caused if the system stopped responding, crashed, or lost power unexpectedly.
Error5/7/2024 2:13:36 AMvolmgr162None

Dump file generation succeded.
Warning5/7/2024 2:11:00 AMDisplay4101None

Display driver amduw23g stopped responding and has successfully recovered.
Warning5/7/2024 2:06:07 AMDisplay4101None

Display driver amduw23g stopped responding and has successfully recovered.


Updating Drivers

As a first step to try and remedy this, I always update drivers. I updated the following:

  • chipset: 
    • 4.07.13.2243 -> 5.11.02.217 (from Asus)
    • 6.02.07.2300 (from AMD after above didn't fix it)
  • video: a version installed in 2024 -> 24.5.1


Updating the BIOS

I found some posts online that said it could be due to the motherboard, so I decided to try updating the BIOS to see if that would help. Unfortunately, it did not.

Before updating the BIOS/UEFI make sure to write down your changes as they will be reset.

BIOS/UEFI Settings

  • Expo -> Enabled
  • Fan Curves
    • CPU
      • 20C -> 20%
      • 60C -> 40%
      • 85C -> 70%
      • 90C -> 100%
    • System
      • 20C -> 30%
      • 50C -> 50%
      • 85C -> 80%
      • 90C -> 100%
  • Advanced Mode (F7)
    • Tool -> ASUS Armoury Crate
      •  Download & Install -> Disabled
    • AI Tweaker -> Precision Boost Override
      • Curve Optimizer
        • All Cores
        • Negative
        • 30
      • Precision Boost Override -> AMD Eco Mode
      • AMD Eco Mode -> cTDP 65W
    • AI Tweaker -> SOC Offset -> negative -> 0.03 (however this caused the pc to hang on warm-boots so I use the below settings instead)
    • AI Tweaker -> CPU SOC Voltage -> Manual
      • VDD SOC Voltage Override -> 1.2

Update the BIOS

After updating the BIOS, you will need to reapply the settings.


Old video drivers

Since all the updates didn't work, I tried installing old video drivers that I knew worked from 24.5.1 to 23.10.2. Luckily this seems to have done the trick and my system is stable again with >27 days of uptime.


Slow folding

Unfortunately, it looks like my solution may be short lived as to get expected folding performance, I need to update to 24.6.1: https://foldingforum.org/viewtopic.php?t=41637&sid=d9b1c6f33f52801aaca8c31fc3fe52d1 So fingers crossed that this release is also stable.

Update 2024-07-29: I had a freeze after roughly 11 days of uptime

Update 2024-07-31: My PC crashed overnight after only 1.5 days of uptime


24.7.1

Update 2024-07-31: I updated the graphics drivers to 24.7.1. Here is the process that I used:

  • Downloaded the AMD driver cleanup utility (from here)
  • Downloaded the full updated AMD graphics driver (for 5600 XT)
  • Disabled Ethernet/Wi-Fi
    • I do this so that Windows doesn't try to "helpfully" download and install other graphic driver versions
  • Ran the AMD driver cleanup utility
    • Had it reboot me into Safe-Mode
    • It removed the drivers and prompted me to reboot, which I did
  • Installed the new drivers (had to approve the big red scary box because of no internet)
  • Rebooted
  • Enabled Ethernet/Wi-Fi


Update 2024-08-02: My computer has crashed twice in the past 2 days so I decided to try DDU

  • Downloaded Display Driver Uninstaller (aka DDU)
    • I downloaded from Guru3D
  • Disabled Ethernet/Wi-Fi
  • Rebooted into Safe Mode
  • Extracted the EXE from the ZIP file
  • Ran the EXE, it will extract even more files
  • Ran "Display Driver Uninstaller.exe"
  • Unchecked the final option (Disable Windows Update Driver Downloads)
    • Since we already disabled internet access this is unnecessary and DDU recommends reenabling afterwards anyway so this saves a step
  • Close the options
  • Device Type -> GPU
  • Device -> AMD
  • Clicked "Clean and restart"
  • Waited for it to do its thing and reboot
  • Installed the 24.7.1 drivers again
  • Rebooted
  • Enabled Ethernet/Wi-Fi

 

Appendix

Sources

15 July 2024

Intel SSD upgrade for r730xd

I got 2 used intel ssds to improve VM performance and to reduce power usage


Check SMART attributes


Firmware Update Adventure

Intel Memory and Storage Tool CLI

My first attempt was to use Intel cli to update the firmware, but it did not work.


Solidigm

My second attempt was to use Solidigm cli to update the firmware, but it did not work through the raid controller and had to be attached to a different SATA controller.

  • Installation
  • Usage
  • Firmware Update
    • sst load -ssd <index>
    • Status : Firmware update failed.
      • If your drives are behind a RAID card, you may have to remove them for updating.
  • Firmware Update using a USB to SATA enclosure
    • sst show -ssd
    • Unfortunately, the drive no longer appeared :-(
  • Firmware Update using Windows with USB to SATA enclosure
    • The drive appeared and would run tests
    • However attempting to update the firmware resulted in an error and the USB port being disabled until the PC was rebooted
  • Firmware Update using a JMB585 PCIe to SATA card, a SATA to eSATA bracket, and an external eSATA enclosure
    • Finally was able to update the firmware
    • Notes:
      • the firmware did not jump to the latest version and had to be updated incrementally
        • G2010140 -> G2010160 -> G2010170
      • the firmware update requested a reboot after installing so I did that
    • sst show -ssd
    • sst show -a -ssd <index> | grep Firmware
    • sst load -ssd <index>
    • Status : Firmware updated successfully. Please reboot the system.


Replacing the existing 1.2 TB drives

  • Setup the partitions
    • I used my rpool mirror instructions from here but made the following changes
      • removed the last-lba line
      • removed the start from all lines
      • removed the size from the final partition
      • don't run the zpool attach
  • Copy the rpool data
    • I am following the wizardry provided here
    • Add a mirror of the new disks to form a striped mirror
      • zpool add rpool mirror /dev/disk/by-id/ata-INTEL_SSDSC2BX800G4_<SERIAL1>-part3 /dev/disk/by-id/ata-INTEL_SSDSC2BX800G4_<SERIAL2>-part3
    • Check the mirror names and size
      • zpool status rpool
      • zpool list rpool
    • Remove the old mirror
      • zpool remove rpool mirror-0
    • Check for when "Evacuation of mirror" is done
      • zpool status rpool
      • remove: Removal of vdev 0 copied 10.7G in 0h1m
    • Check new size
      • zpool list rpool
  • Shutdown and remove the drives and reboot to make sure everything is working as intended
  • Remove the old drives from proxmox-boot-tool
    • proxmox-boot-tool status
    • proxmox-boot-tool clean
    • proxmox-boot-tool status
  • Remove all data from old drives
    • put the drives back in
    • wipe them using your favorite tool (eg. shred or dd)
      • dd if=/dev/zero of=/dev/sdX -bs=1M status=progress
      • dd if=/dev/urandom of=/dev/sdX -bs=1M status=progress


Conclusion

I saw a 7-8W drop in idle power usage and an increase in responsiveness.


Appendix

Sources


10 June 2024

r730xd Server Part 3: Software

 I will be using Proxmox Helper Scripts (https://tteck.github.io/Proxmox/ or https://Helper-Scripts.com) to help configure the different LXCs and VMs that I want.


Disable nag screen

As I was tired of having to confirm that I didn't have a subscription, I ripped these commands from Proxmox VE Tools -> Proxmox VE Post Install (https://raw.githubusercontent.com/tteck/Proxmox/main/misc/post-pve-install.sh) and ran on the Shell command line

  • echo "DPkg::Post-Invoke { \"dpkg -V proxmox-widget-toolkit | grep -q '/proxmoxlib\.js$'; if [ \$? -eq 1 ]; then { echo 'Removing subscription nag from UI...'; sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/}' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; }; fi\"; };" >/etc/apt/apt.conf.d/no-nag-script
  • apt --reinstall install proxmox-widget-toolkit


Setup Users

My philosophy was to put all actual users in the 1000s and system users in the 2000s
  • user1
    • useradd user1
    • usermod -g users user1
    • adduser user1 user1
    • id user1
  • user2
    • useradd user2
    • usermod -g users user2
    • adduser user2 user2
    • id user2
  • mythtv
    • groupadd -g 2001 mythtv
    • useradd -u 2001 -g 2001 mythtv
  • nginx
    • groupadd -g 2002 nginx
    • useradd -u 2002 -g 2002 nginx
  • edit /etc/subuid and add
    • root:1000:1000
    • root:2000:1000
  • edit /etc/subgid and add
    • root:100:1
    • root:1000:1000
    • root:2000:1000


Import ZFS

  • zpool import storage
  • I decided not to map the drive in Proxmox, but if you wanted to you would do that here
    • proxmox -> Datacenter -> Storage -> Add -> ZFS


Fix Directory/File Permissions

  • /storage/mythtv
    • cd /storage/mythtv
    • ls -al
    • find ./ -user <current owner> -print0 | xargs -0 chown -h mythtv
    • find ./ -group <current group> -print0 | xargs -0 chgrp -h mythtv
  • /storage/containers/mythtv
    • cd /storage/containers/mythtv
    • ls -al
    • find ./ -user <current owner> -print0 | xargs -0 chown -h mythtv
    • find ./ -group <current group> -print0 | xargs -0 chgrp -h mythtv
  • /storage/containers/webserver
    • cd /storage/containers
    • chown -R nginx webserver
    • chgrp -R nginx webserver


Create a Docker LXC

Now I needed a Docker LXC to run my webserver and MythTV

  • bash -c "$(wget -qLO - https://github.com/tteck/Proxmox/raw/main/ct/docker.sh)"
  • I then edited the config to set a static IP and change the hostname
    • docker -> Network -> net0 -> Edit
    • docker -> DNS -> Hostname -> Edit
  • Add users
    • nas
      • groupadd -g 2000 nas
      • useradd -u 2000 -g 2000 nas
    • mythtv
      • groupadd -g 2001 mythtv
      • useradd -u 2001 -g 2001 mythtv
    • nginx
      • groupadd -g 2002 nginx
      • useradd -u 2002 -g 2002 nginx


MythTV

  • Edit /storage/containers/mythtv/docker-compose.yml
    • Change the User Ids and Groups Ids to 2001
  • Test
    • docker compose up -d
  • If it looks like API port changed from 6544 to 6744, then you need to fix the IPs
  • Check pin and update backend ip
    • apt-get install default-mysql-client
    • mysql -p -h 127.0.0.1 -P 3306 mythconverg
      • select * from settings where value like '%pin%'
      • update settings set data = '192.168.1.31' where data = '192.168.1.11' ;
      • quit;
  • Restart MythTV and Test
    • docker compose down && docker compose up -d
  • This time I put a copy of docker-mythtv.service in /storage/container/mythtv so I can easily copy it to /etc/systemd/system/ in the future
    • make sure to change `docker-compose` to `docker compose`
  • docker compose down
  • systemctl enable docker-mythtv
  • systemctl start docker-mythtv


Webserver

  • Test
    • docker compose up -d
    • docker compose down
  • This time I put a copy of docker-webserver.service, certbot.service, and certbot.timer in /storage/container/webserver/systemd so I can easily copy it to /etc/systemd/system/ in the future
    • make sure to change `docker-compose` to `docker compose`
  • cp certbot.service certbot.timer docker-webserver.server /etc/systemd/system/
  • systemctl enable docker-webserver
  • systemctl start docker-webserver
  • systemctl enable certbot.timer


Create a Debian LXC for File Sharing

  • following:
  • bash -c "$(wget -qLO - https://github.com/tteck/Proxmox/raw/main/ct/debian.sh)"
  • Add users/groups
    • <container> -> Console
    • user1
      • useradd user1
      • usermod -g users user1
      • adduser user1 user1
      • id user2
    • user2
      • useradd user2
      • usermod -g users user2
      • adduser user2 user2
      • id user2
    • nas
      • groupadd -g 2000 nas
      • useradd nas -u 2000 -g 2000 -m -s /bin/bash
      • adduser nas sudo
      • passwd nas
  • shutdown the container
  • Set a static IP and change the hostname
    • <container> -> Network -> net0 -> Edit
    • <container> -> DNS -> Hostname -> Edit
  • Add more compute/memory (2 cores/1024MB)
    • <container> -> Resources -> Cores -> Edit
    • <container> -> Resources -> Memory -> Edit
  • Add our storage
    • edit /etc/pve/lxc/<container id>.conf
    • add a line for each of your datasets like the below examples:
      • mp0: /storage/folder1/dataset1,mp=/storage/folder1/dataset1
      • mp1: /storage/folder1/dataset2,mp=/storage/folder1/dataset2
      • mp2: /storage/dataset3,mp=/storage/dataset3
  • Map the users
    • Notes
      • /etc/subuid and /etc/subgid need to specify the user starting the lxc container (root)
      • /etc/pve/lxc/<container id>.conf needs to map all ids and not just the ones you want to remap
    • edit /etc/pve/lxc/<container id>.conf add these lines
      • lxc.idmap: u 0 100000 1000
      • lxc.idmap: u 1000 1000 1000
      • lxc.idmap: u 2000 102000 63535
      • lxc.idmap: g 0 100000 100
      • lxc.idmap: g 100 100 1
      • lxc.idmap: g 101 100101 899
      • lxc.idmap: g 1000 1000 1000
      • lxc.idmap: g 2000 102000 63535
  • Change the drive permissions
    • I couldn't get the container to boot with trying to remap root so don't do this step
    • cd /rpool/data/subvol-<container id>-disk-0
    • find ./ -user 100000 -print0 | xargs -0 chown -h 2000
    • find ./ -group 100000 -print0 | xargs -0 chgrp -h 2000
  • Start the container
  • Install cockpit
    • apt install cockpit --no-install-recommends
    • wget https://github.com/45Drives/cockpit-file-sharing/releases/download/v3.3.7/cockpit-file-sharing_3.3.7-1focal_all.deb
    •  wget https://github.com/45Drives/cockpit-navigator/releases/download/v0.5.10/cockpit-navigator_0.5.10-1focal_all.deb
    • wget https://github.com/45Drives/cockpit-identities/releases/download/v0.1.12/cockpit-identities_0.1.12-1focal_all.deb
    • apt install ./*.deb
    • rm *.deb
  • Configure cockpit
    • https://192.168.X.X:9090
    • use nas to login
    • enable administrative access
    • Identities
      • Set a Samba password for each of the users
    • File Sharing
      • Click "Fix Now"
      • Global Settings
        • Toggle Global MacOS Shares
        • Add `allow insecure wide links = yes` to Advanced
        • Apply
      • Add your shares
      • I used the following to ensure all users can access others files in advanced
        • create mask = 0664
        • force create mode = 0664
        • directory mask = 0775
        • force directory mode = 0775
      • I used the following to be able to follow symlinks
        • follow symlinks = yes
        • wide links = yes


Create a Ubuntu VM for VNC and Handbrake

I have read that x264 sees reduced performance with over 6 threads, so I gave the VM 12 virtual cores since I want to be able to process 2 discs at a time.

  • bash -c "$(wget -qLO - https://github.com/tteck/Proxmox/raw/main/vm/ubuntu2404-vm.sh)"
  • Edit Cloud-Init
    • ubuntu -> Cloud-Init
    • set user/pass
    • set static IP
  • Disable start at boot
    • ubuntu -> Options -> Start at boot -> Edit
    • uncheck and the hit OK
  • Change resources
    • 12 Cores
    • 24 GB of memory (2 GB per core)
    • added 16 GB of storage
  • Console
    • start VM
    • login
  • Enable ssh with password
    • /etc/ssh/sshd_config.d/10_users.conf
      • Match User username
        • PasswordAuthentication yes
    • sudo systemctl restart ssh
  • VNC server
    • sudo apt install tigervnc-standalone-server
  • A window manager and terminal to use inside VNC
    • sudo apt install xfce4 xfce4-terminal
  • Keep proxmox console as text
    • sudo systemctl set-default multi-user.target
  • Start VNC
    • tigervncserver :1 -geometry 1600x900 -depth 24 -localhost no -SecurityTypes VncAuth,TLSVnc -xstartup /usr/bin/startxfce4
  • Add handbrake
    • sudo apt install handbrake libdvd-pkg
    • sudo dpkg-reconfigure libdvd-pkg
  • Set timezone (Added 2024-0620)
    • timedatectl list-timezones
    • sudo timedatectl set-timezone America/New_York
  • Setup samba shares
    • sudo apt install cifs-utils
    • create a file to save samba credentials in (eg smbcredentials)
      • username=username
      • password=password
    • mount the shares
      • sudo mount -t cifs //192.168.1.XX/nas /storage/encrypted/nas -o credentials=/home/<username>/smbcredentials,uid=<username>,gid=users
  • Add qemu agent (added 2024-07-29)
    • sudo apt install qemu-guest-agent
    • sudo systemctl start qemu-guest-agent


Appendix

Error
  •  Failed to run lxc.hook.pre-start for container
    • are your zfs pools mounted?
  • make sure cifs-utils are installed
    • sudo apt install cifs-utils
  • samba files are all owned by root
    • make sure to add the uid and gid to the mount command
Sources

05 June 2024

r730xd Server Part 2: Lowering Idle Power

 As the plan is to have the server on 24/7, I wanted to lower the idle power usage. All power numbers were manually captured from a smart outlet.


Baseline

1 x e3-1225v3, 4 x 8GB, 1 SSD, 2 x WD Red Plus 6TB, 1 x JMB585

  • in Ubuntu no load
    • ~35W

2 x e5-2670v3, 8 x 16GB, 1 x 10K 2.5" SAS

  • in Proxmox no load
    • ~95W (93.6 to 100)
    • 4% fans
  • stress -c 48
    • 290W
    • 8% fans
    • 70C + 77C (inlet 16C, exhaust 39C)


Removing a processor

This will lower the PCIe connectivity, but should save power. To be able to remove a processor, I needed to buy a CPU socket cover and an airflow guide

  • Socket 2011-3 cover: $6.99 + tax
  • Dell CPU Blank airflow guide 21PJD: $11.02 + tax
    • Note: this will not allow you to install blanks into the memory slots so dust could be an issue
  • Updated total: $452 + tax

1 x e5-2670v3, 4 x 16GB, 1 x 10K 2.5" SAS

  • in Proxmox no load
    • ~81W (80.5 to 85.4)
    • 4% fans
  • stress -c 24
    • 166W
    • 8% fans
    • 67C (inlet 15C, exhaust 27C)

1 x e5-2670v3, 8 x 16GB, 1 x 10K 2.5" SAS

  • in Proxmox no load
    • ~82W (81.4 to 85.2)
    • 4% fans
  • stress -c 24
    • 174W
    • 8% fans
    • 68C (inlet 15C, exhaust 27C)

This means that the memory used only about ~1W at idle for all 4 sticks and ~8W at full load. This means that running a single processor will save me about 13W.


Adding a second drive

Adding the second 1.2TB SAS drive increased my idle power usage by ~4.5W

  • in Proxmox no load
    • ~86.5W
    • 4% fans


Making the jump from a Xeon v3 (22nm) to v4 (14nm)

For this upgrade I bought used processors

  • 2 x 2680 v4: $21.58 + tax
  • Updated total: $474 + tax

I moved from a 2670 v3 to a 2680 v4 in hopes that it would shave off a couple of watts at idle, unfortunately it uses ~1.5W more. So it seems that each core uses about 1W at idle.

  • in Proxmox no load
    • ~88W (87.4 to 89.1)
    • 4% fans
  • stress -c 28
    • 205-206W
    • 80C (inlet 17C, exhaust 30C)

While not improving the idle power usage, it will be a large boost in both single-core (13%) and multi-core performance (23%) https://www.cpubenchmark.net/compare/2779vs2337/Intel-Xeon-E5-2680-v4-vs-Intel-Xeon-E5-2670-v3


Setting governor to powersave

Tried changing the governor to save idle power, but did not notice any change.
  • apt-get install linux-cpupower
  • cpupower frequency-set -g powersave


Appendix

Sources

26 May 2024

Dockerize MythTV

To prepare for my new server, I needed to migrate the rest of MythTV including its MySQL database to Docker containers.


Migrate MythTV Backend and MySQL to Docker

  • Edit docker-compose-webserver.service to remove references to mysql.service
    • This step is only necessary if you followed my other guide that dockerized mythweb
    • sudo systemctl daemon-reload
  • Stop and Disable MythTV Backend
    • sudo systemctl stop mythtv-backend
    • sudo systemctl disable mythtv-backend
  • Create directories and set permissions
    • sudo mkdir -p /storage/containers/mythtv/mysql/lib
    • sudo chown -R mysql /storage/containers/mythtv/mysql
    • sudo chgrp -R mysql /storage/containers/mythtv/mysql
  • Dump the current mythconverg database to a file and update the hostname
    • sudo su
    • mysqldump -p<existing root password> mythconverg > mythconverg.mysqldump
    • sed "s/'<old hostname>'/'mythtv-backend'/g" mythconverg.mysqldump > mythconverg.mysqldump.host
    • exit
  • Stop and disable current MySQL instance
    • sudo systemctl stop mysql
    • sudo systemctl disable mysql
  • Identify the needed UIDs and GIDs
    • id mysql && id mythtv
  • Create the docker-compose.yml with just a MySQL section
# Begin docker-compose.yml
version: '3.5'
services:
    mythtv-mysql:
        container_name: 'mythtv-mysql'
        hostname: 'mythtv-mysql'
        user: '<mysql uid>:<mysql gid>'
        image: mysql:latest
        restart: always
        ports:
            - '3306:3306'
        environment:
            - MYSQL_ROOT_PASSWORD=RootSuperSecretPassword
            - MYSQL_USER=mythtv
            - MYSQL_PASSWORD=YourSuperSecretPassword
        volumes:
            - ./mysql/lib:/var/lib/mysql
# End docker-compose.yml
  • Restore the database:
    • sudo docker-compose up --build
    • sudo mysql -p -h 127.0.0.1 -P 3306
      • create database mythconverg ;
      • connect mythconverg ;
      • source mythconverg.mysqldump.host ;
      • grant all privileges on mythconverg to 'mythtv'@'%' ;
      • grant all privileges on mythconverg.* to 'mythtv'@'%' ;
      • quit ;
    • Use Ctrl-C to stop the container
  • Add the backend to docker-compose.yml
# Begin docker-compose.yml
version: '3.5'
services:
    mythtv-mysql:
        container_name: 'mythtv-mysql'
        hostname: 'mythtv-mysql'
        user: '<mysql uid>:<mysql gid>'
        image: mysql:latest
        restart: always
        ports:
            - '3306:3306'
        environment:
            - MYSQL_ROOT_PASSWORD=RootSuperSecretPassword
            - MYSQL_USER=mythtv
            - MYSQL_PASSWORD=YourSuperSecretPassword
        volumes:
            - ./mysql/lib:/var/lib/mysql
    mythtv-backend:
        container_name: 'mythtv-backend'
        hostname: 'mythtv-backend'
        user: '<mythtv uid>:<mythtv gid>'
        image: dheaps/mythbackend:latest
        restart: always
        depends_on:
            - mythtv-mysql
        network_mode: host
        # entrypoint: 'echo backend disabled'
        environment:
            - USER_ID=<mythtv uid>
            - GROUP_ID=<mythtv gid>
            - DATABASE_HOST=host.docker.internal
            - DATABASE_PORT=3306
            - DATABASE_NAME=mythconverg
            - DATABASE_USER=mythtv
            - DATABASE_PWD=YourSuperSecretPassword
            - TZ=America/New_York
        volumes:
            - /storage/mythtv:/var/lib/mythtv
        extra_hosts:
            - host.docker.internal:host-gateway
# End docker-compose.yml
  • Test it out
    • docker-compose up --build
    • Ctrl-C to stop it once you confirm it works
  • Add it to systemd: /etc/systemd/system/docker-mythtv.service
# Begin docker-mythtv.service
[Unit]
Description=Docker Compose MythTV Service
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/storage/containers/mythtv
ExecStart=/usr/bin/docker-compose up --build -d
ExecStop=/usr/bin/docker-compose down
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target
# End docker-mythtv.service

  • Enable and start the service
    • sudo systemctl enable docker-mythtv
    • sudo systemctl start docker-mythtv
  • I also had to update docker-compose.yml for mythweb to use DATABASE_HOST=host.docker.internal and add the extra_hosts


Appendix

Errors

  • MythCoreContext::CheckSubnet(): Repeat denied connection from ip address
    • Connect to the MySQL database
      • sudo mysql -p -h 127.0.0.1 -P 3306
    • Run one of the following:
      • update settings set data = 1 where value = 'AllowConnFromAll' ;
      • OR
      • insert into settings(value, data, hostname)
      • values('AllowConnFromAll', '1', 'mythtv-backend')
      • ;
  • only one instance of "host" network is allowed
    • ensure that you are using either external host network or network_mode

Sources



17 April 2024

r730xd Server Part 1: Initial Build

In order to support more than the 2 hard drives I could in the TS140, I needed a new system. Here were my requirements:

  • price < $500
  • reasonable noise level
  • more than 4 cores
  • ECC RAM (preferably at least 128GB)
  • 8 or more spots for hard drives

I was looking at some older SuperMicro and Dell systems. I read several posts about the power supplies being louder on the SuperMicro so I decided to go with the Dell r730xd that supports 12 x 3.5" drives in the front and 2 x 2.5" drives in the rear.


Hardware

  • r730xd used - $350 + tax
    • 2 x e5-2670v3 12 cores each
    • 128 GB ECC DDR4 (8 x 16GB)
    • PERC H730p Mini raid controller
    • 1 x 2.5" caddie with 1.2TB 10K SAS drive
    • iDRAC 8 Enterprise license
  • 12 x 3.5" used caddies - $60 + tax
    • SAS or SATA caddie both work for holding sata drives
  • 1 x 2.5" caddie with 1.2 TB 10K SAS drive - $24 + tax
    • this is a second drive for a boot mirror
  • total: $434 + tax


TLDR; Pros/Cons

  • Pros
    • Many many cores
    • Loads of RAM with expandability
    • Thermal solution works quite well even under full load with fans at 6-8% (2640-2880 rpm) on auto keeping the processors around 77C
    • iDRAC is quite useful especially the HTML5 virtual console (requires Enterprise license)
  • Cons
    • No hardware reset for iDRAC
  • Somewhere in the middle
    • idle power usage of 94-96W (with a single 2.5" drive) is higher than I would like
      • Fans @ 4% (2280 rpm)
      • 18W for iDRAC even when powered down
    • installing hard drive
      • when installing an older drive (250GB WD) fans spun up to 40% (7320 rpm), this may have been because it was unable to read temp or was failing
      • installing a 3TB WD Red drive caused the fans to go to 6% (2680 rpm)
    • Fan noise
      • 45-50% (8880-9840 rpm) is noticeable with the basement door closed
      • 30% (6480 rpm) is noticeable with the basement door open
      • 15-20% (4080-4920 rpm) about as loud as a running fridge
      • 10% (3240 rpm) a low constant hum
      • 6% (2640 rpm) quieter than seeking dvd drives


BIOS/iDRAC reset and setup

First I did a BIOS reset by moving the jumper. Unfortunately, this did not reset the iDRAC, and there does not seem to be a way to do this with hardware. For this you will need a VGA monitor and keyboard. I followed this video to do it: https://www.youtube.com/watch?v=R5pYfqDtzQw

Reset BIOS

  • F2 for System Setup
  • System BIOS
  • Default
  • Finish and Confirm
  • Reboot

BIOS Settings to change from default

  • Boot Settings -> Boot Mode -> UEFI
  • System Profile Settings -> System Profile -> Performance per Watt (OS)
  • Integrated Devices -> USB 3.0 Setting -> Enable (Added 2024-06-07)
  • Finish and Confirm
  • Reboot

Reset iDRAC

  • F2 for System Setup
  • iDRAC Settings
  • Reset iDRAC configurations to defaults
  • Finish and Confirm
  • Reboot

Then I was able to configure iDRAC from its default 192.168.0.120 to an unused IP on my network.

  • F2 for System Setup
  • iDRAC Settings
  • Network
  • Update Static IP Address (and Subnet/Gateway if applicable)
  • Back
  • Finish and Confirm
  • Reboot


Memory Testing

While memtest86 isn't the best memory tester available, it is free and doesn't require an OS to be installed. I used version 10.7, which I downloaded the ISO for loading onto my Ventoy USB from here: https://www.memtest86.com/downloads/memtest86-iso.zip

It took about 24 hours to do all 4 passes of the test patterns.


Update iDRAC

Here is where I downloaded the iDRAC update from: https://www.dell.com/support/home/en-us/product-support/product/poweredge-r730xd/drivers. You should download the version for windows for uploading through the Web UI. Then apply the updates from the iDRAC interface: Login to iDRAC -> iDRAC Settings -> Update and Rollback -> upload

At first I download the win64 version of the latest available (2.85.85.85), but the update would fail due to it not validating. Here is the update path that I went with: 2.61.60.60 -> 2.63.60.61 (win32) -> 2.75.100.75 (win32) -> 2.85.85.85 (win64)

After the first update the iDRAC appeared to be unresponsive, so I let it sit for ~20 minutes and it was still unresponsive, however I could ping it. At this point I held in the "i" button for ~20s to restart the iDRAC. This brought it back to life.

Here is a video that I found helpful: https://www.youtube.com/watch?v=dea-PA1na0c


Update the rest of the firmware

I always update the BIOS separately

Update BIOS/UEFI:

  • Login to iDRAC -> iDRAC Settings -> Update and Rollback -> HTTPS
  • HTTPS Address: downloads.dell.com
  • Check for Updates
  • Select the BIOS update and click "Install and Reboot"
  • The system will then reboot and install the new BIOS

Update Raid/Network:

  • Login to iDRAC -> iDRAC Settings -> Update and Rollback -> HTTPS
  • HTTPS Address: downloads.dell.com
  • Check for Updates
  • Select the Raid and Network update and click "Install and Reboot"
  • The system will then reboot and install the new BIOS


Set Raid card to HBA mode

This will pass the drives directly to the OS to manage the software raid.

Login to iDRAC -> Storage -> Controllers -> Setup -> Controller Mode -> Action -> HBA


Proxmox install

I downloaded Proxmox 8.1 from: https://www.proxmox.com/en/downloads

I was using a Ventoy USB to do my Proxmox 8.1 install, but it was giving me an error. However, I found that you need to use Ventoy >= 1.0.97 (https://github.com/ventoy/Ventoy/releases/tag/v1.0.97). So I updated my Ventoy USB and then the install proceeded.

During the setup here are some of the values that I chose:

  • Target -> Options
    • If you only have 1/2 of your boot drives
      • ZFS (RAID0)
      • Harddisk 0 - 1.09TB
      • Harddisk 1 - Do not use
    • If you have both go ahead and setup the mirror
      • ZFS (RAID1)
      • Harddisk 0 - 1.09TB
      • Harddisk 1 - 1.09TB
  • Timezone: America/New_York
  • Password and Email
  • Management
    • Make sure to select the correct management interface (easier if network is hooked up before starting setup)
    • Hostname: r730xd.home.arpa
    • IP Address: pick a free IP
    • Gateway/DNS

After the setup, login to the web ui: https://<IP>:8006

  • Disable Proxmox Enterprise repos as they require a license
    • Click on the hostname (r730xd)
    • Remove the subscription update repository
      • Updates -> Repositories
      • Highlight "pve pve-enterprise" and click "Disable"
      • Highlight "ceph-quincy enterprise" and click "Disable"
    • Add the No Subscript update repository
  • Update your install
    • Updates
    • Click "Refresh"
    • Close the window when it is done
    • Click "Upgrade"
    • Type "y" and enter


Add the rpool mirror (if not configured at install)

  • Determine if using grub or systemd-boot
    • proxmox-boot-tool status
    • efibootmgr -v
  • Copy the partition table over (removing disk label-id and uuids so sfdisk generates new ones)
    • sfdisk -d /dev/sda > part_table
    • sed -e '/^label-id:/d' -e 's/,\s*uuid=[-0-9A-F]*//g' part_table | sfdisk /dev/sdb
  • Copy the bios boot
    • dd if=/dev/sda1 of=/dev/sdb1
  • Prepare EFI partition
    • dd if=/dev/sda2 of=/dev/sdb2 Don't do this as it keeps the UUID
    • OR
    • proxmox-boot-tool format /dev/sdb2
  • Initialize the EFT partition
    • proxmox-boot-tool init /dev/sdb2
    • OR if using grub
    • proxmox-boot-tool init /dev/sdb2 grub
  • Get current zpool drive
    • zpool status
  • Add the mirror
    • zpool attach rpool scsi-XXXXXXXXX-part3 /dev/disk/by-id/scsi-YYYYYYYYY-part3
  • ZFS will then resilver the drive, to check if done run
    • zpool status


intel_pstate

Trying to lower the idle power usage, I wanted to try a different cpu governor driver.
  • check whether it is intel_pstate or intel_cpufreq
    • apt install cpufrequtils
    • cpufreq-info | head -n 13
  • Determine if using grub or systemd-boot
    • proxmox-boot-tool status
    • efibootmgr -v
  • to enable intel_pstate for grub boot:
    • edit /etc/default/grub
    • add intel_pstate=active to GRUB_CMDLINE_LINUX_DEFAULT
      • example: GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_pstate=active"
    • proxmox-boot-tool refresh
    • wait for grub to finish updating and then reboot
  • to enable intel_pstate for systemd-boot
    • edit /etc/kernel/cmdline
    • add intel_pstate=active to the end
    • proxmox-boot-tool refresh
    • wait for it to update and then reboot
  • ensure it is now intel_pstate
    • cpufreq-info | head -n 13
  • unfortunately this did not change idle power usage


Fan Information

Here are the fan values from my r730xd

  •  4% -> 2280 rpm -> 10 cfm
  •  6% -> 2640 rpm -> 12 cfm
  •  9% -> 3000 rpm -> 18 cfm
  • 12% -> 3600 rpm -> 21 cfm
  • 15% -> 4080 rpm -> 24 cfm
  • 20% -> 4920 rpm -> 30 cfm
  • 25% -> 5640 rpm -> 36 cfm
  • 30% -> 6480 rpm -> 41 cfm
  • 40% -> 7320 rpm -> 53 cfm
  • 50% -> 8160 rpm -> 64 cfm


Appendix

Sources

04 April 2024

Checking if two video files are the same aside from metadata

As I wanted to make sure that two video files were identical aside from metadata, I decided to write a script to help me. The script will create a hash from the audio and video data without the header data.

Caveats:

  • There is a chance for hash collisions, so double check the results manually before deleting
  • This script doesn't flag videos as duplicates if they are the same video but have different resolution, bitrate, audio data, etc


Requirements

  • ffmpeg
  • md5sum


Shell Version

Initial shell script to compare to 2 files: 

#!/bin/sh
file1="$1"
file2="$2"

flags="-fflags +bitexact -flags:v +bitexact -flags:a +bitexact -c copy -f matroska"

file1hash=$(ffmpeg -i "$file1" $flags -c copy -f matroska -loglevel error - | md5sum | cut -f1 -d" ")
file2hash=$(ffmpeg -i "$file2" $flags -c copy -f matroska -loglevel error - | md5sum | cut -f1 -d" ")

echo "$file1hash $file1"
echo "$file2hash $file2"


Example Shell

$./diffvideo.sh file1.m4v file2.m4v
cb31XXXXXXXXXXXXXXXXXXXXXXXXXXXX file1.m4v
cb31XXXXXXXXXXXXXXXXXXXXXXXXXXXX file2.m4v


Python Version

Expanded python script to compare more files:

#!/usr/bin/env python3

import argparse
import shlex
import subprocess


def setup_cli():
    parser = argparse.ArgumentParser(
        prog='',
        description='',
        epilog='',
    )
    parser.add_argument('filenames', nargs='*')
    return parser


def check_files(filenames):
    hashes = {'not_a_video': []}
    for file in filenames:
        flags = '-fflags +bitexact -flags:v +bitexact -flags:a +bitexact'
        cmd = f'ffmpeg -i "{file}" {flags} -c copy -f matroska -'
        ff_proc = subprocess.run(shlex.split(cmd), capture_output=True)
        if ff_proc.returncode != 0:
            hashes['not_a_video'].append(file)
            continue
        hash_proc = subprocess.run('md5sum', capture_output=True, input=ff_proc.stdout)
        filehash = hash_proc.stdout.decode().split()[0]
        if filehash not in hashes:
            hashes[filehash] = []
        hashes[filehash].append(file)

    return hashes


def print_results(hashes):
    not_a_video = hashes.pop('not_a_video')
    singles = {}
    dupes = {}
    for key, value in hashes.items():
        if len(value) > 1:
            dupes[key] = value
        else:
            singles[key] = value

    if not_a_video:
        print('\nNot a video:')
    for each in not_a_video:
        print(f'    {each}')

    if dupes:
        print('\nDuplicates found:')
    for key, value in dupes.items():
        print(f'    {key}')
        for v in value:
            print(f'        {v}')

    if singles:
        print('\nNo Duplicates for these files:')
    for key, value in singles.items():
        print(f'    {value[0]}')


if __name__ == "__main__":
    parser = setup_cli()
    args = parser.parse_args()
    hashes = check_files(args.filenames)
    print_results(hashes)


Example Python

$./diffvideo.py *

Not a video:
    test.txt
    file.docx

Duplicates found:
    cb31XXXXXXXXXXXXXXXXXXXXXXXXXXXX
        file1.m4v
        file2.m4v
    ab76XXXXXXXXXXXXXXXXXXXXXXXXXXXX
        file5.m4v
        file6.m4v

No duplicates for these files:
    file3.m4v
    file4.m4v


Appendix

Sources