diff options
Diffstat (limited to 'post')
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 Binary files differnew file mode 100755 index 0000000..d64be2e --- /dev/null +++ b/post/framework-server-p2/current-lab.jpg diff --git a/post/framework-server-p2/ethernet.png b/post/framework-server-p2/ethernet.png Binary files differnew file mode 100755 index 0000000..f39110d --- /dev/null +++ b/post/framework-server-p2/ethernet.png diff --git a/post/framework-server-p2/server-front.png b/post/framework-server-p2/server-front.png Binary files differnew file mode 100755 index 0000000..31e34da --- /dev/null +++ b/post/framework-server-p2/server-front.png diff --git a/post/framework-server-p2/server-inside.png b/post/framework-server-p2/server-inside.png Binary files differnew file mode 100755 index 0000000..79e7139 --- /dev/null +++ b/post/framework-server-p2/server-inside.png 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 Binary files differnew file mode 100755 index 0000000..76cda35 --- /dev/null +++ b/post/framework-server/bios.jpg diff --git a/post/framework-server/bios2.png b/post/framework-server/bios2.png Binary files differnew file mode 100755 index 0000000..094e37e --- /dev/null +++ b/post/framework-server/bios2.png diff --git a/post/framework-server/case.jpg b/post/framework-server/case.jpg Binary files differnew file mode 100755 index 0000000..a40c172 --- /dev/null +++ b/post/framework-server/case.jpg diff --git a/post/framework-server/dmz.png b/post/framework-server/dmz.png Binary files differnew file mode 100755 index 0000000..372c12b --- /dev/null +++ b/post/framework-server/dmz.png diff --git a/post/framework-server/dns.jpg b/post/framework-server/dns.jpg Binary files differnew file mode 100755 index 0000000..0b32528 --- /dev/null +++ b/post/framework-server/dns.jpg diff --git a/post/framework-server/dri.png b/post/framework-server/dri.png Binary files differnew file mode 100755 index 0000000..a578c79 --- /dev/null +++ b/post/framework-server/dri.png diff --git a/post/framework-server/error.jpg b/post/framework-server/error.jpg Binary files differnew file mode 100755 index 0000000..429eef8 --- /dev/null +++ b/post/framework-server/error.jpg diff --git a/post/framework-server/eth.jpg b/post/framework-server/eth.jpg Binary files differnew file mode 100755 index 0000000..f8ad12a --- /dev/null +++ b/post/framework-server/eth.jpg diff --git a/post/framework-server/fail.png b/post/framework-server/fail.png Binary files differnew file mode 100755 index 0000000..f0e06db --- /dev/null +++ b/post/framework-server/fail.png diff --git a/post/framework-server/feelsbadman.png b/post/framework-server/feelsbadman.png Binary files differnew file mode 100755 index 0000000..b1c2a26 --- /dev/null +++ b/post/framework-server/feelsbadman.png diff --git a/post/framework-server/fix1.png b/post/framework-server/fix1.png Binary files differnew file mode 100755 index 0000000..b36489e --- /dev/null +++ b/post/framework-server/fix1.png diff --git a/post/framework-server/fix2.png b/post/framework-server/fix2.png Binary files differnew file mode 100755 index 0000000..5b64900 --- /dev/null +++ b/post/framework-server/fix2.png diff --git a/post/framework-server/fix3.png b/post/framework-server/fix3.png Binary files differnew file mode 100755 index 0000000..9af2433 --- /dev/null +++ b/post/framework-server/fix3.png diff --git a/post/framework-server/fw1.png b/post/framework-server/fw1.png Binary files differnew file mode 100755 index 0000000..72a95ee --- /dev/null +++ b/post/framework-server/fw1.png diff --git a/post/framework-server/fw2.png b/post/framework-server/fw2.png Binary files differnew file mode 100755 index 0000000..cec00e1 --- /dev/null +++ b/post/framework-server/fw2.png diff --git a/post/framework-server/imp.png b/post/framework-server/imp.png Binary files differnew file mode 100755 index 0000000..c11b806 --- /dev/null +++ b/post/framework-server/imp.png diff --git a/post/framework-server/lab.png b/post/framework-server/lab.png Binary files differnew file mode 100755 index 0000000..6591a8b --- /dev/null +++ b/post/framework-server/lab.png diff --git a/post/framework-server/lan.png b/post/framework-server/lan.png Binary files differnew file mode 100755 index 0000000..461d598 --- /dev/null +++ b/post/framework-server/lan.png diff --git a/post/framework-server/mistakes.jpg b/post/framework-server/mistakes.jpg Binary files differnew file mode 100755 index 0000000..d4b2e12 --- /dev/null +++ b/post/framework-server/mistakes.jpg diff --git a/post/framework-server/nas.jpg b/post/framework-server/nas.jpg Binary files differnew file mode 100755 index 0000000..75f5251 --- /dev/null +++ b/post/framework-server/nas.jpg diff --git a/post/framework-server/net1.png b/post/framework-server/net1.png Binary files differnew file mode 100755 index 0000000..a0a4eff --- /dev/null +++ b/post/framework-server/net1.png diff --git a/post/framework-server/net2.png b/post/framework-server/net2.png Binary files differnew file mode 100755 index 0000000..c5ad118 --- /dev/null +++ b/post/framework-server/net2.png diff --git a/post/framework-server/network.png b/post/framework-server/network.png Binary files differnew file mode 100755 index 0000000..1b1fba6 --- /dev/null +++ b/post/framework-server/network.png diff --git a/post/framework-server/pbr.png b/post/framework-server/pbr.png Binary files differnew file mode 100755 index 0000000..2b1e330 --- /dev/null +++ b/post/framework-server/pbr.png diff --git a/post/framework-server/pbr1.png b/post/framework-server/pbr1.png Binary files differnew file mode 100755 index 0000000..4d7f075 --- /dev/null +++ b/post/framework-server/pbr1.png diff --git a/post/framework-server/pbr2.png b/post/framework-server/pbr2.png Binary files differnew file mode 100755 index 0000000..0a07839 --- /dev/null +++ b/post/framework-server/pbr2.png diff --git a/post/framework-server/pfnet.png b/post/framework-server/pfnet.png Binary files differnew file mode 100755 index 0000000..67cc5f4 --- /dev/null +++ b/post/framework-server/pfnet.png diff --git a/post/framework-server/physical.png b/post/framework-server/physical.png Binary files differnew file mode 100755 index 0000000..fc1cb81 --- /dev/null +++ b/post/framework-server/physical.png diff --git a/post/framework-server/port1.png b/post/framework-server/port1.png Binary files differnew file mode 100755 index 0000000..1b72ab1 --- /dev/null +++ b/post/framework-server/port1.png diff --git a/post/framework-server/port2.png b/post/framework-server/port2.png Binary files differnew file mode 100755 index 0000000..37ff887 --- /dev/null +++ b/post/framework-server/port2.png diff --git a/post/framework-server/rproxy.png b/post/framework-server/rproxy.png Binary files differnew file mode 100755 index 0000000..0d3f0bf --- /dev/null +++ b/post/framework-server/rproxy.png diff --git a/post/framework-server/ups.jpg b/post/framework-server/ups.jpg Binary files differnew file mode 100755 index 0000000..4cd7aee --- /dev/null +++ b/post/framework-server/ups.jpg diff --git a/post/framework-server/vps.png b/post/framework-server/vps.png Binary files differnew file mode 100755 index 0000000..7392495 --- /dev/null +++ b/post/framework-server/vps.png diff --git a/post/framework-server/wg.png b/post/framework-server/wg.png Binary files differnew file mode 100755 index 0000000..18896a0 --- /dev/null +++ b/post/framework-server/wg.png diff --git a/post/framework-server/wrtnet.png b/post/framework-server/wrtnet.png Binary files differnew file mode 100755 index 0000000..73d435d --- /dev/null +++ b/post/framework-server/wrtnet.png diff --git a/post/framework-server/wrtnet2.png b/post/framework-server/wrtnet2.png Binary files differnew file mode 100755 index 0000000..34cd6b9 --- /dev/null +++ b/post/framework-server/wrtnet2.png diff --git a/post/framework-server/wtf.jpg b/post/framework-server/wtf.jpg Binary files differnew file mode 100755 index 0000000..995fefe --- /dev/null +++ b/post/framework-server/wtf.jpg 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 Binary files differnew file mode 100755 index 0000000..ee5050c --- /dev/null +++ b/post/listing-my-fav-advice/balance.jpg diff --git a/post/listing-my-fav-advice/boss.jpg b/post/listing-my-fav-advice/boss.jpg Binary files differnew file mode 100755 index 0000000..631a78a --- /dev/null +++ b/post/listing-my-fav-advice/boss.jpg diff --git a/post/listing-my-fav-advice/chewing.gif b/post/listing-my-fav-advice/chewing.gif Binary files differnew file mode 100755 index 0000000..12b7d16 --- /dev/null +++ b/post/listing-my-fav-advice/chewing.gif diff --git a/post/listing-my-fav-advice/indulgence.jpg b/post/listing-my-fav-advice/indulgence.jpg Binary files differnew file mode 100755 index 0000000..446e3fb --- /dev/null +++ b/post/listing-my-fav-advice/indulgence.jpg diff --git a/post/listing-my-fav-advice/money.jpg b/post/listing-my-fav-advice/money.jpg Binary files differnew file mode 100755 index 0000000..451ff7c --- /dev/null +++ b/post/listing-my-fav-advice/money.jpg 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 Binary files differnew file mode 100755 index 0000000..a2a9363 --- /dev/null +++ b/post/nas-upgrade/cockpit-lxc.png diff --git a/post/nas-upgrade/ethernet.png b/post/nas-upgrade/ethernet.png Binary files differnew file mode 100755 index 0000000..f39110d --- /dev/null +++ b/post/nas-upgrade/ethernet.png diff --git a/post/nas-upgrade/nas-chassis.png b/post/nas-upgrade/nas-chassis.png Binary files differnew file mode 100755 index 0000000..5d70b60 --- /dev/null +++ b/post/nas-upgrade/nas-chassis.png diff --git a/post/nas-upgrade/oldnas.png b/post/nas-upgrade/oldnas.png Binary files differnew file mode 100755 index 0000000..15ad609 --- /dev/null +++ b/post/nas-upgrade/oldnas.png diff --git a/post/nas-upgrade/zfs-pool.png b/post/nas-upgrade/zfs-pool.png Binary files differnew file mode 100755 index 0000000..ecf9605 --- /dev/null +++ b/post/nas-upgrade/zfs-pool.png 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 Binary files differnew file mode 100755 index 0000000..4e3d972 --- /dev/null +++ b/post/nixos-p1/boot.png diff --git a/post/nixos-p1/dwl.png b/post/nixos-p1/dwl.png Binary files differnew file mode 100755 index 0000000..8ecbe4d --- /dev/null +++ b/post/nixos-p1/dwl.png diff --git a/post/nixos-p1/fox.jpg b/post/nixos-p1/fox.jpg Binary files differnew file mode 100755 index 0000000..3ace57f --- /dev/null +++ b/post/nixos-p1/fox.jpg diff --git a/post/nixos-p1/rice.png b/post/nixos-p1/rice.png Binary files differnew file mode 100755 index 0000000..4fd97cf --- /dev/null +++ b/post/nixos-p1/rice.png 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 Binary files differnew file mode 100755 index 0000000..30c3522 --- /dev/null +++ b/post/programming-as-art/code.png diff --git a/post/programming-as-art/math.png b/post/programming-as-art/math.png Binary files differnew file mode 100755 index 0000000..bbdc372 --- /dev/null +++ b/post/programming-as-art/math.png diff --git a/post/programming-as-art/teaching.png b/post/programming-as-art/teaching.png Binary files differnew file mode 100755 index 0000000..9bf5dce --- /dev/null +++ b/post/programming-as-art/teaching.png diff --git a/post/programming-as-art/wand.png b/post/programming-as-art/wand.png Binary files differnew file mode 100755 index 0000000..5eefc9c --- /dev/null +++ b/post/programming-as-art/wand.png 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 Binary files differnew file mode 100755 index 0000000..8ecbe4d --- /dev/null +++ b/post/programs/dwl.png 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 Binary files differnew file mode 100755 index 0000000..d042d7a --- /dev/null +++ b/post/self-host/6imv05.jpg diff --git a/post/self-host/elections.jpg b/post/self-host/elections.jpg Binary files differnew file mode 100755 index 0000000..ac4ac96 --- /dev/null +++ b/post/self-host/elections.jpg diff --git a/post/self-host/freedom.jpg b/post/self-host/freedom.jpg Binary files differnew file mode 100755 index 0000000..d62048a --- /dev/null +++ b/post/self-host/freedom.jpg diff --git a/post/self-host/office.png b/post/self-host/office.png Binary files differnew file mode 100755 index 0000000..9cff3ce --- /dev/null +++ b/post/self-host/office.png diff --git a/post/self-host/police.jpg b/post/self-host/police.jpg Binary files differnew file mode 100755 index 0000000..dde2b44 --- /dev/null +++ b/post/self-host/police.jpg diff --git a/post/self-host/why.jpg b/post/self-host/why.jpg Binary files differnew file mode 100755 index 0000000..eda5402 --- /dev/null +++ b/post/self-host/why.jpg |
