Building that $79 Black Friday FreeBSD Server (MicroCenter Edition)

No, this is not really a server

Building that $79 Black Friday FreeBSD Server (MicroCenter Edition)
No, this is not really a server

Having built my first PC to learn Linux bad in the mid-90s by assembling it from random parts from San Antonio newspaper want-ads (yes, that thing before Craigslist) I like to get my hand dirty with hardware, but it is not something I do much these days in the age of the cloud.

(And dirty is fine, cutting my fingers on motherboards or cases is not something I ever enjoyed — or blood. And Raspberry Pi’s really don’t count because they just work, although I do admit to keeping an eye out for the the Pi 5’s even though I think they are way overpriced! )

But I’d been looking for a mindless hardware project while on PTO to take a break from reading (and food) and I’d been eying the budget Lenovo laptops at Best Buy and MicroCenter all week

I hadn’t bought any hardware in a while since I bought a Hyundai Mini PC over the Summer.

Best thing since a Netbook?

Being a cheapskate (which results in too many damn computers with very little power to do really anything besides feed metrics somewhwere) the $79.99 price tag got my attention!

Normal price was $149 which I wouldn’t even consider but under a $100, let’s do it! I quickly Googled to see if there were any challenges getting the hardware to work on Linux. It seemed the only issues were wireless and sound, neither which I cared about. There also seemed a lot of HAM Radio users interested in using this hardware for some reason, but I didn’t go too far down that rabbit hole.

Also I was more interested in having a cheap BSD box, because I miss those days of actually running BSD on baremetal! I did actually boot into Windows 10 for some reason.

The wireless works, just mistyped my WPA password!

Which BSD and Why?

With way too many Raspberry Pi’s and Dells that won’t die I didn’t see the point of actually installing Linux. It would likely just works. This is generic Intel Celeron hardware and chipsets are pretty well supported and need to have SOME diversity on my home network which is mostly Ubuntu and Debian.

Although I have actually used NetBSD before really it is between Open and FreeBSD. Heads or Tails. I went with OpenBSD and booting from the AMI BIOS to the USB allowed me to get to the familiar installer and partitioning tool that really hasn’t changed much since the 1990s.

Choose GPT not MBR!

I made the mistake of picking MBR and not GPT the first time but it led me down a rabbit hole of using the EFI Shell to boot from the USB because I couldn’t get the USB to show up in the BIOS boot selection.

OpenBSD booted (and rebooted) just fine but I realized that I would have to compile tailscale from scratch to get it working and it was available in the built-in binary package. Also, I generally prefer FreeBSD whenever possible. I find there is also greater availability of pre-compiled binaries for FreeBSD AMD than OpenBSD in Open Source projects.

[mfranz@evolvefsbsd13 ~]$ uname -a 
FreeBSD evolvefsbsd13 13.2-RELEASE FreeBSD 13.2-RELEASE releng/13.2-n254617-525ecfdad597 GENERIC amd64

Inside the Hardware

Make no mistake, this is ChromeBook grade (from 3–4 years ago) level hardware and you shouldn’t expect much from the Apollo Lake hardware first released in 2016!

CPU: Intel(R) Celeron(R) CPU N3450 @ 1.10GHz (1094.40-MHz K8-class CPU) 
  Origin="GenuineIntel"  Id=0x506c9  Family=0x6  Model=0x5c  Stepping=9 
  Features=0xbfebfbff<FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CLFLUSH,DTS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE> 
  Features2=0x4ff8ebbf<SSE3,PCLMULQDQ,DTES64,MON,DS_CPL,VMX,EST,TM2,SSSE3,SDBG,CX16,xTPR,PDCM,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,TSCDLT,AESNI,XSAVE,OSXSAVE,RDRAND> 
  AMD Features=0x2c100800<SYSCALL,NX,Page1GB,RDTSCP,LM> 
  AMD Features2=0x101<LAHF,Prefetch> 
  Structured Extended Features=0x2294e283<FSGSBASE,TSCADJ,SMEP,ERMS,NFPUSG,MPX,PQE,RDSEED,SMAP,CLFLUSHOPT,PROCTRACE,SHA> 
  Structured Extended Features3=0x2c000400<MD_CLEAR,IBPB,STIBP,ARCH_CAP> 
  XSAVE Features=0xf<XSAVEOPT,XSAVEC,XINUSE,XSAVES> 
  IA32_ARCH_CAPS=0x79<RDCL_NO,SKIP_L1DFL_VME,SSB_NO,MDS_NO> 
  VT-x: PAT,HLT,MTF,PAUSE,EPT,UG,VPID,VID,PostIntr 
  TSC: P-state invariant, performance statistics 
