aboutsummaryrefslogtreecommitdiff
path: root/post
diff options
context:
space:
mode:
authorKumar Damani <me@kumardamani.net>2026-07-24 04:29:08 +0000
committerKumar Damani <me@kumardamani.net>2026-07-24 04:29:08 +0000
commit3d615f7b4c19abf34f23ff09ea587a597f2de42a (patch)
tree10a0e4c3e0fa2c9b0254bb1826ae89f67fbc7df0 /post
parent62fcd12a0a1ea557334dec1fa0cfdce69d003bd8 (diff)
converted to typst
Diffstat (limited to 'post')
-rw-r--r--post/framework-server-p2.typ104
-rwxr-xr-xpost/framework-server-p2/current-lab.jpgbin0 -> 37401 bytes
-rwxr-xr-xpost/framework-server-p2/ethernet.pngbin0 -> 110306 bytes
-rwxr-xr-xpost/framework-server-p2/server-front.pngbin0 -> 87328 bytes
-rwxr-xr-xpost/framework-server-p2/server-inside.pngbin0 -> 221831 bytes
-rw-r--r--post/framework-server.typ558
-rwxr-xr-xpost/framework-server/bios.jpgbin0 -> 162196 bytes
-rwxr-xr-xpost/framework-server/bios2.pngbin0 -> 289613 bytes
-rwxr-xr-xpost/framework-server/case.jpgbin0 -> 111978 bytes
-rwxr-xr-xpost/framework-server/dmz.pngbin0 -> 69096 bytes
-rwxr-xr-xpost/framework-server/dns.jpgbin0 -> 59205 bytes
-rwxr-xr-xpost/framework-server/dri.pngbin0 -> 9650 bytes
-rwxr-xr-xpost/framework-server/error.jpgbin0 -> 43548 bytes
-rwxr-xr-xpost/framework-server/eth.jpgbin0 -> 107918 bytes
-rwxr-xr-xpost/framework-server/fail.pngbin0 -> 164105 bytes
-rwxr-xr-xpost/framework-server/feelsbadman.pngbin0 -> 32798 bytes
-rwxr-xr-xpost/framework-server/fix1.pngbin0 -> 23658 bytes
-rwxr-xr-xpost/framework-server/fix2.pngbin0 -> 67102 bytes
-rwxr-xr-xpost/framework-server/fix3.pngbin0 -> 27163 bytes
-rwxr-xr-xpost/framework-server/fw1.pngbin0 -> 29985 bytes
-rwxr-xr-xpost/framework-server/fw2.pngbin0 -> 15422 bytes
-rwxr-xr-xpost/framework-server/imp.pngbin0 -> 341529 bytes
-rwxr-xr-xpost/framework-server/lab.pngbin0 -> 85363 bytes
-rwxr-xr-xpost/framework-server/lan.pngbin0 -> 87550 bytes
-rwxr-xr-xpost/framework-server/mistakes.jpgbin0 -> 62973 bytes
-rwxr-xr-xpost/framework-server/nas.jpgbin0 -> 139364 bytes
-rwxr-xr-xpost/framework-server/net1.pngbin0 -> 22726 bytes
-rwxr-xr-xpost/framework-server/net2.pngbin0 -> 21835 bytes
-rwxr-xr-xpost/framework-server/network.pngbin0 -> 55633 bytes
-rwxr-xr-xpost/framework-server/pbr.pngbin0 -> 14982 bytes
-rwxr-xr-xpost/framework-server/pbr1.pngbin0 -> 33683 bytes
-rwxr-xr-xpost/framework-server/pbr2.pngbin0 -> 8422 bytes
-rwxr-xr-xpost/framework-server/pfnet.pngbin0 -> 9831 bytes
-rwxr-xr-xpost/framework-server/physical.pngbin0 -> 79028 bytes
-rwxr-xr-xpost/framework-server/port1.pngbin0 -> 6063 bytes
-rwxr-xr-xpost/framework-server/port2.pngbin0 -> 44834 bytes
-rwxr-xr-xpost/framework-server/rproxy.pngbin0 -> 48318 bytes
-rwxr-xr-xpost/framework-server/ups.jpgbin0 -> 151532 bytes
-rwxr-xr-xpost/framework-server/vps.pngbin0 -> 30087 bytes
-rwxr-xr-xpost/framework-server/wg.pngbin0 -> 23335 bytes
-rwxr-xr-xpost/framework-server/wrtnet.pngbin0 -> 57663 bytes
-rwxr-xr-xpost/framework-server/wrtnet2.pngbin0 -> 12214 bytes
-rwxr-xr-xpost/framework-server/wtf.jpgbin0 -> 41867 bytes
-rw-r--r--post/listing-my-fav-advice.typ87
-rwxr-xr-xpost/listing-my-fav-advice/balance.jpgbin0 -> 18818 bytes
-rwxr-xr-xpost/listing-my-fav-advice/boss.jpgbin0 -> 122736 bytes
-rwxr-xr-xpost/listing-my-fav-advice/chewing.gifbin0 -> 735263 bytes
-rwxr-xr-xpost/listing-my-fav-advice/indulgence.jpgbin0 -> 78009 bytes
-rwxr-xr-xpost/listing-my-fav-advice/money.jpgbin0 -> 21475 bytes
-rw-r--r--post/nas-upgrade.typ148
-rwxr-xr-xpost/nas-upgrade/cockpit-lxc.pngbin0 -> 72110 bytes
-rwxr-xr-xpost/nas-upgrade/ethernet.pngbin0 -> 110306 bytes
-rwxr-xr-xpost/nas-upgrade/nas-chassis.pngbin0 -> 72957 bytes
-rwxr-xr-xpost/nas-upgrade/oldnas.pngbin0 -> 89215 bytes
-rwxr-xr-xpost/nas-upgrade/zfs-pool.pngbin0 -> 79343 bytes
-rw-r--r--post/nixos-p1.typ459
-rwxr-xr-xpost/nixos-p1/boot.pngbin0 -> 12893 bytes
-rwxr-xr-xpost/nixos-p1/dwl.pngbin0 -> 3082421 bytes
-rwxr-xr-xpost/nixos-p1/fox.jpgbin0 -> 30886 bytes
-rwxr-xr-xpost/nixos-p1/rice.pngbin0 -> 1670023 bytes
-rw-r--r--post/programming-as-art.typ98
-rwxr-xr-xpost/programming-as-art/code.pngbin0 -> 530926 bytes
-rwxr-xr-xpost/programming-as-art/math.pngbin0 -> 398307 bytes
-rwxr-xr-xpost/programming-as-art/teaching.pngbin0 -> 410632 bytes
-rwxr-xr-xpost/programming-as-art/wand.pngbin0 -> 356173 bytes
-rw-r--r--post/programs.typ103
-rwxr-xr-xpost/programs/dwl.pngbin0 -> 3082421 bytes
-rw-r--r--post/self-host.typ138
-rwxr-xr-xpost/self-host/6imv05.jpgbin0 -> 66020 bytes
-rwxr-xr-xpost/self-host/elections.jpgbin0 -> 97041 bytes
-rwxr-xr-xpost/self-host/freedom.jpgbin0 -> 300014 bytes
-rwxr-xr-xpost/self-host/office.pngbin0 -> 1443597 bytes
-rwxr-xr-xpost/self-host/police.jpgbin0 -> 190074 bytes
-rwxr-xr-xpost/self-host/why.jpgbin0 -> 110502 bytes
74 files changed, 1695 insertions, 0 deletions
diff --git a/post/framework-server-p2.typ b/post/framework-server-p2.typ
new file mode 100644
index 0000000..e40b8e7
--- /dev/null
+++ b/post/framework-server-p2.typ
@@ -0,0 +1,104 @@
+#import "/global/common.typ": *
+
+#let doc = [
+My process of converting my Framework server back into a laptop.
+
+My wife needs an upgrade from her 2015 MacBook Pro, but shelling out a cool
+\$1600 + tax for one of the shiny new _M_ MacBooks for the 16GB variant hardly
+seems an ideal proposition now that Apple has relinquished consideration of its
+customers who would prefer to amortize upgrades over the lifespan of a machine.
+It seems that leaving the Mac platform is our only consumer-friendly option,
+which avoids fighting a losing battle with Apple w.r.t. upgradability.
+
+#quote(block: true)[Framework has entered the chat.]
+
+Meanwhile, Framework seems to have upheld its promise of providing a path to
+long-term upgradability for its products. The new Ryzen mainboards being
+compatible with my original Framework 13 (2021) is an example of this. So at
+this point, I'm far more inclined to commit to the Framework ecosystem for my
+wife (and probably myself) than Apple.
+
+Other than the initial non-trivial pain of migrating her from macOS to Windows,
+she should have a substantially better user-experience running all of the Adobe
+crapware she wants on my old Framework.
+
+*The only problem is that my entire home-lab currently
+#pagelink("post/framework-server")[runs on my Framework].*
+
+Time to go shopping!
+
+= The Pledge
+
+We'll be using second-hand equipment as much as possible. After all, the point
+of all this is to avoid spending \$1600 on a new laptop. So we should be well
+under that to make it worthwhile.
+
+I picked these up from eBay:
+
+#fig("framework-server-p2/server-front.png", alt: "server front")
+#fig("framework-server-p2/ethernet.png", alt: "ethernet adapter")
+
+#table(
+ columns: 2,
+ [Part], [Price (shipped)],
+ [HP Z240 Workstation Intel Xeon 3.4GHz 16G RAM 180G SSD Nvidia K620], [\$150],
+ [Mellanox ConnectX-2 PCIe x8 10Gbe SFP+ network card], [\$23],
+)
+
+#quote(block: true)[
+ My Framework currently has 32GB of memory, and while this is much less, it
+ will still be okay with my current utilization for my current workload.
+]
+
+One nice thing about this case is that it would be possible to rack-mount this
+workstation sideways on a standard rack shelf if I decided to go that route in
+the future.
+
+Also, I don't presently have 10Gb networking equipment at home to plug anything
+into that network card, but I'm getting it now for future-proofing.
+
+IPMI would have been nice-to-have, but I decided that for this price, and the
+bonus of that Nvidia K620 was too good to pass up! This is an immediate upgrade
+from my current integrated Iris GPU on my Framework server.
+
+#fig("framework-server-p2/server-inside.png", alt: "server inside")
+
+All of my home-lab VMs, and LXC containers run within Proxmox. So I set up a
+fresh Proxmox here.
+
+Fortunately for me, `lspci` showed all the hardware on the first go. But to use
+(pass-through) the Nvidia GPU in my guests, I need to first set up the Proxmox
+host. See my git repo for what I did to make this work.
+
+= The Turn
+
+To make the migration of our services _less painful_, we utilize Proxmox's
+migration features. We just need to make sure our nodes are part of a cluster.
+
+*Create the cluster on the old node.* Then, from the new node, we *join* the
+existing cluster.
+
+#quote(block: true)[
+ Proxmox 8 will not let a node with existing guests join a cluster.
+]
+
+= The Prestige
+
+Now it really is as easy as selecting a VM or an LXC container, hitting the
+Migrate button, and watching your guest fly away to the new node! For guests
+with large OS disks, it takes a little longer to copy over since my network is
+slow. Eventually, I will use Ceph-backed VM storage to make this a
+zero-downtime op.
+
+In a few minutes, I could knock out all of my services. Refer to my gitlab
+project to see how I handled the Nvidia K60 pass-through to my Nextcloud AIO
+instance and Plex guests.
+
+Here's what my "rack" looks like now:
+
+#fig("framework-server-p2/current-lab.jpg", alt: "current lab")
+
+Once everything was back online, I powered down the old Framework server and
+re-installed it back onto its laptop chassis, bought a W10 license, and
+finished the rest of the installation.
+]
diff --git a/post/framework-server-p2/current-lab.jpg b/post/framework-server-p2/current-lab.jpg
new file mode 100755
index 0000000..d64be2e
--- /dev/null
+++ b/post/framework-server-p2/current-lab.jpg
Binary files differ
diff --git a/post/framework-server-p2/ethernet.png b/post/framework-server-p2/ethernet.png
new file mode 100755
index 0000000..f39110d
--- /dev/null
+++ b/post/framework-server-p2/ethernet.png
Binary files differ
diff --git a/post/framework-server-p2/server-front.png b/post/framework-server-p2/server-front.png
new file mode 100755
index 0000000..31e34da
--- /dev/null
+++ b/post/framework-server-p2/server-front.png
Binary files differ
diff --git a/post/framework-server-p2/server-inside.png b/post/framework-server-p2/server-inside.png
new file mode 100755
index 0000000..79e7139
--- /dev/null
+++ b/post/framework-server-p2/server-inside.png
Binary files differ
diff --git a/post/framework-server.typ b/post/framework-server.typ
new file mode 100644
index 0000000..4e9d5b6
--- /dev/null
+++ b/post/framework-server.typ
@@ -0,0 +1,558 @@
+#import "/global/common.typ": *
+
+#let doc = [
+How I re-purposed my Framework as a standalone server for my home-lab.
+
+#quote(block: true)[
+ This is not sponsored by Framework ... though I wish it were :)
+]
+
+= Primary Motivation
+
+I \#feelsbad for abusing my lowly NAS -
+
+#img("framework-server/feelsbadman.png", alt: "feelsbadman", width: "150px")
+
+Its not it's fault that its owner expected it to run Collabora Online while
+running all his other services without instantly crashing...
+
+#fig("framework-server/error.jpg", alt: "meme of error page")
+
+Did I learn anything? Basically a NAS should just do NAS things like worry
+about storage. Compute should be handled by something else.
+
+#quote(block: true)[Lesson learned.]
+
+= Secondary Motivation
+
+Battery life is an issue with this gen.
+
+For my personal laptop I'd want something that has "all day" battery like the
+newer gen Intels or Ryzens.
+
+My plan is to snag one of those when prices become more attractive and retrofit
+it into my now hollow laptop chassis.
+
+Isn't this the Framework
+#extlink("https://frame.work/ca/en/about#what-we-re-fixing")[mission]?
+
+#quote(block: true)[
+ "Even better, what we've done to enable repair also opens up upgradability
+ and customization. This lets you get exactly the product you need and
+ extends usable lifetime too."
+]
+
+= Idea
+
+Re-purpose my 99%-of-the-time idle personal Framework laptop which is already
+overkill for the remaining 1%-of-the-time tasks, to be a hypervisor server.
+
+Setup my home-lab services there, and provide data storage for those services
+over NFS from my NAS.
+
+I'll setup a dedicated "workstation" VM for those 1%-of-the-time tasks.
+
+#fig("framework-server/physical.png", alt: "physical architecture image")
+
+= Prior to starting!
+
+To avoid making the same mistakes I made, do the following *while the mainboard
+is still in the laptop chassis!*
+
+#fig("framework-server/mistakes.jpg", alt: "mistakes meme")
+
++ *Update your BIOS firmware to at least 3.17.* It is *impossible* to do so
+ once the battery is un-plugged from the board on older firmwares. I learned
+ this the hard-way. This update will provide the critical options below for
+ this process to be feasible.
++ In your BIOS settings, enable options for optimizing CPU performance over
+ battery life.
++ In your BIOS settings, enable "Standalone operation".
++ In your BIOS settings, under "Boot" enable the option to power-on on
+ power-attach.
+ #fig("framework-server/bios.jpg", alt: "bios image")
++ Install Proxmox VE. Since this will require a screen, and keyboard input, you
+ might as well do it now. See the #link(<hypervisor>)[hypervisor] section
+ below.
+
+#html.hr()
+
+= Build
+
+== Server
+
+I'm using my original
+#extlink("https://frame.work/ca/en/products/mainboard-11th-gen-intel-core?v=FRANFG000B")[Framework
+ 13] laptop.
+
+#fig("framework-server/case.jpg", alt: "case image")
+
+Its an i7-1165G7 - yes a "mobile" CPU. Am I asking for trouble? We'll see. Its
+more than powerful enough for me (for now).
+
+Alternatively you could build/use another server.
+
+If you are also using the Framework 13, then you'll want to make sure that you
+are running at least *BIOS 3.17*. See the #link(<issues>)[issues] section below
+about my troubles.
+
+== Case
+
+As you can see above, I opted for the
+#extlink("https://frame.work/ca/en/products/cooler-master-mainboard-case")[Coolermaster
+ Case] because honestly it looks cool.
+
+Alternatively, you could self-print the
+#extlink("https://github.com/FrameworkComputer/Framework-Laptop-13")[community]
+3D case or get someone else to print it.
+
+== Network Connectivity
+
+I opted for the 2.5G
+#extlink("https://frame.work/ca/en/products/ethernet-expansion-card")[ethernet
+ expansion card] from Framework.
+
+#fig("framework-server/eth.jpg", alt: "framework eth adapter image")
+
+I suppose one could also use a WiFi card, but it makes more sense to go wired
+in a 24/7 "on" configuration.
+
+Alternatively, most thunderbolt-ethernet dongles should do the job. You'd want
+to check that there are Linux drivers for it.
+
+Since I host a few publicly accessible services (this blog for example), I also
+need a public static IP under which an internet user can access these services.
+
+So I opt for a cheap VPS from
+#extlink("https://www.racknerd.com/kvm-vps")[Racknerd]. These are about a \$1/mo
+for a public IPv4 IP, and a decent amount of network bandwidth.
+
+#fig("framework-server/vps.png", alt: "racknerd vps pricing image")
+
+== Storage
+
+=== for VMs
+
+I used the 1TB NVME drive I had on my Framework.
+
+=== for Data
+
+_You should have a storage solution (NAS) in place already!_
+
+#fig("framework-server/nas.jpg", alt: "nas image")
+
+Setting this up is beyond the scope of this post. You can check out my DIY ZFS
+backed NAS setup
+#extlink("https://gitlab.com/kdam0/vps#nas-equipment")[here]. I've had no
+(storage related) issues with my NAS since its inception over a year ago.
+
+Then when I need to allocate space for a new service I do:
+
+```bash
+zfs create <pool>/<dataset>
+zfs set compression=on/off
+zfs set sharenfs="..." sharesmb=".."
+```
+
+Then when the time comes, configure the NFS mount on the client VM that
+requires access to this data store:
+
+```bash
+mount -t nfs hostname-of-your-nas:/mnt/pool/dataset /mnt/data
+```
+
+There are also many options for pre-made NAS appliances such as Synology.
+
+== Power
+
+Highly recommend a UPS such as
+#extlink("https://www.amazon.ca/APC-BE600M1-Back-Uninterrupted-Electronics-Computers/dp/B01FWAZEIU/ref=sr_1_6?crid=28ZH7JP9IYXPU&keywords=ups&qid=1690928556&sprefix=ups%2Caps%2C172&sr=8-6")[this].
+
+#fig("framework-server/ups.jpg", alt: "ups image")
+
+Even if you don't care about uptime, *you should care about data integrity*
+issues resulting from abrupt power-loss.
+
+A UPS should buy you enough time to power things down gracefully.
+
+= Hypervisor <hypervisor>
+
+I opted for
+#extlink("https://www.proxmox.com/en/proxmox-virtual-environment/overview")[Proxmox
+ VE] since v8 was just released, I've been itching to try it out. Now felt
+like the right time.
+
+There is also a Terraform
+#extlink("https://registry.terraform.io/providers/Telmate/proxmox/latest/docs")[provider]
+allowing provisioning of VMs, and LXC Containers through code. Neat!
+
+#quote(block: true)[
+ I recommend you do this *before* taking the mainboard out of the laptop
+ chassis as you will need to provide keyboard input, as well as see whats
+ going on the screen.
+]
+
+- Install it. I just followed the
+ #extlink("https://www.proxmox.com/en/proxmox-virtual-environment/get-started")[official
+ instructions].
+
+- Under your host (mine's `pve`), under System, Network, create a bridge
+ `vmbr0` with:
+
+#fig("framework-server/net1.png", alt: "proxmox net image")
+
+This will make your Proxmox host available in your home network. *Set this to
+something else if you like.*
+
+#quote(block: true)[
+ You should also reserve the corresponding IP in your home router for this
+ host.
+]
+
+While you're here, create another bridge `vmbr1` with `VLAN Aware` checked:
+
+#fig("framework-server/net2.png", alt: "proxmox net image")
+
+#quote(block: true)[
+ We are going to create our home-lab network primarily on `vmbr1`. Think of
+ `vmbr0` as a _management_ bridge.
+]
+
+= Network
+
+I always find it best to sort out networking *before* we start building stuff.
+
+Since I'm basically starting over, I want to do it properly. A few design
+goals:
+
++ I want segregation of my home-lab services from my non-home-lab hosts (my
+ "workstation" VM for example), as well as the rest of my home network.
++ I don't want to keep track of static IP leases, everything should be DHCP,
+ and DNS.
++ I want all traffic to/from my home-lab segment to be encrypted. Non-home-lab
+ traffic does not need to be encrypted.
++ I need some way to make these services publicly accessible over the internet.
+
+The first two goals necessitate a virtual firewall/router deployment capable of
+_selectively_ routing a segment of my network over a VPN.
+
+Here is what I would like:
+
+#fig("framework-server/network.png", alt: "network architecture")
+
+== Goals: 1,2
+
+At first I went with the popular pfSense VM. For a #link(<pfsense>)[few]
+reasons, I abandoned it quickly.
+
+#html.hr()
+
+Then I decided to try out OpenWRT, and boy am I glad I did.
+
+#html.hr()
+
+I gave it two networking interfaces, each `vbmrX` we created earlier:
+
+#fig("framework-server/pfnet.png", alt: "openwrt bridge image")
+
+- `vmbr0` will be used to access our router from the home-network. It will also
+ be how our router gets access to the internet. Aka. *WAN*.
+- `vmbr1` will be used to create various subnets for our home-lab. Aka. *LAN*.
+
+#quote(block: true)[
+ You should reserve another IP in your home router using the MAC address
+ generated for `net0`. This will be how to access your home-lab router from
+ your home network.
+]
+
+I was able to setup a network with a few VLANs:
+
+#fig("framework-server/wrtnet.png", alt: "openwrt network image")
+
+#quote(block: true)[
+ This means that the next time we create a new VM or LXC container, we can
+ place it on `vmbr1`, with a particular VLAN Tag/`id` and it will start with
+ the corresponding IP for that network.
+]
+
+Few observations:
+
+- The Luci web UI is much more minimal and to the point. The terminology used
+ for things are more in-line with what I'm familiar with.
+- Soon I had the segregation I was looking for thanks to Firewall settings:
+ #fig("framework-server/fw1.png", alt: "firewall settings image")
+- DHCP, *and* DNS working as expected.
+
+== Goals: 3
+
+Then I started working on setting up my VPN (Wireguard) remote on my VPS.
+
+- I followed the script from
+ #extlink("https://github.com/angristan/wireguard-install")[here]. Worked
+ flawlessly.
+- Added a peer through the script - my OpenWRT VM.
+- Setup a domain - eg. `vpn.mydomain.com` to point to my VPS's public IP.
+- Then I enabled the "DMZ" setting (but *not* "Advanced DMZ" - which is
+ probably the _real_ DMZ) on my home ISP router settings, and added my OpenWRT
+ VM to it.
+ #fig("framework-server/dmz.png", alt: "dmz image")
+- I also setup a port-forward for the Wireguard port 51820 from my ISP router
+ settings, to point to my OpenWRT VM's internal port 51820.
+ #fig("framework-server/port1.png", alt: "port forward image")
+
+After all that, I started setting up Wireguard on OpenWRT.
+
+- The corresponding OpenWRT package is called `luci-app-wireguard`.
+- This will give you the ability to create a Wireguard interface on OpenWRT.
+ #fig("framework-server/wg.png", alt: "wg menu image")
+
+- I followed the following excellent tutorial for setting up the Wireguard
+ interface, configured to use my VPS as its peer:
+ #extlink("https://www.youtube.com/watch?v=04q41GEPvKA")[Setting up Wireguard
+ on OpenWRT]
+- Created the new interface and added the firewall settings:
+ #fig("framework-server/wrtnet2.png", alt: "openwrt wg ifrace")
+ #fig("framework-server/fw2.png", alt: "firewall wg settings image")
+
+- As is, this will mean that *only* LAB will have internet access (using the
+ Wireguard interface) - which is not what I want. I still want other subnets
+ to be routed via *WAN*.
+
+*_If only there was a way to route by VLANs..._*
+
+#quote(block: true)[
+ This is known as VPN _split-tunnelling_, or _Policy based routing_.
+]
+
+Luckily OpenWRT has a way to accomplish exactly this with a package called
+`luci-app-pbr`. This will add the PBR setting to your menu:
+
+#fig("framework-server/pbr.png", alt: "pbr setting image")
+
+- I followed the following tutorial:
+ #extlink("https://www.youtube.com/watch?v=FN2qfxNIs2g")[Setting up PBR on
+ OpenWRT]
+
+- Set up the rule for my PBR:
+ #fig("framework-server/pbr2.png", alt: "pbr rule image")
+
+- The default interface is set to `wan`, so everything else should behave as
+ normal:
+ #fig("framework-server/pbr1.png", alt: "pbr global gateways image")
+
+However, it did take many trail & error sessions (see the
+#link(<pbr-dns-leakage>)[dns leakage issues] section below) to get this working
+exactly as I wanted.
+
+*In summary*,
+
+When I create a VM/container in my _Lab_ subnet,
+
+- its external IP is that of my VPS
+- when it reaches out to the internet, it goes through the Wireguard tunnel
+ encrypted, to the VPS, and out the VPS's ISP.
+ #fig("framework-server/lab.png", alt: "lab flow image")
+
+When I create a VM/container *not* in my Lab subnet,
+
+- its external IP is the same as my home-network's public IP
+- when it reaches out to the internet, it goes through my home ISP (NAT), just
+ like all other devices on my home-network.
+ #fig("framework-server/lan.png", alt: "lan flow image")
+
+PBR provides quite granular control over this, for example, if you run a Plex
+server, it frequently needs to access the `plex.tv` domain. You can choose to
+route any source going to `plex.tv` to route via the `wan` interface instead.
+
+== Goals: 4
+
+For publicly accessible services, I need to point their domains to my VPS. I
+use sub-domains, so this is just a matter of creating `CNAME` records for these
+services.
+
+Then we setup our Wireguard on the VPS to forward all 80,443 TCP traffic to our
+Wireguard on OpenWRT. We'd need to add these lines *in addition* to your
+existing VPS `wg0` interface config:
+
+```
+PostUp = iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 80 -j DNAT --to-destination <ip of your OpenWRT wg0>:80
+PostUp = iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 443 -j DNAT --to-destination <ip of your OpenWRT wg0>:443
+...
+PostDown = iptables -t nat -D PREROUTING -p tcp -i eth0 --dport 80 -j DNAT --to-destination <ip of your OpenWRT wg0>:80
+PostDown = iptables -t nat -D PREROUTING -p tcp -i eth0 --dport 443 -j DNAT --to-destination <ip of your OpenWRT wg0>:443
+```
+
+Then we also need to setup port-forwards for 80,443 on OpenWRT going to our
+Reverse Proxy VM/Container.
+
+#fig("framework-server/port2.png", alt: "port forwards image")
+
+I just setup a temporary Caddy container in reverse-proxy mode to test this
+out.
+
+#fig("framework-server/rproxy.png", alt: "reverse-proxy setup image")
+
+Once this works, we can move on to building out our services :)
+
+= Home Lab Services
+
+These are _some_ of the services I run ad LXC container:
+
+- #extlink("https://nextcloud.com/athome/")[Nextcloud] - files, and image
+ storage and sharing (thanks to the excellent
+ #extlink("https://apps.nextcloud.com/apps/memories")[Memories] app). I used
+ the official #extlink("https://github.com/nextcloud/all-in-one")[AIO]
+ install.
+- #extlink("https://www.plex.tv/")[Plex] - media streaming.
+- #extlink("https://github.com/dani-garcia/vaultwarden")[Vaultwarden] - a
+ self-hosted password manager based on Bitwarden.
+- A few static websites.
+
+How I set up these services is beyond the scope of this post. You should check
+out my git repo's #extlink("https://gitlab.com/kdam0/home-lab")[readme] for
+instructions. I will just briefly summarize my process here.
+
+- I use LXC wherever possible as it has lower overhead than VMs.
+- LXC or VM hosts are provisioned by Terraform and services are configured by
+ Ansible.
+
+One thing to note is that as of now, there is no automated way to pass-through
+my iGPU to my LXC containers that would benefit from this - such as Nextcloud
+(for Memories app), Plex etc.
+
+Instead you must edit the config on Proxmox for the corresponding container,
+and add the following lines and restart the container. Edit
+`/etc/pve/lxc/<id of your container>.conf`:
+
+```
+lxc.cgroup2.devices.allow: c 226:0 rwm
+lxc.cgroup2.devices.allow: c 226:128 rwm
+lxc.cgroup2.devices.allow: c 29:0 rwm
+lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir
+lxc.mount.entry: /dev/dri/renderD128 dev/renderD128 none bind,optional,create=file
+```
+
+Then inside your LXC container do `ls -al /dev/dri/` and you should see some
+devices.
+
+#fig("framework-server/dri.png", alt: "gpu devices image")
+
+= Issues <issues>
+
+== Intermittent connectivity loss with Framework
+
+- When I initially started this project, I had already installed Proxmox, and
+ my setup my networking while on BIOS 3.16.
+- However every couple of days (sometimes hours) I was observing loss of
+ connectivity to both my Proxmox host, and my virtual router.
+- When I plugged in a monitor to see what was going on, I saw a few messages on
+ the TTY regarding `usbX disconnected...`.
+- Unplugging and re-plugging in the ethernet card did not fix it.
+- Usually a hard reset was required to bring things back to normal.
+
+I've encountered issues with other Framework peripherals in the past, so I
+reached out to the Framework support folks, and they immediately suggested a
+BIOS update.
+
+So I proceeded to give that a shot from within Proxmox using `fwupmgr`:
+
+#fig("framework-server/fail.png", alt: "bios up fail image")
+
+And to my surprise it was complaining about _battery level_? Its not even
+connected to the battery...
+
+I brought this up to the support and they confirmed my fear that it was not
+possible to update the BIOS while having the battery detached. Yikes!
+
+This was a deal-breaker for this whole project, until they confirmed that once
+I was on 3.17, it would be possible to do future updates without the battery
+being connected.
+
+- So I went ahead and pretty much attached the whole thing back into the laptop
+ chassis
+- Updated to 3.17, and applied "Standalone operation"
+ #fig("framework-server/bios2.png", alt: "bios update image")
+
+- Thankfully, all my connectivity issues have gone away now.
+- Framework support service is excellent!
+
+== Intermittent loss of internet for hosts in Lab Vlan.
+
+This one kept me up for many nights. To summarize:
+
+- in a host in the Lab network, doing an `apt update` the first time would
+ hang, mid-way through
+- running it a few times again, would eventually succeed the operation
+ #fig("framework-server/wtf.jpg", alt: "wtf meme")
+
+Could it be DNS? Could it be PBR? Could it be Wireguard?
+
+After many hours of troubleshooting, I happened to have seen errors during a
+`tcpdump` session on my VPN interface.
+
+Something about `...need to fragment...`. DOH!
+
+- Lab internet access is via VPN (due to PBR).
+- *VPN remote interface has an MTU of 1420, not 1500.*
+- Proxmox `vmbr1` set MTU to 1500 by default.
+- Therefore all hosts in Lab have a MTU mismatch trying to get to the internet.
+
+#quote(block: true)[Fixed. It was not DNS... it was MTU.]
+
+== PBR DNS leakage <pbr-dns-leakage>
+
+The whole point having my Lab traffic go through Wireguard is to prevent my
+home ISP from knowing what I am up to. *DNS queries leaking to my ISP
+completely defeats this purpose!*
+
+Although my external IP would correctly report to being my VPS one, tests like
+#extlink("https://github.com/macvk/dnsleaktest")[this] would show that DNS was
+still being sent to my home ISP.
+
+#fig("framework-server/dns.jpg", alt: "dns meme image")
+
+To fix this, I had to:
+
+- *Un-check* setting default route on the Lab interface.
+ #fig("framework-server/fix1.png", alt: "dns fix 1 image")
+
+- Explicitly set DHCP DNS settings for my Lab gateway interface to use my VPS's
+ `wg0` interface IP.
+ #fig("framework-server/fix2.png", alt: "dns fix 2 image")
+
+- Needed a static route defied for the `wg0` interface targeting the VPN
+ network via the OpenWRT local IP for `wg0` as a gateway.
+ #fig("framework-server/fix3.png", alt: "dns fix 3 image")
+
+== pfSense <pfsense>
+
+Few observations:
+
+- Segregation was working how I wanted it to.
+- A few firewall rules were required to allow access to parts of my
+ home-network - NAS.
+- DHCP, worked out of the box.
+- However, DNS did not.
+
+I'm still not sure what the issue was, but it was probably something small.
+
+More importantly, I was quite overwhelmed with all the options in the UI for
+which I had no knowledge of.
+
+Also, everything in pfSense pretty much _requires_ a UI, which for now is fine,
+but I'd like the option to move to a more automation friendly configuration in
+the future.
+
+= Summary
+
+The Framework laptop is happily fulfilling its destiny as a compute server, and
+so is my NAS as a storage server.
+
+Since switching to this setup, I've observed a dramatic improvement in
+responsiveness for all of my services.
+
+#fig("framework-server/imp.png", alt: "improvement meme image")
+
+Overall I'm quite pleased with how everything turned out once the appropriate
+BIOS was running on the Framework.
+]
diff --git a/post/framework-server/bios.jpg b/post/framework-server/bios.jpg
new file mode 100755
index 0000000..76cda35
--- /dev/null
+++ b/post/framework-server/bios.jpg
Binary files differ
diff --git a/post/framework-server/bios2.png b/post/framework-server/bios2.png
new file mode 100755
index 0000000..094e37e
--- /dev/null
+++ b/post/framework-server/bios2.png
Binary files differ
diff --git a/post/framework-server/case.jpg b/post/framework-server/case.jpg
new file mode 100755
index 0000000..a40c172
--- /dev/null
+++ b/post/framework-server/case.jpg
Binary files differ
diff --git a/post/framework-server/dmz.png b/post/framework-server/dmz.png
new file mode 100755
index 0000000..372c12b
--- /dev/null
+++ b/post/framework-server/dmz.png
Binary files differ
diff --git a/post/framework-server/dns.jpg b/post/framework-server/dns.jpg
new file mode 100755
index 0000000..0b32528
--- /dev/null
+++ b/post/framework-server/dns.jpg
Binary files differ
diff --git a/post/framework-server/dri.png b/post/framework-server/dri.png
new file mode 100755
index 0000000..a578c79
--- /dev/null
+++ b/post/framework-server/dri.png
Binary files differ
diff --git a/post/framework-server/error.jpg b/post/framework-server/error.jpg
new file mode 100755
index 0000000..429eef8
--- /dev/null
+++ b/post/framework-server/error.jpg
Binary files differ
diff --git a/post/framework-server/eth.jpg b/post/framework-server/eth.jpg
new file mode 100755
index 0000000..f8ad12a
--- /dev/null
+++ b/post/framework-server/eth.jpg
Binary files differ
diff --git a/post/framework-server/fail.png b/post/framework-server/fail.png
new file mode 100755
index 0000000..f0e06db
--- /dev/null
+++ b/post/framework-server/fail.png
Binary files differ
diff --git a/post/framework-server/feelsbadman.png b/post/framework-server/feelsbadman.png
new file mode 100755
index 0000000..b1c2a26
--- /dev/null
+++ b/post/framework-server/feelsbadman.png
Binary files differ
diff --git a/post/framework-server/fix1.png b/post/framework-server/fix1.png
new file mode 100755
index 0000000..b36489e
--- /dev/null
+++ b/post/framework-server/fix1.png
Binary files differ
diff --git a/post/framework-server/fix2.png b/post/framework-server/fix2.png
new file mode 100755
index 0000000..5b64900
--- /dev/null
+++ b/post/framework-server/fix2.png
Binary files differ
diff --git a/post/framework-server/fix3.png b/post/framework-server/fix3.png
new file mode 100755
index 0000000..9af2433
--- /dev/null
+++ b/post/framework-server/fix3.png
Binary files differ
diff --git a/post/framework-server/fw1.png b/post/framework-server/fw1.png
new file mode 100755
index 0000000..72a95ee
--- /dev/null
+++ b/post/framework-server/fw1.png
Binary files differ
diff --git a/post/framework-server/fw2.png b/post/framework-server/fw2.png
new file mode 100755
index 0000000..cec00e1
--- /dev/null
+++ b/post/framework-server/fw2.png
Binary files differ
diff --git a/post/framework-server/imp.png b/post/framework-server/imp.png
new file mode 100755
index 0000000..c11b806
--- /dev/null
+++ b/post/framework-server/imp.png
Binary files differ
diff --git a/post/framework-server/lab.png b/post/framework-server/lab.png
new file mode 100755
index 0000000..6591a8b
--- /dev/null
+++ b/post/framework-server/lab.png
Binary files differ
diff --git a/post/framework-server/lan.png b/post/framework-server/lan.png
new file mode 100755
index 0000000..461d598
--- /dev/null
+++ b/post/framework-server/lan.png
Binary files differ
diff --git a/post/framework-server/mistakes.jpg b/post/framework-server/mistakes.jpg
new file mode 100755
index 0000000..d4b2e12
--- /dev/null
+++ b/post/framework-server/mistakes.jpg
Binary files differ
diff --git a/post/framework-server/nas.jpg b/post/framework-server/nas.jpg
new file mode 100755
index 0000000..75f5251
--- /dev/null
+++ b/post/framework-server/nas.jpg
Binary files differ
diff --git a/post/framework-server/net1.png b/post/framework-server/net1.png
new file mode 100755
index 0000000..a0a4eff
--- /dev/null
+++ b/post/framework-server/net1.png
Binary files differ
diff --git a/post/framework-server/net2.png b/post/framework-server/net2.png
new file mode 100755
index 0000000..c5ad118
--- /dev/null
+++ b/post/framework-server/net2.png
Binary files differ
diff --git a/post/framework-server/network.png b/post/framework-server/network.png
new file mode 100755
index 0000000..1b1fba6
--- /dev/null
+++ b/post/framework-server/network.png
Binary files differ
diff --git a/post/framework-server/pbr.png b/post/framework-server/pbr.png
new file mode 100755
index 0000000..2b1e330
--- /dev/null
+++ b/post/framework-server/pbr.png
Binary files differ
diff --git a/post/framework-server/pbr1.png b/post/framework-server/pbr1.png
new file mode 100755
index 0000000..4d7f075
--- /dev/null
+++ b/post/framework-server/pbr1.png
Binary files differ
diff --git a/post/framework-server/pbr2.png b/post/framework-server/pbr2.png
new file mode 100755
index 0000000..0a07839
--- /dev/null
+++ b/post/framework-server/pbr2.png
Binary files differ
diff --git a/post/framework-server/pfnet.png b/post/framework-server/pfnet.png
new file mode 100755
index 0000000..67cc5f4
--- /dev/null
+++ b/post/framework-server/pfnet.png
Binary files differ
diff --git a/post/framework-server/physical.png b/post/framework-server/physical.png
new file mode 100755
index 0000000..fc1cb81
--- /dev/null
+++ b/post/framework-server/physical.png
Binary files differ
diff --git a/post/framework-server/port1.png b/post/framework-server/port1.png
new file mode 100755
index 0000000..1b72ab1
--- /dev/null
+++ b/post/framework-server/port1.png
Binary files differ
diff --git a/post/framework-server/port2.png b/post/framework-server/port2.png
new file mode 100755
index 0000000..37ff887
--- /dev/null
+++ b/post/framework-server/port2.png
Binary files differ
diff --git a/post/framework-server/rproxy.png b/post/framework-server/rproxy.png
new file mode 100755
index 0000000..0d3f0bf
--- /dev/null
+++ b/post/framework-server/rproxy.png
Binary files differ
diff --git a/post/framework-server/ups.jpg b/post/framework-server/ups.jpg
new file mode 100755
index 0000000..4cd7aee
--- /dev/null
+++ b/post/framework-server/ups.jpg
Binary files differ
diff --git a/post/framework-server/vps.png b/post/framework-server/vps.png
new file mode 100755
index 0000000..7392495
--- /dev/null
+++ b/post/framework-server/vps.png
Binary files differ
diff --git a/post/framework-server/wg.png b/post/framework-server/wg.png
new file mode 100755
index 0000000..18896a0
--- /dev/null
+++ b/post/framework-server/wg.png
Binary files differ
diff --git a/post/framework-server/wrtnet.png b/post/framework-server/wrtnet.png
new file mode 100755
index 0000000..73d435d
--- /dev/null
+++ b/post/framework-server/wrtnet.png
Binary files differ
diff --git a/post/framework-server/wrtnet2.png b/post/framework-server/wrtnet2.png
new file mode 100755
index 0000000..34cd6b9
--- /dev/null
+++ b/post/framework-server/wrtnet2.png
Binary files differ
diff --git a/post/framework-server/wtf.jpg b/post/framework-server/wtf.jpg
new file mode 100755
index 0000000..995fefe
--- /dev/null
+++ b/post/framework-server/wtf.jpg
Binary files differ
diff --git a/post/listing-my-fav-advice.typ b/post/listing-my-fav-advice.typ
new file mode 100644
index 0000000..5984f97
--- /dev/null
+++ b/post/listing-my-fav-advice.typ
@@ -0,0 +1,87 @@
+#import "/global/common.typ": *
+
+#let doc = [
+I outline my favourite life advice, where I have heard it, and what it means to
+me.
+
+= Everything in moderation, including moderation.
+
+#table(
+ columns: 2,
+ stroke: none,
+ align: center,
+ img("listing-my-fav-advice/balance.jpg", alt: "balancing rocks"),
+ img("listing-my-fav-advice/indulgence.jpg", alt: "indulgence painting"),
+)
+
+I first heard this one from Kia, my Jitsu instructor at U of T. The first part
+is fairly self-explanatory. The second part says to moderate the moderation. In
+other words, on occasion, it is ok to indulge. After all, some of the best
+moments in life come from indulgence. Don't be the person who is always
+moderating, or you will miss out on 100% of those moments.
+
+This reminds me of a paradigm in Computation called
+#extlink("https://en.wikipedia.org/wiki/Reinforcement_learning")[Reinforcement
+ Learning] (RL), where learning is maximized by balancing existing knowledge,
+with occasional spurts of exploration. Without exploration, we find that we are
+generally unlikely to end up at an optimal solution, thus showing us its
+importance.
+
+If the objective of life is to attain long-term (cumulative) happiness, then we
+can say that moderation is the current knowledge, and occasional indulgence are
+the spurts of exploration, and both must be balanced in order to maximize our
+objective.
+
+= Chew your food. Well.
+
+#fig("listing-my-fav-advice/chewing.gif", alt: "chewing")
+
+This one I got from my grandparents, and it is quite underrated. We all know
+that our digestion health is such a large contributor to our overall
+well-being. Yet we religiously neglect the first step of the process - chewing.
+
+I specifically recall my grandpa saying "_chew it until it becomes a paste_".
+Gross but effective. No matter what your diet is composed of, its not debatable
+that chewing better will only ever help your digestion, never harm.
+
+Another benefit? Sitting down and consciously chewing requires time and effort.
+If you aren't doing it, maybe its a sign that you are rushing. Why are you
+rushing? Maybe its time to re-evaluate some things in your life.
+
+= Don't worry so much about budgeting, focus on earning more.
+
+#fig("listing-my-fav-advice/money.jpg", alt: "money bob ross")
+
+This one is somewhat controversial. I heard it from John Hill on the
+#extlink("https://podcasts.apple.com/us/podcast/super-hoopers-an-nba-podcast/id1053263719")[Super
+ Hoopers podcast], quoting some book. I think this stems from the notion that
+there is a hard limit to how much you can restrict your spending to - \$0. But
+no limit to how much you can earn. So why not focus on that?
+
+I think this is largely a time-management principle. Maybe you've heard the
+idiom "penny wise, and pound foolish". If money is the _penny_, then your time
+is the _pound_. Don't be foolish with your time.
+
+People often will go out of their way believing they are saving a certain
+amount of money but hardly ever factor in the value of the time spent saving
+that amount. And more often than not, that time is spent doing something that
+is not enjoyable.
+
+That same time could've been spent on trying to earn more money than what was
+saved or at the very least doing something actually enjoyable.
+
+= Never work for someone who you don't want to become.
+
+#fig("listing-my-fav-advice/boss.jpg", alt: "boss", width: "50%")
+
+This one has helped me substantially in my career. I believe I heard it from
+someone on Shark Tank (Mark Cuban? Mr. Wonderful? IIRC). More important than
+finding the right role/career is finding the right mentor. I've personally
+switched roles based on this advice, and I can attribute most my success as a
+direct result of this.
+
+We tend to emulate people that we are influenced by. By working for such a
+manager, you are setting yourself up to emulate someone you look up to - which
+is a great thing! I also consider this one of the few advantages of being an
+employee rather than an owner. Don't waste it!
+]
diff --git a/post/listing-my-fav-advice/balance.jpg b/post/listing-my-fav-advice/balance.jpg
new file mode 100755
index 0000000..ee5050c
--- /dev/null
+++ b/post/listing-my-fav-advice/balance.jpg
Binary files differ
diff --git a/post/listing-my-fav-advice/boss.jpg b/post/listing-my-fav-advice/boss.jpg
new file mode 100755
index 0000000..631a78a
--- /dev/null
+++ b/post/listing-my-fav-advice/boss.jpg
Binary files differ
diff --git a/post/listing-my-fav-advice/chewing.gif b/post/listing-my-fav-advice/chewing.gif
new file mode 100755
index 0000000..12b7d16
--- /dev/null
+++ b/post/listing-my-fav-advice/chewing.gif
Binary files differ
diff --git a/post/listing-my-fav-advice/indulgence.jpg b/post/listing-my-fav-advice/indulgence.jpg
new file mode 100755
index 0000000..446e3fb
--- /dev/null
+++ b/post/listing-my-fav-advice/indulgence.jpg
Binary files differ
diff --git a/post/listing-my-fav-advice/money.jpg b/post/listing-my-fav-advice/money.jpg
new file mode 100755
index 0000000..451ff7c
--- /dev/null
+++ b/post/listing-my-fav-advice/money.jpg
Binary files differ
diff --git a/post/nas-upgrade.typ b/post/nas-upgrade.typ
new file mode 100644
index 0000000..9b48839
--- /dev/null
+++ b/post/nas-upgrade.typ
@@ -0,0 +1,148 @@
+#import "/global/common.typ": *
+
+#let doc = [
+Doing it right this time.
+
+Until now I've been using a
+#extlink("https://pine64.org/devices/rockpro64/")[RockPro64] in the (excellent
+for starters) Pine64 #extlink("https://wiki.pine64.org/wiki/NASCase")[NAS case]
+for my NAS. It runs #extlink("https://www.armbian.com/rockpro64/")[Armbian],
+`openzfs`, and I manage my ZFS as needed on the CLI. I share my datasets over
+NFS to my Proxmox guest VMs for access. This has served me reasonably well for
+the past few years. But we have a baby coming soon, and along with that a
+flurry of new photos and videos for my family to store on my NAS. And although
+I _probably_ have enough buffer to survive the initial few months, I certainly
+wish to do better than my current 2xHDD mirrored pool giving me ~4TB of
+storage.
+
+#fig("nas-upgrade/oldnas.png", alt: "nas nas")
+
+= The Plan
+
+Luckily I already possess the hard-drives I need for my desired pool. In total,
+I have 2 HDDs from my current NAS, and 2 spares - all the same 4TB capacity.
+
+I still want to keep my current NAS running as a backup store, but I only need
+1 drive for this purpose (for now). That leaves me with 3 HDDs we can use for
+our new `raidz1` pool which would give me 2 drives for storage and 1 for
+parity.
+
+Now for the platform. I have been a very happy user of
+#extlink("https://www.proxmox.com/en/proxmox-virtual-environment/overview")[Proxmox]
+(on my compute node) and it already comes ready with ZFS support so I'll stick
+with that. I did consider #extlink("https://www.truenas.com")[TrueNAS] (both
+standalone, and virtualized within Proxmox with disk-passthrough), but when it
+comes to storage, I want as few surprises as possible so I stuck with what I
+know. I'm already used to ZFS on the CLI and Proxmox is based on Debian so
+if/when something goes wrong, I don't want to be messing around with an
+unfamiliar UI.
+
+Although I don't want to manage ZFS via a GUI, I'd like a way to manage
+_access_ to my datasets via a GUI.
+#extlink("https://cockpit-project.org")[Cockpit] seems like a good light-weight
+choice. It runs as an LXC container within Proxmox using bind-mounts for the
+dataset paths. I can then select which paths I allow access to over my network
+using NFS, and SMB protocols on a per-user basis.
+
+= Shopping
+
+Needs:
+
+- `>= 3` hot-swappable HDD bays
+- `>= 16` GB RAM (for ZFS)
+- runs Proxmox
+
+Wants:
+
+- IPMI
+- 1U
+- 10Gb networking
+
+On eBay, I ended up checking out with:
+
+#fig("nas-upgrade/nas-chassis.png", alt: "nas chassis")
+#fig("nas-upgrade/ethernet.png", alt: "ethernet adapter")
+
+#table(
+ columns: 2,
+ [Part], [Price (shipped)],
+ [1U 20" Short Depth Supermicro Server X9SCL-F XEON E3-1270 V2 16GB NIC Rails], [\$236],
+ [Mellanox ConnectX-2 PCIe x8 10Gbe SFP+ network card], [\$23],
+)
+
+which gave me everything I needed *and* wanted!
+
+= Build
+
+First I free one of my HDDs from my RockPro64 NAS for use in my new pool. This
+means I am running on a single HDD for the remainder of the migration.
+
+With the free HDD, and my two spares, I get everything assembled, and set up a
+new Proxmox node with a ZFS pool from the UI using the 3 disks.
+
+#fig("nas-upgrade/zfs-pool.png", alt: "proxmox zfs pool")
+
+= Sync
+
+To migrate all of my data from the old pool to the new pool I use
+#extlink("https://github.com/jimsalterjrs/sanoid/tree/master?tab=readme-ov-file#syncoid")[`syncoid`].
+It uses ZFS snapshots to accomplish this. It's awesome.
+
+This takes many hours depending on the size of your pool and your connection,
+but since I saw almost full utilization of my network link I was convinced it's
+the best I can do right now.
+
+I've seen in a few Reddit posts suggesting ways this can be optimized using
+some combination of `zfs send` with `mbuffer` rather than `ssh` which `syncoid`
+uses, but I'm happy with the convenience of `syncoid`.
+
+The best part is that everything can still be running while this is going on!
+This is because only the first sync takes a long time since it needs to copy
+_everything_ over. All subsequent syncs only transfer the delta since the last
+sync which should be pretty quick if your data does not change all that much.
+
+That being said, since I am now running on a single drive, and hitting it hard
+during sync, I do not want to stay in this state for any longer than I need to
+due to potentially leading my single disk to failure.
+
+Once the sync is complete, I do a second sync (for the delta), and promptly
+shut down all of my services to prepare for the cut-over.
+
+= Cockpit
+
+Before I can re-enable my services. I need to expose my datasets on Cockpit.
+
+I create a Debian LXC, and assign the generated MAC a static IP on my network.
+Other than that, I just make sure my container has the NFS feature enabled:
+
+#fig("nas-upgrade/cockpit-lxc.png", alt: "cockpit lxc features")
+
+Setting up user permissions is a pain, but once done I expose the relevant NFS
+as well as Samba paths for my services - replicating my old NAS's shared paths.
+
+= Voila
+
+In my homelab nameserver, I update the A record for my NAS to point to the new
+IP of my Cockpit LXC container, and start my services back up.
+
+I confirm everything is still good by turning off the old NAS, and yep still
+good.
+
+Luckily for me all good on the first try!
+
+= Finishing touches
+
+I set up a cron on my old NAS to sync data nightly from the new pool. This will
+only work while the actual data size on my new pool is less than 4TB, so I'll
+need to get a new drive with higher capacity to keep the backups going in the
+future.
+
+Luckily I should have about a year until I exceed 4TB on the new pool so I'll
+be keeping an eye on deals to snag an 8TB backup drive along with a few spares
+for my new NAS.
+
+= Resources
+
+- #extlink("https://www.apalrd.net/posts/2023/ultimate_nas/")[https://www.apalrd.net/posts/2023/ultimate_nas/]
+- #extlink("https://blog.kye.dev/proxmox-cockpit")[https://blog.kye.dev/proxmox-cockpit]
+]
diff --git a/post/nas-upgrade/cockpit-lxc.png b/post/nas-upgrade/cockpit-lxc.png
new file mode 100755
index 0000000..a2a9363
--- /dev/null
+++ b/post/nas-upgrade/cockpit-lxc.png
Binary files differ
diff --git a/post/nas-upgrade/ethernet.png b/post/nas-upgrade/ethernet.png
new file mode 100755
index 0000000..f39110d
--- /dev/null
+++ b/post/nas-upgrade/ethernet.png
Binary files differ
diff --git a/post/nas-upgrade/nas-chassis.png b/post/nas-upgrade/nas-chassis.png
new file mode 100755
index 0000000..5d70b60
--- /dev/null
+++ b/post/nas-upgrade/nas-chassis.png
Binary files differ
diff --git a/post/nas-upgrade/oldnas.png b/post/nas-upgrade/oldnas.png
new file mode 100755
index 0000000..15ad609
--- /dev/null
+++ b/post/nas-upgrade/oldnas.png
Binary files differ
diff --git a/post/nas-upgrade/zfs-pool.png b/post/nas-upgrade/zfs-pool.png
new file mode 100755
index 0000000..ecf9605
--- /dev/null
+++ b/post/nas-upgrade/zfs-pool.png
Binary files differ
diff --git a/post/nixos-p1.typ b/post/nixos-p1.typ
new file mode 100644
index 0000000..2d248c8
--- /dev/null
+++ b/post/nixos-p1.typ
@@ -0,0 +1,459 @@
+#import "/global/common.typ": *
+
+#let doc = [
+Almost a guide to getting started with NixOS the modern (2023) way.
+
+There seems to be a shortage of written guides on the Internet for setting up
+NixOS the "modern" way - Flakes + Home Manager. It doesn't help that Nix's
+official docs are very disjointed so hopefully this will fill in some gaps that
+I observed when setting it all up.
+
+#fig("nixos-p1/fox.jpg", alt: "meme")
+
+#quote(block: true)[
+ Warning: NixOS is not exactly beginner friendly - you should have
+ familiarity installing Linux distros before trying this.
+]
+
+= But Why NixOS?
+
+Eh... FOMO regarding all the
+#extlink("https://www.google.com/search?q=nixos+memes&tbm=isch")[memes].
+
+There is one particular feature that is intriguing - the ability to roll-back
+your entire system (not incl. BIOS) in case of a misconfiguration or a broken
+update. *You can't do this with Ansible.* This allows you (in theory) to get
+the benefits of a rolling release as well as the stability benefits of a
+traditional distro.
+
+#quote(block: true)[
+ It takes the idea of reproducible builds, and extends it to the OS.
+]
+
+For example, NixOS will present you with all previous "builds" at boot time for
+you to revert to in case something gets messed up.
+
+#fig("nixos-p1/boot.png", alt: "boot prompt")
+
+= Things I want to explore as part of this exercise:
+
++ How hard is it to go from a minimal install to productive? At minimum I need
+ a graphical environment with working vol, mic, camera, wifi, and hibernation.
+ Is it harder than doing the same in something like Manjaro?
++ Is Wayland truly ready?
++ Try out #extlink("https://github.com/djpohly/dwl")[`dwl`] (the Wayland port
+ of `dwm` by the #extlink("https://suckless.org")[suckless] folks)
+
+= Constraints
+
++ I want to stick to the "Nix" way of doing things as much as possible _where
+ it makes sense to me_.
++ Stick to Wayland only applications as much as possible.
+
+= Spoilers! (End result)
+
+#fig("nixos-p1/rice.png", alt: "my rice")
+
+(Probably too ugly for r/unixporn, but works for me :)
+
+= Installation
+
+== Getting a Live USB going
+
+- I used the #extlink("https://nixos.org/download.html#nixos-iso")[minimal iso].
+- Create a bootable USB with the usual - `sudo dd if=/path/to/iso of=/dev/sdX bs=4M`.
+- Boot up.
+- Then start following the steps for
+ #extlink("https://nixos.org/manual/nixos/stable/index.html#sec-installation-manual")[manual
+ installation] from the official guide to complete the install.
+
+#quote(block: true)[
+ Make sure to give SWAP as much space as your memory capacity for
+ hibernation to work properly.
+]
+
+#quote(block: true)[
+ Wifi did not work for me out of the box. So I used my phone to tether via
+ USB.
+]
+
+= First boot
+
+If everything went well, you should be presented with a TTY prompting you to
+login:
+
+```
+NixOS ...
+Login: <your username>
+Password: <your password>
+```
+
+Once you login, you will still just have a TTY, but we can now go ahead and
+start installing our graphical environment.
+
+= Housekeeping
+
+- You should have two NixOS config files in `/etc/nixos/`:
+
+```
+configuration.nix
+hardware-configuration.nix
+```
+
+- Edit the `configuration.nix` file by setting the correct values for hostname,
+ networking, timezone and users. I also add a few basic system-wide packages
+ here such as `git, rsync, neovim, htop` etc.
+
+- To _apply and use_ your changes to any of these files you need to run:
+
+```bash
+sudo nixos-rebuild switch
+```
+
+- Since we want all our configuration to be version controlled, I copied these
+ files to live under my user's config: `~/.config/{nix, nixpkgs}/`:
+
+```bash
+cp /etc/nix/nix.conf ~/.config/nix/nix.conf
+cp /etc/nixos/configuration.nix ~/.config/nixpkgs/configuration.nix
+```
+
+Nix will now use these user-specific files to read its config :)
+
+== Flakes Support
+
+Nix (the pkg mgr) does not come with Flakes support out-of-the-box. So we need
+to enable it:
+
++ In `~/.config/nix/nix.conf` add:
+
+```
+experimental-features = nix-command flakes
+```
+
++ Apply it:
+
+```bash
+sudo nixos-rebuild switch
+```
+
+Read about #extlink("https://nixos.wiki/wiki/Flakes")[Flakes].
+
+== Home Manager Support
+
+Now we can install the Home-Manager flake.
+
++ Init our base flake:
+
+```bash
+cd ~/.config/nixpkgs
+nix flake init
+```
+
+This should generate two files:
+
+```
+flake.nix
+flake.lock
+```
+
++ Next we tell `flake.nix` to manage all our configuration (system + home) for
+ our system:
+
+```nix
+{
+ description = "NixOS configuration";
+
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
+ home-manager.url = "github:nix-community/home-manager";
+ home-manager.inputs.nixpkgs.follows = "nixpkgs";
+ nixos-hardware.url = "github:NixOS/nixos-hardware/master";
+ };
+
+ outputs = inputs@{ nixpkgs, home-manager, nixos-hardware, ... }: {
+ nixosConfigurations = {
+ # Change below to use your hostname from configuration.nix
+ "art-sr" = nixpkgs.lib.nixosSystem {
+ system = "x86_64-linux";
+ modules = [
+ ./configuration.nix
+ nixos-hardware.nixosModules.framework
+ home-manager.nixosModules.home-manager
+ {
+ home-manager.useGlobalPkgs = true;
+ home-manager.useUserPackages = true;
+ # Change below to use your username from configuration.nix
+ home-manager.users.kdam0 = import ./home.nix;
+
+ # Optionally, use home-manager.extraSpecialArgs to pass
+ # arguments to home.nix
+ }
+ ];
+ };
+ };
+ };
+}
+```
+
+#quote(block: true)["art-sr" is my hostname for this machine.]
+
+In my case, I also have the following two lines specifically to load settings
+for my hardware:
+
+```
+ nixos-hardware.url = "github:NixOS/nixos-hardware/master";
+ ...
+ nixos-hardware.nixosModules.framework
+```
+
+you will need to modify these values based on your
+#extlink("https://github.com/NixOS/nixos-hardware")[hardware support].
+
++ Create a `~/.config/nixpkgs/home.nix` file with your values:
+
+```nix
+{ config, pkgs, ...}:
+{
+ home.username = "kdam0";
+ home.homeDirectory = "/home/kdam0";
+
+ programs.home-manager.enable = true;
+ home.stateVersion = "22.11";
+
+ services.gpg-agent = {
+ enable = true;
+ defaultCacheTtl = 1800;
+ enableSshSupport = true;
+ };
+}
+```
+
++ Apply:
+
+```bash
+sudo nixos-rebuild switch
+```
+
+#quote(block: true)[
+ It took a few attempts to get NixOS to re-build successfully. I ran into a
+ few different issues involving users, and hostnames while following the
+ official docs until I arrived at the configs above which worked.
+]
+
+Read about
+#extlink("https://nix-community.github.io/home-manager/index.html#ch-nix-flakes")[Home
+ Manager flake].
+
+*This would be a good time init a git repo in `~/.config/nixpkgs/` and publish
+your progress.*
+
+= Setting up the GUI
+
+== Window Manager + bar + system info.
+
+Getting `dwl` is easy enough. In my `home.nix`:
+
+```
+ home.packages = [
+ pkgs.dwl
+ ...
+ ];
+```
+
+This will install `dwl` on a rebuild. Then I can run it with `dwl`.
+
+Oh it fails...something about permissions... In
+`~/.config/nixpkgs/configuration.nix` make sure you have:
+
+```
+ security.polkit.enable = true;
+```
+
+Oh it fails again with GLE errors :( Add:
+
+```
+ hardware.opengl = {
+ enable = true;
+ driSupport = true;
+ };
+```
+
+*Sweet now it launches!*
+
+But of course I need to configure the keys - that's the whole point of a WM.
+Additionally, `dwl` requires a re-build on every config change...
+
+*How do I tell Nix to use my config file while installing/building `dwl`?*
+
+Lucking all packages (`pkgs.*`) build files are defined on their GitHub. We can
+see that we are allowed to pass in a `conf` argument to
+#extlink("https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/window-managers/dwl/default.nix")[this]
+file.
+
+After a bit of digging around, I arrived at how to do it:
+
++ First copy your `config.h` to `~/.config/nixpkgs/dwl/config.h`.
++ Then point to it in your `home.nix`:
+
+```
+ home.packages = [
+ (pkgs.dwl.override {
+ # trying to supply config.home.homeDirectory here leads to "impure" usage.
+ # so disabling it for now.
+ # conf = (builtins.readFile "${config.home.homeDirectory}/.config/dwl/config.h");
+ conf = ./dwl/config.h;
+ })
+ ...
+ ];
+```
+
+#quote(block: true)[
+ I know I can just clone the source myself and build it, but I like to use
+ the default package manager whenever possible to manage packages.
+]
+
+Of course since `dwl` is as minimal as it gets, it does not ship with a bar. We
+have many options for which bar to use, I have very little use for a bar, so I
+kept it very simple and went with `somebar`:
+
+```
+ home.packages = [
+ ...
+ pkgs.somebar
+ ...
+ ];
+```
+
+If you want status info on your bar you can use something like `someblocks` -
+which will let you script simple scripts with text output you want displayed in
+each block. This will need to be cloned and built manually as it is not
+available in the Nix repos.
+
+Oh but you probably don't have `make` or any requirements to actually build
+it...fear not:
+
+```bash
+nix-shell -p gnumake
+```
+
+which put you in a temporary environment with all the common build tools
+available. Now you can:
+
+```bash
+sudo make install
+```
+
+`wbg` is a simple background setter for Wayland......aaaand BAM!
+
+#fig("nixos-p1/dwl.png", alt: "dwl pic")
+
+== Terminal
+
+I use #extlink("https://codeberg.org/dnkl/foot")[`foot`].
+
+Create the config file in `~/.config/nixpkgs/foot/foot.ini`:
+
+```
+# for transparency #
+[colors]
+alpha=0.7
+```
+
+Use it in `home.nix`:
+
+```
+ home.file.".config/foot/foot.ini".source = ../../common/foot/foot.ini;
+```
+
+#quote(block: true)[I use this pattern for pretty much all my _dotfiles_:]
+
+```
+ # script that sets a bg.
+ home.file."bg.sh".source = common/bg.sh;
+ # script that starts my gui env.
+ home.file."start.sh".source = common/start.sh;
+ # foot config
+ home.file.".config/foot/foot.ini".source = common/foot/foot.ini;
+ # wofi config (app launcher)
+ home.file.".config/wofi/style.css".source = common/wofi/style.css;
+ # mako config (notifications)
+ home.file.".config/mako/config".source = common/mako/config;
+```
+
+== Sound
+
+In my `configuration.nix`:
+
+```
+ security.rtkit.enable = true;
+ services.pipewire = {
+ enable = true;
+ alsa.enable = true;
+ alsa.support32Bit = true;
+ pulse.enable = true;
+ wireplumber.enable = true;
+ media-session.enable = false;
+ jack.enable = true;
+ systemWide = false;
+ };
+```
+
+== Nextcloud
+
+I want a purely CLI way to handle this, and a periodic sync is sufficient for
+me. We do this with `systemd-timers` (Nix advises against `cron`). In my
+`home.nix`:
+
+```
+ systemd.user.services = {
+ nextcloud-sync = {
+ Unit = {
+ Description = "Auto sync Nextcloud";
+ After = "network-online.target";
+ };
+ Service = {
+ Type = "simple";
+ EnvironmentFile = "${config.home.homeDirectory}/.nextcloud.env";
+ ExecStart = ''
+ ${pkgs.nextcloud-client}/bin/nextcloudcmd \
+ -h --non-interactive \
+ --user "''${NEXTCLOUD_USER}" \
+ --password "''${NEXTCLOUD_PASSWORD}" \
+ ''${NEXTCLOUD_DIR} \
+ ''${NEXTCLOUD_URL}
+ '';
+ TimeoutStopSec = "180";
+ KillMode = "process";
+ KillSignal = "SIGINT";
+ };
+ Install.WantedBy = ["multi-user.target"];
+ };
+ };
+ systemd.user.timers = {
+ nextcloud-sync = {
+ Unit.Description = "Automatic sync files with Nextcloud when booted up after 5 minutes then rerun every 10 minutes";
+ Timer.OnUnitActiveSec = "10min";
+ Install.WantedBy = ["multi-user.target" "timers.target"];
+ };
+ };
+ systemd.user.startServices = true;
+```
+
+= Conclusions
+
++ Yes setting things up from a minimal iso is harder than in Manjaro. Although
+ I got everything I wanted working, there were many times I felt like giving
+ up. (Aside: I am _so grateful_ for Manjaro, and Arch wikis). That said, I
+ expect this friction is a one-time cost for building familiarity with Nix,
+ and well worth the benefits that come with it.
++ You bet Wayland is ready. Multi-monitor works out-of-the-box, all my apps
+ support it, and things just _feel_ more polished than I have ever felt with
+ Xorg.
++ `dwl` is as awesome as I had hoped! This is my daily driver now.
+
+= My configs
+
+All the configs discussed (and more) are in my
+#extlink("https://gitlab.com/kdam0/dotfiles-nix")[nixdotfiles repo].
+]
diff --git a/post/nixos-p1/boot.png b/post/nixos-p1/boot.png
new file mode 100755
index 0000000..4e3d972
--- /dev/null
+++ b/post/nixos-p1/boot.png
Binary files differ
diff --git a/post/nixos-p1/dwl.png b/post/nixos-p1/dwl.png
new file mode 100755
index 0000000..8ecbe4d
--- /dev/null
+++ b/post/nixos-p1/dwl.png
Binary files differ
diff --git a/post/nixos-p1/fox.jpg b/post/nixos-p1/fox.jpg
new file mode 100755
index 0000000..3ace57f
--- /dev/null
+++ b/post/nixos-p1/fox.jpg
Binary files differ
diff --git a/post/nixos-p1/rice.png b/post/nixos-p1/rice.png
new file mode 100755
index 0000000..4fd97cf
--- /dev/null
+++ b/post/nixos-p1/rice.png
Binary files differ
diff --git a/post/programming-as-art.typ b/post/programming-as-art.typ
new file mode 100644
index 0000000..ef80e33
--- /dev/null
+++ b/post/programming-as-art.typ
@@ -0,0 +1,98 @@
+#import "/global/common.typ": *
+
+#let doc = [
+Why there is art in programming.
+
+During my early days as a CS student, one of the first mind-blowing moments was
+watching `Hello World!` getting printed out to the console thousands of times
+in just two functional lines of code.
+
+```python
+for _ in range(1, 1001):
+ print("Hello World!")
+```
+
+At the time it felt like having the
+#extlink("https://harry-potter-compendium.fandom.com/wiki/Elder_Wand")[Elder Wand].
+
+#fig("programming-as-art/wand.png", alt: "Dumbledore with Elder Wand pic")
+
+But there was more to our lesson. The TA then asks us to put our newly found
+power to use by computing the sum of 1 to 100. Of course, it was a natural
+application of what we had just done earlier:
+
+```python
+sum = 0
+for i in range(1, 100+1):
+ sum = sum + i
+```
+
+Sure enough we saw the answer `5050` in the console. But then the TA reminds us
+that we are making our computers *work too hard*. In other words, the computer
+needs to do one-hundred ADD instructions in order to make this computation
+happen.
+
+What if the number was a million? How well would our method scale?
+
+Well then it would take a million ADD instructions. We call this scaling
+_linearly_ with the input size. Later we would formalize this to $cal(O)(n)$
+(pronounced: _Big Oh of N_).
+
+The TA hinted that there is a better way, and that we already know of the
+better way in math.
+
+#fig("programming-as-art/teaching.png", alt: "Teaching meme")
+
+$ S_n = sum_(i=1)^n i = 1 + 2 + ... + n = (n (n + 1)) / 2 $
+
+With this we are no longer using loops, but a known mathematical fact about
+sequences. If you don't belive me, see the
+#extlink("https://letstalkscience.ca/educational-resources/backgrounders/gauss-summation")[proof].
+
+Written as code:
+
+```python
+sum = n (n + 1) / 2
+```
+
+This one-liner solves our problem with just 3 (ADD, MULTIPLY, DIVIDE)
+instructions. Crucially, it does not depend on the size of the input like our
+previous solution, thus *no matter the input, it always takes 3 instructions to
+compute!* This is a HUGE win!
+
+#fig("programming-as-art/math.png", alt: "Math meme")
+
+Later we would formalize this to $cal(O)(1)$, or _constant_ scaling.
+
+#quote(block: true)[
+ Yes, yes I know IRL the complier would optimize the loop solution such
+ that it does not take N instructions but for the purposes of learning we
+ were not allowed to depend on that.
+]
+
+Looking back at it now, both solutions are equally correct, and modern
+compilers would optimize the first solution in the final instructions sent to
+the cpu, such that any performance differences would be negligible. In other
+words, the computer wouldn't acutally be _working so hard_.
+
+Objectively, the first solution is more readable, and friendly to a new
+observer than the second.
+
+_Why then am I still so drawn to the second solution?_
+
+The first solution reminds me of the saying "to a hammer, eveything looks like
+a nail". Its a brute force approach. In comparison, the second solution is
+using the exact tool for our particular problem. It somehow feels personalized
+and dare I say _romantic_.
+
+When I reflect on moments like this, it reminds me that there is emergent
+elegance and beauty even in the seemingly arbitrary sequence of symbols that is
+`code`.
+
+#fig("programming-as-art/code.png", alt: "The Matrix code going by image")
+
+Programming is not quite as _objective_ as people would have you believe. There
+are trade-offs to each solution, and which solution you prefer relect on the
+trade-offs you are willing to accept, which varies by the observer: much like
+_art_.
+]
diff --git a/post/programming-as-art/code.png b/post/programming-as-art/code.png
new file mode 100755
index 0000000..30c3522
--- /dev/null
+++ b/post/programming-as-art/code.png
Binary files differ
diff --git a/post/programming-as-art/math.png b/post/programming-as-art/math.png
new file mode 100755
index 0000000..bbdc372
--- /dev/null
+++ b/post/programming-as-art/math.png
Binary files differ
diff --git a/post/programming-as-art/teaching.png b/post/programming-as-art/teaching.png
new file mode 100755
index 0000000..9bf5dce
--- /dev/null
+++ b/post/programming-as-art/teaching.png
Binary files differ
diff --git a/post/programming-as-art/wand.png b/post/programming-as-art/wand.png
new file mode 100755
index 0000000..5eefc9c
--- /dev/null
+++ b/post/programming-as-art/wand.png
Binary files differ
diff --git a/post/programs.typ b/post/programs.typ
new file mode 100644
index 0000000..fb675f7
--- /dev/null
+++ b/post/programs.typ
@@ -0,0 +1,103 @@
+#import "/global/common.typ": *
+
+#let doc = [
+The programs and equipment I use on a daily basis.
+
+= Programs and Equipment I Use
+
+I'm about getting things done quickly and having as little latency between my
+thoughts and actions on the computer.
+
+I like having vim-like bindings and prefer running programs in the terminal for
+simplicity's sake. That said, I'm very much against the cringe meme that things
+in the terminal are "cooler" or "nerdier". Terminals are good for most tasks,
+but useless for others, for example, browsing the web (I admit this unfortunate
+fact with much consternation) or looking at maps.
+
+== Software I Use
+
+=== OS Distribution
+
+#extlink("https://nixos.org/")[NixOS]. NixOS is an immutable OS where you are
+only allowed to modify the system via declarative config files.
+
+I've distro-hopped between Manjaro, Void, Debian, and Fedora, but since NixOS
+this has largely stopped as I'm quite happy with my NixOS + Home Manager setup.
+I did like Debian, and Fedora as well.
+
+You can find my configs #extlink("https://gitlab.com/kdam0/dotfiles-nix")[here].
+There is a dedicated #pagelink("post/nixos-p1")[post] about this.
+
+=== Desktop Environment
+
+I've settled on #extlink("https://github.com/djpohly/dwl")[DWL] after many
+years of hopping. Its clean, functional, and extremely light.
+
+Prior to this, I've used Bsmpw + Sxhkd, i3, Gnome, KDE Plasma etc. I'm glad
+these exist and people get use out of it, but for now I do not miss it.
+
+#fig("programs/dwl.png", alt: "DWL")
+
+=== Text Editor
+
+#extlink("https://neovim.io/")[(neo)vim]. Less of a text editor and more of a
+lifestyle. Check out my dotfiles for this. No, I'm not going to ever switch to
+emacs.
+
+#fig("https://neovim.io/images/showcase/telescope_helptags.png", alt: "Neovim")
+
+=== Web Browser
+
+#extlink("https://www.mozilla.org/en-US/firefox/features/")[Firefox] /
+#extlink("https://brave.com")[Brave] /
+#extlink("https://vivaldi.com")[Vivaldi]. I have tried Chromium, Qutebrowser in
+the past.
+
+=== File Manager
+
+#extlink("https://github.com/ranger/ranger")[ranger]. Yes, I've tried `nnn` and
+others. Yes I know its not the fastest, but something about Ranger makes me
+keep coming back to it.
+
+#fig("https://raw.githubusercontent.com/ranger/ranger-assets/master/screenshots/twopane.png", alt: "ranger")
+
+== Where can I find good software options?
+
+The program of your dreams is probably listed below:
+
+- The #extlink("https://suckless.org/rocks/")[suckless] website's list of
+ programs that "rock". Generally minimalist programs.
+- A more comprehensive
+ #extlink("https://github.com/mayfrost/guides/blob/master/ALTERNATIVES.md")[list]
+ of minimalist software.
+- #extlink("https://directory.fsf.org/wiki/Main_Page")[FSF's Free Software
+ Directory]. Emphasis on libre software (although most software in the links
+ above will have free licenses as well).
+- #extlink("https://wiki.installgentoo.com/index.php/List_of_recommended_GNU/Linux_software")[Gentoo
+ Wiki Recommendations] A good mix of programs for novices and advanced
+ users.
+
+== Hardware I Use
+
+=== Laptop
+
+#strike[The main laptop I use is the
+#extlink("https://frame.work/")[Framework laptop]. I'm a huge fan of the whole
+upgradability concept coming from a few generations of ThinkPads.]
+
+I've since re-purposed this laptop to be
+#pagelink("post/framework-server")[something else].
+
+== What I don't use
+
+Proprietary software.
+
+I'm not going to endorse proprietary services that have gone out of their way
+to spy on or politically suppress their users, just as Facebook, Discord etc.
+One of the many take-aways you should get from me is that the use of
+libre/free software, by its nature, is more constructive and extensible; and
+*that's the point*.
+
+There are philosophical reasons for this I talk about
+#pagelink("post/self-host")[here].
+]
diff --git a/post/programs/dwl.png b/post/programs/dwl.png
new file mode 100755
index 0000000..8ecbe4d
--- /dev/null
+++ b/post/programs/dwl.png
Binary files differ
diff --git a/post/self-host.typ b/post/self-host.typ
new file mode 100644
index 0000000..0fed382
--- /dev/null
+++ b/post/self-host.typ
@@ -0,0 +1,138 @@
+#import "/global/common.typ": *
+
+#let doc = [
+My reasons for self-hosting.
+
+= Digital freedom/independence
+
+#fig("self-host/freedom.jpg", alt: "Freedom pic")
+
+To put it simply, if you use a service such as Lastpass, iCloud, Dropbox,
+GDrive, OneDrive, etc. to store your data, *you do not own it*.
+
+You are _trusting_ corp. X to store it, secure it, and make it available to
+you. Beyond the obvious privacy pitfalls with this, there are many other things
+that could go wrong with your data being stored this way:
+
+- Corp. X could vanish/close/"declare bankruptcy" (as with many crypto corps.
+ lately), and you lose your data.
+- Corp. X could make a policy change and lock you out from accessing your
+ account.
+- Or you could "forget" to pay the bills a few times and get locked out.
+- Corp. X could get hacked, and your data gets stolen. This is the latest
+ trend!
+- Many other doomsday scenarios.
+
+Personally, I don't feel comfortable depending on the existence of corp. X
+_for data that is important to me_ i.e. a lifetime's worth of documents,
+memories, and passwords etc. I sleep much better at night knowing I am avoiding
+most if not all of the risks above.
+
+= Privacy <privacy>
+
+Normies often ask me some variation of:
+
+- Why do I care if corp. X has my data? I have nothing to hide!
+- Since I'm aware of targeted advertising, it won't work on me, so why should
+ I care if corp. X has my data?
+
+#fig("self-host/why.jpg", alt: "my pic", width: "75%")
+
+To such questions, I follow-up with:
+
+#quote(block: true)[*Do you want to contribute to a dystopian
+ (#extlink("https://en.wikipedia.org/wiki/Orwellian")[Orwellian]) future?*]
+
+#fig("self-host/police.jpg", alt: "thought police", width: "75%")
+
+If your answer is _yes_, then no need to read further, the following will not
+change your mind.
+
+If your answer is _no_, but you aren't convinced that/how these are related,
+then the _argument goes something like this..._
+
+- We live in a world of mass data-collection/surveillance.
+- This enables corp. X to use techniques such as ML (Machine Learning) to
+ build/train models (or "AI" - Artificial Intelligence) that aim to predict
+ human behaviour.
+- That by itself is not a problem here.
+- The problems arise when corp. X use these techniques for profit without
+ regard for the harm they cause at a _population level_.
+
+I have unfortunately lived through enough of these cases to be able to cite a
+few recent examples:
+
+- Instagram (etc.) designs its apps/products optimizing for maximum addiction
+ (see
+ #extlink("https://sitn.hms.harvard.edu/flash/2018/dopamine-smartphones-battle-time/")[Smartphones
+ and dopamine]). Think slot-machines. You might think you are "too smart"
+ to fall for these tricks, and you might be right, but what about the millions
+ of adolescents using these platforms who aren't as wise as you? The data
+ collected, and techniques developed from _your usage_ enables platforms to
+ target not only you, but _all_ users on the platform, including the most
+ vulnerable.
+
+ Unfortunately, many of these kids will end up suffering from mental-health,
+ body-image, self-esteem issues (see
+ #extlink("https://onlinedegrees.unr.edu/online-master-of-public-health/impact-of-social-media-on-youth-mental-health/")[Mental
+ health and social media]), and for some it *will be fatal*. I do not
+ think this is morally acceptable, and is primary reason I refuse to
+ participate in social-media platforms.
+
+ #fig("self-host/6imv05.jpg", alt: "Depression")
+
+You could say "well that's due to bad parenting", but the point remains that
+more and more of the digital world is having _real world_ negative consequences
+regardless of your individual participation level. Another example:
+
+- By now its well known that Facebook's (etc.) targeted advertising played a
+ significant a role in the 2016 US Elections (see
+ #extlink("https://www.theverge.com/2017/12/11/16761016/former-facebook-exec-ripping-apart-society")[Excerpt
+ from Facebook ex-exec]). Facebook was able to do this thanks to its users
+ voluntarily giving personal information for two decades. However, the
+ policies that come out of this election has real world consequences to
+ millions (if not billions) of people, regardless of their _individual_
+ Facebook usage, which undermines the very purpose of a democratic republic.
+ Regardless of your political affiliation, it should worry you that this
+ _can_ happen.
+
+ #fig("self-host/elections.jpg", alt: "Elections")
+
+To summarize, it might not be a problem if individuals disregard their privacy
+at the individual level, but in aggregate, a _population-wide_ disregard has
+dystopian consequences.
+
+So the question you have to ask yourself is:
+
+#quote(block: true)[*What can I do?*]
+
+Start by *valuing your privacy*. Then, follow some of these tips to _say no..._
+
+- *Limit your exposure to these services.* If a friend stops talking to you
+ because of this, then congratulations, you've just gotten rid of a fake
+ friend. You're welcome.
+- #extlink("https://wiki.r-selfhosted.com/getting-started/what-is-self-hosting/")[Self-host]
+ as much as you can. You can see how I
+ #extlink("https://gitlab.com/kdam0/vps")[implement] this and replicate it
+ yourself, though it is a bit involved for normies.
+- If neither of the above work for you, then you'll need to do some research to
+ find an alternative source that you can trust isn't doing the same thing. Use
+ #extlink("https://github.com/awesome-selfhosted/awesome-selfhosted")[this]
+ as a starting point and try to search (Ctrl+f) for your service. For eg.
+ Twitter, and Instagram both have popular options available.
+- *Stop using Chrome.* If you must use it, use
+ #extlink("https://brave.com/")[Brave] instead. I advocate for
+ #extlink("https://www.mozilla.org/en-US/firefox/new/?redirect_source=firefox-com")[Firefox].
+ Neither are perfect, but both offer privacy respecting options in their
+ settings. Specifically disabling cross-site tracking is important. Beyond
+ that, install an ad-blocker extension such as
+ #extlink("https://ublockorigin.com/")[UBlock Origin] on both of them. Don't
+ forget to do the same on your mobile device!
+- Things get more complicated on cell-phones. I suggest switching to a privacy
+ respecting operating-system such as
+ #extlink("https://grapheneos.org/")[GrapheneOS]. Short of this, you can only
+ limit your usage.
+- Support government policies that respect user-privacy.
+
+#fig("self-host/office.png", alt: "office pic", width: "75%")
+]
diff --git a/post/self-host/6imv05.jpg b/post/self-host/6imv05.jpg
new file mode 100755
index 0000000..d042d7a
--- /dev/null
+++ b/post/self-host/6imv05.jpg
Binary files differ
diff --git a/post/self-host/elections.jpg b/post/self-host/elections.jpg
new file mode 100755
index 0000000..ac4ac96
--- /dev/null
+++ b/post/self-host/elections.jpg
Binary files differ
diff --git a/post/self-host/freedom.jpg b/post/self-host/freedom.jpg
new file mode 100755
index 0000000..d62048a
--- /dev/null
+++ b/post/self-host/freedom.jpg
Binary files differ
diff --git a/post/self-host/office.png b/post/self-host/office.png
new file mode 100755
index 0000000..9cff3ce
--- /dev/null
+++ b/post/self-host/office.png
Binary files differ
diff --git a/post/self-host/police.jpg b/post/self-host/police.jpg
new file mode 100755
index 0000000..dde2b44
--- /dev/null
+++ b/post/self-host/police.jpg
Binary files differ
diff --git a/post/self-host/why.jpg b/post/self-host/why.jpg
new file mode 100755
index 0000000..eda5402
--- /dev/null
+++ b/post/self-host/why.jpg
Binary files differ