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.
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.
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.
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
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!