real memory  = 6442450944 (6144 MB) 
avail memory = 3894743040 (3714 MB)

But it does have 4 cores, compared to a Hyandai MiniPC (which I have as a Linux Desktop) which only has 2.

Vendor ID:               GenuineIntel 
  Model name:            Intel(R) Celeron(R) N4020 CPU @ 1.10GHz 
    CPU family:          6 
    Model:               122 
    Thread(s) per core:  1 
    Core(s) per socket:  2 
    Socket(s):           1 
    Stepping:            8 
    CPU max MHz:         2800.0000 
    CPU min MHz:         800.0000 
    BogoMIPS:            2188.80 
    Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse 
                         2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopolog 
                         y nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg  
                         cx16 xtpr pdcm sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave rdrand lahf_lm 3dnowprefetc 
                         h cpuid_fault cat_l2 cdp_l2 ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ 
                         ad fsgsbase tsc_adjust smep erms mpx rdt_a rdseed smap clflushopt intel_pt sha_ni xsaveopt xsavec xgetbv1 
                          xsaves dtherm ida arat pln pts umip rdpid md_clear arch_capabilities 
Virtualization features:  
  Virtualization:        VT-x

As you can see it has the necessarily virtualization features to run Linux KVM or bhyve which I wanted to do.

Believe it or not, ifconfig still works!

[mfranz@evolvefsbsd13 ~]$ ifconfig -a 
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384 
        options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6> 
        inet6 ::1 prefixlen 128 
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
        inet 127.0.0.1 netmask 0xff000000 
        groups: lo 
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL> 
ue0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500 
        options=280099<RXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,LINKSTATE,RXCSUM_IPV6> 
        ether d0:37:45:be:08:97 
        inet 192.168.12.197 netmask 0xffffff00 broadcast 192.168.12.255 
        media: Ethernet autoselect (1000baseT <full-duplex>) 
        status: active 
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> 
tailscale0: flags=8043<UP,BROADCAST,RUNNING,MULTICAST> metric 0 mtu 1280 
        options=80000<LINKSTATE> 
        inet 100.113.44.142 netmask 0xffffffff broadcast 100.113.44.142 
        inet6 fd7a:115c:a1e0:ab12:4843:cd96:6271:2c8e prefixlen 48 
        groups: tun 
        nd6 options=101<PERFORMNUD,NO_DAD> 
        Opened by PID 1176 
tap0: flags=8902<BROADCAST,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500 
        options=80000<LINKSTATE> 
        ether 58:9c:fc:00:6b:36 
        groups: tap 
        media: Ethernet autoselect 
        status: no carrier 
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL> 
bridge0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 
        ether 58:9c:fc:10:0b:0c 
        id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15 
        maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200 
        root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0 
        member: tap0 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP> 
                ifmaxaddr 0 port 4 priority 128 path cost 2000000 
        member: ue0 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP> 
                ifmaxaddr 0 port 2 priority 128 path cost 20000 
        groups: bridge 
        nd6 options=9<PERFORMNUD,IFDISABLED>

I’ve been using the USB Gigabit Ethernet interface (since it doesn’t have an RJ-45) with no issues

root@evolvefsbsd13:~ # usbconfig 
ugen0.1: <Intel XHCI root HUB> at usbus0, cfg=0 md=HOST spd=SUPER (5.0Gbps) pwr=SAVE (0mA) 
ugen0.2: <Quectel EC25-AF> at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (500mA) 
ugen0.3: <Generic USB2.0-CRW> at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (500mA) 
ugen0.4: <Realtek 802.11n WLAN Adapter> at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (500mA) 
ugen0.5: <vendor 0x058f USB 2.0 Camera> at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (200mA) 
ugen0.6: <TP-LINK USB 10/100/1000 LAN> at usbus0, cfg=0 md=HOST spd=SUPER (5.0Gbps) pwr=ON (64mA)

I have not tried to get the built-in wireless card working, yet.

The Base Packages

FreeBSD package management has come a long way. You really don’t have to mess with Ports anymore, which is fine with me!

root@evolvefsbsd13:~ # pkg info 
bash-5.2.15                    GNU Project's Bourne Again SHell 
ca_root_nss-3.93               Root certificate bundle from the Mozilla Project 
gettext-runtime-0.22_1         GNU gettext runtime libraries and programs 
htop-3.2.2_1                   Better top(1) - interactive process viewer 
indexinfo-0.3.1                Utility to regenerate the GNU info page index 
mosh-1.4.0                     Mobile terminal that supports intermittent connectivity 
perl5-5.34.1_3                 Practical Extraction and Report Language 
pkg-1.20.8                     Package manager 
protobuf-3.21.12,1             Data interchange format library 
readline-8.2.1                 Library for editing command lines as they are typed 
tailscale-1.54.0               Mesh VPN that makes it easy to connect your devices

