diff options
| author | Jan Tuomi <jan@jantuomi.fi> | 2026-01-05 21:15:44 +0200 |
|---|---|---|
| committer | Jan Tuomi <jan@jantuomi.fi> | 2026-01-05 21:39:06 +0200 |
| commit | 09e410b21358e1475261499ccf6a75fac2da12d4 (patch) | |
| tree | 26bde85dbe6be7502d1eca29263e404e92633f94 /content/posts/home-server-part-3 | |
| parent | b2b9388f789c58a5b6ee1cbf9edfe88013d3fc63 (diff) | |
Refactor and colocate assets
Diffstat (limited to 'content/posts/home-server-part-3')
| -rw-r--r-- | content/posts/home-server-part-3/index.md | 77 | ||||
| -rw-r--r-- | content/posts/home-server-part-3/pursotin_fastfetch.png | bin | 0 -> 285448 bytes | |||
| -rw-r--r-- | content/posts/home-server-part-3/pursotin_raidz.svg | 1 |
3 files changed, 78 insertions, 0 deletions
diff --git a/content/posts/home-server-part-3/index.md b/content/posts/home-server-part-3/index.md new file mode 100644 index 0000000..0b553ba --- /dev/null +++ b/content/posts/home-server-part-3/index.md @@ -0,0 +1,77 @@ +--- +title: "A home server journey, part 3: Installation" +date: 2025-12-23 +description: | + This is the third episode in a series where I set up a FreeBSD home server, explaining all the steps, problems and solutions along the way. This time we're installing the OS for the first time. +extra: + kind: note +--- + +This is the third episode in a series where I set up a FreeBSD home server, explaining all the steps, problems and solutions along the way. This time we're installing the OS for the first time. + +Check out episodes [1](/posts/home-server-part-1) and [2](/posts/home-server-part-2). + +{{ toc() }} + +## Installing FreeBSD + +Installation should be pretty straightforward. I'm going to go with the latest stable release installer (`14.3-RELEASE`) in the `amd64` + `memstick.iso` variety. Let's burn the installer onto a memory stick, plug it in, and was enter the install wizard. + +> Note from the future! `15.0-RELEASE` is already out, and I have recently updated to it. This post is already outdated! + +The initial idea is this: + +- ZFS, for all the automatic durability gains and easy-to-setup RAID1+0 (stripe of mirrors) +- encrypted ZFS datasets (kinda similar to partitions) for **jails**, which would contain all the actual services +- unencrypted root, so that I can reboot the machine remotely, physically unattended + +> [Jails](https://docs.freebsd.org/en/books/handbook/jails/) are a lightweight way to containerize applications. They can get a separate process space, network stack, file system, root user, among others. They use the same kernel as the host, so they are more similar to LXC or OCI containers (think Docker, but more mature and flexible) than to virtual machines, which in FreeBSD are managed with [bhyve](https://docs.freebsd.org/en/books/handbook/virtualization/#virtualization-host-bhyve). +> +> Teaser: we will be installing `bhyve` later too. + +Using the install wizard, I set up the system following my rough plan. And here we go, all up and running: + +{{ fig(src="pursotin_fastfetch.png", alt="Fastfetch output showing the machine specs. Disregard the uptime (I took the screenshot way later)") }} + +### RAIDZ + +You might notice that I bought 4 x 1 TB of NVMe disks, but `fastfetch` is only showing ~2TB. That's because I set up the disks into a "RAID 1+0" configuration: + +{{ fig(src="pursotin_raidz.svg", alt='A "RAID 1+0" configuration') }} + +RAID 1+0 is a combination of two RAID levels. RAID 1, or _mirror_, consumes two disks to produce one virtual disk that has the capacity of only one physical disk but can withstand the loss of either one. ZFS can automatically heal missing data in a member of a mirror by copying it over from the healthy member. RAID 0, or _stripe_, consumes two disks to produce a disk that has the capacity of the sum of its member capacities as well as double I/O speed, but fails if either member disk fails. The combination of these is a useful way to get increased speed and increased durability at the price of half your raw capacity. + +## Threat profile and encryption + +To figure out what level and what kind of at-rest encryption I need, I need to stop and think about the threat model. + +Scenario A, _online intruder_. An attacker that gains shell access can exfiltrate any data that the user has access to, since the decryption key has been activated at boot. At-rest encryption won't help here. + +Scenario B, _burglar_. An intruder grabs the machine and brings it to a place where they can inspect the disks, possibly with sophisticated recovery tools. + +- In a non-encrypted-root install, everything outside the encrypted jails is instantly accessible. Stored API keys and similar secrets leak. The administrator must take great care not to keep _anything_ of value on the unencrypted partition(s), and store everything in encrypted datasets. +- An encrypted root would be safe from this attack, assuming the cryptography used in the encryption is bulletproof. + +Scenario C, _evil maid attack_. A friend, spouse or similar tampers with the unattended physical system. Illegitimate access is blocked by requiring login and keeping the credentials in my personal vault. If the whole disk is encrypted, the worst thing the attacker can do is cause temporary harm and possibly data loss by powering off the system. If not, the attacker can do all kinds of nasty things, like booting a live environment and copying the disk contents, replacing the kernel/bootloader, installing malware etc. + +## Conclusion + +It makes sense to encrypt the whole thing. + +⚠️ But wait a minute! This is against my initial idea: + +> unencrypted root, so that I can reboot the machine remotely, physically unattended + +Encrypting the whole disk loses the ability to do unattended reboots. A bit inconvenient, but it is what it is. I'll just make sure to only reboot when I'm physically near the machine, which should be often, considering I work from home and the server is, uh, right there. + +Because of this architectural change, I ended up installing FreeBSD for a second time, now with full disk encryption. + +## System disk? + +Sometimes a separate small system disk is used in addition to a redundant array of "data disks". I decided to not pursue this setup, since then the system would not benefit from the RAIDZ redundancy and self-healing capabilities. In fact, I'd imagine that the ability to repair the OS and packages is even more important to me than repairing bulk data. + +I decided to keep the system next to the data on the disks (a "traditional" install). + +## To be continued + +In the next part(s) we will be looking at networking. I had some – let's say curious – issues with DHCP leases from the ISP. We'll also take a look at my jail setup. diff --git a/content/posts/home-server-part-3/pursotin_fastfetch.png b/content/posts/home-server-part-3/pursotin_fastfetch.png Binary files differnew file mode 100644 index 0000000..241f5e9 --- /dev/null +++ b/content/posts/home-server-part-3/pursotin_fastfetch.png diff --git a/content/posts/home-server-part-3/pursotin_raidz.svg b/content/posts/home-server-part-3/pursotin_raidz.svg new file mode 100644 index 0000000..d2942ac --- /dev/null +++ b/content/posts/home-server-part-3/pursotin_raidz.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:lucid="lucid" width="592" height="289.33"><g transform="translate(-889.0000000000001 -251.66666666666669)" lucid:page-tab-id="jJFWJm6nolyj"><path d="M890 473.33a6 6 0 0 1 6-6h98a6 6 0 0 1 6 6V534a6 6 0 0 1-6 6h-98a6 6 0 0 1-6-6z" stroke="#282c33" stroke-width="2" fill="#fff"/><use xlink:href="#a" transform="matrix(1,0,0,1,895.0000000000001,472.33333333333337) translate(19.19753086419753 37.46527777777778)"/><use xlink:href="#b" transform="matrix(1,0,0,1,895.0000000000001,472.33333333333337) translate(68.45679012345678 37.46527777777778)"/><path d="M1040 473.33a6 6 0 0 1 6-6h98a6 6 0 0 1 6 6V534a6 6 0 0 1-6 6h-98a6 6 0 0 1-6-6z" stroke="#282c33" stroke-width="2" fill="#fff"/><use xlink:href="#a" transform="matrix(1,0,0,1,1045,472.33333333333337) translate(19.19753086419753 37.46527777777778)"/><use xlink:href="#c" transform="matrix(1,0,0,1,1045,472.33333333333337) translate(68.45679012345678 37.46527777777778)"/><path d="M1220 473.33a6 6 0 0 1 6-6h98a6 6 0 0 1 6 6V534a6 6 0 0 1-6 6h-98a6 6 0 0 1-6-6z" stroke="#282c33" stroke-width="2" fill="#fff"/><use xlink:href="#a" transform="matrix(1,0,0,1,1225,472.3333333333333) translate(19.19753086419753 37.46527777777778)"/><use xlink:href="#d" transform="matrix(1,0,0,1,1225,472.3333333333333) translate(68.45679012345678 37.46527777777778)"/><path d="M1370 473.33a6 6 0 0 1 6-6h98a6 6 0 0 1 6 6V534a6 6 0 0 1-6 6h-98a6 6 0 0 1-6-6z" stroke="#282c33" stroke-width="2" fill="#fff"/><use xlink:href="#a" transform="matrix(1,0,0,1,1375,472.3333333333333) translate(19.19753086419753 37.46527777777778)"/><use xlink:href="#e" transform="matrix(1,0,0,1,1375,472.3333333333333) translate(68.45679012345678 37.46527777777778)"/><path d="M890 366a6 6 0 0 1 6-6h248a6 6 0 0 1 6 6v68a6 6 0 0 1-6 6H896a6 6 0 0 1-6-6z" stroke="#282c33" stroke-width="2" fill="#f2f3f5"/><use xlink:href="#f" transform="matrix(1,0,0,1,895.0000000000001,365) translate(86.88271604938272 39.65277777777778)"/><use xlink:href="#b" transform="matrix(1,0,0,1,895.0000000000001,365) translate(150.7716049382716 39.65277777777778)"/><path d="M1220 366a6 6 0 0 1 6-6h248a6 6 0 0 1 6 6v68a6 6 0 0 1-6 6h-248a6 6 0 0 1-6-6z" stroke="#282c33" stroke-width="2" fill="#f2f3f5"/><use xlink:href="#f" transform="matrix(1,0,0,1,1225,365) translate(86.88271604938272 39.65277777777778)"/><use xlink:href="#c" transform="matrix(1,0,0,1,1225,365) translate(150.7716049382716 39.65277777777778)"/><path d="M890 258.67a6 6 0 0 1 6-6h578a6 6 0 0 1 6 6v68a6 6 0 0 1-6 6H896a6 6 0 0 1-6-6z" stroke="#282c33" stroke-width="2" fill="#fff"/><use xlink:href="#g" transform="matrix(1,0,0,1,895.0000000000001,257.6666666666667) translate(261.04938271604937 39.65277777777778)"/><path d="M945 465.83v-8.45" stroke="#3a414a" fill="none"/><path d="M945.48 466.33h-.96v-.5h.96z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M945 442.62l4.63 14.26h-9.26z" stroke="#3a414a" fill="#3a414a"/><path d="M1095 465.83v-8.45" stroke="#3a414a" fill="none"/><path d="M1095.47 466.33h-.94v-.5h.94z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1095 442.62l4.63 14.26h-9.27z" stroke="#3a414a" fill="#3a414a"/><path d="M1275 465.83v-8.45" stroke="#3a414a" fill="none"/><path d="M1275.47 466.33h-.94v-.5h.94z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1275 442.62l4.63 14.26h-9.27z" stroke="#3a414a" fill="#3a414a"/><path d="M1425 465.83v-8.45" stroke="#3a414a" fill="none"/><path d="M1425.47 466.33h-.94v-.5h.94z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1425 442.62l4.63 14.26h-9.27z" stroke="#3a414a" fill="#3a414a"/><path d="M1020 358.5v-8.45" stroke="#3a414a" fill="none"/><path d="M1020.48 359h-.96v-.5h.96z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1020 335.3l4.63 14.25h-9.27z" stroke="#3a414a" fill="#3a414a"/><path d="M1350 358.5v-8.45" stroke="#3a414a" fill="none"/><path d="M1350.47 359h-.94v-.5h.94z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1350 335.3l4.63 14.25h-9.27z" stroke="#3a414a" fill="#3a414a"/><defs><path fill="#3a414a" d="M30-248c118-7 216 8 213 122C240-48 200 0 122 0H30v-248zM63-27c89 8 146-16 146-99s-60-101-146-95v194" id="h"/><path fill="#3a414a" d="M24-231v-30h32v30H24zM24 0v-190h32V0H24" id="i"/><path fill="#3a414a" d="M135-143c-3-34-86-38-87 0 15 53 115 12 119 90S17 21 10-45l28-5c4 36 97 45 98 0-10-56-113-15-118-90-4-57 82-63 122-42 12 7 21 19 24 35" id="j"/><path fill="#3a414a" d="M143 0L79-87 56-68V0H24v-261h32v163l83-92h37l-77 82L181 0h-38" id="k"/><g id="a"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#h"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#i"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.864197530864196,0)" xlink:href="#j"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,31.975308641975307,0)" xlink:href="#k"/></g><path fill="#3a414a" d="M101-251c68 0 85 55 85 127S166 4 100 4C33 4 14-52 14-124c0-73 17-127 87-127zm-1 229c47 0 54-49 54-102s-4-102-53-102c-51 0-55 48-55 102 0 53 5 102 54 102" id="l"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#l" id="b"/><path fill="#3a414a" d="M27 0v-27h64v-190l-56 39v-29l58-41h29v221h61V0H27" id="m"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#m" id="c"/><path fill="#3a414a" d="M101-251c82-7 93 87 43 132L82-64C71-53 59-42 53-27h129V0H18c2-99 128-94 128-182 0-28-16-43-45-43s-46 15-49 41l-32-3c6-41 34-60 81-64" id="n"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#n" id="d"/><path fill="#3a414a" d="M126-127c33 6 58 20 58 59 0 88-139 92-164 29-3-8-5-16-6-25l32-3c6 27 21 44 54 44 32 0 52-15 52-46 0-38-36-46-79-43v-28c39 1 72-4 72-42 0-27-17-43-46-43-28 0-47 15-49 41l-32-3c6-42 35-63 81-64 48-1 79 21 79 65 0 36-21 52-52 59" id="o"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#o" id="e"/><path fill="#3a414a" d="M240 0l2-218c-23 76-54 145-80 218h-23L58-218 59 0H30v-248h44l77 211c21-75 51-140 76-211h43V0h-30" id="p"/><path fill="#3a414a" d="M114-163C36-179 61-72 57 0H25l-1-190h30c1 12-1 29 2 39 6-27 23-49 58-41v29" id="q"/><path fill="#3a414a" d="M100-194c62-1 85 37 85 99 1 63-27 99-86 99S16-35 15-95c0-66 28-99 85-99zM99-20c44 1 53-31 53-75 0-43-8-75-51-75s-53 32-53 75 10 74 51 75" id="r"/><g id="f"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.456790123456788,0)" xlink:href="#i"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,23.33333333333333,0)" xlink:href="#q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.679012345679006,0)" xlink:href="#q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,38.02469135802468,0)" xlink:href="#r"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.37037037037036,0)" xlink:href="#q"/></g><path fill="#3a414a" d="M185-189c-5-48-123-54-124 2 14 75 158 14 163 119 3 78-121 87-175 55-17-10-28-26-33-46l33-7c5 56 141 63 141-1 0-78-155-14-162-118-5-82 145-84 179-34 5 7 8 16 11 25" id="s"/><path fill="#3a414a" d="M59-47c-2 24 18 29 38 22v24C64 9 27 4 27-40v-127H5v-23h24l9-43h21v43h35v23H59v120" id="t"/><path fill="#3a414a" d="M115-194c55 1 70 41 70 98S169 2 115 4C84 4 66-9 55-30l1 105H24l-1-265h31l2 30c10-21 28-34 59-34zm-8 174c40 0 45-34 45-75s-6-73-45-74c-42 0-51 32-51 76 0 43 10 73 51 73" id="u"/><path fill="#3a414a" d="M100-194c63 0 86 42 84 106H49c0 40 14 67 53 68 26 1 43-12 49-29l28 8c-11 28-37 45-77 45C44 4 14-33 15-96c1-61 26-98 85-98zm52 81c6-60-76-77-97-28-3 7-6 17-6 28h103" id="v"/><g id="g"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#s"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#t"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.98765432098765,0)" xlink:href="#q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.33333333333333,0)" xlink:href="#i"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,33.20987654320987,0)" xlink:href="#u"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,45.55555555555555,0)" xlink:href="#v"/></g></defs></g></svg>
\ No newline at end of file |
