From 558bdd9e5d222c60fb4c324b1139e63b654d39d2 Mon Sep 17 00:00:00 2001 From: Joey Hafner Date: Fri, 28 Jun 2024 23:40:22 -0700 Subject: [PATCH] Reorganize "articles" into "homelab" category --- Jafner.dev/config.toml | 14 ++--- .../Homelab Tour}/Apps.png | Bin .../content/homelab/Homelab Tour/cover.png | Bin 0 -> 22886 bytes .../Homelab Tour/index.md} | 53 +++++++++--------- 4 files changed, 35 insertions(+), 32 deletions(-) rename Jafner.dev/content/{articles => homelab/Homelab Tour}/Apps.png (100%) create mode 100644 Jafner.dev/content/homelab/Homelab Tour/cover.png rename Jafner.dev/content/{articles/Homelab Tour Series - Intro.md => homelab/Homelab Tour/index.md} (93%) diff --git a/Jafner.dev/config.toml b/Jafner.dev/config.toml index 51e29ece..97600ef3 100644 --- a/Jafner.dev/config.toml +++ b/Jafner.dev/config.toml @@ -22,13 +22,13 @@ enableGitInfo = false enableEmoji = true enableMissingTranslationPlaceholders = false disableRSS = true -disableSitemap = true +disableSitemap = false disable404 = false disableHugoGeneratorInject = false [permalinks] [permalinks.section] - articles = "/articles/" + homelab = "/homelab/" projects = "/projects/" pages = "/" @@ -116,7 +116,7 @@ disableHugoGeneratorInject = false [[menu.main]] identifier = "about" name = "About" - url = "about" + url = "about-me" weight = 10 [[menu.main]] identifier = "experience" @@ -124,9 +124,9 @@ disableHugoGeneratorInject = false url = "experience" weight = 20 [[menu.main]] - identifier = "articles" - name = "Articles" - url = "articles" + identifier = "homelab" + name = "Homelab" + url = "homelab" weight = 30 [[menu.main]] identifier = "projects" @@ -138,4 +138,4 @@ disableHugoGeneratorInject = false [markup.tableOfContents] endLevel = 3 ordered = false - startLevel = 1 + startLevel = 2 diff --git a/Jafner.dev/content/articles/Apps.png b/Jafner.dev/content/homelab/Homelab Tour/Apps.png similarity index 100% rename from Jafner.dev/content/articles/Apps.png rename to Jafner.dev/content/homelab/Homelab Tour/Apps.png diff --git a/Jafner.dev/content/homelab/Homelab Tour/cover.png b/Jafner.dev/content/homelab/Homelab Tour/cover.png new file mode 100644 index 0000000000000000000000000000000000000000..877d3dc3fe2bd29e0aea3d74db87f6de55fa8cd6 GIT binary patch literal 22886 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 r|6u?B1Ka-tEB+7i`M Drive`. And it feels luxurious. Knowing that all my phone's photos and videos are stored on my hardware and won't every touch Google's servers. I can take a full-fat video without worrying that 600 MB will eat up a bunch of my quota. Nextcloud also offers a wide swathe of plugins for other functionalities via their [App store](https://apps.nextcloud.com/). -## Manyfold: Library management for 3D models +### Manyfold: Library management for 3D models *3D Model library manager.* | [Manyfold](https://github.com/manyfold3d/manyfold) | [`3d.jafner.net`](https://3d.jafner.net/) | [Configuration](https://gitea.jafner.tools/Jafner/homelab/src/branch/main/fighter/config/vandam) Over the years I've spent a *lot* of money on 3D models for fantasy RPG miniatures. My collection of models is measured in *terrabytes*. And I have a deep appreciation for the creative work of the artists who make these models. But artists, I think, are not naturally inclined toward robust file organization practices. So my "collection" is really more like a pile. @@ -59,12 +62,12 @@ But Manyfold (formerly "VanDAM") has helped enormously with the process of makin I still have a lot of manual work to do though... -## Send: The service formerly known as Firefox Send +### Send: The service formerly known as Firefox Send *Quick and secure file share. [XKCD#949](https://xkcd.com/949/).* | [Send](https://github.com/timvisee/send) | [`send.jafner.net`](https://send.jafner.net/) | [Configuration](https://gitea.jafner.tools/Jafner/homelab/src/branch/main/fighter/config/send) The XKCD comic above articulates and experience I've had enough times. Nextcloud helps a lot when I want to share a file with someone else. But Send covers the cases where a friend wants to send me a file, or a friend is asking me how to send a file to another friend. I can just send them the link. I don't even need to explain how it works, it's built intuitively enough. And I get some peace of mind knowing that the files are encrypted end-to-end. -## Zipline: Clip that +### Zipline: Clip that *Media sharing server (upload screenshots, recordings).* | [Zipline](https://github.com/diced/zipline) | [`zipline.jafner.net`](https://zipline.jafner.net) | [Configuration](https://gitea.jafner.tools/Jafner/homelab/src/branch/main/fighter/config/zipline) This service exists exclusively to let me right click the video file of a gaming highlight, hit "Share", and send the link to my friends as seamlessly as possible *while supporting high-fidelity content*. I record my gameplay at 1440p 120 FPS. Check it out: @@ -75,57 +78,57 @@ This service exists exclusively to let me right click the video file of a gaming That last one's not even 120 fps, I just love to show it. To be honest though, if Youtube supported scripted/automated uploads I would just use that. But it's probably for the best that they don't. -## Home Assistant: Climate control for the Critter Cove +### Home Assistant: Climate control for the Critter Cove *Home automation and monitoring.* | [Home Assistant](https://www.home-assistant.io/) | [`homeassistant.jafner.net`](https://homeassistant.jafner.net) | [Configuration](https://gitea.jafner.tools/Jafner/homelab/src/branch/main/fighter/config/home-assistant) I think a lot of folks start their self-hosting journey with Home Assistant. It's a fantastic tool, and it keeps some of your most important data from being reliant on [often-flakey vendors](https://gizmodo.com/the-never-ending-death-of-smart-home-gadgets-1842456125) who have little interest in supporting their product unless you're giving them money for it. My partner and I have four reptiles, several insects, and a hamster whose climates I simply cannot be bothered to adjust manually every hour of the waking day. So I installed Home Assistant, hooked up warm-side and cool-side [Govee hygrometer/thermometers](https://us.govee.com/products/govee-bluetooth-hygrometer-thermometer-h5075?Style=1*H5075), put the heating lamps on [TP Link smart dimming plugs](https://www.kasasmart.com/us/products/smart-plugs/product-kp405), and wrote some automation to keep everybody in their happy temperature range. -## VyOS: My router is a text file +### VyOS: My router is a text file *Configuration-as-code router OS.* | [VyOS](https://vyos.io/) | [Configuration](https://gitea.jafner.tools/Jafner/homelab/src/branch/main/wizard/config) One day I thought to myself, "do I know how a router works?" The answer was no, so I built one (hardware and configuration) from scratch between the hours of 10 PM and 4 AM to ensure none of my housemates would be disturbed by the requisite internet outage. I deployed the seat-of-my-pants router configuration to "production" overnight and handled about one day's worth of post-deployment support before everything was seamlessly stable. The hardest part was crimping and terminating every single ethernet cable. At least 20 connections. Woof. -## TrueNAS: How I sleep at night +### TrueNAS: How I sleep at night *Data safety provider.* | [TrueNAS](https://www.truenas.com/truenas-scale/) | [Configuration: Main](https://gitea.jafner.tools/Jafner/homelab/src/branch/main/barbarian) | [Configuration: Backup](https://gitea.jafner.tools/Jafner/homelab/src/branch/main/monk) Underpinning every single one of the above services in one way or another is my TrueNAS deployment. It is composed of two hosts: a primary and a backup. Every day, each system takes a [differential snapshot](https://www.truenas.com/docs/scale/24.04/scaleuireference/dataprotection/periodicsnapshottasksscreensscale/) of each dataset, and runs a short [S.M.A.R.T. test](https://www.truenas.com/docs/scale/24.04/scaleuireference/dataprotection/smarttestsscreensscale/) on each disk. Nightly, the most important datasets on the primary are backed up to the backup as an [Rsync task](https://www.truenas.com/docs/scale/24.04/scaleuireference/dataprotection/rsynctasksscreensscale/). And every week it runs a [scrub task](https://www.truenas.com/docs/scale/24.04/scaleuireference/dataprotection/scrubtasksscreensscale/) to ensure the stored data still checksums correctly. And of course, it runs an SMB server and iSCSI target to facilitate clients and applications interacting with their own little data puddle. -# Additional Services: Just for fun +## Additional Services: Just for fun In addition to the important services above, I run a handful of services just for off time. -## Plex: I wish Jellyfin supported SSO +### Plex: I wish Jellyfin supported SSO The superior media server, Plex provides a free (as in beer) solution with a beautiful frontend and comprehensive metadata scraping. Plex has set a standard for serving movies and TV that no alternative service has been able to match. It is the unwelcome incumbent no one has mustered the resources to dethrone. Over the last decade Plex has crept away from its [XBMC](https://en.wikipedia.org/wiki/Kodi_(software)) roots, and leaned into building services that make the business boys happy. They've been investing engineering hours into integrating more and more with external service providers, rather than [updating some of the core functionality](https://www.plexopedia.com/plex-media-server/general/metadata-stored/). And in [2022](https://www.theverge.com/2022/8/24/23319570/plex-security-breach-exposes-usernames-emails-passwords) they leaked my username, email, and (encrypted) password just to be rude to me personally. But I digress... [Jellyfin](https://jellyfin.org/) is the leading opposition. But Jellyfin's [most wanted feature requests](https://features.jellyfin.org/?view=most-wanted) paints a sorry picture of the state of things. Features I consider critical, such as [2FA](https://features.jellyfin.org/posts/26/add-support-for-two-factor-authentication-2fa), [transcoding](https://features.jellyfin.org/posts/284/convert-option-similar-to-plexs-optimise), [offline access for mobile clients](https://features.jellyfin.org/posts/218/support-offline-mode-on-android-mobile), [to-watch lists](https://features.jellyfin.org/posts/576/watchlist-like-netflix), [watch history](https://features.jellyfin.org/posts/633/watched-history), [OIDC support](https://features.jellyfin.org/posts/230/support-for-oidc) / [OAuth support](https://features.jellyfin.org/posts/271/oauth-support), [list collections to which a movie belongs](https://features.jellyfin.org/posts/540/list-all-collections-that-a-movie-belong-to-in-movie-details), and more I'm sure if I just keep scrolling. Maybe a few more years. -## 5eTools: If D&D Beyond was designed by software engineers instead of business boys +### 5eTools: If D&D Beyond was designed by software engineers instead of business boys 5eTools is an insanely high quality, data-driven repository for each and every piece of content ever made for D&D 5th edition. Fortunately, they have a *blocklist* feature to restrict the visible content to only the stuff I've bought the books for. -## Calibre-web: Frontend for the premiere ebook library manager +### Calibre-web: Frontend for the premiere ebook library manager [Calibre-web](https://github.com/janeczku/calibre-web) | [Calibre](https://calibre-ebook.com/) | [`rpg.calibre.jafner.net`](https://rpg.calibre.jafner.net/) | [`sff.calibre.jafner.net`](https://sff.calibre.jafner.net/) Sometimes, rarely, I read a book. Much more freqeuently, I want to check a section from a book. Calibre(-web) affords me access to my entire library of books and ebooks from a web browser. Frustratingly, the owner of the project has decided not to implement generic OAuth2/OIDC support. [But open-source, uh, finds a way.](https://github.com/janeczku/calibre-web/pull/2211#issuecomment-1182460156) -## Minecraft: Geoff \"itzg\" Bourne is a blessing +### Minecraft: Geoff \"itzg\" Bourne is a blessing Hosting game servers for my friends got me into this stuff, and has been a throughline of my life for over 15 years. And Minecraft has been a consistent presence in that domain. Today that task is easier and more polished than ever. Two Docker images, [itzg/mc-router](https://github.com/itzg/mc-router) and [itzg/docker-minecraft-server](https://github.com/itzg/docker-minecraft-server) have handled every Minecraft server I've hosted since late 2020. The configuration is simple and declarative. The best part is the reverse proxying. In 2015 I would head to [WhatsMyIP.org](https://www.whatsmyip.org/), copy the number at the top, and send it to my friends. Then they would manually type it into the connect dialog (copy-paste can be challenging), type something wrong, get a connection error, and call me on Google Hangouts. We'd, eventually get it figured out, but now I can just say "It's `e9.jafner.net`" and that seems to stick a lot better. -# Admin Services: Help me handle all this +## Admin Services: Help me handle all this Nothing since has given me the same high as seeing the green padlock next to `jafner.net` for the first time. After years of typing IPs, memorizing ports, skipping "Your connection is not private" pages, and answering "What's the IP again?", that green padlock was more gratifying than the $60k piece of paper framed on my wall. Below are the tools and services I use to make everything else work *properly*. -## Traefik: One-liner* TLS-certified subdomains +### Traefik: One-liner* TLS-certified subdomains *Docker-integrated reverse proxy.* | [Traefik](https://github.com/traefik/traefik) | [Configuration: Fighter](https://gitea.jafner.tools/Jafner/homelab/src/commit/94e0aed892812adcfd94bd84e588eb474dd7abda/fighter/config/traefik/docker-compose.yml) | [Configuration: Druid](https://gitea.jafner.tools/Jafner/homelab/src/commit/94e0aed892812adcfd94bd84e588eb474dd7abda/druid/config/traefik/docker-compose.yml) *Okay, it's not literally one line. It's five. @@ -151,7 +154,7 @@ I have never been tempted to look for alternatives. I struggle to imagine how a Oh, it would be nice if it handled [dispatching to other Traefik instances](https://gitea.jafner.tools/Jafner/homelab/issues/71) in a more intuitive/simple way. I haven't been able to get that working. -## Keycloak: Sign in to Jafner.net +### Keycloak: Sign in to Jafner.net *IAM provider* | [Keycloak](https://www.keycloak.org/) | [Configuration](https://gitea.jafner.tools/Jafner/homelab/src/commit/94e0aed892812adcfd94bd84e588eb474dd7abda/fighter/config/keycloak) It's easy to allow your password manager's "local accounts" folder slowly grow to dozens or hundreds of credentials as services are trialed, decomissioned, reinstalled, and troubleshooted (troubleshot?). Further, supporting basic account information updates for *users that aren't me* is non-trivial. How many SMTP submission API keys would I need to support each of my services sending their own "Recover your account password" emails? @@ -161,7 +164,7 @@ Keycloak provides much-needed consolidation of account management. Just like a * One day I'll be able to manage *every single Jafner.net application's* ID and access via Keycloak, but a few have held out. But that's an entire article itself. Until then I'll be happy that *most* applications and services either support native OAuth2 or OIDC, or are single-user and can be simply gated behind Traefik forwardauth. -## Wireguard: Road warrior who needs to reboot the Minecraft server +### Wireguard: Road warrior who needs to reboot the Minecraft server *Quick, easy, fast VPN plus quick, easy, fast web UI* | [Wireguard](https://www.wireguard.com/) | [WG-Easy](https://github.com/wg-easy/wg-easy) | [Configuration: Fighter](https://gitea.jafner.tools/Jafner/homelab/src/commit/94e0aed892812adcfd94bd84e588eb474dd7abda/fighter/config/wireguard/docker-compose.yml) | [Configuration: Druid](https://gitea.jafner.tools/Jafner/homelab/src/commit/94e0aed892812adcfd94bd84e588eb474dd7abda/druid/config/wireguard/docker-compose.yml) Every homelabber is faced with the question of how to administrate their server when they aren't sitting (or standing) at their desk at home. It's a great question; you're dipping your toes into [security posture](https://csrc.nist.gov/glossary/term/security_posture), and the constant tension between security and ease-of-access. Using SSH keys instead of passwords is a no-brainer, but do you also configure [SSH 2FA](https://www.digitalocean.com/community/tutorials/how-to-set-up-multi-factor-authentication-for-ssh-on-ubuntu-20-04)? Most folks don't allow SSH traffic directly through the router, but *how* do you build and configure your VPN for SSHing into your server? @@ -176,7 +179,7 @@ The steps I take to secure my SSH hosts are detailed [here](https://gitea.jafner Lots of iteration led to this configuration. I'm sure I'll write it out at some point. -## Grafana, Prometheus, and Uptime-kuma: Observability before I knew what that meant +### Grafana, Prometheus, and Uptime-kuma: Observability before I knew what that meant [Grafana](https://grafana.com/) | [Prometheus](https://prometheus.io/) | [Uptime-kuma](https://github.com/louislam/uptime-kuma) | [Configuration: Monitoring Fighter](https://gitea.jafner.tools/Jafner/homelab/src/commit/94e0aed892812adcfd94bd84e588eb474dd7abda/fighter/config/monitoring) | [Configuration: Uptime-kuma Fighter](https://gitea.jafner.tools/Jafner/homelab/src/commit/94e0aed892812adcfd94bd84e588eb474dd7abda/fighter/config/uptime-kuma/docker-compose.yml) | [Configuration: Monitoring Druid](https://gitea.jafner.tools/Jafner/homelab/src/commit/94e0aed892812adcfd94bd84e588eb474dd7abda/druid/config/monitoring/docker-compose.yml) | [Configuration: Uptime-kuma Druid](https://gitea.jafner.tools/Jafner/homelab/src/commit/94e0aed892812adcfd94bd84e588eb474dd7abda/druid/config/uptime-kuma/docker-compose.yml) Before I knew what "Site Reliability Engineering" was, I had a Grafana instance (using ye olde Telegraf and InfluxDB) showing me pretty graphs. I was exposed to the timeseries database paradigm, and how to query it in a useful way. And later down the line I integrated [Loki](https://grafana.com/docs/loki/latest/) to pull all my Docker container logs into my one pretty visualization platform. I built dashboards for monitoring host health, troubleshooting specific issues, statuspages; I built alert policies to send notifications via Discord and email; and I exported data from practically every service. And then things settled down, and that data-analytics muscle began to atrophy. My environment was stable. So I changed tact. @@ -185,7 +188,7 @@ Uptime-kuma is simple, beautiful, and does all the things I need. HTTP and ping- All this lets me sleep easy knowing that if any of my services go down, I'll get a Discord notification. When someone asks me "Hey, is \ down?" I can answer confidently, "Nope, works on my system." -# Closing thoughts, and looking forward +## Closing thoughts, and looking forward I've not written much about my lab before. It's been a challenge to resist rambling about all the challenges and iterations I walked through to get the lab to the state it's in today. And even just in the process of writing this the last couple days I've come to realize a few low-hanging fruit improvements I could make. While I'm proud of all the things I've tought myself in this process, I could not have done it without hundreds of thousands of hours of freely-contributed projects, Q&As, documentation, tutorials, and every other kind of support.