Given the Python 3.9 ended up being broken (see below) I needed to install 3.11 to get the Datasette LLM CLI to work.

[mfranz@evolvefsbsd13 ~]$ pkg info | grep 311 
py311-setuptools-63.1.0_1      Python packages installer 
py311-sqlite3-3.11.5_7         Standard Python binding to the SQLite3 library (Python 3.11) 
python311-3.11.5               Interpreted object-oriented programming languagePython 3.11)

To get AWS CLIv2 to work you’ll need Linux binaries

[mfranz@evolvefsbsd13 ~]$ pkg info | grep linux 
linux_base-c7-7.9.2009_1       Base set of packages needed in Linux mode (Linux CentOS 7.9.2009)

A Config (or two) to Rule them All

One of the best things about FreeBSD is that you only have one config file (rc.conf) to touch.

[mfranz@evolvefsbsd13 ~]$ cat /etc/rc.conf 
hostname="evolvefsbsd13" 
ifconfig_ue0="DHCP" 
sshd_enable="YES" 
dumpdev="AUTO" 
zfs_enable="YES" 
tailscaled_enable="YES" 
telegraf_enable="YES" 
ntpd_enable="YES" 
linux_enable="YES"

I found the font size too large for the 1366x768 resolution so changed in loader.conf ignoring what ChatGPT told me about vidcontrol

[mfranz@evolvefsbsd13 ~]$ cat /boot/loader.conf 
kern.geom.label.disk_ident.enable="0" 
kern.geom.label.gptid.enable="0" 
cryptodev_load="YES" 
coretemp_load="YES" 
zfs_load="YES" 
screen.font="8x16"

Just How Slow is It?

Based on building a TUI monitoring tool called Bottom the N3450 is only half as fast the the N4020 talking almost 1000 seconds to download and compile about 180 libraries and build the bottom binary.

cargo install bottom
Rust compilation benchmarks

What does ChatGPT Know?

[mfranz@evolvefsbsd13 ~]$ llm "Tell me about my operating system: $(uname -a)" 
Your operating system is FreeBSD 13.2-RELEASE. FreeBSD is a free and open-source Unix-like operating system that is based on the Berkeley Software Distribution (BSD). It is known for its stability, performance, and advanced networking capabilities. 
 
The specific version you are using is FreeBSD 13.2-RELEASE, which indicates it is a stable release of FreeBSD version 13.2. The "releng/13.2-n254617-525ecfdad 
597" portion refers to the specific release engineering branch and revision number. 
 
The term "GENERIC" signifies that you are using the generic version of the FreeBSD kernel, which is a default configuration suitable for a wide range of hardware. 
 
The architecture "amd64" indicates that your operating system is running on a 64-bit AMD or Intel processor. 
 
Overall, FreeBSD is a highly respected operating system preferred by many for its robustness and security features. It is commonly used in servers, networking 
 devices, embedded systems, and as a platform for research and development.

OpenTofu and AWS CLI v2

The binary just works for OpenTofu downloaded from https://github.com/opentofu/opentofu/releases

[mfranz@evolvefsbsd13 ~]$ tofu version 
OpenTofu v1.6.0-alpha5 
on freebsd_amd64

But AWS CLI requires Linux binary emulation to work as documented in https://layer77.net/2023/04/07/installing-aws-cli-tools-v2-on-freebsd-12-4/

Basically the solution is to install awscliv2 via pip3 and then run awscliv2 --install

[mfranz@evolvefsbsd13 ~]$ python3.11 -m pip install awscliv2 --user

After modifying the function install_multiplatoform() in installers.py

Then you can configure as normal and update PATH

[mfranz@evolvefsbsd13 ~]$ ~/.awscliv2/binaries/aws configure 
AWS Access Key ID [None]:

Running Kernel Modules

The only additional kernel modules I enable were for Linux binary compatibility and loading was handled by rc.conf configuration above.

root@evolvefsbsd13:~ # kldstat 
Id Refs Address                Size Name 
 1  115 0xffffffff80200000  1f3e2d0 kernel 
 2    1 0xffffffff8213f000   59dfa8 zfs.ko 
 3    1 0xffffffff826dd000     3728 coretemp.ko 
 4    1 0xffffffff826e1000     a4a0 cryptodev.ko 
 5    1 0xffffffff82f18000     3250 ichsmb.ko 
 6    1 0xffffffff82f1c000     2180 smbus.ko 
 7    1 0xffffffff82f1f000     5ecc ig4.ko 
 8    1 0xffffffff82f25000     6660 u3g.ko 
 9    1 0xffffffff82f2c000     4d90 ucom.ko 
10    1 0xffffffff82f31000     8500 if_ure.ko 
11    1 0xffffffff82f3a000     3178 uether.ko 
12    1 0xffffffff82f3e000     4d00 ng_ubt.ko 
13    6 0xffffffff82f43000     aac8 netgraph.ko 
14    2 0xffffffff82f4e000     a238 ng_hci.ko 
15    4 0xffffffff82f59000     25a8 ng_bluetooth.ko 
16    1 0xffffffff82f5c000     3220 iichid.ko 
17    5 0xffffffff82f60000     31f8 hidbus.ko 
18    1 0xffffffff82f64000     e250 ng_l2cap.ko 
19    1 0xffffffff82f73000    1bee8 ng_btsocket.ko 
20    1 0xffffffff82f8f000     39c0 ng_socket.ko 
21    1 0xffffffff82f93000     21e8 hms.ko 
22    1 0xffffffff82f96000     30a8 hidmap.ko 
23    1 0xffffffff82f9a000     3328 hmt.ko 
24    1 0xffffffff82f9e000     22b0 hconf.ko 
25    1 0xffffffff82fa1000     2a08 mac_ntpd.ko 
26    1 0xffffffff82fa4000    2dca0 linux64.ko 
27    4 0xffffffff82fd2000     be88 linux_common.ko 
28    1 0xffffffff82fde000    14b98 netlink.ko 
29    1 0xffffffff82ff3000    31a80 linux.ko 
30    1 0xffffffff83025000     2260 pty.ko 
31    1 0xffffffff83028000     3530 fdescfs.ko 
32    1 0xffffffff8302c000     73b0 linprocfs.ko 
33    1 0xffffffff83034000     3284 linsysfs.ko

Things that (I) Broke

One of the main reasons to use non-popular operating system (No offense, BSD guys, I still love you, but the cloud killed you. You are largely irrelevant, now) is that there are rough edges. This is how Linux used to be in the 90s and 2000s but now is a relatively smooth experience. Back in the day, things breaking is what made you humble. It helped you learn how things work.

Automated Booting (on OpenBSD)

I initially installed did whole disk MBR when blowing away the Windows partitions with fdisk, which caused it to fail into the EFI Shell. When Installed OpenBSD the second time with GPT it worked and no issues with FreeBSD.

Time Sync and Telegraf

During the initial install session, I manually set the clock and didn’t set the time correctly to Local or UTC. As a result my telegraf metrics didn’t show up correctly due to a mismatch with my InfluxDB Server

As soon as as I did the ntpdate dance to set the clock properly, it just worked, but I was stumped that all my metrics were a flat line and I didn’t realize it was a time issue until the next morning when I saw the previous day’s metrics (when I was building Python wheel’s from source) rendered properly.

Python Package Compilation (OpenAI dependencies)

The OpenAI Python SDK requires a number of libraries that on Linux are just pulled in as pre-compiled wheels, but on FreeBSD (even amd64) they had to compiled. I did not time the llm install but easily took 45 minutes to an hour after I realized that Pydantic needed cargo/rust installed (which just worked from pkg )

Python 3.9 and SQLite3

After finally getting llm to install (after all the OpenAI Rust libraries finally completed compiling) I got an error like this.

[mfranz@evolvefsbsd13 ~]$ python3.9 
Python 3.9.18 (main, Nov  9 2023, 01:19:38) 
[Clang 14.0.5 (https://github.com/llvm/llvm-project.git llvmorg-14.0.5-0-gc1238 on freebsd13 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import sqlite3 
Traceback (most recent call last): 
  File "<stdin>", line 1, in <module> 
  File "/usr/local/lib/python3.9/sqlite3/__init__.py", line 57, in <module> 
    from sqlite3.dbapi2 import * 
  File "/usr/local/lib/python3.9/sqlite3/dbapi2.py", line 27, in <module> 
    from _sqlite3 import * 
ModuleNotFoundError: No module named '_sqlite3'

And with 3.11 it just works.

[mfranz@evolvefsbsd13 ~]$ python3.11 
Python 3.11.5 (main, Nov  9 2023, 04:18:19) [Clang 14.0.5 (https://github.com/llvm/llvm-project.git llvmorg-14.0.5-0-gc12386 on freebsd13 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import sqlite3 
>>>

Racked & Stacked (UPS and all)

I’ll probably move this down to the basement eventually, but for now, I’ve got it perfrectly racked and cabled under my desk! BTW, one of the best things about using laptops as “servers” is that they have built-in battery backup (assuming the battery is still) good!

This is not an ad for Brooks or Baseboarders!