{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "Series of posts about my homelab Archive",
  "home_page_url": "https://pype.dev/homelab/",
  "feed_url": "https://pype.dev/homelab/archive/feed.json",
  "description": "My thoughts and streams of consciousness organized into barely coherent posts about things",
  "authors": [
    {
      "name": "Nic Payne"
    }
  ],
  "items": [
    {
      "id": "https://pype.dev/harbor-faulted-disk-replacement/",
      "url": "https://pype.dev/harbor-faulted-disk-replacement/",
      "title": "The Faulted Disk: harbor Replacement Writeup",
      "content_html": "\u003cp\u003eThe sequel to \u003ca href=\"/panicking-led-to-losing-my-desktop\"\u003epanicking-led-to-losing-my-desktop\u003c/a\u003e — this time the monitoring actually caught the disk dying, and nothing was lost.\u003c/p\u003e\n\u003ch2 id=\"what-happened\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eWhat happened\u003c/span\u003e \u003ca href=\"#what-happened\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eharbor\u003c/code\u003e is my replica pool — a 10.9T mirror (2x 12TB) that receives syncoid snapshots from \u003ccode\u003etank\u003c/code\u003e. One side of the mirror, a Seagate Exos \u003ccode\u003eST12000NM0127\u003c/code\u003e (serial \u003ccode\u003eZJV4QFLB\u003c/code\u003e, \u003ccode\u003e/dev/sdb\u003c/code\u003e), went \u003cstrong\u003eFAULTED\u003c/strong\u003e with 14 read + 22 checksum errors.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emirror-0                              DEGRADED     0     0     0\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  ata-ST12000VN0008-2PH103_ZTM0NFDW  ONLINE       0     0     0\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  ata-ST12000NM0127_ZJV4QFLB         FAULTED     14     0    22  too many errors\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThe IronWolf mirror side carried the pool — \u003ccode\u003eNo known data errors\u003c/code\u003e. ZFS redundancy did exactly its job.\u003c/p\u003e\n\u003ch2 id=\"the-difference-from-last-time\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eThe difference from last time\u003c/span\u003e \u003ca href=\"#the-difference-from-last-time\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eLast failure: no monitoring, found out by accident months later, desktop died.\u003c/p\u003e\n\u003cp\u003eThis failure: SigNoz + node-exporter\u0026rsquo;s ZFS collector → \u003ccode\u003enode_zfs_zpool_state{state=\u0026quot;degraded\u0026quot;}\u003c/code\u003e → alert rule → Gotify → my phone. The gotify notification fired \u003cem\u003ebefore\u003c/em\u003e I knew anything was wrong.\u003c/p\u003e\n\u003ch2 id=\"diagnosis\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eDiagnosis\u003c/span\u003e \u003ca href=\"#diagnosis\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eBefore \u003ccode\u003ezpool clear\u003c/code\u003e or replace — check SMART. \u003ccode\u003esmartctl-exporter\u003c/code\u003e already scrapes all disks into SigNoz, so I didn\u0026rsquo;t even need sudo:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eReallocated_Sector_Ct\u003c/code\u003e raw = \u003cstrong\u003e3024\u003c/strong\u003e and counting\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eOffline_Uncorrectable\u003c/code\u003e value/worst still 100 but raw errors climbing\u003c/li\u003e\n\u003cli\u003eSMART overall: still PASS (SMART\u0026rsquo;s overall bit is conservative until threshold)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e3k+ remapped sectors is a platter going bad — not a cable blip. Verdict: replace, don\u0026rsquo;t clear.\u003c/p\u003e\n\u003ch2 id=\"the-swap-the-annoying-part\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eThe swap (the annoying part)\u003c/span\u003e \u003ca href=\"#the-swap-the-annoying-part\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHot-plug is never as smooth as it should be:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003ezpool offline harbor \u0026lt;old\u0026gt;\u003c/code\u003e to stop writes to the dead drive — actually skipped; drive fell off the bus on its own\u003c/li\u003e\n\u003cli\u003eNew IronWolf \u003ccode\u003eZTN1CQ07\u003c/code\u003e in hand → plugged into ghost\u0026rsquo;s SATA → \u003cstrong\u003edidn\u0026rsquo;t enumerate\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003eForced rescan (\u003ccode\u003eecho \u0026quot;- - -\u0026quot; | sudo tee /sys/class/scsi_host/host*/scan\u003c/code\u003e) → nothing\u003c/li\u003e\n\u003cli\u003eMoved it to the \u003cem\u003eold drive\u0026rsquo;s port\u003c/em\u003e → nothing\u003c/li\u003e\n\u003cli\u003eSabrent USB dock on aurora → dock enumerated as \u003ccode\u003e0B\u003c/code\u003e device, no disk behind it → reseated + replugged → \u003cstrong\u003edrive spun up and appeared\u003c/strong\u003e: \u003ccode\u003e/dev/sdd\u003c/code\u003e, 10.9T, old ZFS partition table on it (used drive — \u003ccode\u003epart1\u003c/code\u003e/\u003ccode\u003epart9\u003c/code\u003e layout)\u003c/li\u003e\n\u003cli\u003eBack to ghost, direct SATA → enumerated as \u003ccode\u003esdb\u003c/code\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eLesson: \u0026ldquo;spins up but doesn\u0026rsquo;t enumerate\u0026rdquo; on direct SATA + dock-shows-0B = seating/power problem, not DOA. The drive was fine all along.\u003c/p\u003e\n\u003ch2 id=\"the-replace\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eThe replace\u003c/span\u003e \u003ca href=\"#the-replace\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo zpool replace harbor \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  ata-ST12000NM0127_ZJV4QFLB \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  ata-ST12000VN0008-2PH103_ZTN1CQ07\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eResilver: \u003cstrong\u003e8.80T in 18h38m, 0 errors\u003c/strong\u003e (~154M/s). Pool stayed online and usable the whole time.\u003c/p\u003e\n\u003cp\u003eOne gotcha: after resilver, \u003ccode\u003ezpool status\u003c/code\u003e showed \u003ccode\u003eerrors: 1 data errors\u003c/code\u003e — but \u003ccode\u003ezpool status -v\u003c/code\u003e showed an \u003cstrong\u003eempty error list\u003c/strong\u003e. The corrupted data was already repaired; the counter was just stale. \u003ccode\u003esudo zpool clear harbor\u003c/code\u003e → clean.\u003c/p\u003e\n\u003ch2 id=\"the-monitoring-that-made-this-possible\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eThe monitoring that made this possible\u003c/span\u003e \u003ca href=\"#the-monitoring-that-made-this-possible\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eWired during this session (all now in SigNoz):\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003enode_zfs_zpool_state\u003c/code\u003e — pool health (node-exporter zfs collector)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esmartctl-exporter\u003c/code\u003e — SMART attributes incl. reallocated sectors (the early-death signal)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ezfs-metrics.sh\u003c/code\u003e textfile bridge — sanoid \u003ccode\u003e--monitor-*\u003c/code\u003e exit codes, zpool error counters, scrub ages, resilver %, syncoid last-success\u003c/li\u003e\n\u003cli\u003eAlert rules → Gotify → phone\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe replication alerting even proved itself live: syncoid failed twice during the resilver window and I got paged on both. Turned out to be send-time contention — self-healed once resilver finished — but the notification path works end to end.\u003c/p\u003e\n\u003ch2 id=\"remaining-homework\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eRemaining homework\u003c/span\u003e \u003ca href=\"#remaining-homework\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eBuy the replacement spare (the shelf\u0026rsquo;s empty now)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e10Fold\u003c/code\u003e datasets are garbage + have zero snapshots — destroy\u003c/li\u003e\n\u003cli\u003eEvery scheduled job emits \u003ccode\u003ecron_last_success_epoch\u003c/code\u003e now — if a job dies silently again, I\u0026rsquo;ll know\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSame failure as April, opposite outcome. Redundancy did the protection; monitoring did the \u003cem\u003edetection\u003c/em\u003e. You need both.\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e\u003cem\u003eCo-authored with Devin, who ran the monitoring stack, the SMART diagnosis, and the alerting loop.\u003c/em\u003e\u003c/p\u003e\n",
      "content_text": "\nThe sequel to [panicking-led-to-losing-my-desktop](/panicking-led-to-losing-my-desktop) — this time the monitoring actually caught the disk dying, and nothing was lost.\n\n## What happened\n\n`harbor` is my replica pool — a 10.9T mirror (2x 12TB) that receives syncoid snapshots from `tank`. One side of the mirror, a Seagate Exos `ST12000NM0127` (serial `ZJV4QFLB`, `/dev/sdb`), went **FAULTED** with 14 read + 22 checksum errors.\n\n``` text\nmirror-0                              DEGRADED     0     0     0\n  ata-ST12000VN0008-2PH103_ZTM0NFDW  ONLINE       0     0     0\n  ata-ST12000NM0127_ZJV4QFLB         FAULTED     14     0    22  too many errors\n```\n\nThe IronWolf mirror side carried the pool — `No known data errors`. ZFS redundancy did exactly its job.\n\n## The difference from last time\n\nLast failure: no monitoring, found out by accident months later, desktop died.\n\nThis failure: SigNoz + node-exporter's ZFS collector → `node_zfs_zpool_state{state=\"degraded\"}` → alert rule → Gotify → my phone. The gotify notification fired *before* I knew anything was wrong.\n\n## Diagnosis\n\nBefore `zpool clear` or replace — check SMART. `smartctl-exporter` already scrapes all disks into SigNoz, so I didn't even need sudo:\n\n- `Reallocated_Sector_Ct` raw = **3024** and counting\n- `Offline_Uncorrectable` value/worst still 100 but raw errors climbing\n- SMART overall: still PASS (SMART's overall bit is conservative until threshold)\n\n3k+ remapped sectors is a platter going bad — not a cable blip. Verdict: replace, don't clear.\n\n## The swap (the annoying part)\n\nHot-plug is never as smooth as it should be:\n\n1. `zpool offline harbor \u003cold\u003e` to stop writes to the dead drive — actually skipped; drive fell off the bus on its own\n2. New IronWolf `ZTN1CQ07` in hand → plugged into ghost's SATA → **didn't enumerate**\n3. Forced rescan (`echo \"- - -\" | sudo tee /sys/class/scsi_host/host*/scan`) → nothing\n4. Moved it to the *old drive's port* → nothing\n5. Sabrent USB dock on aurora → dock enumerated as `0B` device, no disk behind it → reseated + replugged → **drive spun up and appeared**: `/dev/sdd`, 10.9T, old ZFS partition table on it (used drive — `part1`/`part9` layout)\n6. Back to ghost, direct SATA → enumerated as `sdb`\n\nLesson: \"spins up but doesn't enumerate\" on direct SATA + dock-shows-0B = seating/power problem, not DOA. The drive was fine all along.\n\n## The replace\n\n``` bash\nsudo zpool replace harbor \\\n  ata-ST12000NM0127_ZJV4QFLB \\\n  ata-ST12000VN0008-2PH103_ZTN1CQ07\n```\n\nResilver: **8.80T in 18h38m, 0 errors** (~154M/s). Pool stayed online and usable the whole time.\n\nOne gotcha: after resilver, `zpool status` showed `errors: 1 data errors` — but `zpool status -v` showed an **empty error list**. The corrupted data was already repaired; the counter was just stale. `sudo zpool clear harbor` → clean.\n\n## The monitoring that made this possible\n\nWired during this session (all now in SigNoz):\n\n- `node_zfs_zpool_state` — pool health (node-exporter zfs collector)\n- `smartctl-exporter` — SMART attributes incl. reallocated sectors (the early-death signal)\n- `zfs-metrics.sh` textfile bridge — sanoid `--monitor-*` exit codes, zpool error counters, scrub ages, resilver %, syncoid last-success\n- Alert rules → Gotify → phone\n\nThe replication alerting even proved itself live: syncoid failed twice during the resilver window and I got paged on both. Turned out to be send-time contention — self-healed once resilver finished — but the notification path works end to end.\n\n## Remaining homework\n\n- Buy the replacement spare (the shelf's empty now)\n- `10Fold` datasets are garbage + have zero snapshots — destroy\n- Every scheduled job emits `cron_last_success_epoch` now — if a job dies silently again, I'll know\n\nSame failure as April, opposite outcome. Redundancy did the protection; monitoring did the *detection*. You need both.\n\n---\n\n*Co-authored with Devin, who ran the monitoring stack, the SMART diagnosis, and the alerting loop.*\n",
      "summary": "The sequel to panicking-led-to-losing-my-desktop — this time the monitoring actually caught the disk dying, and nothing was lost.",
      "date_published": "2026-10-06T21:30:00Z",
      "date_modified": "2026-10-06T21:30:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "zfs",
        "tech",
        "backup"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-871/",
      "url": "https://pype.dev/thoughts-871/",
      "title": "💭 Docker | Atuin Docs",
      "content_text": "\n\u003ca href=\"https://docs.atuin.sh/self-hosting/docker/#using-systemd-to-manage-your-atuin-server\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://docs.atuin.sh/self-hosting/docker/#using-systemd-to-manage-your-atuin-server\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - Docker | Atuin Docs\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://docs.atuin.sh/self-hosting/docker/#using-systemd-to-manage-your-atuin-server\"\u003eDocker | Atuin Docs\u003c/a\u003e\n\n---\n\nA 2-fer... So I want to host atuin and share shell history across my machines on my tailnet I think... it's such a nice interface but I barely use it so I'm sure the features will improve some aspects of my life. And secondly, this section on using systemd is interesting... I hadn't thought to use systemd to schedule container upgrades - sounds incredibly trivial and probably a widely practiced thing now that I say it out loud... Saving here for implementing something... sometime...\n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "A 2-fer... So I want to host atuin and share shell history across my machines on my tailnet I think... it's such a nice",
      "date_published": "2025-11-22T20:58:59Z",
      "date_modified": "2025-11-22T20:58:59Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "upgrades",
        "docker",
        "ssh",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/homelabbing-realization-configs-and-git/",
      "url": "https://pype.dev/homelabbing-realization-configs-and-git/",
      "title": "Homelabbing Realization - Configs and Git",
      "content_html": "\u003ch2 id=\"realization\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eRealization\u003c/span\u003e \u003ca href=\"#realization\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI\u0026rsquo;m back to brainstorming migrations away from Docker Compose to something that\nsolves multi-node networking and secrets but I don\u0026rsquo;t want to go to k8s\u0026hellip; so my\noptions are probably Docker Swarm or Nomad. As I wrestle mentally here I was\nthinking about one of my issues with multi-node setup is that I still keep\neverything out of one git repo, so if something gets managed remotely then I\nget out of sync. Best example is dashy, Due to some constraint of wanting to be\nas close to zero-day deployment-ready as possible, I think I overcomplicate\nsome of the simple stuff - like it\u0026rsquo;s ok to just have to put a file on a server\nfor a container to start the first time\u0026hellip; That doesn\u0026rsquo;t mean ansible is a\nrequirement, in fact lately I\u0026rsquo;ve just leaned into just recipes. But even then,\nI cornered myself into tracking my dashy config in git, so I\u0026rsquo;m hesitant to ever\nupdate it in the browser cause I\u0026rsquo;ll have to redownload the config, reconcile\nthe formatting differences in my repo (there\u0026rsquo;s a reason for this that a linter\ndoesn\u0026rsquo;t ssolve\u0026hellip;), etc\u0026hellip;. but in all of my brainstorming I just decided that\nmy dashy config doesn\u0026rsquo;t have to live in git\u0026hellip; it can just be on the zfs\nstorage, which is backed up, and configured via the app itself\u0026hellip; the config\ncan simply be apart of the data and container lifecycle, it doesn\u0026rsquo;t have to be\napart of the infra lifecycle.\u003c/p\u003e\n",
      "content_text": "\n## Realization\n\nI'm back to brainstorming migrations away from Docker Compose to something that\nsolves multi-node networking and secrets but I don't want to go to k8s... so my\noptions are probably Docker Swarm or Nomad. As I wrestle mentally here I was\nthinking about one of my issues with multi-node setup is that I still keep\neverything out of one git repo, so if something gets managed remotely then I\nget out of sync. Best example is dashy, Due to some constraint of wanting to be\nas close to zero-day deployment-ready as possible, I think I overcomplicate\nsome of the simple stuff - like it's ok to just have to put a file on a server\nfor a container to start the first time... That doesn't mean ansible is a\nrequirement, in fact lately I've just leaned into just recipes. But even then,\nI cornered myself into tracking my dashy config in git, so I'm hesitant to ever\nupdate it in the browser cause I'll have to redownload the config, reconcile\nthe formatting differences in my repo (there's a reason for this that a linter\ndoesn't ssolve...), etc.... but in all of my brainstorming I just decided that\nmy dashy config doesn't have to live in git... it can just be on the zfs\nstorage, which is backed up, and configured via the app itself... the config\ncan simply be apart of the data and container lifecycle, it doesn't have to be\napart of the infra lifecycle.\n",
      "summary": "I'm back to brainstorming migrations away from Docker Compose to something that solves multi-node networking and secrets but I don't want to go to k8s... so...",
      "date_published": "2025-11-13T05:48:15Z",
      "date_modified": "2025-11-13T05:48:15Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "note"
      ]
    },
    {
      "id": "https://pype.dev/repoflow-robot-user/",
      "url": "https://pype.dev/repoflow-robot-user/",
      "title": "RepoFlow Robot User",
      "content_html": "\u003cp\u003eI\u0026rsquo;m trying to lean into \u003ca href=\"https://repoflow.io\"\u003erepoFlow\u003c/a\u003e at home, and model some slightly better\npatterns than open borders to artifacts across all my services. As I\u0026rsquo;m getting repoflow\ngoing I see that I can make users in the console, but then I do have to invite\nusers to workspaces with a manually generate invite link.\u003c/p\u003e\n\u003cp\u003eThe workspaces an abstraction layer, and in each workspace can be many kinds of\nrepositories. For my purposes I\u0026rsquo;ll probably have 2 workspaces, even though 1\nwould almost certainly suffice.\u003c/p\u003e\n\u003cp\u003eThere doesn\u0026rsquo;t seem to be a way to add a user to a workspace from the admin\nsetting so for a while I was pretty confused why I couldn\u0026rsquo;t add my robot user\nto a docker repository in my main workspace\u0026hellip;\u003c/p\u003e\n\u003cp\u003eAfter generating the invite link and accepting though then I see in the workspace settings a\nsimple click to give the robot user access to all repos (if you want)\u003c/p\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20251111122419_580b2ad4.png\" alt=\"20251111122419_580b2ad4.png\"\u003e\n\u003c/figure\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20251110162252_6c7b2fe9.png\" alt=\"20251110162252_6c7b2fe9.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e\u003ccode\u003eCan manage\u003c/code\u003e allows the user to mutate tags (ie. push \u003ccode\u003elatest\u003c/code\u003e docker tags). If\nthe user only has \u003ccode\u003eCan deploy\u003c/code\u003e then they can only create new artifacts (ie. not\nmutate any tags)\u003c/p\u003e\n",
      "content_text": "\nI'm trying to lean into [repoFlow](https://repoflow.io) at home, and model some slightly better\npatterns than open borders to artifacts across all my services. As I'm getting repoflow\ngoing I see that I can make users in the console, but then I do have to invite\nusers to workspaces with a manually generate invite link.\n\nThe workspaces an abstraction layer, and in each workspace can be many kinds of\nrepositories. For my purposes I'll probably have 2 workspaces, even though 1\nwould almost certainly suffice.\n\nThere doesn't seem to be a way to add a user to a workspace from the admin\nsetting so for a while I was pretty confused why I couldn't add my robot user\nto a docker repository in my main workspace...\n\nAfter generating the invite link and accepting though then I see in the workspace settings a\nsimple click to give the robot user access to all repos (if you want)\n\n![20251111122419_580b2ad4.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20251111122419_580b2ad4.png)\n\n![20251110162252_6c7b2fe9.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20251110162252_6c7b2fe9.png)\n\n`Can manage` allows the user to mutate tags (ie. push `latest` docker tags). If\nthe user only has `Can deploy` then they can only create new artifacts (ie. not\nmutate any tags)\n",
      "summary": "I'm trying to lean into repoFlow at home, and model some slightly better patterns than open borders to artifacts across all my services. As I'm getting...",
      "date_published": "2025-11-10T09:24:25Z",
      "date_modified": "2025-11-10T09:24:25Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/proxy-pull-docker-images-from-self-hosted-container-registry-through-self-hosted-repoflow/",
      "url": "https://pype.dev/proxy-pull-docker-images-from-self-hosted-container-registry-through-self-hosted-repoflow/",
      "title": "Proxy Pull Docker Images From Self-Hosted Container Registry Through Self-Hosted Repoflow",
      "content_html": "\u003cp\u003eThis post is a short write-up of an issue I had while exploring \u003ca href=\"https://repoflow.io\"\u003eReploflow\u003c/a\u003e - a\nsuper solid artifactory-esq replacement for the homelab (and enterprise!). I\u0026rsquo;ve been playing with\nit and have tried to setup a few artifact repos that I\u0026rsquo;m familiar with - docker\nand pypi.\u003c/p\u003e\n\u003ch2 id=\"pypi\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003ePyPi\u003c/span\u003e \u003ca href=\"#pypi\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThis isn\u0026rsquo;t a post about repoflow, but I had an issue with pypi and Tomer was\nEXTREMELY responsive in helping to fix my issue and patch repoflow within a day\nof me reporting the issue via email!\u003c/p\u003e\n\u003ch2 id=\"docker\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eDocker\u003c/span\u003e \u003ca href=\"#docker\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eFor docker I have a few options I just wanted to see work - obviously\nproxy pull from Dockerhub for ease, but also in the interim I\u0026rsquo;d like to proxy\npull from my original container registry to avoid having to update any homelab config just yet.\nNow, obviously I\u0026rsquo;ll have to update all my build pipelines to start using\nrepoflow, and my homelab configuration to reference the repoflow docker\nrepository rather than my existing registry.\u003c/p\u003e\n\u003cp\u003eBut there\u0026rsquo;s something to bear in mind if maintaining that middle registry -\nturns out a there\u0026rsquo;s a default namespace in dockerhub \u003ccode\u003e/library/\u003c/code\u003e and repoflow\nexpects this standard across any docker registry, so it\u0026rsquo;s pull paths fully\nresolve to an incorrect tag if you don\u0026rsquo;t take this into account in your\nexisting infrastructure.\u003c/p\u003e\n\u003cp\u003eTLDR: if you tag an image \u003ccode\u003emyregistry/ubuntu:latest\u003c/code\u003e and push it\nthen try to pull it back through repoflow then repoflow expects the image to be\n\u003ccode\u003emyregistry/library/ubuntu:latest\u003c/code\u003e. I think repoflow should support\nconfigurating the namespace/org for the images - but in the meantime I can\ngo find all my images and update my build scripts to add /library/ to my\ntags\u0026hellip; or while I\u0026rsquo;m doing that I can just push to repoflow directly\u0026hellip; All in\nall, nice little lesson on namespaces in docker repos and third-party tooling.\u003c/p\u003e\n",
      "content_text": "\nThis post is a short write-up of an issue I had while exploring [Reploflow](https://repoflow.io) - a\nsuper solid artifactory-esq replacement for the homelab (and enterprise!). I've been playing with\nit and have tried to setup a few artifact repos that I'm familiar with - docker\nand pypi. \n\n## PyPi\n\nThis isn't a post about repoflow, but I had an issue with pypi and Tomer was\nEXTREMELY responsive in helping to fix my issue and patch repoflow within a day\nof me reporting the issue via email!\n\n## Docker\n\nFor docker I have a few options I just wanted to see work - obviously\nproxy pull from Dockerhub for ease, but also in the interim I'd like to proxy\npull from my original container registry to avoid having to update any homelab config just yet.\nNow, obviously I'll have to update all my build pipelines to start using\nrepoflow, and my homelab configuration to reference the repoflow docker\nrepository rather than my existing registry. \n\nBut there's something to bear in mind if maintaining that middle registry -\nturns out a there's a default namespace in dockerhub `/library/` and repoflow\nexpects this standard across any docker registry, so it's pull paths fully\nresolve to an incorrect tag if you don't take this into account in your\nexisting infrastructure.\n\nTLDR: if you tag an image `myregistry/ubuntu:latest` and push it\nthen try to pull it back through repoflow then repoflow expects the image to be\n`myregistry/library/ubuntu:latest`. I think repoflow should support\nconfigurating the namespace/org for the images - but in the meantime I can\ngo find all my images and update my build scripts to add /library/ to my\ntags... or while I'm doing that I can just push to repoflow directly... All in\nall, nice little lesson on namespaces in docker repos and third-party tooling. \n\n",
      "summary": "This post is a short write-up of an issue I had while exploring Reploflow - a super solid artifactory-esq replacement for the homelab (and enterprise!). I've...",
      "date_published": "2025-08-12T06:59:02Z",
      "date_modified": "2025-08-12T06:59:02Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "repoflow"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-764/",
      "url": "https://pype.dev/thoughts-764/",
      "title": "💭 My Ultimate Self-hosting Setup",
      "content_text": "\n\u003ca href=\"https://codecaptured.com/blog/my-ultimate-self-hosting-setup/\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://codecaptured.com/blog/my-ultimate-self-hosting-setup/\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - My Ultimate Self-hosting Setup\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://codecaptured.com/blog/my-ultimate-self-hosting-setup/\"\u003eMy Ultimate Self-hosting Setup\u003c/a\u003e\n\n---\n\ngreat post on self-hosting. I think in a lot of similar ways and had a siar journey. There's things I want to accomplish as time goes on, looking for motivation to get a post like this going myself\n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "great post on self-hosting. I think in a lot of similar ways and had a siar journey. There's things I want to accomplish",
      "date_published": "2025-07-25T19:56:38Z",
      "date_modified": "2025-07-25T19:56:38Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/using-restic-to-backup-my-home-directory/",
      "url": "https://pype.dev/using-restic-to-backup-my-home-directory/",
      "title": "Using restic to backup my home directory",
      "content_text": "\n# Intro\n\nI need to backup my personal $HOME to my NAS cause there's a lot in there, and\nmostly my git projects with .env files all over. Plus some docker data\n\n## Why Not ZFS?\n\nGREAT QUESTION! It's because I struggled getting all the syncoid/sanoid\nrequirements installed on my Aurora OS.... I like the immutable desktop trend,\nbut I don't understand rpm-ostree enough to properly get all the lower level\nkernel stuff setup in a way I trust. So because I don't have ZFS at $HOME\nwhat's a boy to do?\n\n`rsync` would probably work fine especially if I [[rsync-like-a-pro]] but I figured I could cobble together some other tech and broaden my horizons...\n\n## Enter restic\n\nApparently [restic](https://restic.net/) has been around for a while, and you can run it in a container... awesome that's all I needed to hear...\n\n## How?\n\nI'll use a docker compose stack for this... typically I think running `restic`\nright on the host is the way to go, but on my desktop I float between my host\nand distroboxes and to keep things as simple as possible, even though less\nefficient, I want to manage everything through containers as my homelab gets\nbuilt out and eventually I'll have a more full-featured ecosystem.\n\n## The Value\n\nYou can find code below and an example repo that more or less is what I use for my desktop backup but that's primarily what I was after.... backing up the data on my desktop to my NAS in a way that:\n\n1. I wouldn't have to \"remember\" how I was doing it\n\n- I accomplish this by having good git repo organization and README files that explain my own usage patterns\n\n2. Tracked snapshots\n\n- I need some kind of snapshotting - `zfs` has spoiled me, and turns out `restic` has some amount of support for it\n\n3. Running in docker would be ideal for now so that I don't need to worry about installing specific binaries across machine while I build out my patterns\n\nWith this setup I get to backup my $HOME to my NAS which contains 1. docker\nvolume info for all the AI workloads I run on my desktop and 2. all my\nsensitive info in my git repos is at least backed up in a way that I can\nrecover `.env` files with relative ease...\n\n# Code\n\nCheck out the [Example GH\nRepo](https://github.com/pypeaday/docker-compose-restic) but I'll drop key file\ncontents here for a quick read if you're interested in some of the setup... but\nthe blog post mostly ends here\n\n## The Files\n\nWe have a `docker-compose.yml` of course\n\n```yaml\nservices:\n  backup:\n    image: restic/restic:latest\n    network_mode: host\n    container_name: restic_backup\n    hostname: restic-backup-runner\n    env_file:\n      - .env\n    environment:\n      # The location of the backup repository inside the container\n      - RESTIC_REPOSITORY=/target\n      # The location of the password file inside the container\n      - RESTIC_PASSWORD_FILE=/password\n    volumes:\n      # --- Source and Config Mounts ---\n      - \"${BACKUP_SOURCE}:/source:ro\"\n      - \"${RESTIC_PASSWORD_FILE}:/password:ro\"\n      - \"./backup-and-prune.sh:/usr/local/bin/backup-and-prune:ro\"\n\n      # --- Persistent Data Mounts ---\n      - \"./.ssh:/root/.ssh:rw\"\n      - \"./.cache:/root/.cache:rw\"\n\n    # Set the default entrypoint to our new script. This will be executed when\n    # the container starts, unless overridden.\n    entrypoint: [\"/usr/local/bin/backup-and-prune\"]\n```\n\nYour `.env` file will need to look like this\n\n```bash\n``# HOST related variables\n# The source directory to back up (absolute path)\nBACKUP_SOURCE=/home/nic\n\n# --- Restic Configuration ---\n# The file containing the restic repository password (absolute path on host)\nHOST_RESTIC_PASSWORD_FILE=/home/nic/projects/personal/homelab-mono/dataops/docker/.restic-password\n# The SSH private key to use for connecting to the NAS (absolute path on host)\n# It's recommended to use a dedicated key for this purpose.\nSSH_PRIVATE_KEY_FILE=/home/nic/.skm/ghost/id_rsa\n\n# Container Env Vars\n# the container makes the sftp connection using my credentials, but nonetheless the container needs them, so this isn't envrc stuff\n\n# --- SFTP/SSH Connection Details for the NAS ---\nSFTP_USER=nic\nSFTP_HOST=ghost\n# The path on the NAS where the restic repository will be stored\nSFTP_PATH=/tank/encrypted/nas/nic-home/\n\n# --- Restic Configuration ---\n\nRESTIC_REPOSITORY=/target\nRESTIC_PASSWORD_FILE=/password\n```\n\nAnd then the backup script that the container will execute is something like this:\n\n```bash\n\n#!/bin/sh\nset -e # Exit immediately if a command exits with a non-zero status.\n\n# Construct the repository path from environment variables passed by docker-compose\nREPO=\"sftp:${SFTP_USER}@${SFTP_HOST}:${SFTP_PATH}\"\n\n# 1. Run the backup\n# -----------------\necho \"--- Starting backup for ${BACKUP_SOURCE} ---\"\nrestic backup /source --verbose -r \"${REPO}\"\necho \"--- Backup complete ---\"\n\n# 2. Clean up old snapshots according to the policy\n# --------------------------------------------------\necho \"--- Pruning old snapshots ---\n(Policy: keep last 7 daily, 4 weekly, 6 monthly)\"\nrestic forget \\\n    --prune \\\n    --keep-daily 7 \\\n    --keep-weekly 4 \\\n    --keep-monthly 6 \\\n    -r \"${REPO}\"\n\necho \"--- Backup and prune process finished successfully ---\"\n```\n\n## Systemd\n\nFinally there's a systemd unit and timer file in there so you can setup a systemd service for the backup\n\n### service\n\n```bash\n\n[Unit]\nDescription=Run Restic backup to NAS using Docker Compose\n# We are running this as a user service, so we assume that the system-level\n# docker.service is already running.\nAfter=network-online.target\n\n[Service]\nType=oneshot\n# Set the working directory to where your docker-compose.yml and .env file are located\nWorkingDirectory=/home/user/nas-backup/docker\n\n# The command to execute. We use the full path to docker-compose for reliability.\n# You may need to adjust this path if 'docker compose' is installed elsewhere.\nExecStart=/usr/bin/docker compose run --rm backup\n\n[Install]\nWantedBy=default.target\n```\n\n### timer\n\n```bash\n\n[Unit]\nDescription=Run Restic backup job daily\n\n[Timer]\n# Run daily at 2:00 AM\nOnCalendar=daily\n# Or uncomment for a specific time:\n# OnCalendar=*-*-* 02:00:00\n\n# Run the backup immediately if the last scheduled run was missed (e.g., if the computer was off)\nPersistent=true\n\n[Install]\nWantedBy=timers.target\n```\n",
      "summary": "I need to backup my personal $HOME to my NAS cause there's a lot in there, and mostly my git projects with .env files all over. Plus some docker data",
      "date_published": "2025-07-16T09:12:26Z",
      "date_modified": "2025-07-16T09:12:26Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/jellyfin/",
      "url": "https://pype.dev/jellyfin/",
      "title": "Jellyfin",
      "content_html": "\u003cp\u003eJellyfin is the media server software I run at home\u003c/p\u003e\n",
      "content_text": "\nJellyfin is the media server software I run at home\n",
      "summary": "Jellyfin is the media server software I run at home",
      "date_published": "2025-07-11T20:39:00Z",
      "date_modified": "2025-07-11T20:39:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "note"
      ]
    },
    {
      "id": "https://pype.dev/ghost/",
      "url": "https://pype.dev/ghost/",
      "title": "Ghost",
      "content_text": "\n# Intro\n\nGhost is my primary application server. These are the specs...\n\n\u003e I wrote about some of the specs in [[homelab-journey-part-1#current-homelab-setup]] but here is where I will keep up to date information\n\n## Why\n\nWhy `ghost`? I don't know... I was going for a theme at one point it time, or\nseveral points rather... and after giving up on the theatrics of a fully\nconsistent harry potter naming scheme across all my homelab entities, I decided\nto just come up with some short aliases that were easy to type. So `ghost` was\nborn, and the backup server is `ghost-vault`.\n\n## CPU\n\nI have a `AMD Ryzen 7 5700G with Radeon Graphics @ 16x 4.426GHz` in this bad\nboy... why this chip? Well I knew I wanted many cores, and I was previously on\na Ryzn 5 3600, which was fine but I noticed that as I started to develop with\ncontainers more that I was going to want to take advnaatage of more cores...\n\nI also was pretty sure that the built-in graphics would be enough for the\nacceleration requirements I had in mind - which was primarily [[jellyfin]].\n\nAt this point in time, I think AMD was still beating Intel on most of the\nbenchmarks I tended to care about (I was watching channels like Bitwit and LTT\nat the time of building this machine)\n\nSo because of the moderate amount of cores and built-in GPU, I paid $229 for it\naccording to my Amazon history, and it's currently priced at $174, so that's a\npretty sweet deal if you're on AM4 and looking to upgrade in July of 2025\n\n## Memory\n\nI maxxed her out at 128 Gee Beez. I snagged that kit of Crucial that's all\nblack that we've all seen on Amazon. I paid aboaut $90 for it, it's currently\npriced way high for some reason, which is unfortunate. It's been totally fine\nfor me as far as memory performance goes - in that it's stable and I don't\nthink about it...\n\n## Boot\n\nI have a 1 TB NVMe in here to boot from. I think it's a Crucial P3\n\n## Storage\n\nStorage is the interesting bit, it's supposed to be the most rock solid but\nit's also been the most fluid for me from a hardware perspective, and as of my\nmost recent case migration I think I'm in a good spot..\n\n\u003e The case is a Sagitatius 8-bay NAS Chassis from aliexpress\n\nI use\n[zfs](https://openzfs.github.io/openzfs-docs/Getting%20Started/index.html)\nand recommend you do to.... but this isn't a post about that\n\nMy primary zpool is a 12TB ZFS Mirror, and I have another 12TB ZFS Mirror as an\non-prem replica plugged into this same box.\n\nThere is a 4TB drive that serves as frigate's media directory - I wanted a\ndedicated drive due to the write-intensive nature of the NVR.\n\n\u003e I backup to an offsite box using syncoid\n\n## OS\n\nI am currently running Ubuntu Server 24.04\n\nI am eager for Ubuntu to get zfs in their release that contains the zfs data\ncorruption with encrypted datasets but I don't expect to see it until 26.04 at\nthe earliest _fingers crossed_.\n\n## KVM\n\nI recently purchased a [jetkvm](https://www.jetkvm.com/) and it's exactly what\nI need for both my main server and my backup off-site... An amazingly simple\nand elegant solution to remote KVM.\n\n## Applications\n\nCurrently I use `docker compose` to manage practically everything. Stay tuned\nfor more about those things\n\nI also have a few ansible playbooks for setting up my shell and some utilities\non my computers, including the server. They're in\n[github](https://github.com/pypeaday/ansible-playbooks)\n\nFind more at [[the-homelab]]\n",
      "summary": "Ghost is my primary application server. These are the specs...",
      "date_published": "2025-07-11T20:23:35Z",
      "date_modified": "2025-07-11T20:23:35Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/the-homelab/",
      "url": "https://pype.dev/the-homelab/",
      "title": "The Homelab",
      "content_text": "\n# The Lab\n\nThis is the landing page for my homelab posts. It isn't a feed because I will\nwrite things here and link out to relevant parts of the homelab.\n\nI'll probably have notes about the hardware mostly here.\n\n## Primary Application Server\n\nMy main server is called [[ghost]]\n\n## Current Homelab Setup\n\n\u003e I copied this our of [[homelab-journey-part-1#current-homelab-setup]] for now to stub out what this page will link to\n\n## Ad blocking | Pi-Hole\n\nHardware: pi-3\n\nI have a Raspberry Pi 3 hardwired in that is running pi-hole so that's been a\npart of my infrastructure now for a long time.\n\n## Router | OPNSense\n\n!!! note \"stats\"\n\n    CPU: i5-8700\n\n    Memory: 8GB of whatever was in the box\n\n    Storage: 1TB SSD\n\nMy router is an old Optiplex SFF 5060 I got from Amazon for less than $100.\nSo I'm running a x86 system for my router with\nOpenSense on it. Just seemed it to be another home lab standard and I'd like to\nsomeday bring pi-hole over there or use AdGuard or integrate those two things\nmaybe a little bit more completely but right now they are mostly separate.\n\n## Networking | VLANs\n\nThere's a\nmanaged switch in there for some VLAN tomfoolery for my cameras and an IOT\nnetwork type of a thing.\n\n## Networking | VPN | Tailscale\n\nThey're on tailscale as well so my DNS happens over tailscale.\n\n## My Desktop\n\n!!! note \"stats\"\n\n    CPU: Ryzen 7 5700X\n\n    GPU: Nvidia 3090\n\n    Memory: 64 GB\n\n    Storage: 4TB SSD + 2 TB HDD for zfs backup\n\n    OS: Universal Blue Aurora\n\nMy daily-driver desktop is somewhat apart of my homelab now as I have a 3090 in\nthere with 20 GB of VRAM so I can run some heavier LLMs for self-hosted AI\nworkloads. Everything in that space runs in a container and then I manage\ndocker containers with compose stacks and portainer for visibility.\n\n### Applications\n\nSome of the apps I run here are ollama, open-webui, automatic1111's stable diffusion webui, whisper-webui\n",
      "summary": "This is the landing page for my homelab posts. It isn't a feed because I will write things here and link out to relevant parts of the homelab.",
      "date_published": "2025-07-11T20:22:51Z",
      "date_modified": "2025-07-11T20:22:51Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-746/",
      "url": "https://pype.dev/thoughts-746/",
      "title": "💭 Docker Brings Compose to the AI Agent Era | Docker",
      "content_text": "\n\u003ca href=\"https://www.docker.com/blog/build-ai-agents-with-docker-compose/\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://www.docker.com/blog/build-ai-agents-with-docker-compose/\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - Docker Brings Compose to the AI Agent Era | Docker\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://www.docker.com/blog/build-ai-agents-with-docker-compose/\"\u003eDocker Brings Compose to the AI Agent Era | Docker\u003c/a\u003e\n\n---\n\nSeems like docker is leaning harder into compose - which is great for me as a heavy compose user. I had heard about some of the LLM enablements directly through docker desktop - for example taking fuller advantage of the host's compute power without paying the penalty of the nvidia runtime or something... I can't claim to have followed it all but I heard \"run LLMs in docker directly for a bigger boost\" and I'm in.\n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "Seems like docker is leaning harder into compose - which is great for me as a heavy compose user. I had heard about some",
      "date_published": "2025-07-11T11:49:41Z",
      "date_modified": "2025-07-11T11:49:41Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "docker",
        "ai",
        "homelab",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-740/",
      "url": "https://pype.dev/thoughts-740/",
      "title": "💭 restic · Backups done right!",
      "content_text": "\n\u003ca href=\"https://restic.net/\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://restic.net/\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - restic · Backups done right!\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://restic.net/\"\u003erestic · Backups done right!\u003c/a\u003e\n\n---\n\nWelp, I need to be backing up my desktop home directory, specifically a directory of docker volume data... I thought duplicati made sense, but that mostly targets cloud-based backends, and rsync is great but I wasn't sure how i wanted to manage the job. \nThrough a little AI chat I learned about restic and am working on a compose stack to run restic in a container to regularly backup my home directory via sftp to my NAS to then be swept up in my NAS backup workflow\n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "Welp, I need to be backing up my desktop home directory, specifically a directory of docker volume data... I thought dup",
      "date_published": "2025-07-08T11:53:41Z",
      "date_modified": "2025-07-08T11:53:41Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "nas",
        "homelab",
        "backups",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-to-nostr/",
      "url": "https://pype.dev/thoughts-to-nostr/",
      "title": "Thoughts To Nostr",
      "content_text": "\nI am trying to use [[temporal]] at home for running automated pipelines. It's\ndefinitely overkill for my use case but this is America...\n\nSo my first project is a system that takes my [[thoughts]] and posts them to\n[[nostr]] as I briefly discussed in [[testing-a-postiz-change-locally]].\n\nI have temporal infrastructure setup in homelab-compose and then\nhomelab-temporal should probably be homelab-temporal-pipelines or something,\nbut it's the app code. I also have a repo homelab-social-media-pipelines -\nwhich has been consolidated down into homelab-temporal. once that all works I\ncan destroy the homelab-social-media-pipelines repo\n\nNOTE: everything is moving to homelab-mono\n\n## Issue 01\n\nI am currently hitting a stupid python issue:\n\n```\nnic in homelab-temporal   main    ×2  ×4  ×7 via   v3.12.8(homelab-temporal)   (dev) 󰒄\n⬢ [devbox] ❯ python -c \"from homelab_temporal.postiz.postiz_client import PostizClient\"\n(homelab-temporal)\nnic in homelab-temporal   main    ×2  ×4  ×7 via   v3.12.8(homelab-temporal)   (dev) 󰒄\n⬢ [devbox] ❯ python scripts/postiz/simple_post.py\nTraceback (most recent call last):\n  File \"/home/nic/projects/personal/homelab-temporal/scripts/postiz/simple_post.py\", line 3, in \u003cmodule\u003e\n    from homelab_temporal.postiz.postiz_client import PostizClient, process_for_nostr, process_for_x\nModuleNotFoundError: No module named 'homelab_temporal'\n```\n\nvery dumb venv problem...\n\n## Resolution\n\nneed to use `python -m` because the script is outside the project root? see [[2025-07-08-notes]] and the chatgpt notes for more on this but it works now\n\n## Thoughts Order\n\nas of [[2025-07-11-notes]] I have the thoughts ordering correct - we post the oldest thoughts up to the newest ones. Now I want more intros for the notes so they don't get too repetitive\n\n## TODOs\n\n[x] - destroy the homelab-social-media-pipelines repo\n\n[] - think about how to structure things more... monorepo in homelab-temporal might be hard to manage with AI tools due to context management... unsure though\n\n[] - create workflow and activities for thoughts to nostr... revisit diagram to see what you need to build out in the temporal repo\n\n[] - do something like this for github stars and then blog posts\n\n---\n\nI need to update my templates for nostr og images using this as fodder\n\n```html\n\u003c!-- HTML Meta Tags --\u003e\n\u003ctitle\u003eNostr Design\u003c/title\u003e\n\u003cmeta\n  name=\"description\"\n  content=\"A comprehensive resource for designers and developers to build successful nostr products\"\n/\u003e\n\n\u003c!-- Facebook Meta Tags --\u003e\n\u003cmeta property=\"og:url\" content=\"https://nostrdesign.org\" /\u003e\n\u003cmeta property=\"og:type\" content=\"website\" /\u003e\n\u003cmeta property=\"og:title\" content=\"Nostr Design\" /\u003e\n\u003cmeta\n  property=\"og:description\"\n  content=\"A comprehensive resource for designers and developers to build successful nostr products\"\n/\u003e\n\u003cmeta\n  property=\"og:image\"\n  content=\"https://nostrdesign.org/img/nostr-cover.jpg\"\n/\u003e\n\n\u003c!-- Twitter Meta Tags --\u003e\n\u003cmeta name=\"twitter:card\" content=\"summary_large_image\" /\u003e\n\u003cmeta property=\"twitter:domain\" content=\"nostrdesign.org\" /\u003e\n\u003cmeta property=\"twitter:url\" content=\"https://nostrdesign.org\" /\u003e\n\u003cmeta name=\"twitter:title\" content=\"Nostr Design\" /\u003e\n\u003cmeta\n  name=\"twitter:description\"\n  content=\"A comprehensive resource for designers and developers to build successful nostr products\"\n/\u003e\n\u003cmeta\n  name=\"twitter:image\"\n  content=\"https://nostrdesign.org/img/nostr-cover.jpg\"\n/\u003e\n```\n\n## Dockerizing\n\nI think I wnt to dockerize my workers and workflows... build them out of the `homelab-temporal` repo but then run them in compose stacks... that can get stitched together better but for now that'll probably be a good target.\nI have things to think about though... for example the blog builder needs my ssh keys, or an ssh key for a user... also git is a little mess up anyways\n\n- temporal [link](https://temporal-ui.paynepride.com/namespaces/default/workflows/blog-build-ee488b69-6cdf-4819-bccd-df183cf8ec13/01981101-e48b-712a-96db-328ce720c13c/history)\n\n## Temporal\n\nI haev temporal workflows and stuff that all seem to work\n\non [[ 2025-08-08-notes ]] I had issues with my nostr relay being too public, so I shut it down, reconfigured postiz and stuff and got it workign again, more restricted and in-memory database\n",
      "summary": "I am trying to use temporal at home for running automated pipelines. It's definitely overkill for my use case but this is America...",
      "date_published": "2025-07-08T08:30:35Z",
      "date_modified": "2025-07-08T08:30:35Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "projects",
        "nostr",
        "homelab",
        "pipelines"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-737/",
      "url": "https://pype.dev/thoughts-737/",
      "title": "💭 HomeBox",
      "content_text": "\n\u003ca href=\"https://homebox.software/en/\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://homebox.software/en/\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - HomeBox\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://homebox.software/en/\"\u003eHomeBox\u003c/a\u003e\n\n---\n\nI stumbled onto homebox this morning scrolling a newsletter and it looks like something I've been lightly thinking about for a while. I have wanted a way to track all the things in my house, but I haven't given it enough thought to come up with the specific manner in which to do it. I've seen other asset trackers but today this one excited me. \nI spun it up at home quick and it looks great - It'll take quite a lot of time to fill it out but here's a few features I love out of the gate:\n\n1. the default setup seems very useful - pre-populated locations and tags for cataloging assets reduces the barrier to entry for me\n2. it's pretty nice lookin\n3. there's a label generator including qr codes that take you to the record in your homebox... I had an idea for something like this a while ago - qr codes to link to instructions for things around the house (like cleaning the oven or something). So it's neat to see that similar idea played out in another more useful way!\n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "I stumbled onto homebox this morning scrolling a newsletter and it looks like something I've been lightly thinking about",
      "date_published": "2025-07-07T10:48:12Z",
      "date_modified": "2025-07-07T10:48:12Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "asset-management",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-735/",
      "url": "https://pype.dev/thoughts-735/",
      "title": "💭 Self-Hosting A Cluster On Old Phones | Hackaday",
      "content_text": "\n\u003ca href=\"https://hackaday.com/2025/04/09/self-hosting-a-cluster-on-old-phones/?ref=dailydev\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://hackaday.com/2025/04/09/self-hosting-a-cluster-on-old-phones/?ref=dailydev\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - Self-Hosting A Cluster On Old Phones | Hackaday\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://hackaday.com/2025/04/09/self-hosting-a-cluster-on-old-phones/?ref=dailydev\"\u003eSelf-Hosting A Cluster On Old Phones | Hackaday\u003c/a\u003e\n\n---\n\nCame across a blog and article on using a mobile OS to self-host a cluster on old phones... I happen to keep several old android phones lying around and although I'm not presently super interested in figuring out an android/arm based homelab, I am excited for the next coming years when I'm sure it'll only get easier, phones will only be more powerful, and perhaps we'll be running full blown CV pipeline in k8s clusters running on Pixel devices!\n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "Came across a blog and article on using a mobile OS to self-host a cluster on old phones... I happen to keep several old",
      "date_published": "2025-07-06T11:30:17Z",
      "date_modified": "2025-07-06T11:30:17Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "k8s",
        "linux",
        "android",
        "homelab",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/github-star-sorter/",
      "url": "https://pype.dev/github-star-sorter/",
      "title": "Github Star Sorter",
      "content_html": "\u003cp\u003eI wrote a simple app to sort, tag, and create tickets at home for my github\nstars\u0026hellip; As of right now I have 1.3k stars and no convenient way to view them\nor remember which ones were ones I actually wanted to do something with. This\nsimple UI makes scrolling the stars list easy, updates is easy, and the kicker\nfor me is Kanboard integration so I can click a button from the stars UI and\nget a ticket made in my kanboard instance so that the work I want to do is in\nfront of me and not hidden by Github\u0026rsquo;s shockingly HORRIBLE UI.\u003c/p\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250701125804_c41ec692.png\" alt=\"20250701125804_c41ec692.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/pypeaday/gh-star-sorter\"\u003eGH Link\u003c/a\u003e\u003c/p\u003e\n",
      "content_text": "\nI wrote a simple app to sort, tag, and create tickets at home for my github\nstars... As of right now I have 1.3k stars and no convenient way to view them\nor remember which ones were ones I actually wanted to do something with. This\nsimple UI makes scrolling the stars list easy, updates is easy, and the kicker\nfor me is Kanboard integration so I can click a button from the stars UI and\nget a ticket made in my kanboard instance so that the work I want to do is in\nfront of me and not hidden by Github's shockingly HORRIBLE UI.\n\n![20250701125804_c41ec692.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250701125804_c41ec692.png)\n\n[GH Link](https://github.com/pypeaday/gh-star-sorter)\n",
      "summary": "I wrote a simple app to sort, tag, and create tickets at home for my github stars... As of right now I have 1.3k stars and no convenient way to view them or...",
      "date_published": "2025-07-01T08:01:31Z",
      "date_modified": "2025-07-01T08:01:31Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/temporal/",
      "url": "https://pype.dev/temporal/",
      "title": "temporal",
      "content_html": "\u003cp\u003e\u003ca href=\"https://temporal.io/\"\u003eTemporal\u003c/a\u003e is a workflow orchestrator that I\u0026rsquo;m interested in\u003c/p\u003e\n",
      "content_text": "\n[Temporal](https://temporal.io/) is a workflow orchestrator that I'm interested in\n",
      "summary": "Temporal is a workflow orchestrator that I'm interested in",
      "date_published": "2025-06-24T21:21:43Z",
      "date_modified": "2025-06-24T21:21:43Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "temporal"
      ]
    },
    {
      "id": "https://pype.dev/traefik-and-grpc-for-temporal-at-home/",
      "url": "https://pype.dev/traefik-and-grpc-for-temporal-at-home/",
      "title": "Traefik and gRPC for Temporal at home",
      "content_text": "\n# Temporal Networking Woes\n\nSomeday I will potentially write up some stuff about [[temporal]] but for now\nit's a workflow orchestrator that I'm interested in and I wanted to PoC it in\nmy homelab by replacing a simple cron job to build my blog with a temporal\nworkflow and activity. I was IMMEDIATELY thwarted by a networking error that\nfeels crazy to me but maybe won't be to others... so enjoy the problem and if\nyou're here from a Google search, I hope it's helpful.\n\nGetting started with Temporal I wanted to have the server and associated\ncomponents on my server, but I expected to be running workflows and workers\non another computer. \n\nFor most of my apps I slap some [[traefik]] labels on\nand we're good to go. But I got a wild set of errors trying to run a worker on\nmy desktop and connect it to the temporal server on my server over https.... it\nended up being because I needed to setup a special protocol in traefik for the\nreverse proxy to appropriately proxy the grpc call.\n\nSo I had a normal set of labels on my temporal container, went to run a worker\nand got this nasty work of art\n\n```\nRuntimeError: Failed client connect: `get_system_info` call error after connection: Status { code: Internal, message: \"protocol error: received message with invalid compression flag: 73 (valid flags are 0 and 1) while receiving response with status: 500 Internal Server Error\", metadata: MetadataMap { headers: {\"content-type\": \"text/plain; charset=utf-8\", \"content-length\": \"21\", \"date\": \"Wed, 25 Jun 2025 02:12:44 GMT\"} }, source: None }\n```\n\nThank God I had kind of seen this at work one other time in my life, and we\nnever fixed the issue there but I knew what it was... we had traefik acting as\na load balancer (as do I at home) and the traefik load balancer was \"balancing\ntraffic using https\"... no, I do not really know what I'm saying. But what I do\nknow is that in order for the Temporal Server and Worker to communicate,\ntraefik has to properly route the traffic for gRPC instead of https.\n\n!!! warning \"\"\n    I can't stress enough how little I know about the difference between https and grpc or why the load balancer cares... there's clearly something in the networking stack that is extremely relevant here\n\nBut the fix is NOT hard thankfully, and it's even on [traefik's website](https://doc.traefik.io/traefik/user-guides/grpc/#traefik-configuration) - the warning annotation there tells you what you need - which is one more traefik label...\n\n```yaml\ntraefik.http.services.\u003cmy-service-name\u003e.loadbalancer.server.scheme=h2c\n```\n\nSo after setting the loadbalancer.server.scheme to `h2c` I could run my worker just fine!\n\n![20250625021838_4d7104c2.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250625021838_4d7104c2.png)\n",
      "summary": "Someday I will potentially write up some stuff about temporal but for now it's a workflow orchestrator that I'm interested in and I wanted to PoC it in my...",
      "date_published": "2025-06-24T20:55:42Z",
      "date_modified": "2025-06-24T20:55:42Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "temporal",
        "grpc"
      ]
    },
    {
      "id": "https://pype.dev/nextcloud-php-opache-memory-consumption/",
      "url": "https://pype.dev/nextcloud-php-opache-memory-consumption/",
      "title": "Nextcloud PHP Opache Memory Consumption",
      "content_html": "\u003ch1 id=\"intro\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eIntro\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eToday I was combing through Nextcloud, just taking a gander at the apps, updates, etc.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe OPcache buffer is nearly full. To assure that all scripts can be hold in\ncache, it is recommended to apply \u0026ldquo;opcache.memory_consumption\u0026rdquo; to your PHP\nconfiguration with a value higher than \u0026ldquo;128\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eSo I know \u003cem\u003enothing\u003c/em\u003e about \u003ccode\u003ephp\u003c/code\u003e and I had no idea where to set this\u0026hellip; Also I\u0026rsquo;m\nrunning Nextcloud in a container so any updates will be blown away when the\ncontainer is removed (say next time I update Nextcloud)\u0026hellip;\u003c/p\u003e\n\u003cp\u003eAfter a little duckduckgoing I came across \u003ca href=\"https://www.reddit.com/r/NextCloud/comments/1gpxl5b/need_help_with_php_opcache_module_warning/\"\u003ethis reddit\npost\u003c/a\u003e\nwhere a guy had the same issue\u0026hellip;\u003c/p\u003e\n\u003cp\u003eThe long and short of it is that on \u003cem\u003esingle instance nextcloud deployments\u003c/em\u003e\nthis php memory consumption value can be too low for Nextcloud to keep up with\nthe demand\u0026hellip; You can see in the message they just recommend upping the value.\u003c/p\u003e\n\u003cp\u003eSo I had to think about how to persist the change and have it take effect now\nideally without affecting any users too much\u0026hellip; So here\u0026rsquo;s what I did - made the\nchange in 2 places:\u003c/p\u003e\n\u003ch2 id=\"in-the-container\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eIn the container\u003c/span\u003e \u003ca href=\"#in-the-container\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI exec\u0026rsquo;d into the container and used this handy \u003ccode\u003esed\u003c/code\u003e command \u003ccode\u003esed -i 's/^opcache\\.memory_consumption\\s*=\\s*128$/opcache.memory_consumption=256/' /usr/local/etc/php/conf.d/opcache-recommended.ini\u003c/code\u003e to update the value in the\nrunning container - and I guess \u003ccode\u003ephp\u003c/code\u003e maybe is loaded up dynamically or\nsomething? but the warning did go away\u0026hellip;.\u003c/p\u003e\n\u003cp\u003eSo how to persist this change when the filesystem is blown away when the\ncontainer is updated?\u003c/p\u003e\n\u003ch2 id=\"in-the-config\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eIn the config\u003c/span\u003e \u003ca href=\"#in-the-config\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI set the env var \u003ccode\u003ePHP_OPCACHE_MEMORY_CONSUMPTION\u003c/code\u003e in the \u003ccode\u003edocker-compose.yml\u003c/code\u003e\nfile to 256 and voila\u0026hellip; the change should persist\u0026hellip;\u003c/p\u003e\n",
      "content_text": "\n# Intro\n\nToday I was combing through Nextcloud, just taking a gander at the apps, updates, etc.\n\n\u003e The OPcache buffer is nearly full. To assure that all scripts can be hold in\n\u003e cache, it is recommended to apply \"opcache.memory_consumption\" to your PHP\n\u003e configuration with a value higher than \"128\"\n\nSo I know _nothing_ about `php` and I had no idea where to set this... Also I'm\nrunning Nextcloud in a container so any updates will be blown away when the\ncontainer is removed (say next time I update Nextcloud)...\n\nAfter a little duckduckgoing I came across [this reddit\npost](https://www.reddit.com/r/NextCloud/comments/1gpxl5b/need_help_with_php_opcache_module_warning/)\nwhere a guy had the same issue...\n\nThe long and short of it is that on _single instance nextcloud deployments_\nthis php memory consumption value can be too low for Nextcloud to keep up with\nthe demand... You can see in the message they just recommend upping the value.\n\nSo I had to think about how to persist the change and have it take effect now\nideally without affecting any users too much... So here's what I did - made the\nchange in 2 places:\n\n## In the container\n\nI exec'd into the container and used this handy `sed` command `sed -i\n's/^opcache\\.memory_consumption\\s*=\\s*128$/opcache.memory_consumption=256/'\n/usr/local/etc/php/conf.d/opcache-recommended.ini` to update the value in the\nrunning container - and I guess `php` maybe is loaded up dynamically or\nsomething? but the warning did go away....\n\nSo how to persist this change when the filesystem is blown away when the\ncontainer is updated?\n\n## In the config\n\nI set the env var `PHP_OPCACHE_MEMORY_CONSUMPTION` in the `docker-compose.yml`\nfile to 256 and voila... the change should persist...\n",
      "summary": "Today I was combing through Nextcloud, just taking a gander at the apps, updates, etc.",
      "date_published": "2025-06-23T08:46:20Z",
      "date_modified": "2025-06-23T08:46:20Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "nextcloud"
      ]
    },
    {
      "id": "https://pype.dev/quit-issueing-200s-for-500s/",
      "url": "https://pype.dev/quit-issueing-200s-for-500s/",
      "title": "Quit issueing 200s for 500s",
      "content_html": "\u003ch1 id=\"stop-this-nonsense\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eStop this nonsense\u003c/span\u003e\u003c/h1\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250622115500_5bd3bc21.png\" alt=\"20250622115500_5bd3bc21.png\"\u003e\n\u003c/figure\u003e\n",
      "content_text": "\n# Stop this nonsense\n\n![20250622115500_5bd3bc21.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250622115500_5bd3bc21.png)\n",
      "date_published": "2025-06-22T06:55:21Z",
      "date_modified": "2025-06-22T06:55:21Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "nonsense",
        "google",
        "veo3"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-711/",
      "url": "https://pype.dev/thoughts-711/",
      "title": "💭 Control Your n8n Instance Remotely with Telegram Bot Commands …",
      "content_text": "\n\u003ca href=\"https://n8n.io/workflows/4928-control-your-n8n-instance-remotely-with-telegram-bot-commands/\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://n8n.io/workflows/4928-control-your-n8n-instance-remotely-with-telegram-bot-commands/\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - Control Your n8n Instance Remotely with Telegram Bot Commands | n8n workflow template\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://n8n.io/workflows/4928-control-your-n8n-instance-remotely-with-telegram-bot-commands/\"\u003eControl Your n8n Instance Remotely with Telegram Bot Commands | n8n workflow template\u003c/a\u003e\n\n---\n\nI'm doing a lot of thinking and brainstorming about how I want to run some pipelines I have in my head, at home... things like image gen for blog posts, posting to various social media, click to generate qr codes and send emails, etc... things that require a lot of integration. \n\nI tried n8n a while ago with 1 use case, it didn't work but times have changed and whatever was wrong for that use case is now just fixed with a few updates... so I'm strongly considering n8n as a platform I build my workflows on, and using telegram as a simple entry-point into workflow execution is kind of intriguing... imagine sending a message to telegram to generate an image with SD based on a picture you took with our phone, maybe do something else with that image (turn it into a qr code or something), and then email it? all with a text message and pic? that sounds pretty cool... not sure what I\"ll have spun up but I am excited to be making some progress on the automation ideas\n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "I'm doing a lot of thinking and brainstorming about how I want to run some pipelines I have in my head, at home... thing",
      "date_published": "2025-06-22T00:38:53Z",
      "date_modified": "2025-06-22T00:38:53Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "n8n",
        "homelab",
        "todo",
        "telegram",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/thinking-in-diagrams/",
      "url": "https://pype.dev/thinking-in-diagrams/",
      "title": "Thinking In Diagrams",
      "content_text": "\n# Intro\n\nSomething I didn't appreciate earlier on in my career (and I'm only 8 as far as\nthe age of that career goes anyways) was thinking through problems with\ndiagrams... I've often approached a problem with code first, and immediately\nstarted implementing a solution. There's nothing actually wrong with that especially when considering:\n\n1. people think differently\n2. some people think with their fingers\n3. recognizing that the first thing you build should be thrown away should give you freedom to \"just start\"\n\nNow with that said, let's chat about how awesome diagrams are though...\n\n1. they put context in front of you without details\n2. you can express many more components of a system in a consumable way when compared to code\n3. diagrams help prioritize work and bubble up maybe unforseen dependencies\n4. they force you to wireframe before getting lost in the details\n\n## Wireframing\n\nOne of my biggest issue when I \"just start coding\" is not having a direction...\nI can put a few place holders `def this:` `def that:` in a few python modules,\nbut without having every place holder in front of me it is hard to keep them\nstraight, know the order or dependencies, etc.\n\nDiagrams aren't beholden to a text file or series of them, and you can fit much\nmore on your screen because you have all the X-Y available to you instead of\nthe height of your monitor times your formatted lined length (usually 120 for\nme).\n\nDiagrams also make it easy to spew out onto a page the different components you\nneed for a solution, without committing to an order (something that I cannot\nexpress well in scripts)\n\n## A Plan\n\nDiagramming with purpose can get you to the place of having almost a\npaint-by-number experience building your app/system/etc. Beecause you separate\nthe implemetation from the design and when you implement BASED on a design\nrather than implement to DISCOVER a design you will be more efficient and in my\nexperience I've improved my ability to forsee issues that I wouldn't have seen,\nor have historically missed, by putting the design down in front of me, the\ndetails of any integrations, etc. before starting to \"just code\".\n\n## Good Enough\n\nA final note about diagrams for right now is that they're easy to leave as\n\"good enough\". The point was to get a guide for solving a problem.\n\nDiagrams don't have to be picture perfect, even for documentation's sake. They\ncan even remain somewhat unfinished (permitted you don't get yourself into a\nbind of treating diagrams as docs that you didn't clean up)\n\nHere's an example of what I mean - I'm working on a simple workflow to take [my-thoughts](/my-thoughts) and post them to [[nostr]]. I started with a diagram like this...\n\n![20250622112223_f1838d9b.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250622112223_f1838d9b.png)\n\n\u003e In parallel I'm working on posting my blog to other social media - this small\n\u003e workflow is apart of a larger initiative I'm working on at home\n\nAS you can see this diagram isn't super detailed or pretty. But what it does it\nhelp me see the high level points of bringing my published thoughts to nostr as\nposts.\n\nAfter I have the simple steps, I've started diagramming out more details of each step:\n\n![20250622112415_f18663e3.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250622112415_f18663e3.png)\n\nThe diagram is easy to put notes on, add some color to for problems not yet solved, etc.\n\nAnd then with this diagram in front of me, it's easy to begin building\nsmall-scoped components that will be assembled to my larger system, but without\nthe pressure of constructing every part of the system at once\n\n# Fin\n\nDiagrams help me break up a problem into manageable chunks so that I can put\nthe things I need later on the back-burner and can focus on one achievable\nthing at a time.\n",
      "summary": "Something I didn't appreciate earlier on in my career (and I'm only 8 as far as the age of that career goes anyways) was thinking through problems with...",
      "date_published": "2025-06-20T06:55:31Z",
      "date_modified": "2025-06-20T06:55:31Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "dev-ops",
        "planning"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-709/",
      "url": "https://pype.dev/thoughts-709/",
      "title": "💭 pypeaday/whose-turn-is-it: Simple uv webapp to determine order…",
      "content_text": "\n\u003ca href=\"https://github.com/pypeaday/whose-turn-is-it\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://github.com/pypeaday/whose-turn-is-it\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - pypeaday/whose-turn-is-it: Simple uv webapp to determine order fo players for an event\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://github.com/pypeaday/whose-turn-is-it\"\u003epypeaday/whose-turn-is-it: Simple uv webapp to determine order fo players for an event\u003c/a\u003e\n\n---\n\nWe pray together as a family every night, but every single flipping night my daughter's fight about the order we go in... well, NO MORE!\n\nI built a simple uv fastapi app that randomly sorts a list from an environment var `PLAYERS` and presents it in the web page at `/generate`.\n\nSuper easy `uv run` at home...\n\nI love that with enough knowledge, or the right kind of knowledge, you can build like anything you want!\n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "We pray together as a family every night, but every single flipping night my daughter's fight about the order we go in..",
      "date_published": "2025-06-20T01:23:26Z",
      "date_modified": "2025-06-20T01:23:26Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "reflection",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/homelab-youtube-podcasts-to-audiobookshelf-pipeline/",
      "url": "https://pype.dev/homelab-youtube-podcasts-to-audiobookshelf-pipeline/",
      "title": "Homelab Youtube Podcasts to AudioBookShelf Pipeline",
      "content_text": "\nI wrote about using [[homelab-pinchflat]] for at-home mashup creation and a song flow\nfor church. But I use it for more than, that and here's another prime use case\n\nThere are podcasts on YouTube I want to follow - The Standup with Prime, or\nShawn Ryan's show. Basically I use pinchflat to download the audio and serve up\nthose files in ABS (audiobookshelf)\n",
      "summary": "I wrote about using homelab-pinchflat for at-home mashup creation and a song flow for church. But I use it for more than, that and here's another prime use case",
      "date_published": "2025-06-18T13:53:12Z",
      "date_modified": "2025-06-18T13:53:12Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "audiobookshelf",
        "pinchflat"
      ]
    },
    {
      "id": "https://pype.dev/source-up-for-nested-envrc/",
      "url": "https://pype.dev/source-up-for-nested-envrc/",
      "title": "source_up for nested .envrc",
      "content_html": "\u003ch1 id=\"tldr\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eTLDR\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eI have a use case for nesting directories with cascading .envrc files. and ran\ninto an issue where the parent environment was being reset by the child\nenvironment. The fix is \u003ccode\u003esource_up\u003c/code\u003e\u003c/p\u003e\n\u003ch1 id=\"context\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eContext\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eI manage some infrastructure at home with a folder like this:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e├── homelab\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│   ├── .envrc\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│   └── stack1\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│       ├── .envrc\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eI do this so that the \u0026ldquo;homelab-wide\u0026rdquo; terraform variables can be exported with\n\u003ccode\u003eTF_VAR_the_variable\u003c/code\u003e in the \u003ccode\u003ehomelab/.envrc\u003c/code\u003e and then the stack specific\nvariables in \u003ccode\u003estack1/.envrc\u003c/code\u003e get exported like \u003ccode\u003eTF_VAR_stack_specific_var\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eFor example, my cloudflare account id is needed in every stack, but the\ncloudflare zone id is different per stack - so instead of copying the account\nid var to every stack (however the vars are managed), I can set it in a parent\n.envrc and share it in nested stack directories\u003c/p\u003e\n\u003ch2 id=\"problem\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eProblem\u003c/span\u003e \u003ca href=\"#problem\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e# homelab/.envrc\n#!/bin/bash\nexport VAR_FOO=BAR\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eSo when I \u003ccode\u003ecd homelab\u003c/code\u003e I get\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003enic in /tmp/homelab   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ direnv allow\ndirenv: loading /tmp/homelab/.envrc\ndirenv: export +VAR_FOO\n\nnic in /tmp/homelab   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ env | grep VAR\nVAR_FOO=BAR\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eYou can see \u003ccode\u003eVAR_FOO\u003c/code\u003e is set\u0026hellip; but now I\u0026rsquo;ll \u003ccode\u003ecd stack1\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003enic in /tmp/homelab   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ cd stack1\ndirenv: error /tmp/homelab/stack1/.envrc is blocked. Run `direnv allow` to approve its content\n\nnic in /tmp/homelab/stack1   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ direnv allow\ndirenv: loading /tmp/homelab/stack1/.envrc\ndirenv: export +VAR_BAZ\n\nnic in /tmp/homelab/stack1   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ env | grep VAR\nVAR_BAZ=BAM\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eAs you can see \u003ccode\u003eVAR_FOO\u003c/code\u003e was unset, and \u003ccode\u003eVAR_BAZ\u003c/code\u003e is set\u0026hellip; so \u003ccode\u003ehomelab/.envrc\u003c/code\u003e was blown away!\u003c/p\u003e\n\u003ch2 id=\"fix\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eFix\u003c/span\u003e \u003ca href=\"#fix\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eEdit \u003ccode\u003estack1/.envrc\u003c/code\u003e with a \u003ccode\u003esource_up\u003c/code\u003e command\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e# stack1/.envrc # NEW\n#!/bin/bash\nsource_up  # source the parent environment\nexport VAR_BAZ=BAM\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eAfter the edit\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003enic in /tmp/homelab/stack1   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ vim .envrc\ndirenv: error /tmp/homelab/stack1/.envrc is blocked. Run `direnv allow` to approve its content\n\nnic in /tmp/homelab/stack1   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET  took 5s\n⬢ [devbox] ❯ direnv allow\ndirenv: loading /tmp/homelab/stack1/.envrc\ndirenv: loading /tmp/homelab/.envrc\ndirenv: export +VAR_BAZ +VAR_FOO\n\nnic in /tmp/homelab/stack1   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ env | grep VAR\nVAR_FOO=BAR\nVAR_BAZ=BAM\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eBoth vars are set!\u003c/p\u003e\n",
      "content_text": "\n# TLDR\n\nI have a use case for nesting directories with cascading .envrc files. and ran\ninto an issue where the parent environment was being reset by the child\nenvironment. The fix is `source_up`\n\n# Context\n\nI manage some infrastructure at home with a folder like this:\n\n```bash\n.\n├── homelab\n│   ├── .envrc\n│   └── stack1\n│       ├── .envrc\n```\n\nI do this so that the \"homelab-wide\" terraform variables can be exported with\n`TF_VAR_the_variable` in the `homelab/.envrc` and then the stack specific\nvariables in `stack1/.envrc` get exported like `TF_VAR_stack_specific_var`.\n\nFor example, my cloudflare account id is needed in every stack, but the\ncloudflare zone id is different per stack - so instead of copying the account\nid var to every stack (however the vars are managed), I can set it in a parent\n.envrc and share it in nested stack directories\n\n## Problem\n\n```\n# homelab/.envrc\n#!/bin/bash\nexport VAR_FOO=BAR\n```\n\nSo when I `cd homelab` I get\n\n```\nnic in /tmp/homelab   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ direnv allow\ndirenv: loading /tmp/homelab/.envrc\ndirenv: export +VAR_FOO\n\nnic in /tmp/homelab   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ env | grep VAR\nVAR_FOO=BAR\n\n```\n\nYou can see `VAR_FOO` is set... but now I'll `cd stack1`\n\n```\nnic in /tmp/homelab   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ cd stack1\ndirenv: error /tmp/homelab/stack1/.envrc is blocked. Run `direnv allow` to approve its content\n\nnic in /tmp/homelab/stack1   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ direnv allow\ndirenv: loading /tmp/homelab/stack1/.envrc\ndirenv: export +VAR_BAZ\n\nnic in /tmp/homelab/stack1   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ env | grep VAR\nVAR_BAZ=BAM\n\n```\n\nAs you can see `VAR_FOO` was unset, and `VAR_BAZ` is set... so `homelab/.envrc` was blown away!\n\n## Fix\n\nEdit `stack1/.envrc` with a `source_up` command\n\n```\n# stack1/.envrc # NEW\n#!/bin/bash\nsource_up  # source the parent environment\nexport VAR_BAZ=BAM\n\n```\n\nAfter the edit\n\n```\nnic in /tmp/homelab/stack1   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ vim .envrc\ndirenv: error /tmp/homelab/stack1/.envrc is blocked. Run `direnv allow` to approve its content\n\nnic in /tmp/homelab/stack1   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET  took 5s\n⬢ [devbox] ❯ direnv allow\ndirenv: loading /tmp/homelab/stack1/.envrc\ndirenv: loading /tmp/homelab/.envrc\ndirenv: export +VAR_BAZ +VAR_FOO\n\nnic in /tmp/homelab/stack1   (dev) 󰒄 󱔎 NO PYTHON ENVIORNMENT SET\n⬢ [devbox] ❯ env | grep VAR\nVAR_FOO=BAR\nVAR_BAZ=BAM\n\n```\n\nBoth vars are set!\n",
      "summary": "I have a use case for nesting directories with cascading .envrc files. and ran into an issue where the parent environment was being reset by the child...",
      "date_published": "2025-06-17T09:52:17Z",
      "date_modified": "2025-06-17T09:52:17Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "direnv",
        "cli"
      ]
    },
    {
      "id": "https://pype.dev/stable-diffusion-qr-codes-for-josh/",
      "url": "https://pype.dev/stable-diffusion-qr-codes-for-josh/",
      "title": "Stable Diffusion QR Codes for Josh",
      "content_html": "\u003ch1 id=\"after-my-blunder\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eAfter my blunder\u003c/span\u003e\u003c/h1\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250627111955_e86d5db2.png\" alt=\"20250627111955_e86d5db2.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1),(serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2), (ultra realistic: 1.2)\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1),y\nSteps: 30, Sampler: Euler a, Schedule type: Automatic, CFG scale: 7, Seed: 784129766, Size: 1536x1536, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.8, Pixel Perfect: True, Control Mode: Balanced\u0026rdquo;, ControlNet 1: \u0026ldquo;Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.75, Pixel Perfect: True, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003ch1 id=\"final-candidates\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eFinal Candidates\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eTurns out upscaling can mess up the design\u0026hellip; so I generated new ones at the high res instead of using AI to upscale\u003c/p\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621122040_2dfef68f.png\" alt=\"20250621122040_2dfef68f.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1),(serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2), (ultra realistic: 1.2)\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\u003c/p\u003e\n\u003cp\u003eSteps: 30, Sampler: Euler a, Schedule type: Automatic, CFG scale: 7, Seed: 1827707865, Size: 1536x1536, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 1536, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 1.0, Pixel Perfect: False, Control Mode: Balanced\u0026rdquo;, ControlNet 1: \u0026ldquo;Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.88, Pixel Perfect: False, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eI turned the brightness down on the above one a little and got a better result\u003c/p\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621122629_1058a54f.png\" alt=\"20250621122629_1058a54f.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1),(serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2), (ultra realistic: 1.2)\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\u003c/p\u003e\n\u003cp\u003eSteps: 30, Sampler: Euler a, Schedule type: Automatic, CFG scale: 7, Seed: 1827707865, Size: 1536x1536, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 1536, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.85, Pixel Perfect: False, Control Mode: Balanced\u0026rdquo;, ControlNet 1: \u0026ldquo;Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.75, Pixel Perfect: False, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003ch1 id=\"some-favorites\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eSome favorites\u003c/span\u003e\u003c/h1\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621020431_d6c69cd2.png\" alt=\"20250621020431_d6c69cd2.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (green orange:1.0), (serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2), (ultra realistic: 1.1)\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\u003c/p\u003e\n\u003cp\u003eSteps: 30, Sampler: Euler a, Schedule type: Automatic, CFG scale: 7, Seed: 2926433856, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 1.0, Pixel Perfect: False, Control Mode: Balanced\u0026rdquo;, ControlNet 1: \u0026ldquo;Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.85, Pixel Perfect: False, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003chr\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621020700_37cf8c79.png\" alt=\"20250621020700_37cf8c79.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1),(serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2), (ultra realistic: 1.2)\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\u003c/p\u003e\n\u003cp\u003eSteps: 30, Sampler: Euler a, Schedule type: Automatic, CFG scale: 7, Seed: 1827707865, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 1.0, Pixel Perfect: False, Control Mode: Balanced\u0026rdquo;, ControlNet 1: \u0026ldquo;Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.88, Pixel Perfect: False, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003ch1 id=\"codes-and-prompts\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eCodes and prompts\u003c/span\u003e\u003c/h1\u003e\n\u003chr\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250617112815_b986db88.png\" alt=\"20250617112815_b986db88.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003eprompt: (breathtaking scenic view:1.2), (fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear blue water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (birch trees:1.0), (serene nature:1.2), (ultra-realistic:1.3), (8K landscape photography:1.3), (photorealistic:1.2), (atmospheric lighting:1.2)\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\u003c/p\u003e\n\u003cp\u003eSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Karras, CFG scale: 7, Seed: 2206746812, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.15, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.85, Pixel Perfect: True, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003chr\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250617113111_d9075159.png\" alt=\"20250617113111_d9075159.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(breathtaking scenic view:1.2), (fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (birch trees:1.0), (serene nature:1.2), (ultra-realistic:1.3), (8K landscape photography:1.3), (photorealistic:1.2), (greens and blues:1.2)\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\nSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Karras, CFG scale: 7, Seed: 2485699904, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.1, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: True, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003chr\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250617113250_839c12e2.png\" alt=\"20250617113250_839c12e2.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(breathtaking scenic view:1.2), (fjord:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (birch trees:1.0), (serene nature:1.2), (ultra-realistic:1.3), (8K landscape photography:1.3), (photorealistic:1.2), (green:1.2)\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\nSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Karras, CFG scale: 8, Seed: 1055874558, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.1, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: True, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"top-contendor\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eTop Contendor\u003c/span\u003e \u003ca href=\"#top-contendor\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250618005414_d77ff449.png\" alt=\"20250618005414_d77ff449.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(breathtaking scenic view:1.2), (fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (green orange:1.0), (serene nature:1.2), (ultra-realistic:1.3), (8K landscape photography:1.3), (gaming concept art:1.2),\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\u003c/p\u003e\n\u003cp\u003eSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Karras, CFG scale: 8.5, Seed: 1240242415, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.1, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: False, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003chr\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250618005451_84cd9350.png\" alt=\"20250618005451_84cd9350.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(breathtaking scenic view:1.2), (fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (green orange:1.0), (serene nature:1.2), (ultra-realistic:1.3), (8K landscape photography:1.3), (gaming concept art:1.2),\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\u003c/p\u003e\n\u003cp\u003eSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Karras, CFG scale: 8.5, Seed: 1240242416, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.1, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: False, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eScans!\u003c/p\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621004622_6c9a66df.png\" alt=\"20250621004622_6c9a66df.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (green orange:1.0), (serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2),\u003c/p\u003e\n\u003cp\u003e(blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\u003c/p\u003e\n\u003cp\u003eSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Exponential, CFG scale: 7, Seed: 4060643233, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.4, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: True, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n\u003chr\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621004844_64e6b94b.png\" alt=\"20250621004844_64e6b94b.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003e(fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (green blue:1.0), (serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2),\u003c/p\u003e\n\u003cp\u003eNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\u003c/p\u003e\n\u003cp\u003eSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Exponential, CFG scale: 7, Seed: 3713594572, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \u0026ldquo;Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.4, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: True, Control Mode: Balanced\u0026rdquo;, Version: v1.9.4\u003c/p\u003e\n",
      "content_text": "\n# After my blunder\n\n![20250627111955_e86d5db2.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250627111955_e86d5db2.png)\n\n(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1),(serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2), (ultra realistic: 1.2)\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1),y\nSteps: 30, Sampler: Euler a, Schedule type: Automatic, CFG scale: 7, Seed: 784129766, Size: 1536x1536, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.8, Pixel Perfect: True, Control Mode: Balanced\", ControlNet 1: \"Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.75, Pixel Perfect: True, Control Mode: Balanced\", Version: v1.9.4\n\n# Final Candidates\n\nTurns out upscaling can mess up the design... so I generated new ones at the high res instead of using AI to upscale\n\n![20250621122040_2dfef68f.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621122040_2dfef68f.png)\n\n(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1),(serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2), (ultra realistic: 1.2)\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\n\nSteps: 30, Sampler: Euler a, Schedule type: Automatic, CFG scale: 7, Seed: 1827707865, Size: 1536x1536, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 1536, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 1.0, Pixel Perfect: False, Control Mode: Balanced\", ControlNet 1: \"Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.88, Pixel Perfect: False, Control Mode: Balanced\", Version: v1.9.4\n\n---\n\nI turned the brightness down on the above one a little and got a better result\n\n![20250621122629_1058a54f.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621122629_1058a54f.png)\n\n(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1),(serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2), (ultra realistic: 1.2)\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\n\nSteps: 30, Sampler: Euler a, Schedule type: Automatic, CFG scale: 7, Seed: 1827707865, Size: 1536x1536, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 1536, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.85, Pixel Perfect: False, Control Mode: Balanced\", ControlNet 1: \"Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.75, Pixel Perfect: False, Control Mode: Balanced\", Version: v1.9.4\n\n# Some favorites\n\n![20250621020431_d6c69cd2.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621020431_d6c69cd2.png)\n\n(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (green orange:1.0), (serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2), (ultra realistic: 1.1)\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\n\nSteps: 30, Sampler: Euler a, Schedule type: Automatic, CFG scale: 7, Seed: 2926433856, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 1.0, Pixel Perfect: False, Control Mode: Balanced\", ControlNet 1: \"Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.85, Pixel Perfect: False, Control Mode: Balanced\", Version: v1.9.4\n\n---\n\n![20250621020700_37cf8c79.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621020700_37cf8c79.png)\n\n(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1),(serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2), (ultra realistic: 1.2)\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\n\nSteps: 30, Sampler: Euler a, Schedule type: Automatic, CFG scale: 7, Seed: 1827707865, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 1.0, Pixel Perfect: False, Control Mode: Balanced\", ControlNet 1: \"Module: none, Model: control_v1p_sd15_brightness [5f6aa6ed], Weight: 0.25, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.25, Guidance End: 0.88, Pixel Perfect: False, Control Mode: Balanced\", Version: v1.9.4\n\n# Codes and prompts\n\n---\n\n![20250617112815_b986db88.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250617112815_b986db88.png)\n\nprompt: (breathtaking scenic view:1.2), (fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear blue water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (birch trees:1.0), (serene nature:1.2), (ultra-realistic:1.3), (8K landscape photography:1.3), (photorealistic:1.2), (atmospheric lighting:1.2)\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\n\nSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Karras, CFG scale: 7, Seed: 2206746812, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.15, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.85, Pixel Perfect: True, Control Mode: Balanced\", Version: v1.9.4\n\n---\n\n![20250617113111_d9075159.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250617113111_d9075159.png)\n\n(breathtaking scenic view:1.2), (fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (birch trees:1.0), (serene nature:1.2), (ultra-realistic:1.3), (8K landscape photography:1.3), (photorealistic:1.2), (greens and blues:1.2)\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\nSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Karras, CFG scale: 7, Seed: 2485699904, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.1, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: True, Control Mode: Balanced\", Version: v1.9.4\n\n---\n\n![20250617113250_839c12e2.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250617113250_839c12e2.png)\n\n(breathtaking scenic view:1.2), (fjord:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (birch trees:1.0), (serene nature:1.2), (ultra-realistic:1.3), (8K landscape photography:1.3), (photorealistic:1.2), (green:1.2)\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\nSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Karras, CFG scale: 8, Seed: 1055874558, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.1, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: True, Control Mode: Balanced\", Version: v1.9.4\n\n---\n\n## Top Contendor\n\n![20250618005414_d77ff449.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250618005414_d77ff449.png)\n\n(breathtaking scenic view:1.2), (fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (green orange:1.0), (serene nature:1.2), (ultra-realistic:1.3), (8K landscape photography:1.3), (gaming concept art:1.2),\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\n\nSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Karras, CFG scale: 8.5, Seed: 1240242415, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.1, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: False, Control Mode: Balanced\", Version: v1.9.4\n\n---\n\n![20250618005451_84cd9350.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250618005451_84cd9350.png)\n\n(breathtaking scenic view:1.2), (fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (green orange:1.0), (serene nature:1.2), (ultra-realistic:1.3), (8K landscape photography:1.3), (gaming concept art:1.2),\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\n\nSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Karras, CFG scale: 8.5, Seed: 1240242416, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.1, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: False, Control Mode: Balanced\", Version: v1.9.4\n\n---\n\nScans!\n\n![20250621004622_6c9a66df.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621004622_6c9a66df.png)\n\n(fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (green orange:1.0), (serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2),\n\n(blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\n\nSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Exponential, CFG scale: 7, Seed: 4060643233, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.4, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: True, Control Mode: Balanced\", Version: v1.9.4\n\n---\n\n![20250621004844_64e6b94b.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250621004844_64e6b94b.png)\n\n(fjords of Finland:1.3), (steep forested cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), , (early morning light:1.2), (golden hour glow:1.1), (pine trees:1.1), (green blue:1.0), (serene nature:1.2), (8K landscape photography:1.3), (gaming concept art:1.2),\n\nNegative prompt: (blurry:1.3), (low resolution:1.3), (overexposed:1.2), (cartoonish:1.3), (unrealistic colors:1.3), (people:1.1), (city buildings:1.2), (vehicles:1.2), (text:1.3), (distortion:1.2)\n\nSteps: 30, Sampler: DPM++ 2M SDE, Schedule type: Exponential, CFG scale: 7, Seed: 3713594572, Size: 768x768, Model hash: 4199bcdd14, Model: revAnimated_v122EOL, ControlNet 0: \"Module: none, Model: controlnetQRPatternQR_v2Sd15 [2d8d5750], Weight: 1.4, Resize Mode: Crop and Resize, Processor Res: 512, Threshold A: 0.5, Threshold B: 0.5, Guidance Start: 0.0, Guidance End: 0.8, Pixel Perfect: True, Control Mode: Balanced\", Version: v1.9.4\n",
      "summary": "(fjords of Finland:1.3), (steep cliffs:1.1), (crystal-clear water:1.2), (reflection of sky on water:1.1), (early morning light:1.2), (golden hour glow:1.1),...",
      "date_published": "2025-06-17T06:27:28Z",
      "date_modified": "2025-06-17T06:27:28Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "digital-harbor",
        "qr",
        "stable-diffusion"
      ]
    },
    {
      "id": "https://pype.dev/u-blue-aurora-upgrade-broke-hwa-docker/",
      "url": "https://pype.dev/u-blue-aurora-upgrade-broke-hwa-docker/",
      "title": "U-Blue Aurora Upgrade Broke HWA Docker",
      "content_html": "\u003cp\u003eI use Universal Blue\u0026rsquo;s \u003ca href=\"https://getaurora.dev/en\"\u003eAurora\u003c/a\u003e distribution on my daily driver desktop, and\nI rebooted today which led what I imagine is a kernel update. This broke all of\nmy docker containers using a GPU.\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003envidia-container-cli: detection error: open failed: /usr/lib/libnvidia-tls.so.570.153.02: no such file or directory: unknown\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThankfully a reboot and booting into the older environment fixes everything\u0026hellip;\nLinux and immutability FTW\u003c/p\u003e\n\u003ch2 id=\"related\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eRelated\u003c/span\u003e \u003ca href=\"#related\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://universal-blue.discourse.group/t/cannot-use-nvidia-runtime-in-docker-since-update-to-fedora-42/8812/3\"\u003eDiscorse Thread\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n",
      "content_text": "\nI use Universal Blue's [Aurora](https://getaurora.dev/en) distribution on my daily driver desktop, and\nI rebooted today which led what I imagine is a kernel update. This broke all of\nmy docker containers using a GPU.\n\n```\nnvidia-container-cli: detection error: open failed: /usr/lib/libnvidia-tls.so.570.153.02: no such file or directory: unknown\n```\n\nThankfully a reboot and booting into the older environment fixes everything...\nLinux and immutability FTW\n\n## Related\n\n* [Discorse Thread](https://universal-blue.discourse.group/t/cannot-use-nvidia-runtime-in-docker-since-update-to-fedora-42/8812/3)\n\n",
      "summary": "I use Universal Blue's Aurora distribution on my daily driver desktop, and I rebooted today which led what I imagine is a kernel update. This broke all of my...",
      "date_published": "2025-06-15T08:42:09Z",
      "date_modified": "2025-06-15T08:42:09Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "universal-blue"
      ]
    },
    {
      "id": "https://pype.dev/homelab-pinchflat/",
      "url": "https://pype.dev/homelab-pinchflat/",
      "title": "Homelab Pinchflat",
      "content_text": "\n# Why?\n\nI've written about [[self-hosted-media]] before and addressed some thoughts with YouTube. \n\nLately though I've had 2 use cases for offline YouTube media and I'm now\nsolving this problem by using [pinchflat](https://pinchflat.com/) as my `ytdl`\nsolution + file system organization for use throughout my homelab.\n\n## Use Case 1\n\nAt church we use pre-recorded music to sing along to, or at least we used to,\nthankfully as of June 2025 we're doing live-music every week. But in the before\ntimes I would strip the audio out of song files we had purchased and then made\nlyric videos with the instrumental tracks. As we wanted to try new songs out we\ndidn't want to purchase them in case they didn't work out for us to use and\nthat ends up being a waste (church budget is very tight). So using songs\navailable on YouTube is an easy solution, but the only way to strip the vocals\nand see if the song sounded right with our singers and equipment was to make\nthe lyric video and rehearse it... Chicken or Egg problem unless we can freely\ntry it before purchasing... So using Pinchflat we can download songs in that\nplaylist, I can edit the files, the team can try it out, and if we like it we\ncan use it without hitting the budget any harder than necessary.\n\n\u003e Pinchflat syncs that playlist to a folder on my NAS that another process\n\u003e watches and performs the audio stripping workflow\n\n## Use Case 2\n\nI just wrote about [[if-you-want-something-make-it-so-song-style]] which is the\nsecond use case - cutting mashups of my favorite songs on youtube and then\nhosting them myself for easy listening\n\n# The Setup\n\nI run it in docker compose like practically all my other services\n\n```yml\nservices:\n  pinchflat:\n    container_name: \"pinchflat\"\n    image: \"ghcr.io/kieraneglin/pinchflat:latest\"\n    ports:\n      - \"8945:8945\"\n    volumes:\n      - \"/tank/encrypted/docker/the-pit-zfs/pinchflat/config:/config:rw\"\n      - \"/tank/encrypted/nas/media/downloads/pinchflat/downloads:/downloads:rw\"\n    environment:\n      TZ: \"America/Chicago\"\n      PUID: \"1000\"\n      PGID: \"1000\"\n    restart: unless-stopped\n    deploy:\n      resources:\n        limits:\n          memory: \"4g\"\n```\n\n# The GUI\n\nThe WebUI is easy to navigate - you organize your downloads however you want with \"sources\", and here's how I setup the source for these mashups that I want to edit... I add them to my playlist and Pinchflat grabs them for me automatically\n![20250614144201_fa16e7ac.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250614144201_fa16e7ac.png)\n\n![20250614144307_bdf12ee0.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250614144307_bdf12ee0.png)\n\nThat's basically it - then as you can see in the compose file, I get the files in a folder on my NAS and from there I can edit them as I need.\n\n## Example\n\nThe church app that does the audio processing is in a compose stack with the\npinchflat download directory on the host mounted in - this is how containers in\ndifferent stacks can share data, by sharing a filesystem bind mount\n\n```yml\nservices:\n  olivet_watcher_app:\n    image: pypeaday/vocal-remover-watcher\n    container_name: olivet-youtube-watcher\n    volumes:\n      - /tank/encrypted/nas/media/downloads/pinchflat/downloads:/input:ro\n      - /tank/encrypted/docker/vocal_remover_app/watcher-app/processed_mp3s:/output\n      - /tank/encrypted/docker/vocal_remover_app/watcher-app/db:/data\n    working_dir: /app\n```\n\n",
      "summary": "I've written about self-hosted-media before and addressed some thoughts with YouTube.",
      "date_published": "2025-06-14T08:51:21Z",
      "date_modified": "2025-06-14T08:51:21Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/if-you-want-something-make-it-so-song-style/",
      "url": "https://pype.dev/if-you-want-something-make-it-so-song-style/",
      "title": "If You Want Something Make It So - Song Style",
      "content_text": "\nIn grad school a professor of mine, Mark Hunacek, said one of the most profound\nthings I've ever heard to the tune \"if you want it, then make it so\"... It's a\ngreat benefit to mathematicians at the bar to start a conversation with \"hey\nlet's assume X because we can\"...\n\nThis phrase has affected my work greatly to the work I do and how I go about it- \nit's literally changed how I design some of my code. But I also want this\nmantra to flow into other parts of my life...\n\n\u003e So here's a post about how I use Pinchflat and Davinci Resolve to tickle my\n\u003e brain with bespoke versions of beautifully crafted mashups\n\nIn this example I took a Goobsie mashup, cut the part I didn't like quite as\nmuch (though admittedly it's still beautiful) and spliced it with itself to\ngive me a longer running version of a musical piece that takes me to another\nworld...\n\n[OG Youtube Mashup](https://www.youtube.com/watch?v=7v7nreDnmDg)\n\n## Acquiring the Media\n\nPinchflat isn't really necessary here, anyone can use `youtubedl` or another\ntool to download from YouTube. I do use Pinchflat to subscribe to Youtube\nplaylists to automate this process for me. See more about that in\n[[homelab-pinchflat]]\n\n## Creating the Mashup\n\nSo Goobsie makes actually good mashups, and I'm not anything even remotely close to an audio engineer or whatever, but there's a segment of this song that just strikes my whole body in a unique way and I want to sometimes just listen to it conveniently... So enter Davinci Resolve... Basically I took the downloaded file, added it twice to a timeline, and then faded in and out until it sounded ok to me.\n\n![20250614135418_b75bc26a.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250614135418_b75bc26a.png)\n\n## Listening to the Mashup\n\nSo now how do I listen to this?\n\nFor the moment, it's a favorite in my Jellyfin library and I listen through\nthat client. It's a TODO item for me to set-up a more music-centric streaming\nservice\n\n\n!!! info \"Go Forth\"\n    So Go Forth - and if you want something, make it so",
      "summary": "In grad school a professor of mine, Mark Hunacek, said one of the most profound things I've ever heard to the tune \"if you want it, then make it so\"... It's...",
      "date_published": "2025-06-14T08:44:14Z",
      "date_modified": "2025-06-14T08:44:14Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "series-if-you-want-it-make-it-so",
        "music"
      ]
    },
    {
      "id": "https://pype.dev/zsa-typing-challenge-issue/",
      "url": "https://pype.dev/zsa-typing-challenge-issue/",
      "title": "ZSA typing challenge issue",
      "content_html": "\u003ch1 id=\"zsa\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eZSA\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eI love \u003ca href=\"https://zsa.io\"\u003ezsa\u003c/a\u003e and have been using a moonlander for a few years now.\u003c/p\u003e\n\u003cp\u003eThey recently launched \u003ca href=\"https://typ.ing\"\u003etyp.ing\u003c/a\u003e as a way to train your typing skills - it\u0026rsquo;s a lot like \u003ca href=\"https://monkeytype.com\"\u003emonkeytype\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eI have a thought about it \u003ca href=\"https://thoughts.waylonwalker.com/post/682\"\u003ehere\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"today-s-challenge\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eToday’s Challenge\u003c/span\u003e \u003ca href=\"#today-s-challenge\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI went to do today\u0026rsquo;s daily challenge and have ran into an issue where part of\nthe challenge is to type \u003ccode\u003e/\u003c/code\u003e the forward slash character but it\u0026rsquo;s actually a\nkeybind on the website for navigation (well done btw!)\u003c/p\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250613130724_06b0f9ef.png\" alt=\"20250613130724_06b0f9ef.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003eSo when I try to type the challenge I actually bring up the nav menu\u003c/p\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250613131031_ce06cf48.png\" alt=\"20250613131031_ce06cf48.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003eSo for today I\u0026rsquo;ll take the error on the character to complete it and maybe ZSA\ncan look into this?\u003c/p\u003e\n",
      "content_text": "\n# ZSA\n\nI love [zsa](https://zsa.io) and have been using a moonlander for a few years now.\n\nThey recently launched [typ.ing](https://typ.ing) as a way to train your typing skills - it's a lot like [monkeytype](https://monkeytype.com).\n\nI have a thought about it [here](https://thoughts.waylonwalker.com/post/682)\n\n## Today's Challenge\n\nI went to do today's daily challenge and have ran into an issue where part of\nthe challenge is to type `/` the forward slash character but it's actually a\nkeybind on the website for navigation (well done btw!)\n\n![20250613130724_06b0f9ef.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250613130724_06b0f9ef.png)\n\nSo when I try to type the challenge I actually bring up the nav menu\n\n![20250613131031_ce06cf48.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250613131031_ce06cf48.png)\n\nSo for today I'll take the error on the character to complete it and maybe ZSA\ncan look into this?\n",
      "summary": "I love zsa and have been using a moonlander for a few years now.",
      "date_published": "2025-06-13T08:07:41Z",
      "date_modified": "2025-06-13T08:07:41Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "zsa",
        "typing"
      ]
    },
    {
      "id": "https://pype.dev/double-check-your-dns-records/",
      "url": "https://pype.dev/double-check-your-dns-records/",
      "title": "Double Check Your DNS Records",
      "content_html": "\u003ch1 id=\"my-blog\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eMy Blog\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eI host \u003ca href=\"https://pype.dev\"\u003emy blog\u003c/a\u003e on cloudflare and manage my infra with\nterraform. I got a 522 when I went to \u003ccode\u003ehttps://www.pype.dev\u003c/code\u003e recently and I\nwondered why since \u003ccode\u003ehttps://pype.dev\u003c/code\u003e worked fine\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"terraform\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eTerraform\u003c/span\u003e \u003ca href=\"#terraform\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI had this right in the terraform:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eresource\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;cloudflare_pages_domain\u0026#34; \u0026#34;cf_domain\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e  account_id\u003c/span\u003e   \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003elocal\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003eaccount_id\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e  project_name\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003ecloudflare_pages_project\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003ebuild_config\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003ename\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e  domain\u003c/span\u003e       \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;pype.dev\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eBut turns out the \u003ccode\u003ewww\u003c/code\u003e record was commented out for some reason in my terraform code:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eresource\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;cloudflare_pages_domain\u0026#34; \u0026#34;cf_domain_www\u0026#34;\u003c/span\u003e {\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e  account_id\u003c/span\u003e   \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003elocal\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003eaccount_id\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e  project_name\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003ecloudflare_pages_project\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003ebuild_config\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003ename\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003e  domain\u003c/span\u003e       \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;www.pype.dev\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eA quick \u003ccode\u003eterraform apply -auto-approve\u003c/code\u003e (careful with this) and we\u0026rsquo;re up and\nrunning with the \u003ccode\u003ewww\u003c/code\u003e record now\u003c/p\u003e\n",
      "content_text": "\n# My Blog\n\nI host [my blog](https://pype.dev) on cloudflare and manage my infra with\nterraform. I got a 522 when I went to `https://www.pype.dev` recently and I\nwondered why since `https://pype.dev` worked fine...\n\n## Terraform\n\nI had this right in the terraform:\n\n```hcl\nresource \"cloudflare_pages_domain\" \"cf_domain\" {\n  account_id   = local.account_id\n  project_name = cloudflare_pages_project.build_config.name\n  domain       = \"pype.dev\"\n}\n```\n\nBut turns out the `www` record was commented out for some reason in my terraform code:\n\n```hcl\nresource \"cloudflare_pages_domain\" \"cf_domain_www\" {\n  account_id   = local.account_id\n  project_name = cloudflare_pages_project.build_config.name\n  domain       = \"www.pype.dev\"\n}\n```\n\nA quick `terraform apply -auto-approve` (careful with this) and we're up and\nrunning with the `www` record now\n\n",
      "summary": "I host my blog on cloudflare and manage my infra with terraform. I got a 522 when I went to recently and I wondered why since worked fine...",
      "date_published": "2025-06-13T06:53:50Z",
      "date_modified": "2025-06-13T06:53:50Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "dns",
        "terraform",
        "cloudflare"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-685/",
      "url": "https://pype.dev/thoughts-685/",
      "title": "💭 qwen3",
      "content_text": "\n\u003ca href=\"https://ollama.com/library/qwen3\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://ollama.com/library/qwen3\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - qwen3\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://ollama.com/library/qwen3\"\u003eqwen3\u003c/a\u003e\n\n---\n\nI really don't know much about every self-hostable LLM out there... so much as happened. I am blessed at home with a pretty beefy GPU and so although I don't know all the deets, I can run a lot of the reasonably large \"open source\" models. The one I've been playing with lately is qwen3. The conversational flow has felt more natural with it compared to llama3.2 or dolphin3. Granted I might need to update something and my experience is limited. I've also had good experience with gemma3 as a noteworthy contender for my go-to LLM right now in open-webui\n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "I really don't know much about every self-hostable LLM out there... so much as happened. I am blessed at home with a pre",
      "date_published": "2025-06-11T02:23:23Z",
      "date_modified": "2025-06-11T02:23:23Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "llm",
        "ollama",
        "homelab",
        "qwen",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-680/",
      "url": "https://pype.dev/thoughts-680/",
      "title": "💭 News - Apps - App Store - Nextcloud",
      "content_text": "\n\u003ca href=\"https://apps.nextcloud.com/apps/news\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://apps.nextcloud.com/apps/news\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - News - Apps - App Store - Nextcloud\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://apps.nextcloud.com/apps/news\"\u003eNews - Apps - App Store - Nextcloud\u003c/a\u003e\n\n---\n\nI just started using FreshRSS to get familiar with subscribing to RSS feeds and leaning into that as opposed to social media... Twitter has become basically just a news outlet for me, not a place to connect with devs (except for 2 or 3 who are active). RSS seems like such cool and ancient technology that is protected from the corporate tentacles that hold up every social media outlet save for nostr... \n\nSo as I look for an RSS reader and/or feed aggregator this Nextcloud plugin seems like a good choice to look at since I'm already hosting NC.. although do I really want to lean into it for more and more?\n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "I just started using FreshRSS to get familiar with subscribing to RSS feeds and leaning into that as opposed to social m",
      "date_published": "2025-06-09T11:37:39Z",
      "date_modified": "2025-06-09T11:37:39Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "rss",
        "news",
        "nextcloud",
        "homelab",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/example-for-andrew/",
      "url": "https://pype.dev/example-for-andrew/",
      "title": "Example For Andrew",
      "content_html": "\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250608194801_809d5306.png\" alt=\"20250608194801_809d5306.png\"\u003e\n\u003c/figure\u003e\n",
      "content_text": "\n![20250608194801_809d5306.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250608194801_809d5306.png)\n",
      "date_published": "2025-06-08T14:48:53Z",
      "date_modified": "2025-06-08T14:48:53Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/i-built-a-simple-app-for-adding-images-to-my-blog/",
      "url": "https://pype.dev/i-built-a-simple-app-for-adding-images-to-my-blog/",
      "title": "I built a simple app for adding images to my blog",
      "content_text": "\n# Quick Deets\n\nI built a simple fastAPI app called \"shotput\" that I run locally inside a git repo where I save images for my blog. The app is simple:\n\n1. upload image from clipboard\n2. app commits image to repo (path is configurable)\n3. app pushes the commit (auto-push configurable)\n4. app returns a markdown link I can paste in my blog that uses statically.io (see [[statically-io-to-help-me-out]]) to serve the image from the repo to my blog\n\nSee the image repo with app details at [images.pype.dev](https://github.com/pypeaday/images.pype.dev)\n\n# Usage\n\nAnyone could copy the script and config to their own git repo to put images in\nand run this at home - instructions are in the readme but for simple running on localhost it's just `uv run`\n\n# Example\n\n![20250607130609_dadd33eb.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250607130609_dadd33eb.png)\n\npasting an image let's you copy the markdown link for easy pasting\n\n```markdown\n![20250607130609_dadd33eb.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250607130609_dadd33eb.png)\n```\n",
      "summary": "I built a simple fastAPI app called \"shotput\" that I run locally inside a git repo where I save images for my blog. The app is simple:",
      "date_published": "2025-06-07T13:30:28Z",
      "date_modified": "2025-06-07T13:30:28Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "python",
        "uv"
      ]
    },
    {
      "id": "https://pype.dev/double-check-your-cidr-blocks/",
      "url": "https://pype.dev/double-check-your-cidr-blocks/",
      "title": "Double check your CIDR blocks!",
      "content_html": "\u003ch1 id=\"tl-dr\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003etl;dr\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eCopy paste - don\u0026rsquo;t rely on typing correctly\u0026hellip;\u003c/p\u003e\n\u003ch1 id=\"the-issue\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eThe Issue\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eI use tailscale at home and generally love it. One thing I use it for is\nwhitelisting - so I have some apps publically available and my homelab ones\nhave DNS with SSL certs by LE but I whitelist to only my private IPs so that I\ncan use https at home basically. However I have had a few issues\nwith a couple apps, and I kind of chaulked it up to \u0026ldquo;network protocol this\u0026rdquo;\n\u0026ldquo;need to figure out that header that\u0026rdquo; but ultimately I was being lazy and the\nissues weren\u0026rsquo;t catastrophic\u0026hellip; it was things like:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ecouldn\u0026rsquo;t get to my NVR by DNS, so I\u0026rsquo;d have to use tailscale_ip:port\u003c/li\u003e\n\u003cli\u003ecouldn\u0026rsquo;t login with my user in jellyfin cause I lock me down to LAN only\nsince I dont\u0026rsquo; use a password\u003c/li\u003e\n\u003cli\u003egotify wouldn\u0026rsquo;t connect using DNS\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThese things aren\u0026rsquo;t huge but they are annoying and today I decided to figure it out.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"typo\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eTypo!\u003c/span\u003e \u003ca href=\"#typo\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI\u0026rsquo;m not an expert yet but I think the main problem was the CIDR block I was\nusing in my traefik config.\u003c/p\u003e\n\u003cp\u003eThis\u0026rsquo;ll shock some of you but \u003ccode\u003e10.64.0.0/10\u003c/code\u003e and \u003ccode\u003e100.64.0.0/10\u003c/code\u003e are not the\nsame blocks!\u003c/p\u003e\n\u003cdiv class=\"admonition warning\"\u003e\n\u003cp class=\"admonition-title\"\u003eCheck your CIDRs\u003c/p\u003e\n\u003cp\u003eIt\u0026rsquo;s always DNS, and even when it\u0026rsquo;s not, it\u0026rsquo;s still probably networking\u003c/p\u003e\n\u003c/div\u003e\n",
      "content_text": "\n# tl;dr\n\nCopy paste - don't rely on typing correctly...\n\n# The Issue\n\nI use tailscale at home and generally love it. One thing I use it for is\nwhitelisting - so I have some apps publically available and my homelab ones\nhave DNS with SSL certs by LE but I whitelist to only my private IPs so that I\ncan use https at home basically. However I have had a few issues\nwith a couple apps, and I kind of chaulked it up to \"network protocol this\"\n\"need to figure out that header that\" but ultimately I was being lazy and the\nissues weren't catastrophic... it was things like:\n\n1. couldn't get to my NVR by DNS, so I'd have to use tailscale_ip:port\n2. couldn't login with my user in jellyfin cause I lock me down to LAN only\n   since I dont' use a password\n3. gotify wouldn't connect using DNS\n\n\u003e These things aren't huge but they are annoying and today I decided to figure it out.\n\n## Typo!\n\nI'm not an expert yet but I think the main problem was the CIDR block I was\nusing in my traefik config.\n\nThis'll shock some of you but `10.64.0.0/10` and `100.64.0.0/10` are not the\nsame blocks!\n\n!!! warning \"Check your CIDRs\"\n    It's always DNS, and even when it's not, it's still probably networking\n",
      "summary": "Copy paste - don't rely on typing correctly...",
      "date_published": "2025-06-07T07:27:31Z",
      "date_modified": "2025-06-07T07:27:31Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "tailscale",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/homelab-journey-part-1/",
      "url": "https://pype.dev/homelab-journey-part-1/",
      "title": "homelab-journey-part-1",
      "content_text": "\n# Introduction\n\nI want to start writing about my homelab and this first post can be a short\nintroduction to how I got into homelabbing and a review of my current hardware.\nI'll hopefully write about the evolution of my homelab to get to this\ncurrent point and then start writing about updates as new things hit the lab.\n\n# The Journey\n\n## Applications | Pi-Hole\n\nI started with a pi-hole appliance running on a pi-0 I\nhad lying around. So, a little introduction into SSH and foreign operating\nsystems (I was loosely familiar with Linux and so Raspbian wasn't a huge deal\nto start with) and then you could just [install pi-hole](https://docs.pi-hole.net/main/basic-install/).\nAfter installing it I got to learn a little bit about networking, DNS, DHCP,\netc. all from just exploring and trying out the features of pi-hole.\n\n## Hardware\n\nFrom there I happened to come into a few computers kind of for free that a church was\nrecycling and so now with new-to-me x86 hardware and armed with a tiny bit of\ndocker experience at work - I thought \"well I wonder if I could run pi-hole in\ndocker on a Linux machine?\" and that opened the door to running other things in docker.\n\n# Applications | Free-NAS\n\nI quickly decided I wanted a NAS after talking with a friend at work, and one\nof those computers that I inherited was the perfect target for Freenas by iX\nsystems (Freenas has since morphed into a few things - primarily TrueNAS Core\nfor the homelabber). That got me somewhat familiar with jails (which is a BSD\nconcept as FreeNAS was based on FreeBSD, not Linux) and running\ncontainers in different ways and then I decided I wanted Linux so I rebuilt with\nUbuntu.\n\n!!! note \"\"\n\n    there's been several hardware changes and such in there but that\n    does more or less get me to arrive at where I'm at today which is I have a\n    few different boxes running pretty standard operating systems for their\n    purposes and they are as follows.\n\n# Current Homelab Setup\n\n!!! note \"Find updated information at [[the-homelab]]\"\n\n## Ad blocking | Pi-Hole\n\nHardware: pi-3\n\nI have a Raspberry Pi 3 hardwired in that is running pi-hole so that's been a\npart of my infrastructure now for a long time.\n\n## Router | OPNSense\n\n!!! note \"stats\"\n\n    CPU: i5-8700\n\n    Memory: 8GB of whatever was in the box\n\n    Storage: 1TB SSD\n\nMy router is an old Optiplex SFF 5060 I got from Amazon for less than $100.\nSo I'm running a x86 system for my router with\nOpenSense on it. Just seemed it to be another home lab standard and I'd like to\nsomeday bring pi-hole over there or use AdGuard or integrate those two things\nmaybe a little bit more completely but right now they are mostly separate.\n\n## Networking | VLANs\n\nThere's a\nmanaged switch in there for some VLAN tomfoolery for my cameras and an IOT\nnetwork type of a thing.\n\n## Networking | VPN | Tailscale\n\nThey're on tailscale as well so my DNS happens over tailscale.\n\n## My Desktop\n\n!!! note \"stats\"\n\n    CPU: Ryzen 7 5700X\n\n    GPU: Nvidia 3090\n\n    Memory: 64 GB\n\n    Storage: 4TB SSD + 2 TB HDD for zfs backup\n\n    OS: Universal Blue Aurora\n\nMy daily-driver desktop is somewhat apart of my homelab now as I have a 3090 in\nthere with 20 GB of VRAM so I can run some heavier LLMs for self-hosted AI\nworkloads. Everything in that space runs in a container and then I manage\ndocker containers with compose stacks and portainer for visibility.\n\n### Applications\n\nSome of the apps I run here are ollama, open-webui, automatic1111's stable diffusion webui, whisper-webui\n\n## NAS / Server\n\n!!! note \"stats\"\n\n    CPU: Ryzen 7 5700G\n\n    GPU: None right now\n\n    Memory: 128 GB\n\n    Storage: 2x12 TB ZFS Mirror + another 2x12 TB ZFS Mirror + 500GB disk for NVR\n\n    OS: Ubuntu Server 24.04\n\nAt the moment I am managing containers using Docker Compose stacks. Many\napplications have their own stack but then I also have stacks of many\napplications. The Compose files are all organized by host and they're in git\nand I use GitHub as my main get back and remote storage.\n\n### Applications\n\nThere are currently 74 containers running on my server, I will not list them all but here's some highlights:\n\n- traefik\n- portainer\n- nextcloud\n- jellyfin\n- \\*arr stack\n- code-server\n- kanboard\n\nI regularly spin up compose stacks to try new things as I hear about them in\nnewsletters and such - I will be making an attempt to write about them more\nfrequently in a homelabbing series\n",
      "summary": "I want to start writing about my homelab and this first post can be a short introduction to how I got into homelabbing and a review of my current hardware....",
      "date_published": "2025-06-05T08:19:57Z",
      "date_modified": "2025-06-05T08:19:57Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "series-homelab"
      ]
    },
    {
      "id": "https://pype.dev/backups-interrupted-by-full-disk-usage/",
      "url": "https://pype.dev/backups-interrupted-by-full-disk-usage/",
      "title": "Backups interrupted by full disk usage",
      "content_html": "\u003cp\u003eI just got a message from HCIO that my primary backup script is late\u0026hellip; This\nhappens every now and then but I decided to check on it\u0026hellip; Quickly \u003ccode\u003essh\u003c/code\u003e in and\nI notice it takes a long time to connect, but nothing errors out\u0026hellip; I\u0026rsquo;ve been\nin the game long enough to think this kind of latency is often disk IO. After\nwaiting a bit and haulting the zshrc sourcing, I hit a \u003ccode\u003esudo dust / -H\u003c/code\u003e and bam\u0026hellip;\nThere\u0026rsquo;s a container logfile that\u0026rsquo;s about 80GB sitting in \u003ccode\u003e/var\u003c/code\u003e\u0026hellip;\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e  75G   │ │ │ │   ┌── 57409a7f8d3168b368e0230babd08ec2e20aabb288806aa13652db1e653a0eee-json.log\n  75G   │ │ │ │ ┌─┴ 57409a7f8d3168b368e0230babd08ec2e20aabb288806aa13652db1e653a0eee           \n  76G   │ │ │ ├─┴ containers                                                                   \n  83G   │ │ ├─┴ docker                                                                         \n  85G   │ ├─┴ lib                                                                              \n  90G   ├─┴ var                                                                                \n 117G ┌─┴ /\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eEasy enough to remove, but I need to setup some alerts on disk usage, and\nidentify the container to limit the log file size\u003c/p\u003e\n\u003cdiv class=\"admonition info\"\u003e\n\u003cp class=\"admonition-title\"\u003eUseful Notifications\u003c/p\u003e\n\u003cp\u003eI use healthchecks.io to monitor several scripts. You can self-host it but\nI use the hosted service since he has simple Signal integration\u003c/p\u003e\n\u003c/div\u003e\n",
      "content_text": "\n\nI just got a message from HCIO that my primary backup script is late... This\nhappens every now and then but I decided to check on it... Quickly `ssh` in and\nI notice it takes a long time to connect, but nothing errors out... I've been\nin the game long enough to think this kind of latency is often disk IO. After\nwaiting a bit and haulting the zshrc sourcing, I hit a `sudo dust / -H` and bam...\nThere's a container logfile that's about 80GB sitting in `/var`...\n\n```\n  75G   │ │ │ │   ┌── 57409a7f8d3168b368e0230babd08ec2e20aabb288806aa13652db1e653a0eee-json.log\n  75G   │ │ │ │ ┌─┴ 57409a7f8d3168b368e0230babd08ec2e20aabb288806aa13652db1e653a0eee           \n  76G   │ │ │ ├─┴ containers                                                                   \n  83G   │ │ ├─┴ docker                                                                         \n  85G   │ ├─┴ lib                                                                              \n  90G   ├─┴ var                                                                                \n 117G ┌─┴ /\n```\n\nEasy enough to remove, but I need to setup some alerts on disk usage, and\nidentify the container to limit the log file size\n\n!!! info \"Useful Notifications\"\n\n    I use healthchecks.io to monitor several scripts. You can self-host it but\n    I use the hosted service since he has simple Signal integration\n\n\n",
      "summary": "I just got a message from HCIO that my primary backup script is late... This happens every now and then but I decided to check on it... Quickly in and I...",
      "date_published": "2025-06-03T21:08:50Z",
      "date_modified": "2025-06-03T21:08:50Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/homelab-computer-vision-pipelines/",
      "url": "https://pype.dev/homelab-computer-vision-pipelines/",
      "title": "homelab-computer-vision-pipelines",
      "content_html": "\u003cp\u003eDone in 11 seconds! Subtitle and audio files are in the outputs folder.\u003c/p\u003e\n\u003cp\u003eI wanted to talk through an idea I have for some computer vision pipelines at home.\nI heard of a tool called Roboflow, which is like a no-code computer vision pipeline training\nand inference tool.\nIt seems very cool.\nI also use Frigate at home, and Frigate supports lots of detection on the NVR side.\nAnd so deploying a model in Frigate or using Roboflow, depending on what kind of customization\nyou would need, you can have these detections potentially be as accurate as you want, at\nleast with Roboflow.\nThe thing is, I don\u0026rsquo;t know about Frigate, but my ideas are if I have a model at home\nthat knows me and my wife and my children by name, then when monitored areas issue detections,\nfor example, say I\u0026rsquo;m in the backyard and the temperature is above 80 degrees, have a home\nassistant kick on a sprinkler system or something like that.\nAnd if my wife is back there and it\u0026rsquo;s 80 degrees, don\u0026rsquo;t do that because she wouldn\u0026rsquo;t want that\nsprinkler on or whatever.\nI think that something like that would be very feasible once you have the model.\nSo you would need a way to train the model, which would require gathering data and labeling\nit.\nThen you could train a model in lots of ways, but you need to have the deployment in mind.\nIf the deployment was Frigate, you would need to be able to compile that model into some\nTensorFlow Lite thing that can run on a TPU.\nThat sounds very possible.\nOtherwise, the Roboflow would probably be the platform for training, and then they make\nthe deployment kind of a one-click thing.\nFrom there, I guess either way, Frigate is running the inference, and so the home assistant\nintegration would be about the same.\nFrigate sends notifications over MQTT, and based on the Frigate blueprint that I\u0026rsquo;m using\nfor home assistant anyway, based on the object and whatever other conditions you want to\nset in an automation, you do whatever you want to do in home assistant.\nThat sounds neat.\u003c/p\u003e\n",
      "content_text": "\nDone in 11 seconds! Subtitle and audio files are in the outputs folder.\n\nI wanted to talk through an idea I have for some computer vision pipelines at home.\nI heard of a tool called Roboflow, which is like a no-code computer vision pipeline training\nand inference tool.\nIt seems very cool.\nI also use Frigate at home, and Frigate supports lots of detection on the NVR side.\nAnd so deploying a model in Frigate or using Roboflow, depending on what kind of customization\nyou would need, you can have these detections potentially be as accurate as you want, at\nleast with Roboflow.\nThe thing is, I don't know about Frigate, but my ideas are if I have a model at home\nthat knows me and my wife and my children by name, then when monitored areas issue detections,\nfor example, say I'm in the backyard and the temperature is above 80 degrees, have a home\nassistant kick on a sprinkler system or something like that.\nAnd if my wife is back there and it's 80 degrees, don't do that because she wouldn't want that\nsprinkler on or whatever.\nI think that something like that would be very feasible once you have the model.\nSo you would need a way to train the model, which would require gathering data and labeling\nit.\nThen you could train a model in lots of ways, but you need to have the deployment in mind.\nIf the deployment was Frigate, you would need to be able to compile that model into some\nTensorFlow Lite thing that can run on a TPU.\nThat sounds very possible.\nOtherwise, the Roboflow would probably be the platform for training, and then they make\nthe deployment kind of a one-click thing.\nFrom there, I guess either way, Frigate is running the inference, and so the home assistant\nintegration would be about the same.\nFrigate sends notifications over MQTT, and based on the Frigate blueprint that I'm using\nfor home assistant anyway, based on the object and whatever other conditions you want to\nset in an automation, you do whatever you want to do in home assistant.\nThat sounds neat.\n",
      "summary": "Done in 11 seconds! Subtitle and audio files are in the outputs folder.",
      "date_published": "2025-05-31T08:18:55Z",
      "date_modified": "2025-05-31T08:18:55Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "tech",
        "homelab",
        "computer-vision"
      ]
    },
    {
      "id": "https://pype.dev/backups-are-dope/",
      "url": "https://pype.dev/backups-are-dope/",
      "title": "Backups are dope",
      "content_text": "\nI accidently chown'd -R an app directory and it totally screwed up the database\nfolder. Luckily I zfs replicate my docker volumes to another drive even on the\nsame host, so a quick [rsync] from /harbor/encrypted/docker/manyfold to\n/tank/encrypted/docker/manyfold got me back up and running since I hadn't\nreplicated the messed up permission set yet\n\nQ: How to link to my rsync like a pro post?\n\nA: Wikilinks `[[rsync-like-a-pro]]` [[rsync-like-a-pro]]\n",
      "summary": "I accidently chown'd -R an app directory and it totally screwed up the database folder. Luckily I zfs replicate my docker volumes to another drive even on...",
      "date_published": "2025-05-27T19:42:27Z",
      "date_modified": "2025-05-27T19:42:27Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "tech",
        "homelab",
        "zfs",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/searxng/",
      "url": "https://pype.dev/searxng/",
      "title": "SearXNG",
      "content_html": "\u003cp\u003eI heard about \u003ca href=\"https://searxng.org\"\u003eSearXNG\u003c/a\u003e on a couple podcasts and saw it trending on GitHub\nseveral times before I finally decided to stand it up.\nI used it transparently when trying out \u003ca href=\"https://khoj.dev/\"\u003ekhoj\u003c/a\u003e, a self-hosted AI LLM agent\nplayground kind of a thing, but I\u0026rsquo;ve also been messing around with \u003ca href=\"https://openwebui.com\"\u003eOpen-WebUI\u003c/a\u003e to\nhave a self-hosted ChatGPT-like experience.\nI don\u0026rsquo;t know if SearchXNG used to be harder to set up, but it was pretty simple with a Docker Compose up\nand a couple configuration options given my personal homelab setup. Using it feels\nvery nice.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eservices\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eredis\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003econtainer_name\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eredis\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eimage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003edocker.io/valkey/valkey:8-alpine\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ecommand\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003evalkey-server --save 30 1 --loglevel warning\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003erestart\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eunless-stopped\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003evolumes\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003e./data/redis:/data\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003elogging\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003edriver\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;json-file\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eoptions\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003emax-size\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1m\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003emax-file\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003esearxng\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003econtainer_name\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003esearxng\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eimage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003edocker.io/searxng/searxng:latest\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003erestart\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eunless-stopped\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eports\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;8080:8080\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003evolumes\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003e./data/searxng:/etc/searxng:rw\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eenv_file\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003e.env\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eenvironment\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"c\"\u003e# - SEARXNG_BASE_URL=https://${SEARXNG_HOSTNAME:-localhost}/\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003eUWSGI_WORKERS=${SEARXNG_UWSGI_WORKERS:-4}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003eUWSGI_THREADS=${SEARXNG_UWSGI_THREADS:-4}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003elogging\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003edriver\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;json-file\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eoptions\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003emax-size\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1m\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003emax-file\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eI love the self-hosted aspect. I love not seeing any ads on my search\nresults. I did a few searches where I know what results to expect and\nit did okay.\nIt is good right now at filtering out garbage in my results.\u003c/p\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://dropper.wayl.one/api/file/4ff5953c-bc8d-4978-8509-b43582460a0b.png\" alt=\"SearXNG\"\u003e\n\u003c/figure\u003e\n\u003cp\u003eSo I look forward to tweaking it and using it as a search\nbackend with open web UI. Next on my list is having enough resources to run\nOllama and a stable diffusion generator at the same time and have image\ngeneration working through open web UI.\u003c/p\u003e\n",
      "content_text": "\n\nI heard about [SearXNG](https://searxng.org) on a couple podcasts and saw it trending on GitHub\nseveral times before I finally decided to stand it up. \nI used it transparently when trying out [khoj](https://khoj.dev/), a self-hosted AI LLM agent\nplayground kind of a thing, but I've also been messing around with [Open-WebUI](https://openwebui.com) to\nhave a self-hosted ChatGPT-like experience. \nI don't know if SearchXNG used to be harder to set up, but it was pretty simple with a Docker Compose up\nand a couple configuration options given my personal homelab setup. Using it feels\nvery nice. \n\n```yaml\nservices:\n  redis:\n    container_name: redis\n    image: docker.io/valkey/valkey:8-alpine\n    command: valkey-server --save 30 1 --loglevel warning\n    restart: unless-stopped\n    volumes:\n      - ./data/redis:/data\n    logging:\n      driver: \"json-file\"\n      options:\n        max-size: \"1m\"\n        max-file: \"1\"\n\n  searxng:\n    container_name: searxng\n    image: docker.io/searxng/searxng:latest\n    restart: unless-stopped\n    ports:\n      - \"8080:8080\"\n    volumes:\n      - ./data/searxng:/etc/searxng:rw\n    env_file: .env\n    environment:\n      # - SEARXNG_BASE_URL=https://${SEARXNG_HOSTNAME:-localhost}/\n      - UWSGI_WORKERS=${SEARXNG_UWSGI_WORKERS:-4}\n      - UWSGI_THREADS=${SEARXNG_UWSGI_THREADS:-4}\n    logging:\n      driver: \"json-file\"\n      options:\n        max-size: \"1m\"\n        max-file: \"1\"\n```\n\nI love the self-hosted aspect. I love not seeing any ads on my search\nresults. I did a few searches where I know what results to expect and\nit did okay. \nIt is good right now at filtering out garbage in my results. \n\n![SearXNG](https://dropper.wayl.one/api/file/4ff5953c-bc8d-4978-8509-b43582460a0b.png)\n\nSo I look forward to tweaking it and using it as a search\nbackend with open web UI. Next on my list is having enough resources to run\nOllama and a stable diffusion generator at the same time and have image\ngeneration working through open web UI.\n\n",
      "summary": "I heard about SearXNG on a couple podcasts and saw it trending on GitHub several times before I finally decided to stand it up. I used it transparently when...",
      "date_published": "2025-05-25T08:33:10Z",
      "date_modified": "2025-05-25T08:33:10Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/grafana-gotify-for-push-notifications/",
      "url": "https://pype.dev/grafana-gotify-for-push-notifications/",
      "title": "Grafana + Gotify for push notifications",
      "content_html": "\u003cp\u003eIt\u0026rsquo;s easy to configure push notifications through Gotify from Grafana by setting up a generic \u003ccode\u003eWebhook\u003c/code\u003e Alerting Contact Point\u0026hellip;\u003c/p\u003e\n\u003cp\u003eThe parameters are:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eHTTP Method: POST\u003c/li\u003e\n\u003cli\u003eURL: http://\u003cgotify url\u003e/message\u003c/li\u003e\n\u003cli\u003eAuthentication is done with an app token generated from Gotify, and you put it in \u003ccode\u003eAuthorization Header: Credentials\u003c/code\u003e in the Grafana configuration\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ca href=\"https://dropper.wayl.one/api/file/610b4efb-b4c4-4930-ac63-499d501ba3c3.png\"\u003eSee image\u003c/a\u003e\u003c/p\u003e\n",
      "content_text": "\nIt's easy to configure push notifications through Gotify from Grafana by setting up a generic `Webhook` Alerting Contact Point...\n\nThe parameters are:\n\n* HTTP Method: POST\n* URL: http://\u003cgotify url\u003e/message\n* Authentication is done with an app token generated from Gotify, and you put it in `Authorization Header: Credentials` in the Grafana configuration \n\n[See image](https://dropper.wayl.one/api/file/610b4efb-b4c4-4930-ac63-499d501ba3c3.png)\n",
      "summary": "It's easy to configure push notifications through Gotify from Grafana by setting up a generic Alerting Contact Point...",
      "date_published": "2025-04-07T10:12:51Z",
      "date_modified": "2025-04-07T10:12:51Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "infrastructure",
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/thoughts-479/",
      "url": "https://pype.dev/thoughts-479/",
      "title": "💭 audiobookshelf",
      "content_text": "\n\u003ca href=\"https://www.audiobookshelf.org/\"\u003e\n    \u003cimg\n        src=\"https://shots.wayl.one/shot/?url=https://www.audiobookshelf.org/\u0026height=450\u0026width=800\u0026scaled_width=800\u0026scaled_height=450\u0026selectors=\"\n        alt=\"shot of post - audiobookshelf\"\n        height=450\n        width=800\n    \u003e\n\u003c/a\u003e\n\nHere's my thought on \u003ca href=\"https://www.audiobookshelf.org/\"\u003eaudiobookshelf\u003c/a\u003e\n\n---\n\nAudiobookshelf looks like a solid competitor for booksonic. I've liked the simple subsonic api driven nature of booksonic but my wife would like some more appropriate and easy-to-use organization... booksonic is not a great \"library\"... I'm looking forward to putting this into my homelab soon \n\n---\n\n!!! note\n    This is one of [[ my-thoughts ]]. I picked this up from [Waylon Walker](https://waylonwalker.com)(https://thoughts.waylonwalker.com). It's a short note that I make about someone else's content online.  Learn more about the process [[ thoughts ]]\n",
      "summary": "Audiobookshelf looks like a solid competitor for booksonic. I've liked the simple subsonic api driven nature of booksoni",
      "date_published": "2024-12-29T20:53:19Z",
      "date_modified": "2024-12-29T20:53:19Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "thoughts"
      ]
    },
    {
      "id": "https://pype.dev/add-a-healthcheck-to-your-fastapi-app/",
      "url": "https://pype.dev/add-a-healthcheck-to-your-fastapi-app/",
      "title": "Add a healthcheck to your FastAPI app",
      "content_html": "\u003cp\u003eI\u0026rsquo;m building a few FastAPI apps to throw in docker and run on my homelab\u0026hellip; I wanted to add healthchecks and here\u0026rsquo;s a simple way to do it\u003c/p\u003e\n\u003cp\u003eMake sure to install \u003ccode\u003ecurl\u003c/code\u003e in the dockerfile (near the top for effeciency)\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e# Install curl with minimal dependencies\nRUN apt-get update \u0026amp;\u0026amp; \\\n    apt-get install -y --no-install-recommends curl \u0026amp;\u0026amp; \\\n    apt-get clean \u0026amp;\u0026amp; \\\n    rm -rf /var/lib/apt/lists/*\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThen I recommend making compose files even for single image deployments\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eservices:\n  app:\n    build: .\n    volumes:\n      - type: bind\n        source: .\n        target: /app\n    environment:\n      - PYTHONPATH=/app\n      - DOCKER_ENV=true\n      - UV_VIRTUALENV=/opt/app-env\n    user: \u0026quot;1000:1000\u0026quot;\n    restart: unless-stopped\n    healthcheck:\n      test: [\u0026quot;CMD\u0026quot;, \u0026quot;curl\u0026quot;, \u0026quot;-f\u0026quot;, \u0026quot;http://localhost:8000/health\u0026quot;]\n      interval: 30s\n      timeout: 10s\n      retries: 3\n      start_period: 10s\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThen finally you\u0026rsquo;ll need a \u003ccode\u003e/health\u003c/code\u003e endpoint\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nd\"\u003e@app.get\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;/health\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eresponse_class\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003eHTMLResponse\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003easync\u003c/span\u003e \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003ehealth_check\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s2\"\u003e    A health check endpoint that returns a status message.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s2\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026lt;html\u0026gt;\u0026lt;body\u0026gt;\u0026lt;h1\u0026gt;Service is healthy\u0026lt;/h1\u0026gt;\u0026lt;/body\u0026gt;\u0026lt;/html\u0026gt;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e",
      "content_text": "\nI'm building a few FastAPI apps to throw in docker and run on my homelab... I wanted to add healthchecks and here's a simple way to do it\n\nMake sure to install `curl` in the dockerfile (near the top for effeciency)\n\n```\n# Install curl with minimal dependencies\nRUN apt-get update \u0026\u0026 \\\n    apt-get install -y --no-install-recommends curl \u0026\u0026 \\\n    apt-get clean \u0026\u0026 \\\n    rm -rf /var/lib/apt/lists/*\n\n```\n\nThen I recommend making compose files even for single image deployments\n\n```\nservices:\n  app:\n    build: .\n    volumes:\n      - type: bind\n        source: .\n        target: /app\n    environment:\n      - PYTHONPATH=/app\n      - DOCKER_ENV=true\n      - UV_VIRTUALENV=/opt/app-env\n    user: \"1000:1000\"\n    restart: unless-stopped\n    healthcheck:\n      test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:8000/health\"]\n      interval: 30s\n      timeout: 10s\n      retries: 3\n      start_period: 10s\n\n```\n\nThen finally you'll need a `/health` endpoint\n\n```python\n\n@app.get(\"/health\", response_class=HTMLResponse)\nasync def health_check():\n    \"\"\"\n    A health check endpoint that returns a status message.\n    \"\"\"\n    return \"\u003chtml\u003e\u003cbody\u003e\u003ch1\u003eService is healthy\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e\"\n\n```\n",
      "summary": "I'm building a few FastAPI apps to throw in docker and run on my homelab... I wanted to add healthchecks and here's a simple way to do it",
      "date_published": "2024-12-15T15:41:36Z",
      "date_modified": "2024-12-15T15:41:36Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "python",
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/jellyfin-container-updates-for-hwe-amd/",
      "url": "https://pype.dev/jellyfin-container-updates-for-hwe-amd/",
      "title": "Jellyfin container updates for HWE + AMD",
      "content_html": "\u003cp\u003eI use LSIO Jelyfin container for the easy addon they provide for AMD GPUs but I couldn\u0026rsquo;t get trickplay to work with HWE\u0026hellip;\u003c/p\u003e\n\u003cp\u003eThere was almost NOTHING on the internet about the error, and all the threads were about BSD systems\u0026hellip;\u003c/p\u003e\n\u003cp\u003eThankfully someone posted \u003ca href=\"https://forum.jellyfin.org/t-jellyfin-amd-docker\"\u003eon the formum here\u003c/a\u003e but the only answer was to literally upgrade stuff in the container\u0026hellip;\u003c/p\u003e\n\u003cp\u003eSomeday maybe I\u0026rsquo;ll build off of LSIO to add this, but until then I shell\u0026rsquo;d in and homelab\u0026rsquo;d the hell out of it\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eTHIS IS INSIDE THE CONTAINER - I use Portianer to make it easy\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cpre\u003e\u003ccode\u003e\napt update \u0026amp;\u0026amp; apt install -y curl gpg\n\nmkdir -p /etc/apt/keyrings\n\ncurl -fsSL https://repo.radeon.com/rocm/rocm.gpg.key | gpg --dearmor -o /etc/apt/keyrings/rocm.gpg\n\ncat \u0026lt;\u0026lt;EOF | tee /etc/apt/sources.list.d/rocm.sources\n\nTypes: deb\n\nURIs: https://repo.radeon.com/rocm/apt/latest\n\nSuites: ubuntu\n\nComponents: main\n\nArchitectures: amd64\n\nSigned-By: /etc/apt/keyrings/rocm.gpg\n\nEOF\n\napt update \u0026amp;\u0026amp; apt install -y rocm-opencl-runtime\n\u003c/code\u003e\u003c/pre\u003e\n",
      "content_text": "\nI use LSIO Jelyfin container for the easy addon they provide for AMD GPUs but I couldn't get trickplay to work with HWE... \n\nThere was almost NOTHING on the internet about the error, and all the threads were about BSD systems...\n\nThankfully someone posted [on the formum here](https://forum.jellyfin.org/t-jellyfin-amd-docker) but the only answer was to literally upgrade stuff in the container...\n\nSomeday maybe I'll build off of LSIO to add this, but until then I shell'd in and homelab'd the hell out of it\n\n\u003e THIS IS INSIDE THE CONTAINER - I use Portianer to make it easy\n\n```\n\napt update \u0026\u0026 apt install -y curl gpg\n\nmkdir -p /etc/apt/keyrings\n\ncurl -fsSL https://repo.radeon.com/rocm/rocm.gpg.key | gpg --dearmor -o /etc/apt/keyrings/rocm.gpg\n\ncat \u003c\u003cEOF | tee /etc/apt/sources.list.d/rocm.sources\n\nTypes: deb\n\nURIs: https://repo.radeon.com/rocm/apt/latest\n\nSuites: ubuntu\n\nComponents: main\n\nArchitectures: amd64\n\nSigned-By: /etc/apt/keyrings/rocm.gpg\n\nEOF\n\napt update \u0026\u0026 apt install -y rocm-opencl-runtime\n```\n",
      "summary": "I use LSIO Jelyfin container for the easy addon they provide for AMD GPUs but I couldn't get trickplay to work with HWE...",
      "date_published": "2024-12-14T11:27:15Z",
      "date_modified": "2024-12-14T11:27:15Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "docker",
        "linux",
        "homelab",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/hostnamectl-to-easily-change-hostname/",
      "url": "https://pype.dev/hostnamectl-to-easily-change-hostname/",
      "title": "hostnamectl to easily change hostname",
      "content_html": "\u003cp\u003ehostnamectl is apparently a linux utility for easily changing your hostname in a variety of ways\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e❯ hostnamectl --help\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ehostnamectl \u003cspan class=\"o\"\u003e[\u003c/span\u003eOPTIONS...\u003cspan class=\"o\"\u003e]\u003c/span\u003e COMMAND ...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eQuery or change system hostname.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eCommands:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  status                 Show current hostname settings\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  hostname \u003cspan class=\"o\"\u003e[\u003c/span\u003eNAME\u003cspan class=\"o\"\u003e]\u003c/span\u003e        Get/set system hostname\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  icon-name \u003cspan class=\"o\"\u003e[\u003c/span\u003eNAME\u003cspan class=\"o\"\u003e]\u003c/span\u003e       Get/set icon name \u003cspan class=\"k\"\u003efor\u003c/span\u003e host\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  chassis \u003cspan class=\"o\"\u003e[\u003c/span\u003eNAME\u003cspan class=\"o\"\u003e]\u003c/span\u003e         Get/set chassis \u003cspan class=\"nb\"\u003etype\u003c/span\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e host\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  deployment \u003cspan class=\"o\"\u003e[\u003c/span\u003eNAME\u003cspan class=\"o\"\u003e]\u003c/span\u003e      Get/set deployment environment \u003cspan class=\"k\"\u003efor\u003c/span\u003e host\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  location \u003cspan class=\"o\"\u003e[\u003c/span\u003eNAME\u003cspan class=\"o\"\u003e]\u003c/span\u003e        Get/set location \u003cspan class=\"k\"\u003efor\u003c/span\u003e host\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eOptions:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -h --help              Show this \u003cspan class=\"nb\"\u003ehelp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     --version           Show package version\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     --no-ask-password   Do not prompt \u003cspan class=\"k\"\u003efor\u003c/span\u003e password\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -H --host\u003cspan class=\"o\"\u003e=[\u003c/span\u003eUSER@\u003cspan class=\"o\"\u003e]\u003c/span\u003eHOST  Operate on remote host\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -M --machine\u003cspan class=\"o\"\u003e=\u003c/span\u003eCONTAINER Operate on \u003cspan class=\"nb\"\u003elocal\u003c/span\u003e container\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     --transient         Only \u003cspan class=\"nb\"\u003eset\u003c/span\u003e transient hostname\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     --static            Only \u003cspan class=\"nb\"\u003eset\u003c/span\u003e static hostname\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     --pretty            Only \u003cspan class=\"nb\"\u003eset\u003c/span\u003e pretty hostname\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     --json\u003cspan class=\"o\"\u003e=\u003c/span\u003epretty\u003cspan class=\"p\"\u003e|\u003c/span\u003eshort\u003cspan class=\"p\"\u003e|\u003c/span\u003eoff\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                         Generate JSON output\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eSee the hostnamectl\u003cspan class=\"o\"\u003e(\u003c/span\u003e1\u003cspan class=\"o\"\u003e)\u003c/span\u003e man page \u003cspan class=\"k\"\u003efor\u003c/span\u003e details.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eI learned there\u0026rsquo;s transient and static hostnames, so that\u0026rsquo;s cool\u0026hellip;\u003c/p\u003e\n\u003cp\u003eThe thing I needed was \u003ccode\u003ehostnamectl --static hostname babyblue-aurora\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003epretty sweet tool\u003c/p\u003e\n",
      "content_text": "\nhostnamectl is apparently a linux utility for easily changing your hostname in a variety of ways\n\n```bash\n\n❯ hostnamectl --help\nhostnamectl [OPTIONS...] COMMAND ...\n\nQuery or change system hostname.\n\nCommands:\n  status                 Show current hostname settings\n  hostname [NAME]        Get/set system hostname\n  icon-name [NAME]       Get/set icon name for host\n  chassis [NAME]         Get/set chassis type for host\n  deployment [NAME]      Get/set deployment environment for host\n  location [NAME]        Get/set location for host\n\nOptions:\n  -h --help              Show this help\n     --version           Show package version\n     --no-ask-password   Do not prompt for password\n  -H --host=[USER@]HOST  Operate on remote host\n  -M --machine=CONTAINER Operate on local container\n     --transient         Only set transient hostname\n     --static            Only set static hostname\n     --pretty            Only set pretty hostname\n     --json=pretty|short|off\n                         Generate JSON output\n\nSee the hostnamectl(1) man page for details.\n```\n\nI learned there's transient and static hostnames, so that's cool...\n\nThe thing I needed was `hostnamectl --static hostname babyblue-aurora`\n\npretty sweet tool\n",
      "summary": "hostnamectl is apparently a linux utility for easily changing your hostname in a variety of ways",
      "date_published": "2024-12-06T07:25:59Z",
      "date_modified": "2024-12-06T07:25:59Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "linux",
        "terminal",
        "homelab",
        "cli",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/dns-broke-after-reboot-ubuntu-22-04/",
      "url": "https://pype.dev/dns-broke-after-reboot-ubuntu-22-04/",
      "title": "DNS Broke After Reboot - Ubuntu 22.04",
      "content_html": "\u003cp\u003eI rebooted by server and DNS broke randomly. I have no idea if it was from a kernel update or what but that\u0026rsquo;s the issue with Ubuntu I guess\u0026hellip;\u003c/p\u003e\n\u003cp\u003eAfter much toil and none of the other options working for me (sorry to not have those documented here) this is what got me the vic from this \u003ca href=\"https://askubuntu.com/questions/1406827/how-to-set-dns-on-ubuntu-22-04-when-you-have-no-netplan-config\"\u003eSO Post\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003esudo mkdir /etc/systemd/resolved.conf.d/\nsudo $EDITOR /etc/systemd/resolved.conf.d/dns_servers.conf\u003c/p\u003e\n\u003cp\u003eMost folks probably are good with google (8.8.8.8) and cloudflare (1.1.1.1)\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e[Resolve]\nDNS=8.8.8.8 1.1.1.1\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eBut I decided to use tailscale\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e[Resolve]\nDNS=100.100.100.100\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThen restart systemd-resolved\u003c/p\u003e\n\u003cp\u003esudo systemctl restart systemd-resolved\u003c/p\u003e\n",
      "content_text": "\nI rebooted by server and DNS broke randomly. I have no idea if it was from a kernel update or what but that's the issue with Ubuntu I guess...\n\nAfter much toil and none of the other options working for me (sorry to not have those documented here) this is what got me the vic from this [SO Post](https://askubuntu.com/questions/1406827/how-to-set-dns-on-ubuntu-22-04-when-you-have-no-netplan-config)\n\nsudo mkdir /etc/systemd/resolved.conf.d/\nsudo $EDITOR /etc/systemd/resolved.conf.d/dns_servers.conf\n\nMost folks probably are good with google (8.8.8.8) and cloudflare (1.1.1.1)\n\n```\n[Resolve]\nDNS=8.8.8.8 1.1.1.1\n```\n\nBut I decided to use tailscale\n\n```\n[Resolve]\nDNS=100.100.100.100\n```\n\nThen restart systemd-resolved\n\nsudo systemctl restart systemd-resolved\n",
      "summary": "I rebooted by server and DNS broke randomly. I have no idea if it was from a kernel update or what but that's the issue with Ubuntu I guess...",
      "date_published": "2024-11-22T08:08:40Z",
      "date_modified": "2024-11-22T08:08:40Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/opnsense-bootstrap-recovery/",
      "url": "https://pype.dev/opnsense-bootstrap-recovery/",
      "title": "OPNSense Bootstrap Recovery",
      "content_html": "\u003cp\u003eenabling DHCP WAN port (\u003ccode\u003edhclient \u0026lt;iface\u0026gt;\u003c/code\u003e)- running the bootstrap script - \u003ccode\u003esh /usr/local/sbin/opnsense-bootstrap\u003c/code\u003e\u003c/p\u003e\n",
      "content_text": "\n\nenabling DHCP WAN port (`dhclient \u003ciface\u003e`)- running the bootstrap script - `sh /usr/local/sbin/opnsense-bootstrap`\n\n",
      "summary": "enabling DHCP WAN port ()- running the bootstrap script -",
      "date_published": "2024-11-07T08:40:19Z",
      "date_modified": "2024-11-07T08:40:19Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "infrastructure",
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/recovering-opnsense/",
      "url": "https://pype.dev/recovering-opnsense/",
      "title": "Recovering OPNSense",
      "content_html": "\u003cp\u003eI woke up to faulty internet and after some troubleshooting it turns out the\nroot zfs dataset that OPNSense boots from got corrupted\u0026hellip;\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003ePRO-TIP - Auto backup your OPNSense config to Google Drive, git, or\nnextcloud\u0026hellip; But if you won\u0026rsquo;t then at least back up your OPNSense config\nsomewhere everytime you update it.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eIt\u0026rsquo;s too much to recount every issue, so here\u0026rsquo;s a bullet list what worked.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eOn a fresh drive install OPNSense\u003c/li\u003e\n\u003cli\u003ePlug in the old drive through a USB enclosure - now I\u0026rsquo;m not sure what would\nhappen if you plugged it in along with the new drive and then booted up.\nBecause both drives will have a zfs pool \u003ccode\u003ezroot\u003c/code\u003e and the boot dataset is\nautomounted at \u003ccode\u003e/zroot/ROOT/default\u003c/code\u003e. My old \u003ccode\u003ezroot\u003c/code\u003e pool was \u003ccode\u003eSUSPENDED\u003c/code\u003e so it\ndidn\u0026rsquo;t automount\u003c/li\u003e\n\u003cli\u003eBecause the old \u003ccode\u003ezoot/ROOT/default\u003c/code\u003e was corrupted I did this to mount it RO:\n\u003ccode\u003ezpool import -d \u0026lt;path to zfs partition - /dev/stuff\u0026gt; -N zroot zrootrecovery\u003c/code\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003cp\u003e-d is the zfs flag to import the pool by disk id, -N it to not mount any of\nthe datasets (we need to change mountpoints) and the \u003ccode\u003ezroot zrootrecovery\u003c/code\u003e\nimports the \u003ccode\u003ezroot\u003c/code\u003e pool with a new name\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003col start=\"4\"\u003e\n\u003cli\u003eChange the mountpoints for all the \u003ccode\u003ezrootrecovery\u003c/code\u003e datasets to somewhere\nlike \u003ccode\u003e/mnt/zrootrecovery\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eDepending on the mount point you set you\u0026rsquo;ll find a \u003ccode\u003econfig\u003c/code\u003e directory around\n\u003ccode\u003e/mnt/zrootrecovery/ROOT/default/config\u003c/code\u003e - copy the file you want to another\nmachine via scp or whatever\u003c/li\u003e\n\u003cli\u003eGo to OPNSense webui and recover from that config!\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eAll in all this process took me around 8 hours but I did run into about ever\nissue under the sun (several bad disks in the mix, a laptop that wouldn\u0026rsquo;t live\nboot into a BSD system, etc.)\u003c/p\u003e\n",
      "content_text": "\nI woke up to faulty internet and after some troubleshooting it turns out the\nroot zfs dataset that OPNSense boots from got corrupted...\n\n\u003e PRO-TIP - Auto backup your OPNSense config to Google Drive, git, or\n\u003e nextcloud... But if you won't then at least back up your OPNSense config\n\u003e somewhere everytime you update it.\n\n\nIt's too much to recount every issue, so here's a bullet list what worked.\n\n\n1. On a fresh drive install OPNSense\n2. Plug in the old drive through a USB enclosure - now I'm not sure what would\nhappen if you plugged it in along with the new drive and then booted up.\nBecause both drives will have a zfs pool `zroot` and the boot dataset is\nautomounted at `/zroot/ROOT/default`. My old `zroot` pool was `SUSPENDED` so it\ndidn't automount\n3. Because the old `zoot/ROOT/default` was corrupted I did this to mount it RO:\n`zpool import -d \u003cpath to zfs partition - /dev/stuff\u003e -N zroot zrootrecovery`\n\n\u003e -d is the zfs flag to import the pool by disk id, -N it to not mount any of\n\u003e the datasets (we need to change mountpoints) and the `zroot zrootrecovery`\n\u003e imports the `zroot` pool with a new name\n\n4. Change the mountpoints for all the `zrootrecovery` datasets to somewhere\nlike `/mnt/zrootrecovery`\n5. Depending on the mount point you set you'll find a `config` directory around\n`/mnt/zrootrecovery/ROOT/default/config` - copy the file you want to another\nmachine via scp or whatever\n6. Go to OPNSense webui and recover from that config!\n\nAll in all this process took me around 8 hours but I did run into about ever\nissue under the sun (several bad disks in the mix, a laptop that wouldn't live\nboot into a BSD system, etc.)\n",
      "summary": "I woke up to faulty internet and after some troubleshooting it turns out the root zfs dataset that OPNSense boots from got corrupted...",
      "date_published": "2024-11-06T00:00:00Z",
      "date_modified": "2024-11-06T00:00:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "blog",
        "homelab"
      ]
    },
    {
      "id": "https://pype.dev/docker-remote-add/",
      "url": "https://pype.dev/docker-remote-add/",
      "title": "docker-remote-add",
      "content_html": "\u003cp\u003eAdd from url??\u003c/p\u003e\n\u003cp\u003eADD \u003ca href=\"http://example.com/cars.csv\"\u003ehttp://example.com/cars.csv\u003c/a\u003e /tmp/cars.csv\u003c/p\u003e\n\u003cp\u003eUnpack automatically!? (.tar, .tar.gz, .tgz, .bz2, .tbz2, .txz, .zip)\u003c/p\u003e\n\u003cp\u003eADD myapp.tar.gz /opt/myapp/\u003c/p\u003e\n",
      "content_text": "\nAdd from url??\n\nADD http://example.com/cars.csv /tmp/cars.csv\n\nUnpack automatically!? (.tar, .tar.gz, .tgz, .bz2, .tbz2, .txz, .zip)\n\nADD myapp.tar.gz /opt/myapp/\n",
      "summary": "Add from url??",
      "date_published": "2024-09-17T06:19:00Z",
      "date_modified": "2024-09-17T06:19:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/docker-copy-and-chown/",
      "url": "https://pype.dev/docker-copy-and-chown/",
      "title": "Docker copy and chown",
      "content_html": "\u003cp\u003eCOPY \u0026ndash;chown=myuser:mygroup source-file target-file\u003c/p\u003e\n",
      "content_text": "\nCOPY --chown=myuser:mygroup source-file target-file\n",
      "summary": "COPY --chown=myuser:mygroup source-file target-file",
      "date_published": "2024-09-17T06:18:09Z",
      "date_modified": "2024-09-17T06:18:09Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "linux",
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/interesting-ips-between-jellyfin-clients-and-server-depending-on-tailscale-and-server-address/",
      "url": "https://pype.dev/interesting-ips-between-jellyfin-clients-and-server-depending-on-tailscale-and-server-address/",
      "title": "Interesting IPs between Jellyfin clients and server depending on tailscale and server address",
      "content_html": "\u003cp\u003eWhen connecting from my phone to jellyfin I\u0026rsquo;m seeing some interesting patterns.\u003c/p\u003e\n\u003ch2 id=\"scenarios\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eScenarios\u003c/span\u003e \u003ca href=\"#scenarios\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003ch3 id=\"tailscale-ip-of-phone-is-listed-as-local-network-to-jellyfin\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eTailscale IP of phone is listed as local network to jellyfin\u003c/span\u003e \u003ca href=\"#tailscale-ip-of-phone-is-listed-as-local-network-to-jellyfin\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eWifi: off\nTailscale: on\nUse exit node: on\nLAN access: on\nJellyfin: LAN IP\u003c/p\u003e\n\u003cp\u003eJellyfin sees 192.168.1.1, my router address\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eWifi: off\ntailscale: on\nUse exit node: on\nLAN access: on\nJellyfin: Tailscale magic DNS\u003c/p\u003e\n\u003cp\u003eJellyfin sees the docker bridge network\u003c/p\u003e\n\u003cp\u003eQ: This might be because of traefik somehow\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eWifi: off\ntailsacale: on\nUse exit node: on\nLAN access: off\nJellyfin: LAN IP\u003c/p\u003e\n\u003cp\u003eJellyfin sees the 192.168.1.1\u003c/p\u003e\n\u003cp\u003eQ: Why did this work even work?\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eWifi: off\ntailsacale: on\nUse exit node: on\nLAN access: off\nJellyfin: Tailscale magic DNS\u003c/p\u003e\n\u003cp\u003eJellyfin sees the docker bridge network\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eWifi: off\ntailsacale: on\nUse exit node: off\nLAN access: off\nJellyfin: LAN IP\u003c/p\u003e\n\u003cp\u003eJellyfin sees the 192.168.1.1\u003c/p\u003e\n\u003cp\u003eQ: Why did this work?\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eWifi: off\ntailsacale: on\nUse exit node: off\nLAN access: off\nJellyfin: Tailscale magic DNS\u003c/p\u003e\n\u003cp\u003eJellyfin sees the docker bridge network\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eWifi: on\ntailsacale: of\nUse exit node: off\nLAN access: off\nJellyfin: LAN IP (via pihole DNS)\u003c/p\u003e\n\u003cp\u003eJellyfin sees the IP of my phone\u003c/p\u003e\n\u003chr\u003e\n",
      "content_text": "\nWhen connecting from my phone to jellyfin I'm seeing some interesting patterns.\n\n## Scenarios\n\n### Tailscale IP of phone is listed as local network to jellyfin\n\nWifi: off\nTailscale: on\nUse exit node: on\nLAN access: on\nJellyfin: LAN IP\n\nJellyfin sees 192.168.1.1, my router address\n\n***\n\nWifi: off\ntailscale: on\nUse exit node: on \nLAN access: on\nJellyfin: Tailscale magic DNS\n\nJellyfin sees the docker bridge network\n\nQ: This might be because of traefik somehow\n\n***\n\nWifi: off\ntailsacale: on\nUse exit node: on\nLAN access: off\nJellyfin: LAN IP\n\nJellyfin sees the 192.168.1.1\n\nQ: Why did this work even work?\n\n***\n\nWifi: off\ntailsacale: on\nUse exit node: on\nLAN access: off\nJellyfin: Tailscale magic DNS\n\nJellyfin sees the docker bridge network\n\n***\n\nWifi: off\ntailsacale: on\nUse exit node: off\nLAN access: off\nJellyfin: LAN IP\n\nJellyfin sees the 192.168.1.1\n\nQ: Why did this work?\n\n***\n\nWifi: off\ntailsacale: on\nUse exit node: off\nLAN access: off\nJellyfin: Tailscale magic DNS\n\nJellyfin sees the docker bridge network\n\n***\n\nWifi: on\ntailsacale: of\nUse exit node: off\nLAN access: off\nJellyfin: LAN IP (via pihole DNS)\n\nJellyfin sees the IP of my phone\n\n***\n",
      "summary": "When connecting from my phone to jellyfin I'm seeing some interesting patterns.",
      "date_published": "2024-07-12T06:24:57Z",
      "date_modified": "2024-07-12T06:24:57Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/upgrading-your-kernel-can-f-you-up-whoops/",
      "url": "https://pype.dev/upgrading-your-kernel-can-f-you-up-whoops/",
      "title": "Upgrading your kernel can F you up… whoops",
      "content_html": "\u003cp\u003e\u003ca href=\"https://forum.proxmox.com/threads/update-error-with-coral-tpu-drivers.136888/#post-608975\"\u003ehttps://forum.proxmox.com/threads/update-error-with-coral-tpu-drivers.136888/#post-608975\u003c/a\u003e I lost TPU for frigate, this saved me ass\u003c/p\u003e\n",
      "content_text": "\nhttps://forum.proxmox.com/threads/update-error-with-coral-tpu-drivers.136888/#post-608975 I lost TPU for frigate, this saved me ass\n",
      "summary": "https://forum.proxmox.com/threads/update-error-with-coral-tpu-drivers.136888/#post-608975 I lost TPU for frigate, this saved me ass",
      "date_published": "2024-06-26T10:21:59Z",
      "date_modified": "2024-06-26T10:21:59Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/customize-k9s/",
      "url": "https://pype.dev/customize-k9s/",
      "title": "Customize K9s",
      "content_html": "\u003cp\u003eTo customize k9s use the skins from catppuccin or the ones k9s supplies\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eOUT\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nv\"\u003eXDG_CONFIG_HOME\u003c/span\u003e\u003cspan class=\"k\"\u003e:-\u003c/span\u003e\u003cspan class=\"nv\"\u003e$HOME\u003c/span\u003e\u003cspan class=\"p\"\u003e/.config\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e/k9s/skins\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emkdir -p \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$OUT\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecurl -L https://github.com/catppuccin/k9s/archive/main.tar.gz \u003cspan class=\"p\"\u003e|\u003c/span\u003e tar xz -C \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$OUT\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e --strip-components\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e k9s-main/dist\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThen edit your k9s config\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e# ~/.config/k9s/config.yml\nk9s:\n  ui:\n    skin: catppuccin-mocha\n    # ...or another flavor:\n    # skin: catppuccin-macchiato\n    # skin: catppuccin-frappe\n    # skin: catppuccin-latte\n\n    # ...or the transparent variants:\n    # skin: catppuccin-mocha-transparent\n    # skin: catppuccin-macchiato-transparent\n    # skin: catppuccin-frappe-transparent\n    # skin: catppuccin-latte-transparent\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eOther k9s skins are available \u003ca href=\"https://github.com/derailed/k9s/tree/master/skins\"\u003ehere\u003c/a\u003e\u003c/p\u003e\n",
      "content_text": "\nTo customize k9s use the skins from catppuccin or the ones k9s supplies\n\n```bash\nOUT=\"${XDG_CONFIG_HOME:-$HOME/.config}/k9s/skins\"\nmkdir -p \"$OUT\"\ncurl -L https://github.com/catppuccin/k9s/archive/main.tar.gz | tar xz -C \"$OUT\" --strip-components=2 k9s-main/dist\n```\n\nThen edit your k9s config\n\n```\n# ~/.config/k9s/config.yml\nk9s:\n  ui:\n    skin: catppuccin-mocha\n    # ...or another flavor:\n    # skin: catppuccin-macchiato\n    # skin: catppuccin-frappe\n    # skin: catppuccin-latte\n\n    # ...or the transparent variants:\n    # skin: catppuccin-mocha-transparent\n    # skin: catppuccin-macchiato-transparent\n    # skin: catppuccin-frappe-transparent\n    # skin: catppuccin-latte-transparent\n```\n\nOther k9s skins are available [here](https://github.com/derailed/k9s/tree/master/skins)\n",
      "summary": "To customize k9s use the skins from catppuccin or the ones k9s supplies",
      "date_published": "2024-05-06T11:57:07Z",
      "date_modified": "2024-05-06T11:57:07Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "cli",
        "homelab",
        "tech",
        "k8s",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/kanboard-to-keep-me-focused-on-my-own-ideas/",
      "url": "https://pype.dev/kanboard-to-keep-me-focused-on-my-own-ideas/",
      "title": "Kanboard to keep me focused on my own ideas",
      "content_html": "\u003ch2 id=\"tl-dr\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eTL;DR\u003c/span\u003e \u003ca href=\"#tl-dr\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI\u0026rsquo;ve been using kanboard as a self-hosted kanban board. It\u0026rsquo;s keeping me focused on \u003ca href=\"https://myditialharbor.com\"\u003eDigital Harbor\u003c/a\u003e when I\u0026rsquo;d rather be doing something less productive.\u003c/p\u003e\n\u003ch2 id=\"my-todos\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eMy TODOs\u003c/span\u003e \u003ca href=\"#my-todos\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHere\u0026rsquo;s the thing about my TODOs\u0026hellip; they\u0026rsquo;re everywhere. I\u0026rsquo;ve tried a crazy amount of different organizational tactics for my todo items. I\u0026rsquo;ve tried post-it notes, a journal, \u003ccode\u003eTODO.md\u003c/code\u003e in specific repos, a master \u003ccode\u003etodo\u003c/code\u003e repo, todo CLIs, etc\u0026hellip;\u003c/p\u003e\n\u003cp\u003eThe problem for me was consistency\u0026hellip; I would regularly forget what I was using for TODOs at that moment in my life\u0026hellip; was there a todo file in this project? Do I have a todo repo cloned on this computer? Is this stuff in my journal or on post-it notes?\u003c/p\u003e\n\u003cp\u003eAnd what do I do with new ideas? Do I organize them centrally or use a repo for the idea I have?\u003c/p\u003e\n\u003cp\u003eIt was getting out of hand to a debilitating degree\u0026hellip; For a while I just gave up on being organized at all\u0026hellip; Things would get done as necessary and if I got some motivation to work on something it was immediately smothered with the anxiety of how I was going to organize my work\u0026hellip;\u003c/p\u003e\n\u003cp\u003eAt some point it became too much\u0026hellip; Now, I have some experience with Azure DevOps/Jira for project management and then I came across Kanboard\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"kanboard\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eKanboard\u003c/span\u003e \u003ca href=\"#kanboard\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://kanboard.org/\"\u003eKanboard\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eKanboard is just a self-hosted kanban style todo app. I know there\u0026rsquo;s a ton of these so the TL;DR of my lesson is I picked an app that I would just use based on simplicity of managing and hosting.\u003c/p\u003e\n\u003cp\u003eI have had kanboard running in my homelab for a long time, but I only barely use it intermittenly. And at that rate I didn\u0026rsquo;t spend any real time organizing my tickets, so I wasn\u0026rsquo;t akshuallly using it - it was just a post-it note replacement.\u003c/p\u003e\n\u003cp\u003eBut then I had an idea for a genuine business idea, and if I was going to ever have a hope of making it a reality, I needed to stay organized. This was when I decided to give kanboard a little more effort\u0026hellip; I knew I could always remember that I\u0026rsquo;d chosen an app as my TODO solution (given all the time I spent questioning what I was using at any given point in time). I also knew I could host kanboard so that I could get to it from wherever was necessary because my homelab is relatively easy to add another public service to.\u003c/p\u003e\n\u003cp\u003eSo once I just decided to lean into this thing, I would take advantage of any moments of motivation and just jot down ideas for things that had to get done\u0026hellip; Simple stuff like explore an infra management option, add one feature to a config, or migrate one website to another stack\u0026hellip; And I would just write these things downs until I have enough time free to crack down on a task. The beautiful thing is, when I am struck with just enough time to do something, and the motivation to do something, I don\u0026rsquo;t waste any time deciding what to do - past-me did present-me a favor and decided what was important already\u0026hellip; So as long as I do myself the favor, when I\u0026rsquo;m ready to go I am never beaten by the anxiety of not knowing what I ant to do or how I\u0026rsquo;ll track what I\u0026rsquo;m doing\u0026hellip; I chose kanboard and even though it\u0026rsquo;s not as fast as a terminal TUI,  it is reliable, simple, and keeps me focused on what I need to do.\u003c/p\u003e\n\u003ch2 id=\"the-biggest-benefit\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eThe biggest benefit\u003c/span\u003e \u003ca href=\"#the-biggest-benefit\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eNot only is just having one app as the solution nice because it\u0026rsquo;s centrally managed and accessible from wherever I need to get it, but the TOP feature of kanboard I use is comments on tickets\u0026hellip; I get to continue to do future-me favors, my jotting down where I\u0026rsquo;m at in a task, what\u0026rsquo;s left to do, what I\u0026rsquo;m trying, etc\u0026hellip; and future-me is in a great mood, because when I have that free few minutes, I can just read my own past thoughts and get back up to speed without wasting time trying to remember things I never would\u0026rsquo;ve remembered if I hadn\u0026rsquo;t written them down!\u003c/p\u003e\n",
      "content_text": "\n## TL;DR\n\nI've been using kanboard as a self-hosted kanban board. It's keeping me focused on [Digital Harbor](https://myditialharbor.com) when I'd rather be doing something less productive.\n\n## My TODOs\n\nHere's the thing about my TODOs... they're everywhere. I've tried a crazy amount of different organizational tactics for my todo items. I've tried post-it notes, a journal, `TODO.md` in specific repos, a master `todo` repo, todo CLIs, etc... \n\nThe problem for me was consistency... I would regularly forget what I was using for TODOs at that moment in my life... was there a todo file in this project? Do I have a todo repo cloned on this computer? Is this stuff in my journal or on post-it notes?\n\nAnd what do I do with new ideas? Do I organize them centrally or use a repo for the idea I have?\n\nIt was getting out of hand to a debilitating degree... For a while I just gave up on being organized at all... Things would get done as necessary and if I got some motivation to work on something it was immediately smothered with the anxiety of how I was going to organize my work...\n\nAt some point it became too much... Now, I have some experience with Azure DevOps/Jira for project management and then I came across Kanboard...\n\n## Kanboard\n\n[Kanboard]( https://kanboard.org/ )\n\nKanboard is just a self-hosted kanban style todo app. I know there's a ton of these so the TL;DR of my lesson is I picked an app that I would just use based on simplicity of managing and hosting.\n\nI have had kanboard running in my homelab for a long time, but I only barely use it intermittenly. And at that rate I didn't spend any real time organizing my tickets, so I wasn't akshuallly using it - it was just a post-it note replacement. \n\nBut then I had an idea for a genuine business idea, and if I was going to ever have a hope of making it a reality, I needed to stay organized. This was when I decided to give kanboard a little more effort... I knew I could always remember that I'd chosen an app as my TODO solution (given all the time I spent questioning what I was using at any given point in time). I also knew I could host kanboard so that I could get to it from wherever was necessary because my homelab is relatively easy to add another public service to.\n\nSo once I just decided to lean into this thing, I would take advantage of any moments of motivation and just jot down ideas for things that had to get done... Simple stuff like explore an infra management option, add one feature to a config, or migrate one website to another stack... And I would just write these things downs until I have enough time free to crack down on a task. The beautiful thing is, when I am struck with just enough time to do something, and the motivation to do something, I don't waste any time deciding what to do - past-me did present-me a favor and decided what was important already... So as long as I do myself the favor, when I'm ready to go I am never beaten by the anxiety of not knowing what I ant to do or how I'll track what I'm doing... I chose kanboard and even though it's not as fast as a terminal TUI,  it is reliable, simple, and keeps me focused on what I need to do.\n\n## The biggest benefit\n\nNot only is just having one app as the solution nice because it's centrally managed and accessible from wherever I need to get it, but the TOP feature of kanboard I use is comments on tickets... I get to continue to do future-me favors, my jotting down where I'm at in a task, what's left to do, what I'm trying, etc... and future-me is in a great mood, because when I have that free few minutes, I can just read my own past thoughts and get back up to speed without wasting time trying to remember things I never would've remembered if I hadn't written them down!\n",
      "summary": "I've been using kanboard as a self-hosted kanban board. It's keeping me focused on Digital Harbor when I'd rather be doing something less productive.",
      "date_published": "2024-04-20T18:27:07Z",
      "date_modified": "2024-04-20T18:27:07Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/dhcp-restart-to-save-ubuntu-22-04-server-networking/",
      "url": "https://pype.dev/dhcp-restart-to-save-ubuntu-22-04-server-networking/",
      "title": "DHCP Restart to Save Ubuntu 22.04 Server Networking",
      "content_html": "\u003cp\u003eI moved a computer to a remote location for an off-site backup but when it was powered on it wouldn\u0026rsquo;t show up on any networks. A solution that got me back in was a friend restarting the dhcp client for me:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo dhclient -r -v \u0026lt;interface\u0026gt; \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e sudo dhclient -v \u0026lt;interface\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e",
      "content_text": "\nI moved a computer to a remote location for an off-site backup but when it was powered on it wouldn't show up on any networks. A solution that got me back in was a friend restarting the dhcp client for me:\n\n```bash\nsudo dhclient -r -v \u003cinterface\u003e \u0026\u0026 sudo dhclient -v \u003cinterface\u003e\n```\n",
      "summary": "I moved a computer to a remote location for an off-site backup but when it was powered on it wouldn't show up on any networks. A solution that got me back in...",
      "date_published": "2023-12-31T20:26:50Z",
      "date_modified": "2023-12-31T20:26:50Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/simple-port-forwarding-opnsense/",
      "url": "https://pype.dev/simple-port-forwarding-opnsense/",
      "title": "Simple Port Forwarding OPNSense",
      "content_html": "\u003cp\u003e\u003ca href=\"https://forum.opnsense.org/index.php?topic=8783.0\"\u003ehttps://forum.opnsense.org/index.php?topic=8783.0\u003c/a\u003e\u003c/p\u003e\n",
      "content_text": "\nhttps://forum.opnsense.org/index.php?topic=8783.0\n",
      "summary": "https://forum.opnsense.org/index.php?topic=8783.0",
      "date_published": "2023-10-17T10:26:34Z",
      "date_modified": "2023-10-17T10:26:34Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/refresh-nextcloud-groupfolders-after-messing-around-on-the-filesystem/",
      "url": "https://pype.dev/refresh-nextcloud-groupfolders-after-messing-around-on-the-filesystem/",
      "title": "Refresh Nextcloud Groupfolders after messing around on the filesystem",
      "content_html": "\u003cp\u003eExec in as www-data and run ./occ groupfolders:scan folder_id -v (the -v to see what it\u0026rsquo;s doing)\u003c/p\u003e\n",
      "content_text": "\nExec in as www-data and run ./occ groupfolders:scan folder_id -v (the -v to see what it's doing)\n",
      "summary": "Exec in as www-data and run ./occ groupfolders:scan folder_id -v (the -v to see what it's doing)",
      "date_published": "2023-09-23T12:45:06Z",
      "date_modified": "2023-09-23T12:45:06Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/lsof-to-find-what-s-using-your-filesystem/",
      "url": "https://pype.dev/lsof-to-find-what-s-using-your-filesystem/",
      "title": "lsof to find what’s using your filesystem",
      "content_html": "\u003cp\u003elsof | grep /tank/nas shows me what is using my nas at any time!\u003c/p\u003e\n",
      "content_text": "\nlsof | grep /tank/nas shows me what is using my nas at any time!\n",
      "summary": "lsof | grep /tank/nas shows me what is using my nas at any time!",
      "date_published": "2023-04-09T13:32:38Z",
      "date_modified": "2023-04-09T13:32:38Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "zfs",
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/changing-zfs-key-for-child-datasets-of-encrypted-dataset-after-migration/",
      "url": "https://pype.dev/changing-zfs-key-for-child-datasets-of-encrypted-dataset-after-migration/",
      "title": "Changing ZFS key for child datasets of encrypted dataset after migration",
      "content_html": "\u003cp\u003e➜ pihole sudo zfs load-key -L file:///path/to/.zfs.tank.key tank/encrypted/vms/arch-sandbox\n➜ pihole sudo zfs change-key -o keylocation=file:///path/to/.zfs.tank.key -o keyformat=raw tank/encrypted/vms/arch-sandbox\nNeed to load-key for each individual dataset, then change key location to be a file instead of the prompt\u003c/p\u003e\n",
      "content_text": "\n➜ pihole sudo zfs load-key -L file:///path/to/.zfs.tank.key tank/encrypted/vms/arch-sandbox\n➜ pihole sudo zfs change-key -o keylocation=file:///path/to/.zfs.tank.key -o keyformat=raw tank/encrypted/vms/arch-sandbox\nNeed to load-key for each individual dataset, then change key location to be a file instead of the prompt\n",
      "summary": "➜ pihole sudo zfs load-key -L file:///path/to/.zfs.tank.key tank/encrypted/vms/arch-sandbox ➜ pihole sudo zfs change-key -o...",
      "date_published": "2023-04-08T20:12:22Z",
      "date_modified": "2023-04-08T20:12:22Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "zfs",
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/stable-diffusion-notes/",
      "url": "https://pype.dev/stable-diffusion-notes/",
      "title": "Stable Diffusion Notes",
      "content_html": "\u003ch2 id=\"chatgpt-prompt\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eChatGPT Prompt:\u003c/span\u003e \u003ca href=\"#chatgpt-prompt\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eStable Diffusion is an AI art generation model similar to DALLE-2.\nHere are some prompts for generating art with Stable Diffusion.\u003c/p\u003e\n\u003cp\u003eExample:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eA ghostly apparition drifting through a haunted mansion\u0026rsquo;s grand ballroom, illuminated by flickering candlelight. Eerie, ethereal, moody lighting.\u003c/li\u003e\n\u003cli\u003eportait of a homer simpson archer shooting arrow at forest monster, front game card, drark, marvel comics, dark, smooth\u003c/li\u003e\n\u003cli\u003epirate, deep focus, fantasy, matte, sharp focus\u003c/li\u003e\n\u003cli\u003ered dead redemption 2, cinematic view, epic sky, detailed, low angle, high detail, warm lighting, volumetric, godrays, vivid, beautiful\u003c/li\u003e\n\u003cli\u003ea fantasy style portrait painting of rachel lane / alison brie hybrid in the style of francois boucher oil painting, rpg portrait\u003c/li\u003e\n\u003cli\u003eathena, greek goddess, claudia black, bronze greek armor, owl crown, d \u0026amp; d, fantasy, portrait, headshot, sharp focus\u003c/li\u003e\n\u003cli\u003ecloseup portrait shot of a large strong female biomechanic woman in a scenic scifi environment, elegant, smooth, sharp focus, warframe\u003c/li\u003e\n\u003cli\u003eultra realistic illustration of steve urkle as the hulk, elegant, smooth, sharp focus\u003c/li\u003e\n\u003cli\u003eportrait of beautiful happy young ana de armas, ethereal, realistic anime, clean lines, sharp lines, crisp lines, vibrant color scheme\u003c/li\u003e\n\u003cli\u003eA highly detailed and hyper realistic portrait of a gorgeous young ana de armas, lisa frank, butterflies, floral, sharp focus\u003c/li\u003e\n\u003cli\u003elots of delicious tropical fruits with drops of moisture on table, floating colorful water, mysterious expression, in a modern and abstract setting, with bold and colorful abstract art, blurred background, bright lighting\u003c/li\u003e\n\u003cli\u003e1girl, The most beautiful form of chaos, Fauvist design, Flowing colors, Vivid colors, dynamic angle, fantasy world\u003c/li\u003e\n\u003cli\u003esolo, sitting, close-up, girl in the hourglass, Sand is spilling out of the broken hourglass, flowing sand, huge hourglass art, hologram, particles, nebula, magic circle\u003c/li\u003e\n\u003cli\u003egeometric abstract background, 1girl, depth of field, zentangle, mandala, tangle, entangle, beautiful and aesthetic, dynamic angle, glowing skin, floating colorful sparkles the most beautiful form of chaos, elegant, a brutalist designed, vivid colours, romanticism\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe prompt should adhere to and include all of the following rules:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePrompt should always be written in English, regardless of the input language. Please provide the prompts in English.\u003c/li\u003e\n\u003cli\u003eEach prompt should consist of a description of the scene followed by modifiers divided by commas.\u003c/li\u003e\n\u003cli\u003eWhen generating descriptions, focus on portraying the visual elements rather than delving into abstract psychological and emotional aspects. Provide clear and concise details that vividly depict the scene and its composition, capturing the tangible elements that make up the setting.\u003c/li\u003e\n\u003cli\u003eThe modifiers should alter the mood, style, lighting, and other aspects of the scene.\u003c/li\u003e\n\u003cli\u003eMultiple modifiers can be used to provide more specific details.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eI want you to write me a list of detailed prompts exactly about the IDEA follow the rule at least 6 every time.\u003c/p\u003e\n\u003cp\u003eReady for my idea?\u003c/p\u003e\n\u003ch2 id=\"chatgpt-prompt-for-rpg-v4\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eChatGPT Prompt for RPG V4:\u003c/span\u003e \u003ca href=\"#chatgpt-prompt-for-rpg-v4\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eStable Diffusion is an AI art generation model similar to DALLE-2.\nHere are some pairs of positive and negative prompts for generating art with Stable Diffusion.\u003c/p\u003e\n\u003cp\u003eExample:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003ePositive: A (full body:1.3) shot at 8k resolution, splash art, fantastic comic book style, photorealistic, intense look, anatomical photorealistic digital painting portrait of a (old male:1.3) human (warrior:1.3) in black and gold intricate (heavy armor:1.3) in a (dark and moody universe:1.3), light particle, very detailed skin,samurai, very detailed eyes, (elden ring style:1.3), (warhammer style:1.1), concept artist, global illumination, depth of field, splash art, art by artgerm and greg rutkowski and viktoria gavrilenko\nNegative: (symmetry:1.2), facial marking, crown, horn, (helmet:1.3), (hoodie:1.1), clock, Female, visible hand, asian, two face, big hair, open mouth, cartoon, high contrast, poorly drawn, Scribbles, Low quality, Low rated, Mediocre, Screenshot, Software, UI, watermark, text, overlay, getty images, cropped, low quality\u003c/p\u003e\n\u003col start=\"2\"\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003ePositive: close-up head, facing camera, beautiful satanic female necromancer blood queen, ritualistic (neck tattoo:1.3), (insanely detailed:1.5), ((solo)), (highest quality, Alessandro Casagrande, Greg Rutkowski, Sally Mann, concept art, 4k), (colourful), (high sharpness), ((detailed pupils)), ((painting:1.1)), (digital painting:1.1), detailed face and eyes,Masterpiece, best quality, highly detailed photo:1, 8k, detailed face,photorealistic, (black long Hair:1.1),(young woman),By jeremy mann, by sandra chevrier, by maciej kuciara, smoke and shadow, night, sharp, ((perfect body)), realistic, real shadow, 3d, ((full body)), ((dark and gloomy universe)), (by Michelangelo)\nNegative: crown, (facial marking:1.2), cloth gem, jewel, jewelry, (flower:1.3), (cloak:1.1), (bad art, low detail, pencil drawing, old, mature:1.6), (grainy, low quality, mutated hands and fingers:1.5), (watermark, thin lines:1.3), (deformed, signature:1.2), (big nipples, blurry, ugly, bad anatomy, extra limbs, undersaturated, low resolution), disfigured, deformations, out of frame, amputee, bad proportions, extra limb, missing limbs, distortion, floating limbs, out of frame, poorly drawn face, poorly drawn hands, text, malformed, error, missing fingers, cropped, jpeg artifacts, teeth, unsharp\u003c/p\u003e\n\u003col start=\"3\"\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003ePositive: (Painting:1.3) of (Detailed illustration:1.3) A (full body:1.3) shot at 8k resolution, splash art, fantastic comic book style, photorealistic, intense look, anatomical photorealistic digital painting portrait of a (old male:1.3) human (warrior:1.3) in black and gold intricate (heavy armor:1.3) in a (dark and moody universe:1.3), light particle, very detailed skin,samurai, very detailed eyes, (elden ring style:1.3), (warhammer style:1.1), concept artist, global illumination, depth of field, splash art, art by artgerm and greg rutkowski and viktoria gavrilenko\nNegative:  (symmetry:1.2), facial marking, crown, (horn:1.1), (helmet:1.3), (hoodie:1.1), clock, Female, visible hand, asian, two face, big hair, open mouth, cartoon, high contrast, poorly drawn, Scribbles, Low quality, Low rated, Mediocre, Screenshot, Software, UI, watermark, text, overlay, getty images, cropped, low qualityLow quality,Bad composition,Faded,(Photo:1.5),(Frame:1.3),watermark,signa ture\u003c/p\u003e\n\u003col start=\"4\"\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003ePositive: sci-fi, space rogue thief girl, (smirk:1.1), short hair, black hood, light armor, big grey eyes, beautiful detailed eyes, drawn by Greg Rutkowski, Yoji Shinkawa:0.6\nNegative: open mouth, facial marking, flower, bad-hands-5, lipstick, text, watermark\u003c/p\u003e\n\u003cp\u003eThe prompt should adhere to and include all of the following rules:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEach prompt should consist of a description of the scene followed by modifiers divided by commas.\u003c/li\u003e\n\u003cli\u003eWhen generating descriptions, focus on portraying the visual elements rather than delving into abstract psychological and emotional aspects. Provide clear and concise details that vividly depict the scene and its composition, capturing the tangible elements that make up the setting.\u003c/li\u003e\n\u003cli\u003eThe modifiers should alter the mood, style, lighting, and other aspects of the scene.\u003c/li\u003e\n\u003cli\u003eMultiple modifiers can be used to provide more specific details.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eI want you to write me a list of detailed prompts exactly about the IDEA follow the rule at least 6 every time.\u003c/p\u003e\n\u003cp\u003eReady for my idea?\u003c/p\u003e\n\u003ch3 id=\"ideas\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eIDEAS\u003c/span\u003e \u003ca href=\"#ideas\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIDEA: A slice of pie that is filled with a futuristic city\u003c/p\u003e\n\u003ch2 id=\"artists-i-like\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eArtists I like\u003c/span\u003e \u003ca href=\"#artists-i-like\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://stablediffusion.fr/artists\"\u003eExamples\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eJ. M. W. Turner\u003c/li\u003e\n\u003cli\u003eJean-Baptiste Monge\u003c/li\u003e\n\u003cli\u003eJohn Lasseter\u003c/li\u003e\n\u003cli\u003eJohn Martin\u003c/li\u003e\n\u003cli\u003eRaymond Swanland\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"anime-styles\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eAnime styles\u003c/span\u003e \u003ca href=\"#anime-styles\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eKrenz Cushart\u003c/li\u003e\n\u003cli\u003eKyoto Animation\u003c/li\u003e\n\u003cli\u003eYoshiyuki Sadamoto\u003c/li\u003e\n\u003cli\u003eYuumei\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"scenic\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eScenic\u003c/span\u003e \u003ca href=\"#scenic\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eTed Nasmith\u003c/li\u003e\n\u003cli\u003eTerry Redlin\u003c/li\u003e\n\u003cli\u003eThomas Kinkade\u003c/li\u003e\n\u003cli\u003eThomas Moran\u003c/li\u003e\n\u003cli\u003eThomas W Schaller\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"cityscapes\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eCityscapes\u003c/span\u003e \u003ca href=\"#cityscapes\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eMarc Simonetti\u003c/li\u003e\n\u003cli\u003eWadim Kashin\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"abstract\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eAbstract\u003c/span\u003e \u003ca href=\"#abstract\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eScott Naismith\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"settings-notes\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eSettings notes\u003c/span\u003e \u003ca href=\"#settings-notes\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI tend to like cfg at least on the higher end\u003c/p\u003e\n\u003ch2 id=\"good-prompts\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eGood prompts\u003c/span\u003e \u003ca href=\"#good-prompts\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eAngel of death, shadows and mist, skelletol feathered wings, highly detailed, amazing details, intriciate lines, purple haze, styles Yuumei and Krenz Cushart, UHD, HDR, upscale, 8K photo, concept art\u003c/p\u003e\n\u003ch3 id=\"unicorns\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eUnicorns\u003c/span\u003e \u003ca href=\"#unicorns\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003epositive: unicorn, \u003ca href=\"lora:Unicorns:0.9\"\u003elora:Unicorns:0.9\u003c/a\u003e, portrait, professional photography, 35mm, highly detailed, incredibly realistic, best quality, high quality, highres, purple, \u003ca href=\"lora:mossbeast:0.3\"\u003elora:mossbeast:0.3\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003enegative: (two tails:1.2),FastNegativeV2,(bad-artist:1.0), (loli:1.2), (worst quality, low quality:1.4), (bad_prompt_version2:0.8), bad-hands-5,lowres, bad anatomy, bad hands, ((text)), (watermark), error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, ((username)), blurry, (extra limbs), bad-artist-anime, badhandv4, EasyNegative, ng_deepnegative_v1_75t, verybadimagenegative_v1.3, BadDream,(three hands:1.1),(three legs:1.1),(more than two hands:1.4),(more than two legs,:1.2),\u003c/p\u003e\n",
      "content_text": "\n## ChatGPT Prompt:\n\nStable Diffusion is an AI art generation model similar to DALLE-2.\nHere are some prompts for generating art with Stable Diffusion.\n\nExample:\n\n- A ghostly apparition drifting through a haunted mansion's grand ballroom, illuminated by flickering candlelight. Eerie, ethereal, moody lighting.\n- portait of a homer simpson archer shooting arrow at forest monster, front game card, drark, marvel comics, dark, smooth\n- pirate, deep focus, fantasy, matte, sharp focus\n- red dead redemption 2, cinematic view, epic sky, detailed, low angle, high detail, warm lighting, volumetric, godrays, vivid, beautiful\n- a fantasy style portrait painting of rachel lane / alison brie hybrid in the style of francois boucher oil painting, rpg portrait\n- athena, greek goddess, claudia black, bronze greek armor, owl crown, d \u0026 d, fantasy, portrait, headshot, sharp focus\n- closeup portrait shot of a large strong female biomechanic woman in a scenic scifi environment, elegant, smooth, sharp focus, warframe\n- ultra realistic illustration of steve urkle as the hulk, elegant, smooth, sharp focus\n- portrait of beautiful happy young ana de armas, ethereal, realistic anime, clean lines, sharp lines, crisp lines, vibrant color scheme\n- A highly detailed and hyper realistic portrait of a gorgeous young ana de armas, lisa frank, butterflies, floral, sharp focus\n- lots of delicious tropical fruits with drops of moisture on table, floating colorful water, mysterious expression, in a modern and abstract setting, with bold and colorful abstract art, blurred background, bright lighting\n- 1girl, The most beautiful form of chaos, Fauvist design, Flowing colors, Vivid colors, dynamic angle, fantasy world\n- solo, sitting, close-up, girl in the hourglass, Sand is spilling out of the broken hourglass, flowing sand, huge hourglass art, hologram, particles, nebula, magic circle\n- geometric abstract background, 1girl, depth of field, zentangle, mandala, tangle, entangle, beautiful and aesthetic, dynamic angle, glowing skin, floating colorful sparkles the most beautiful form of chaos, elegant, a brutalist designed, vivid colours, romanticism\n\nThe prompt should adhere to and include all of the following rules:\n\n- Prompt should always be written in English, regardless of the input language. Please provide the prompts in English.\n- Each prompt should consist of a description of the scene followed by modifiers divided by commas.\n- When generating descriptions, focus on portraying the visual elements rather than delving into abstract psychological and emotional aspects. Provide clear and concise details that vividly depict the scene and its composition, capturing the tangible elements that make up the setting.\n- The modifiers should alter the mood, style, lighting, and other aspects of the scene.\n- Multiple modifiers can be used to provide more specific details.\n\nI want you to write me a list of detailed prompts exactly about the IDEA follow the rule at least 6 every time.\n\nReady for my idea?\n\n## ChatGPT Prompt for RPG V4:\n\nStable Diffusion is an AI art generation model similar to DALLE-2.\nHere are some pairs of positive and negative prompts for generating art with Stable Diffusion.\n\nExample:\n\n1. \nPositive: A (full body:1.3) shot at 8k resolution, splash art, fantastic comic book style, photorealistic, intense look, anatomical photorealistic digital painting portrait of a (old male:1.3) human (warrior:1.3) in black and gold intricate (heavy armor:1.3) in a (dark and moody universe:1.3), light particle, very detailed skin,samurai, very detailed eyes, (elden ring style:1.3), (warhammer style:1.1), concept artist, global illumination, depth of field, splash art, art by artgerm and greg rutkowski and viktoria gavrilenko\nNegative: (symmetry:1.2), facial marking, crown, horn, (helmet:1.3), (hoodie:1.1), clock, Female, visible hand, asian, two face, big hair, open mouth, cartoon, high contrast, poorly drawn, Scribbles, Low quality, Low rated, Mediocre, Screenshot, Software, UI, watermark, text, overlay, getty images, cropped, low quality\n\n2. \nPositive: close-up head, facing camera, beautiful satanic female necromancer blood queen, ritualistic (neck tattoo:1.3), (insanely detailed:1.5), ((solo)), (highest quality, Alessandro Casagrande, Greg Rutkowski, Sally Mann, concept art, 4k), (colourful), (high sharpness), ((detailed pupils)), ((painting:1.1)), (digital painting:1.1), detailed face and eyes,Masterpiece, best quality, highly detailed photo:1, 8k, detailed face,photorealistic, (black long Hair:1.1),(young woman),By jeremy mann, by sandra chevrier, by maciej kuciara, smoke and shadow, night, sharp, ((perfect body)), realistic, real shadow, 3d, ((full body)), ((dark and gloomy universe)), (by Michelangelo)\nNegative: crown, (facial marking:1.2), cloth gem, jewel, jewelry, (flower:1.3), (cloak:1.1), (bad art, low detail, pencil drawing, old, mature:1.6), (grainy, low quality, mutated hands and fingers:1.5), (watermark, thin lines:1.3), (deformed, signature:1.2), (big nipples, blurry, ugly, bad anatomy, extra limbs, undersaturated, low resolution), disfigured, deformations, out of frame, amputee, bad proportions, extra limb, missing limbs, distortion, floating limbs, out of frame, poorly drawn face, poorly drawn hands, text, malformed, error, missing fingers, cropped, jpeg artifacts, teeth, unsharp\n\n3. \nPositive: (Painting:1.3) of (Detailed illustration:1.3) A (full body:1.3) shot at 8k resolution, splash art, fantastic comic book style, photorealistic, intense look, anatomical photorealistic digital painting portrait of a (old male:1.3) human (warrior:1.3) in black and gold intricate (heavy armor:1.3) in a (dark and moody universe:1.3), light particle, very detailed skin,samurai, very detailed eyes, (elden ring style:1.3), (warhammer style:1.1), concept artist, global illumination, depth of field, splash art, art by artgerm and greg rutkowski and viktoria gavrilenko\nNegative:  (symmetry:1.2), facial marking, crown, (horn:1.1), (helmet:1.3), (hoodie:1.1), clock, Female, visible hand, asian, two face, big hair, open mouth, cartoon, high contrast, poorly drawn, Scribbles, Low quality, Low rated, Mediocre, Screenshot, Software, UI, watermark, text, overlay, getty images, cropped, low qualityLow quality,Bad composition,Faded,(Photo:1.5),(Frame:1.3),watermark,signa ture\n\n4. \nPositive: sci-fi, space rogue thief girl, (smirk:1.1), short hair, black hood, light armor, big grey eyes, beautiful detailed eyes, drawn by Greg Rutkowski, Yoji Shinkawa:0.6\nNegative: open mouth, facial marking, flower, bad-hands-5, lipstick, text, watermark \n\nThe prompt should adhere to and include all of the following rules:\n\n- Each prompt should consist of a description of the scene followed by modifiers divided by commas.\n- When generating descriptions, focus on portraying the visual elements rather than delving into abstract psychological and emotional aspects. Provide clear and concise details that vividly depict the scene and its composition, capturing the tangible elements that make up the setting.\n- The modifiers should alter the mood, style, lighting, and other aspects of the scene.\n- Multiple modifiers can be used to provide more specific details.\n\nI want you to write me a list of detailed prompts exactly about the IDEA follow the rule at least 6 every time.\n\nReady for my idea?\n\n### IDEAS\n\nIDEA: A slice of pie that is filled with a futuristic city\n\n## Artists I like\n\n[Examples](https://stablediffusion.fr/artists)\n\n- J. M. W. Turner\n- Jean-Baptiste Monge\n- John Lasseter\n- John Martin\n- Raymond Swanland\n\n### Anime styles\n\n- Krenz Cushart\n- Kyoto Animation\n- Yoshiyuki Sadamoto\n- Yuumei\n\n### Scenic\n\n- Ted Nasmith\n- Terry Redlin\n- Thomas Kinkade\n- Thomas Moran\n- Thomas W Schaller\n\n### Cityscapes\n\n- Marc Simonetti\n- Wadim Kashin\n\n### Abstract\n\n- Scott Naismith\n\n## Settings notes\n\nI tend to like cfg at least on the higher end\n\n## Good prompts\n\nAngel of death, shadows and mist, skelletol feathered wings, highly detailed, amazing details, intriciate lines, purple haze, styles Yuumei and Krenz Cushart, UHD, HDR, upscale, 8K photo, concept art\n\n### Unicorns\n\npositive: unicorn, \u003clora:Unicorns:0.9\u003e, portrait, professional photography, 35mm, highly detailed, incredibly realistic, best quality, high quality, highres, purple, \u003clora:mossbeast:0.3\u003e\n\nnegative: (two tails:1.2),FastNegativeV2,(bad-artist:1.0), (loli:1.2), (worst quality, low quality:1.4), (bad_prompt_version2:0.8), bad-hands-5,lowres, bad anatomy, bad hands, ((text)), (watermark), error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, ((username)), blurry, (extra limbs), bad-artist-anime, badhandv4, EasyNegative, ng_deepnegative_v1_75t, verybadimagenegative_v1.3, BadDream,(three hands:1.1),(three legs:1.1),(more than two hands:1.4),(more than two legs,:1.2),\n\n",
      "summary": "Stable Diffusion is an AI art generation model similar to DALLE-2. Here are some prompts for generating art with Stable Diffusion.",
      "date_published": "2023-01-28T14:15:11Z",
      "date_modified": "2023-01-28T14:15:11Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "data",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/ffmpeg-10-bit-videos-to-8-bit/",
      "url": "https://pype.dev/ffmpeg-10-bit-videos-to-8-bit/",
      "title": "FFMPEG 10-bit videos to 8-bit",
      "content_html": "\u003cp\u003e\u003ccode\u003effmpeg -i input.mp4 -map 0 -c:v libx264 -vf format=yuv420p -c:a copy output.mp4\u003c/code\u003e\u003c/p\u003e\n",
      "content_text": "\n`ffmpeg -i input.mp4 -map 0 -c:v libx264 -vf format=yuv420p -c:a copy output.mp4`\n",
      "date_published": "2023-01-16T13:15:53Z",
      "date_modified": "2023-01-16T13:15:53Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "cli",
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/reminder-about-ssh-copy-id-for-ssh-and-ansible/",
      "url": "https://pype.dev/reminder-about-ssh-copy-id-for-ssh-and-ansible/",
      "title": "Reminder about ssh-copy-id for SSH and Ansible",
      "content_html": "\u003cp\u003e\u003ccode\u003essh-copy-id -i my.key.pub \u0026lt;hostname probably from tailscale\u0026gt;\u003c/code\u003e\nthis makes sure I can run ansible from my desktop against VMs on my server\neasily if they have tailscale for the hostname - otherwise use the IP\u003c/p\u003e\n",
      "content_text": "\n`ssh-copy-id -i my.key.pub \u003chostname probably from tailscale\u003e` \nthis makes sure I can run ansible from my desktop against VMs on my server\neasily if they have tailscale for the hostname - otherwise use the IP\n",
      "summary": "this makes sure I can run ansible from my desktop against VMs on my server easily if they have tailscale for the hostname - otherwise use the IP",
      "date_published": "2022-12-28T13:33:07Z",
      "date_modified": "2022-12-28T13:33:07Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/nextcloud-docker-upgrade-error/",
      "url": "https://pype.dev/nextcloud-docker-upgrade-error/",
      "title": "Nextcloud Docker Upgrade Error",
      "content_html": "\u003cp\u003e\u003ca href=\"https://nicolasbouliane.com/blog/nextcloud-docker-upgrade-error\"\u003ehttps://nicolasbouliane.com/blog/nextcloud-docker-upgrade-error\u003c/a\u003e\u003c/p\u003e\n",
      "content_text": "\n\n\nhttps://nicolasbouliane.com/blog/nextcloud-docker-upgrade-error\n",
      "summary": "https://nicolasbouliane.com/blog/nextcloud-docker-upgrade-error",
      "date_published": "2022-12-28T09:39:27Z",
      "date_modified": "2022-12-28T09:39:27Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/systemd-timer-for-syncoid/",
      "url": "https://pype.dev/systemd-timer-for-syncoid/",
      "title": "Systemd timer for syncoid",
      "content_html": "\u003cp\u003eI have a bash script called \u003ccode\u003esyncoid-job\u003c/code\u003e which boils down to a barebones -\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#!/bin/bash\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esyncoid --no-sync-snap --sendoptions\u003cspan class=\"o\"\u003e=\u003c/span\u003ew --no-privilege-elevation \u003cspan class=\"nv\"\u003e$SYNOIC_USER\u003c/span\u003e@\u003cspan class=\"nv\"\u003e$SERVER\u003c/span\u003e:tank/encrypted/nas tank/encrypted/nas\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eI want to run this script hourly but as my user (notice the no-privilege-elevation flag)\u003c/p\u003e\n\u003cp\u003eFirst - create a systemd unit file at \u003ccode\u003e/etc/systemd/system/syncoid-replication.service\u003c/code\u003e\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003eUnit\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eDescription\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003eZFS Replication With Syncoid\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003eService\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eType\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003eoneshot\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eExecStart\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e/\u003cspan class=\"nv\"\u003e$HOME\u003c/span\u003e/dotfiles/syncoid-job\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eUser\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"nv\"\u003e$USER\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eGroup\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"nv\"\u003e$GROUP\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003eInstall\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eWantedBy\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003emulti-user.target\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThen we save the unit file, enable the service, and then start it\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"go\"\u003esystemctl enable syncoid-replication.service\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"go\"\u003esystemctl start syncoid-replication.service\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cblockquote\u003e\n\u003cp\u003eNote this will run that script\u0026hellip; so be ready for syncoid to do its thing\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eNow for the timer\u0026hellip; We create \u003ccode\u003e/etc/systemd/system/syncoid-replication.timer\u003c/code\u003e\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003eUnit\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eDescription\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003eRun syncoid-replication every hour\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003eTimer\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eOnCalendar\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003ehourly\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003eInstall\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eWantedBy\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003etimers.target\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eHit it with a \u003ccode\u003esystemctl enable syncoid-replication.timer\u003c/code\u003e and you\u0026rsquo;re in business!\u003c/p\u003e\n",
      "content_text": "\nI have a bash script called `syncoid-job` which boils down to a barebones - \n\n```bash\n#!/bin/bash\n\nsyncoid --no-sync-snap --sendoptions=w --no-privilege-elevation $SYNOIC_USER@$SERVER:tank/encrypted/nas tank/encrypted/nas\n```\n\nI want to run this script hourly but as my user (notice the no-privilege-elevation flag)\n\nFirst - create a systemd unit file at `/etc/systemd/system/syncoid-replication.service`\n\n```bash\n[Unit]\nDescription=ZFS Replication With Syncoid\n\n[Service]\nType=oneshot\nExecStart=/$HOME/dotfiles/syncoid-job\nUser=$USER\nGroup=$GROUP\n\n[Install]\nWantedBy=multi-user.target\n\n```\n\nThen we save the unit file, enable the service, and then start it\n\n```console\nsystemctl enable syncoid-replication.service\nsystemctl start syncoid-replication.service\n\n```\n\n\u003e Note this will run that script... so be ready for syncoid to do its thing\n\nNow for the timer... We create `/etc/systemd/system/syncoid-replication.timer`\n\n```bash\n[Unit]\nDescription=Run syncoid-replication every hour\n\n[Timer]\nOnCalendar=hourly\n\n[Install]\nWantedBy=timers.target\n\n```\n\nHit it with a `systemctl enable syncoid-replication.timer` and you're in business!\n",
      "summary": "I have a bash script called which boils down to a barebones -",
      "date_published": "2022-12-21T11:38:27Z",
      "date_modified": "2022-12-21T11:38:27Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "zfs",
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/cron-for-nextcloud-in-docker/",
      "url": "https://pype.dev/cron-for-nextcloud-in-docker/",
      "title": "Cron for Nextcloud in Docker",
      "content_html": "\u003cp\u003eAJAX wasn\u0026rsquo;t cutting it, traditional crontab in containers doesn\u0026rsquo;t make much\nsense to me, webcron is recommended but I don\u0026rsquo;t want to register with anything\noutside my LAN\u0026hellip; Turns out you can just spin up an identical container with a\ndifferent entrypoint to /cron.sh that does what you need!\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eNote that this is a task in an Ansible playbook - but the docker-compose is straight forward\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eSo the only thing you need to make sure of is that \u003cem\u003eall\u003c/em\u003e the configuration\noptions - data volumes, user permissions, etc. are \u003cem\u003eidentical\u003c/em\u003e between the\ncontainers running the cron job and the one actually hosting NextCloud. This\nensures that the container running cron has proper access to the database and\nfilesystem - or at least the same access as NextCloud proper.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eNextcloud Cron Docker Container\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003edocker_container\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003enextcloud-cron\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eimage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ nextcloud_image }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003epull\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003elinks\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"l\"\u003enextcloud-mysql:mysql\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eentrypoint\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003e/cron.sh\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003evolumes\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;{{ nextcloud_data_directory }}/nextcloud:/var/www/html:rw\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eMYSQL_HOST\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mysql\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eMYSQL_DATABASE\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;nextcloud\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eMYSQL_USER\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ nextcloud_sql_user }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eMYSQL_PASSWORD\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ nextcloud_sql_password }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eNEXTCLOUD_TRUSTED_DOMAINS\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ nextcloud_hostname }}.{{ ansible_nas_domain }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003ePUID\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ nextcloud_user_id }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003ePGID\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ nextcloud_group_id }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eTZ\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ ansible_nas_timezone }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003erestart_policy\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eunless-stopped\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ememory\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ nextcloud_memory }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e",
      "content_text": "\nAJAX wasn't cutting it, traditional crontab in containers doesn't make much\nsense to me, webcron is recommended but I don't want to register with anything\noutside my LAN... Turns out you can just spin up an identical container with a\ndifferent entrypoint to /cron.sh that does what you need!\n\n\u003e Note that this is a task in an Ansible playbook - but the docker-compose is straight forward\n\nSo the only thing you need to make sure of is that _all_ the configuration\noptions - data volumes, user permissions, etc. are _identical_ between the\ncontainers running the cron job and the one actually hosting NextCloud. This\nensures that the container running cron has proper access to the database and\nfilesystem - or at least the same access as NextCloud proper.\n\n```yaml\n- name: Nextcloud Cron Docker Container\n  docker_container:\n    name: nextcloud-cron\n    image: \"{{ nextcloud_image }}\"\n    pull: true\n    links:\n      - nextcloud-mysql:mysql\n    entrypoint: /cron.sh\n    volumes:\n      - \"{{ nextcloud_data_directory }}/nextcloud:/var/www/html:rw\"\n    env:\n      MYSQL_HOST: \"mysql\"\n      MYSQL_DATABASE: \"nextcloud\"\n      MYSQL_USER: \"{{ nextcloud_sql_user }}\"\n      MYSQL_PASSWORD: \"{{ nextcloud_sql_password }}\"\n      NEXTCLOUD_TRUSTED_DOMAINS: \"{{ nextcloud_hostname }}.{{ ansible_nas_domain }}\"\n      PUID: \"{{ nextcloud_user_id }}\"\n      PGID: \"{{ nextcloud_group_id }}\"\n      TZ: \"{{ ansible_nas_timezone }}\"\n    restart_policy: unless-stopped\n    memory: \"{{ nextcloud_memory }}\"\n\n```\n\n\n\n",
      "summary": "AJAX wasn't cutting it, traditional crontab in containers doesn't make much sense to me, webcron is recommended but I don't want to register with anything...",
      "date_published": "2022-12-13T06:43:45Z",
      "date_modified": "2022-12-13T06:43:45Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "docker",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/you-can-embed-gifs/",
      "url": "https://pype.dev/you-can-embed-gifs/",
      "title": "You can embed gifs?!",
      "content_html": "\u003cp\u003eI learned you can embed gifs and stuch in things other than GH personal pages!\u003c/p\u003e\n\u003cp\u003eSo here I\u0026rsquo;ll keep ones I like and might use later\u003c/p\u003e\n\u003ciframe src=\"https://giphy.com/embed/jXBwoFfPsCCoE\" width=\"25px\" height=\"25px\" frameBorder=\"0\" class=\"giphy-embed\" allowFullScreen\u003e\u003c/iframe\u003e\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/tech-rainbow-jXBwoFfPsCCoE\"\u003evia GIPHY\u003c/a\u003e\u003c/p\u003e\n",
      "content_text": "\nI learned you can embed gifs and stuch in things other than GH personal pages!\n\n\nSo here I'll keep ones I like and might use later\n\n\u003ciframe src=\"https://giphy.com/embed/jXBwoFfPsCCoE\" width=\"25px\" height=\"25px\" frameBorder=\"0\" class=\"giphy-embed\" allowFullScreen\u003e\u003c/iframe\u003e\u003cp\u003e\u003ca href=\"https://giphy.com/gifs/tech-rainbow-jXBwoFfPsCCoE\"\u003evia GIPHY\u003c/a\u003e\u003c/p\u003e\n",
      "summary": "I learned you can embed gifs and stuch in things other than GH personal pages!",
      "date_published": "2022-10-09T13:39:39Z",
      "date_modified": "2022-10-09T13:39:39Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "webdev",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/dont-forget-to-load-xmp/",
      "url": "https://pype.dev/dont-forget-to-load-xmp/",
      "title": "Don’t forget to load XMP!",
      "content_html": "\u003cp\u003eBought some DDR4-3600 speed RAM but only seeing 2666? Load up the BIOS, find DRAM config or something similar, and make sure to load the XMP profile to get that advertised RAM speed!\u003c/p\u003e\n",
      "content_text": "\nBought some DDR4-3600 speed RAM but only seeing 2666? Load up the BIOS, find DRAM config or something similar, and make sure to load the XMP profile to get that advertised RAM speed!\n",
      "summary": "Bought some DDR4-3600 speed RAM but only seeing 2666? Load up the BIOS, find DRAM config or something similar, and make sure to load the XMP profile to get...",
      "date_published": "2022-10-09T07:17:43Z",
      "date_modified": "2022-10-09T07:17:43Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/my-passmark-scores/",
      "url": "https://pype.dev/my-passmark-scores/",
      "title": "My PassMark Scores",
      "content_html": "\u003cdiv class=\"admonition note\"\u003e\n\u003cp class=\"admonition-title\"\u003eBabyblue v2\u003c/p\u003e\n\u003cp\u003eRyzen 5700x + 32 GB 3200 CL16 RAM\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.passmark.com/baselines/V10/display.php?id=503041456656\"\u003e\u003cimg src=\"https://www.passmark.com/baselines/V10/media/503041456656.png\" alt=\"PassMark Rating\" border=\"0\" /\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"admonition note\"\u003e\n\u003cp class=\"admonition-title\"\u003eVenus \u003c/p\u003e\n\u003cp\u003eRyzen 3200G + 16GB 3600 CL16 RAM\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.passmark.com/baselines/V10/display.php?id=502360857958\"\u003e\u003cimg src=\"https://www.passmark.com/baselines/V10/media/502360857958.png\" height=120px alt=\"PassMark Rating\" border=\"0\" /\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"admonition note\"\u003e\n\u003cp class=\"admonition-title\"\u003eHogwarts\u003c/p\u003e\n\u003cp\u003eDual Xeon X5650 @2.67GHz | 90 GB 1883 DDR3 ECC RAM\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.passmark.com/baselines/V10/display.php?id=502361259420\"\u003e\u003cimg src=\"https://www.passmark.com/baselines/V10/media/502361259420.png\" height=120px alt=\"PassMark Rating\" border=\"0\" /\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"admonition note\"\u003e\n\u003cp class=\"admonition-title\"\u003eServer 2 ... Change the name\u003c/p\u003e\n\u003cp\u003eRyzen 5700G + 128GB 3200 CL18 RAM\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.passmark.com/baselines/V10/display.php?id=502361424410\"\u003e\u003cimg src=\"https://www.passmark.com/baselines/V10/media/502361424410.png\" height=120px alt=\"PassMark Rating\" border=\"0\" /\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cdiv class=\"admonition note\"\u003e\n\u003cp class=\"admonition-title\"\u003eServer 2 with XMP enabled and undervolted from 1.35 to 1.2\u003c/p\u003e\n\u003cp\u003eRyzen 5700G + 128GB 3200 CL18 RAM\u003c/p\u003e\n\u003cp\u003eUndervolted to 1.2V (from 1.35)\nXMP enabled\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.passmark.com/baselines/V10/display.php?id=502363064921\"\u003e\u003cimg src=\"https://www.passmark.com/baselines/V10/media/502363064921.png\" height=120px alt=\"PassMark Rating\" border=\"0\" /\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n",
      "content_text": "\n!!! note \"Babyblue v2\"\n\n    Ryzen 5700x + 32 GB 3200 CL16 RAM\n\n    \u003ca href=\"https://www.passmark.com/baselines/V10/display.php?id=503041456656\"\u003e\u003cimg src=\"https://www.passmark.com/baselines/V10/media/503041456656.png\" alt=\"PassMark Rating\" border=\"0\" /\u003e\u003c/a\u003e\n\n!!! note \"Venus \"\n\n    Ryzen 3200G + 16GB 3600 CL16 RAM\n\n    \u003ca href=\"https://www.passmark.com/baselines/V10/display.php?id=502360857958\"\u003e\u003cimg src=\"https://www.passmark.com/baselines/V10/media/502360857958.png\" height=120px alt=\"PassMark Rating\" border=\"0\" /\u003e\u003c/a\u003e\n\n!!! note \"Hogwarts\"\n\n    Dual Xeon X5650 @2.67GHz | 90 GB 1883 DDR3 ECC RAM\n\n    \u003ca href=\"https://www.passmark.com/baselines/V10/display.php?id=502361259420\"\u003e\u003cimg src=\"https://www.passmark.com/baselines/V10/media/502361259420.png\" height=120px alt=\"PassMark Rating\" border=\"0\" /\u003e\u003c/a\u003e\n\n\n!!! note \"Server 2 ... Change the name\"\n\n    Ryzen 5700G + 128GB 3200 CL18 RAM\n\n    \u003ca href=\"https://www.passmark.com/baselines/V10/display.php?id=502361424410\"\u003e\u003cimg src=\"https://www.passmark.com/baselines/V10/media/502361424410.png\" height=120px alt=\"PassMark Rating\" border=\"0\" /\u003e\u003c/a\u003e\n\n!!! note \"Server 2 with XMP enabled and undervolted from 1.35 to 1.2\"\n\n    Ryzen 5700G + 128GB 3200 CL18 RAM\n\n    Undervolted to 1.2V (from 1.35)\n    XMP enabled\n\n    \u003ca href=\"https://www.passmark.com/baselines/V10/display.php?id=502363064921\"\u003e\u003cimg src=\"https://www.passmark.com/baselines/V10/media/502363064921.png\" height=120px alt=\"PassMark Rating\" border=\"0\" /\u003e\u003c/a\u003e\n",
      "summary": "!!! note \"Babyblue v2\"",
      "date_published": "2022-10-08T18:43:29Z",
      "date_modified": "2022-10-08T18:43:29Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/quick-setup-of-zfs-encrytped-datasets-with-sane-permissions/",
      "url": "https://pype.dev/quick-setup-of-zfs-encrytped-datasets-with-sane-permissions/",
      "title": "Quick setup of ZFS encrytped datasets with sane permissions",
      "content_html": "\u003cp\u003eAssuming you have a pool called \u003ccode\u003etank\u003c/code\u003e\u0026hellip;\u003c/p\u003e\n\u003cp\u003eAnd assuming you have an encrypted dataset (See \u003ca href=\"https://arstechnica.com/gadgets/2021/06/a-quick-start-guide-to-openzfs-native-encryption/\"\u003eJim Saltar\u0026rsquo;s short\nintro\u003c/a\u003e)\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eCreate a group for permissions - in my case I have one called \u003ccode\u003ehome\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eThen if there\u0026rsquo;s anything in \u003ccode\u003e/tank/encrypted\u003c/code\u003e his it with \u003ccode\u003echgrp -R home /tank/encrypted\u003c/code\u003e to give the \u003ccode\u003ehome\u003c/code\u003e group ownership\u003c/li\u003e\n\u003cli\u003eNext we need to make sure that the members of \u003ccode\u003ehome\u003c/code\u003e can do the writing\u0026hellip;\nso \u003ccode\u003echmod 775 -R /tank/encrypted\u003c/code\u003e will do the trick\u003c/li\u003e\n\u003cli\u003eFinally we want to make sure that all data created inside our dataset has\nthe same set of permissions with \u003ccode\u003echmod g+s /tank/encrypted\u003c/code\u003e and \u003ccode\u003echmod g+w /tank/encrypted\u003c/code\u003e\u003c/li\u003e\n\u003c/ol\u003e\n",
      "content_text": "\nAssuming you have a pool called `tank`...\n\nAnd assuming you have an encrypted dataset (See [Jim Saltar's short\nintro](https://arstechnica.com/gadgets/2021/06/a-quick-start-guide-to-openzfs-native-encryption/))\n\n1. Create a group for permissions - in my case I have one called `home`\n2. Then if there's anything in `/tank/encrypted` his it with `chgrp -R home\n   /tank/encrypted` to give the `home` group ownership\n3. Next we need to make sure that the members of `home` can do the writing...\n   so `chmod 775 -R /tank/encrypted` will do the trick\n4. Finally we want to make sure that all data created inside our dataset has\n   the same set of permissions with `chmod g+s /tank/encrypted` and `chmod g+w\n   /tank/encrypted`\n\n",
      "summary": "Assuming you have a pool called ...",
      "date_published": "2022-10-06T19:58:01Z",
      "date_modified": "2022-10-06T19:58:01Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "zfs",
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/trick-to-login-to-web-server-on-another-box-on-lan/",
      "url": "https://pype.dev/trick-to-login-to-web-server-on-another-box-on-lan/",
      "title": "Trick to login to web server on another box on lan",
      "content_html": "\u003cp\u003eTODO: change title - add \u0026ndash;listen or \u0026ndash;host or something as 0.0.0.0\u0026hellip; that way it listens not on localhost or 127.0.0.1, but on all addresses!\u003c/p\u003e\n",
      "content_text": "\nTODO: change title - add --listen or --host or something as 0.0.0.0... that way it listens not on localhost or 127.0.0.1, but on all addresses!\n",
      "summary": "TODO: change title - add --listen or --host or something as 0.0.0.0... that way it listens not on localhost or 127.0.0.1, but on all addresses!",
      "date_published": "2022-09-12T18:48:45Z",
      "date_modified": "2022-09-12T18:48:45Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "cli",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/paperless-ngx-filtering-on-ids-instead-of-values/",
      "url": "https://pype.dev/paperless-ngx-filtering-on-ids-instead-of-values/",
      "title": "Paperless-NGX filtering on IDs instead of values",
      "content_html": "\u003cp\u003eTo filter for saved views from the admin console you have to use the \u003ccode\u003eid\u003c/code\u003e of\nthe tag you are using to filter on\u0026hellip;\u003c/p\u003e\n\u003cp\u003eEx: filtering for tags \u0026ldquo;Inbox\u0026rdquo; doesn\u0026rsquo;t work, but for tag 18 does (the id fo the\nInbox tag). I can find that ID by clicking on the tag and looking at the url\nbar\u003c/p\u003e\n",
      "content_text": "\nTo filter for saved views from the admin console you have to use the `id` of\nthe tag you are using to filter on...\n\nEx: filtering for tags \"Inbox\" doesn't work, but for tag 18 does (the id fo the\nInbox tag). I can find that ID by clicking on the tag and looking at the url\nbar\n",
      "summary": "To filter for saved views from the admin console you have to use the of the tag you are using to filter on...",
      "date_published": "2022-08-09T08:28:51Z",
      "date_modified": "2022-08-09T08:28:51Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/mounting-exfat-usb-in-linux/",
      "url": "https://pype.dev/mounting-exfat-usb-in-linux/",
      "title": "Mounting exFAT USB in Linux",
      "content_html": "\u003ch1 id=\"steps\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eSteps\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003e\u003ccode\u003esudo fdisk -l\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003ethen look for the device and partition\u003c/p\u003e\n\u003cp\u003eget the Type column\u003c/p\u003e\n\u003cp\u003emount\u003c/p\u003e\n\u003ch2 id=\"example\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eExample\u003c/span\u003e \u003ca href=\"#example\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e\ndumbledore in /media  NO PYTHON VENV SET \n❯ sudo fdisk -l\n\n...\n\nDevice     Boot    Start      End  Sectors  Size Id Type\n/dev/sdk1  *        2048 60371951 60369904 28.8G  7 HPFS/NTFS/exFAT\n/dev/sdk2       60371952 60437487    65536   32M ef EFI (FAT-12/16/32)\n\n\ndumbledore in /media  NO PYTHON VENV SET \n❯ sudo mount -t ntfs /dev/sdk1 /media/ventoy-usb -o uid=1000                       \nNTFS signature is missing.\nFailed to mount '/dev/sdk1': Invalid argument\nThe device '/dev/sdk1' doesn't seem to have a valid NTFS.\nMaybe the wrong device is used? Or the whole disk instead of a\npartition (e.g. /dev/sda, not /dev/sda1)? Or the other way around?\n\ndumbledore in /media  NO PYTHON VENV SET \n✗ sudo mount -t exfat /dev/sdk1 /media/ventoy-usb -o uid=1000\n\n\u003c/code\u003e\u003c/pre\u003e\n",
      "content_text": "\n# Steps\n\n`sudo fdisk -l`\n\nthen look for the device and partition\n\nget the Type column\n\nmount\n\n## Example\n\n```\n\ndumbledore in /media  NO PYTHON VENV SET \n❯ sudo fdisk -l\n\n...\n\nDevice     Boot    Start      End  Sectors  Size Id Type\n/dev/sdk1  *        2048 60371951 60369904 28.8G  7 HPFS/NTFS/exFAT\n/dev/sdk2       60371952 60437487    65536   32M ef EFI (FAT-12/16/32)\n\n\ndumbledore in /media  NO PYTHON VENV SET \n❯ sudo mount -t ntfs /dev/sdk1 /media/ventoy-usb -o uid=1000                       \nNTFS signature is missing.\nFailed to mount '/dev/sdk1': Invalid argument\nThe device '/dev/sdk1' doesn't seem to have a valid NTFS.\nMaybe the wrong device is used? Or the whole disk instead of a\npartition (e.g. /dev/sda, not /dev/sda1)? Or the other way around?\n\ndumbledore in /media  NO PYTHON VENV SET \n✗ sudo mount -t exfat /dev/sdk1 /media/ventoy-usb -o uid=1000\n\n```\n",
      "date_published": "2022-07-31T07:38:43Z",
      "date_modified": "2022-07-31T07:38:43Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "linux",
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/xrdp-authentication-required-to-create-managed-color-device/",
      "url": "https://pype.dev/xrdp-authentication-required-to-create-managed-color-device/",
      "title": "Xrdp-Authentication-Required-To-Create-Managed-Color-Device",
      "content_html": "\u003cp\u003eI just need to RDP into an Ubuntu box via Remmina and everytime I login I have\nto authenticate to create a color managed device\u0026hellip; which I don\u0026rsquo;t even know\nwhat that is!\u003c/p\u003e\n\u003cp\u003eTo fix it?\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003evim /etc/polkit-1/localauthority.conf.d/02-allow-colord.conf\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003epolkit.addRule(function(action, subject) {\n if ((action.id == \u0026quot;org.freedesktop.color-manager.create-device\u0026quot; ||\n action.id == \u0026quot;org.freedesktop.color-manager.create-profile\u0026quot; ||\n action.id == \u0026quot;org.freedesktop.color-manager.delete-device\u0026quot; ||\n action.id == \u0026quot;org.freedesktop.color-manager.delete-profile\u0026quot; ||\n action.id == \u0026quot;org.freedesktop.color-manager.modify-device\u0026quot; ||\n action.id == \u0026quot;org.freedesktop.color-manager.modify-profile\u0026quot;) \u0026amp;\u0026amp;\n subject.isInGroup(\u0026quot;{users}\u0026quot;)) {\n return polkit.Result.YES;\n }\n });\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eGive\u0026rsquo;r the \u003ccode\u003e:x\u003c/code\u003e, logout, and you\u0026rsquo;re good to go\u003c/p\u003e\n",
      "content_text": "\nI just need to RDP into an Ubuntu box via Remmina and everytime I login I have\nto authenticate to create a color managed device... which I don't even know\nwhat that is!\n\n\nTo fix it?\n\n`vim /etc/polkit-1/localauthority.conf.d/02-allow-colord.conf`\n\n```\npolkit.addRule(function(action, subject) {\n if ((action.id == \"org.freedesktop.color-manager.create-device\" ||\n action.id == \"org.freedesktop.color-manager.create-profile\" ||\n action.id == \"org.freedesktop.color-manager.delete-device\" ||\n action.id == \"org.freedesktop.color-manager.delete-profile\" ||\n action.id == \"org.freedesktop.color-manager.modify-device\" ||\n action.id == \"org.freedesktop.color-manager.modify-profile\") \u0026\u0026\n subject.isInGroup(\"{users}\")) {\n return polkit.Result.YES;\n }\n });\n```\n\nGive'r the `:x`, logout, and you're good to go\n",
      "summary": "I just need to RDP into an Ubuntu box via Remmina and everytime I login I have to authenticate to create a color managed device... which I don't even know...",
      "date_published": "2022-07-18T00:00:00Z",
      "date_modified": "2022-07-18T00:00:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/zfs-permissions-for-sanoid/",
      "url": "https://pype.dev/zfs-permissions-for-sanoid/",
      "title": "ZFS Permissions for Sanoid/Syncoid",
      "content_html": "\u003cp\u003e\u003ccode\u003ezfs allow -u $USER clone,load-key,create,destroy,mount,mountpoint,receive,send,rollback,compression,snapshot,hold,keylocation,bookmark tank\u003c/code\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eload-key only needed if using encrypted datasets\u003c/p\u003e\n\u003c/blockquote\u003e\n",
      "content_text": "\n\n`zfs allow -u $USER clone,load-key,create,destroy,mount,mountpoint,receive,send,rollback,compression,snapshot,hold,keylocation,bookmark tank`\n\n\u003e load-key only needed if using encrypted datasets\n",
      "date_published": "2022-07-08T15:54:58Z",
      "date_modified": "2022-07-08T15:54:58Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "zfs",
        "homelab",
        "cli",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/setup-kvm-to-boot-from-local-pxe-server/",
      "url": "https://pype.dev/setup-kvm-to-boot-from-local-pxe-server/",
      "title": "Setup KVM to boot from local PXE server",
      "content_html": "\u003cp\u003eAssuming you have a PXE server running you only need small edits to the virt-manager config\u003c/p\u003e\n",
      "content_text": "\nAssuming you have a PXE server running you only need small edits to the virt-manager config\n",
      "summary": "Assuming you have a PXE server running you only need small edits to the virt-manager config",
      "date_published": "2022-07-06T12:30:50Z",
      "date_modified": "2022-07-06T12:30:50Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/self-hosted-docker-registry-with-proxy-pull-through/",
      "url": "https://pype.dev/self-hosted-docker-registry-with-proxy-pull-through/",
      "title": "Self-hosted Docker registry with proxy pull through",
      "content_html": "\u003cp\u003eI decided that I want to self-host all my docker images for the purposes of\nregularly rebuilding and security scanning. The first step is to set up a\nregistry, which coincidently enough you can do with a Docker container 😛!\u003c/p\u003e\n\u003cp\u003eInstructions for setting up the proxy are on the offidical docker docs \u003ca href=\"https://docs.docker.com/registry/recipes/mirror/\"\u003ehere\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"deployment\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eDeployment\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eI chose to deploy with Portainer because I already use it for monitoring all my\ndocker containers. I deploy most container with Ansible but use Portainer to\nsetup a few more adhoc or non-git driven applications.\u003c/p\u003e\n",
      "content_text": "\nI decided that I want to self-host all my docker images for the purposes of\nregularly rebuilding and security scanning. The first step is to set up a\nregistry, which coincidently enough you can do with a Docker container 😛!\n\nInstructions for setting up the proxy are on the offidical docker docs [here](https://docs.docker.com/registry/recipes/mirror/)\n\n# Deployment\n\nI chose to deploy with Portainer because I already use it for monitoring all my\ndocker containers. I deploy most container with Ansible but use Portainer to\nsetup a few more adhoc or non-git driven applications.\n",
      "summary": "I decided that I want to self-host all my docker images for the purposes of regularly rebuilding and security scanning. The first step is to set up a...",
      "date_published": "2022-07-06T06:44:35Z",
      "date_modified": "2022-07-06T06:44:35Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "zfs",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/kvm-network-interface-via-nat-ubuntu-20/",
      "url": "https://pype.dev/kvm-network-interface-via-nat-ubuntu-20/",
      "title": "kvm-network-interface-via-nat-ubuntu-20",
      "content_html": "\u003cp\u003eI have started using VMs more and more in my development workflow and it\u0026rsquo;s\nimpossible to work in a VM without an internet connection for me most of the\ntime. Setting up the KVM networking is kind of confusing to me and I\u0026rsquo;ve done it\ntwo different ways. Here is how I set it up on my home desktop using NAT.\u003c/p\u003e\n\u003ch1 id=\"credit\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eCredit\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eFirst thing\u0026rsquo;s first: \u003ca href=\"https://computingforgeeks.com/managing-kvm-network-interfaces-in-linux/\"\u003ecredit to this post\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"commands\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eCommands\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eThere was a \u003ccode\u003edefault\u003c/code\u003e network already made by virt-manager but my VM couldn\u0026rsquo;t connect over it at all\u0026hellip;\u003c/p\u003e\n\u003cp\u003eThese commands got me up and running without even turning the VM off\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI went full on \u003ccode\u003esudo -i\u003c/code\u003e for this just to make it easier - be careful\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"dump-an-existint-network-config\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eDump an existint network config\u003c/span\u003e \u003ca href=\"#dump-an-existint-network-config\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# as root\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003evirsh net-dumpxml default \u0026gt; br1.xml\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003evim br1.xml\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"edit-it\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eEdit it\u003c/span\u003e \u003ca href=\"#edit-it\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI was unsure what the ip range should be so I just stuck with the original blog.\nThe \u003ccode\u003edefault\u003c/code\u003e network had the CIDR block defined as \u003ccode\u003e192.168.122.0/24\u003c/code\u003e which is different from my home network so I guess it\u0026rsquo;s fine?\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;network\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;name\u0026gt;\u003c/span\u003ebr1\u003cspan class=\"nt\"\u003e\u0026lt;/name\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;forward\u003c/span\u003e \u003cspan class=\"na\"\u003emode=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#39;nat\u0026#39;\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;nat\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nt\"\u003e\u0026lt;port\u003c/span\u003e \u003cspan class=\"na\"\u003estart=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#39;1024\u0026#39;\u003c/span\u003e \u003cspan class=\"na\"\u003eend=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#39;65535\u0026#39;\u003c/span\u003e\u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;/nat\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/forward\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;bridge\u003c/span\u003e \u003cspan class=\"na\"\u003ename=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#39;br1\u0026#39;\u003c/span\u003e \u003cspan class=\"na\"\u003estp=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#39;on\u0026#39;\u003c/span\u003e \u003cspan class=\"na\"\u003edelay=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#39;0\u0026#39;\u003c/span\u003e\u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;ip\u003c/span\u003e \u003cspan class=\"na\"\u003eaddress=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#39;192.168.10.1\u0026#39;\u003c/span\u003e \u003cspan class=\"na\"\u003enetmask=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#39;255.255.255.0\u0026#39;\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;dhcp\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nt\"\u003e\u0026lt;range\u003c/span\u003e \u003cspan class=\"na\"\u003estart=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#39;192.168.10.10\u0026#39;\u003c/span\u003e \u003cspan class=\"na\"\u003eend=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#39;192.168.10.100\u0026#39;\u003c/span\u003e\u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;/dhcp\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/ip\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/network\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"define-a-network\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eDefine a network\u003c/span\u003e \u003ca href=\"#define-a-network\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003evirsh net-define br1.xml\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003evirsh net-autostart br1\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThen to check\u0026hellip;\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003evirsh net-list --all\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e Name      State    Autostart   Persistent\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--------------------------------------------\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e br1       active   yes         yes\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e default   active   yes         yes\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"uuid\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eUUID\u003c/span\u003e \u003ca href=\"#uuid\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003evirsh net-uuid br1\u003c/code\u003e\u003c/p\u003e\n\u003ch2 id=\"magic\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eMagic\u003c/span\u003e \u003ca href=\"#magic\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003evirsh attach-interface --domain \u0026lt;NAME OF VM\u0026gt; --type bridge --source br1 --model virtio --config --live\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eMy VM, \u003ccode\u003eubuntu20.04\u003c/code\u003e was running and immediately connected to the newly attached device!\u003c/p\u003e\n\u003ch1 id=\"credit-again\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eCredit again\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eVisit the original post for more details - this serves more as as a quicker set of notes for future me\u003c/p\u003e\n",
      "content_text": "\nI have started using VMs more and more in my development workflow and it's\nimpossible to work in a VM without an internet connection for me most of the\ntime. Setting up the KVM networking is kind of confusing to me and I've done it\ntwo different ways. Here is how I set it up on my home desktop using NAT.\n\n# Credit\n\nFirst thing's first: [credit to this post](https://computingforgeeks.com/managing-kvm-network-interfaces-in-linux/)\n\n# Commands\n\nThere was a `default` network already made by virt-manager but my VM couldn't connect over it at all...\n\nThese commands got me up and running without even turning the VM off\n\n\u003e I went full on `sudo -i` for this just to make it easier - be careful\n\n## Dump an existint network config\n\n```bash\n# as root\n\nvirsh net-dumpxml default \u003e br1.xml\n\nvim br1.xml\n\n```\n\n## Edit it\n\nI was unsure what the ip range should be so I just stuck with the original blog. \nThe `default` network had the CIDR block defined as `192.168.122.0/24` which is different from my home network so I guess it's fine?\n\n```xml\n\u003cnetwork\u003e\n  \u003cname\u003ebr1\u003c/name\u003e\n  \u003cforward mode='nat'\u003e\n    \u003cnat\u003e\n      \u003cport start='1024' end='65535'/\u003e\n    \u003c/nat\u003e\n  \u003c/forward\u003e\n  \u003cbridge name='br1' stp='on' delay='0'/\u003e\n  \u003cip address='192.168.10.1' netmask='255.255.255.0'\u003e\n    \u003cdhcp\u003e\n      \u003crange start='192.168.10.10' end='192.168.10.100'/\u003e\n    \u003c/dhcp\u003e\n  \u003c/ip\u003e\n\u003c/network\u003e\n```\n\n## Define a network\n\n```bash\nvirsh net-define br1.xml\nvirsh net-autostart br1\n```\n\nThen to check...\n\n```bash\nvirsh net-list --all\n\n Name      State    Autostart   Persistent\n--------------------------------------------\n br1       active   yes         yes\n default   active   yes         yes\n```\n\n## UUID\n\n`virsh net-uuid br1`\n\n\n## Magic\n\n`virsh attach-interface --domain \u003cNAME OF VM\u003e --type bridge --source br1 --model virtio --config --live`\n\nMy VM, `ubuntu20.04` was running and immediately connected to the newly attached device!\n\n\n# Credit again\n\nVisit the original post for more details - this serves more as as a quicker set of notes for future me\n\n",
      "summary": "I have started using VMs more and more in my development workflow and it's impossible to work in a VM without an internet connection for me most of the time....",
      "date_published": "2022-06-25T07:20:41Z",
      "date_modified": "2022-06-25T07:20:41Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/reset-ssh-key-passphrase/",
      "url": "https://pype.dev/reset-ssh-key-passphrase/",
      "title": "Reset SSH key passphrase",
      "content_html": "\u003cp\u003eI got into a pickle where I encrypted the ssh keys I use for my SSH connections on LAN, but then I couldn\u0026rsquo;t run my ansible playbook on my server! ssh-keygen -p and leave the new passphrase blank saved my day (although password protected key files are safer!)\u003c/p\u003e\n\u003ch1 id=\"tl-dr-just-reset-it-to-nothing\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eTL;DR - just reset it to nothing\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003e\u003ccode\u003essh-keygen -p\u003c/code\u003e will let you reset the passphrase on your ssh keys (good for you! yay security!)\u003c/p\u003e\n\u003cp\u003eBut I needed to remove the passphrase to quickly deploy an ansible playbook 🤓\u003c/p\u003e\n",
      "content_text": "\nI got into a pickle where I encrypted the ssh keys I use for my SSH connections on LAN, but then I couldn't run my ansible playbook on my server! ssh-keygen -p and leave the new passphrase blank saved my day (although password protected key files are safer!)\n\n# TL;DR - just reset it to nothing\n\n`ssh-keygen -p` will let you reset the passphrase on your ssh keys (good for you! yay security!)\n\nBut I needed to remove the passphrase to quickly deploy an ansible playbook 🤓\n",
      "summary": "I got into a pickle where I encrypted the ssh keys I use for my SSH connections on LAN, but then I couldn't run my ansible playbook on my server! ssh-keygen...",
      "date_published": "2022-06-13T06:55:32Z",
      "date_modified": "2022-06-13T06:55:32Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "cli",
        "linux",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/samba-on-ubuntu-22-needs-inherit-permissions-set/",
      "url": "https://pype.dev/samba-on-ubuntu-22-needs-inherit-permissions-set/",
      "title": "Samba on Ubuntu 22 needs “inherit permissions” set",
      "content_html": "\u003cp\u003esee samba config on hogwarts\u003c/p\u003e\n",
      "content_text": "\nsee samba config on hogwarts\n",
      "summary": "see samba config on hogwarts",
      "date_published": "2022-05-31T06:30:42Z",
      "date_modified": "2022-05-31T06:30:42Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/reindex-nextcloud-after-adding-data-via-cli/",
      "url": "https://pype.dev/reindex-nextcloud-after-adding-data-via-cli/",
      "title": "Reindex Nextcloud After Adding Data via CLI",
      "content_html": "\u003ch1 id=\"my-nextcloud-woes\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eMy Nextcloud woes\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eI wrote \u003ca href=\"%22nextcloud-permissions-with-zfs-and-ansible-nas%22\"\u003ehere\u003c/a\u003e about setting\nup \u003ccode\u003ewww-data\u003c/code\u003e as the owner of any directories you want nextcloud to manage.\nHowever, I regularly struggle wtih permissions issues on my NAS because of the\nexternal storage app anyways so I\u0026rsquo;ve decided to just put our photos in the spot\nNextcloud would otherwise put them, and use this as healthy pressure on our\nfamily to organize our photos and put the ones we care about with the rest of\nour family media.\u003c/p\u003e\n\u003ch1 id=\"migration\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eMigration\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eBecause I had a ton of photos on the NAS anyways that I wanted moved over to\nNextcloud I just rsync\u0026rsquo;d the photos directory on my NAS to the user\u0026rsquo;s photos\ndirectory in nextcloud but they weren\u0026rsquo;t showing up in the web UI!\u003c/p\u003e\n\u003ch1 id=\"the-fix\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eThe Fix?\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eAs www-data I needed to \u003ccode\u003ephp /var/www/nextcloud/occ files:scan --all\u003c/code\u003e inside my\nnextcloud docker container AFTER moving a bunch of photos off my \u0026ldquo;NAS\u0026rdquo; into the\nfolder mounted to the nextcloud container as its data folder! Before I did this\nthey weren\u0026rsquo;t showing up in the web UI/\u003c/p\u003e\n",
      "content_text": "\n# My Nextcloud woes\n\nI wrote [here](\"nextcloud-permissions-with-zfs-and-ansible-nas\") about setting\nup `www-data` as the owner of any directories you want nextcloud to manage.\nHowever, I regularly struggle wtih permissions issues on my NAS because of the\nexternal storage app anyways so I've decided to just put our photos in the spot\nNextcloud would otherwise put them, and use this as healthy pressure on our\nfamily to organize our photos and put the ones we care about with the rest of\nour family media.\n\n# Migration\n\nBecause I had a ton of photos on the NAS anyways that I wanted moved over to\nNextcloud I just rsync'd the photos directory on my NAS to the user's photos\ndirectory in nextcloud but they weren't showing up in the web UI!\n\n# The Fix?\n\nAs www-data I needed to `php /var/www/nextcloud/occ files:scan --all` inside my\nnextcloud docker container AFTER moving a bunch of photos off my \"NAS\" into the\nfolder mounted to the nextcloud container as its data folder! Before I did this\nthey weren't showing up in the web UI/\n",
      "summary": "I wrote here about setting up as the owner of any directories you want nextcloud to manage. However, I regularly struggle wtih permissions issues on my NAS...",
      "date_published": "2022-05-29T15:34:33Z",
      "date_modified": "2022-05-29T15:34:33Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/arr-download-client-config/",
      "url": "https://pype.dev/arr-download-client-config/",
      "title": "arr client config",
      "content_html": "\u003cp\u003eTIL that when setting up download clients for\nradarr/sonarr/lidarr/readarr/bazarr/prowlarr that you can utilize internal DNS\nand instead of hardcoding an IP address of your download client server, can use\njust the CNAME record (ie. instead of 172.10.14.13 I can use\ntransmission.mydomain.com\u0026hellip; notice the lact of http(s)://\u0026hellip; adding that won\u0026rsquo;t\nallow the connection to work/\u003c/p\u003e\n\u003cp\u003eFurthermore, you can use internal DNS to lookup the domain, not the subdomain,\nand expose the port, like \u003ccode\u003emydomain.com:7878\u003c/code\u003e for sonarr. This was simpler to\nmaintain because I don\u0026rsquo;t change which ports an application exposes or utilizes\nhardly ever, plus I don\u0026rsquo;t need to maintain CNAME records for every service!\u003c/p\u003e\n",
      "content_text": "\nTIL that when setting up download clients for\nradarr/sonarr/lidarr/readarr/bazarr/prowlarr that you can utilize internal DNS\nand instead of hardcoding an IP address of your download client server, can use\njust the CNAME record (ie. instead of 172.10.14.13 I can use\ntransmission.mydomain.com... notice the lact of http(s)://... adding that won't\nallow the connection to work/\n\nFurthermore, you can use internal DNS to lookup the domain, not the subdomain,\nand expose the port, like `mydomain.com:7878` for sonarr. This was simpler to\nmaintain because I don't change which ports an application exposes or utilizes\nhardly ever, plus I don't need to maintain CNAME records for every service!\n",
      "summary": "TIL that when setting up download clients for radarr/sonarr/lidarr/readarr/bazarr/prowlarr that you can utilize internal DNS and instead of hardcoding an IP...",
      "date_published": "2022-05-28T13:29:28Z",
      "date_modified": "2022-05-28T13:29:28Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/add-space-to-your-lvm-on-ubuntu/",
      "url": "https://pype.dev/add-space-to-your-lvm-on-ubuntu/",
      "title": "Add space to your LVM on Ubuntu",
      "content_html": "\u003cp\u003eI ran out of space on the SSD in my server when doing some file transfers but only 100GB was used of a 256 GB SSD?\u003c/p\u003e\n\u003ch1 id=\"lvm\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eLVM\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eWhen installing Ubuntu live server the default option for how to partition the\ndisk (in my experience) has been to setup an LVM group that defaults to less\nthan the available space. Most recently I put Ubuntu server on a 256 GB SSD but\nthe main partition was formatted as an LVM group with 100GB of storage\u0026hellip; I\ndidn\u0026rsquo;t think anything of this even though I\u0026rsquo;m mostly used to EXT4.\u003c/p\u003e\n\u003cp\u003eI think the reason for LVMs is performance, but in hindsight, I don\u0026rsquo;t really\ncare much about the performance differences, I really just want all my storage\nthat\u0026rsquo;s fast enough\u003c/p\u003e\n\u003ch1 id=\"extending-the-lvm\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eExtending the LVM\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eA moment of googling brought me to Ubuntu\u0026rsquo;s wiki and I\nlearned that I can expand my LVM to the space I need\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003esudo lvdisplay\u003c/code\u003e and \u003ccode\u003esudo pvdisplay\u003c/code\u003e show detailed views of the logical volumes and physical volumes respectively.\u003c/p\u003e\n\u003cp\u003eTake a look at those and find the volume you need to extend. For me I found this:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --- Logical volume ---\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  LV Path                /dev/ubuntu-vg/ubuntu-lv\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  LV Name                ubuntu-lv\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  VG Name                ubuntu-vg\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  LV Write Access        read/write\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  LV Status              available\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  ...\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eThere\u0026rsquo;s more that you\u0026rsquo;ll see but this is what\u0026rsquo;s relevant - I need to extend the\n\u003ccode\u003eubuntu-lv\u003c/code\u003e logical volume in the \u003ccode\u003eubuntu-vg\u003c/code\u003e volume group.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003esudo lvextend -L +50g ubuntu-vg/ubuntu-lv\u003c/code\u003e gives me 50 more GB of storage which should be enough for at least tonight 🤓\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://wiki.ubuntu.com/Lvm\"\u003eRTFM\u003c/a\u003e\u003c/p\u003e\n",
      "content_text": "\nI ran out of space on the SSD in my server when doing some file transfers but only 100GB was used of a 256 GB SSD?\n\n# LVM\n\nWhen installing Ubuntu live server the default option for how to partition the\ndisk (in my experience) has been to setup an LVM group that defaults to less\nthan the available space. Most recently I put Ubuntu server on a 256 GB SSD but\nthe main partition was formatted as an LVM group with 100GB of storage... I\ndidn't think anything of this even though I'm mostly used to EXT4.\n\nI think the reason for LVMs is performance, but in hindsight, I don't really\ncare much about the performance differences, I really just want all my storage\nthat's fast enough\n\n# Extending the LVM\n\nA moment of googling brought me to Ubuntu's wiki and I\nlearned that I can expand my LVM to the space I need...\n\n`sudo lvdisplay` and `sudo pvdisplay` show detailed views of the logical volumes and physical volumes respectively.\n\nTake a look at those and find the volume you need to extend. For me I found this:\n\n```bash\n  --- Logical volume ---\n  LV Path                /dev/ubuntu-vg/ubuntu-lv\n  LV Name                ubuntu-lv\n  VG Name                ubuntu-vg\n  LV Write Access        read/write\n  LV Status              available\n  ...\n```\n\nThere's more that you'll see but this is what's relevant - I need to extend the\n`ubuntu-lv` logical volume in the `ubuntu-vg` volume group.\n\n`sudo lvextend -L +50g ubuntu-vg/ubuntu-lv` gives me 50 more GB of storage which should be enough for at least tonight 🤓\n\n[RTFM](https://wiki.ubuntu.com/Lvm)\n",
      "summary": "I ran out of space on the SSD in my server when doing some file transfers but only 100GB was used of a 256 GB SSD?",
      "date_published": "2022-05-26T21:33:55Z",
      "date_modified": "2022-05-26T21:33:55Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/tdarr-worker-nodes-share-the-cache/",
      "url": "https://pype.dev/tdarr-worker-nodes-share-the-cache/",
      "title": "Tdarr worker nodes share the cache!",
      "content_html": "\u003cp\u003eWhen working with tdarr remote nodes, they need to have access not only to the\nsame libraries but also the same transcode cache as the server otherwise the\ntranscodes will fail\u0026hellip;\u003c/p\u003e\n\u003ch1 id=\"network-setup\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eNetwork Setup\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eTo explain I\u0026rsquo;ll give a brief overview of my home setup\u003c/p\u003e\n\u003cp\u003eI have an old Dell PowerEdge R610 as my main server running a live server distribution of Ubuntu.\nI use ZFS for my NAS file system, and most of my datasets are accesible over my home network.\nI have a Tdarr server running in a docker container on the R610.\u003c/p\u003e\n\u003cp\u003eIn my office I dailyi drive a gaming desktop with an Nvidia 2060 Super running Ubuntu as well.\nOn that desktop I am running a Tdarr node in a docker container.\nThe container has access to the network folders with my media.\u003c/p\u003e\n\u003ch1 id=\"initial-magic\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eInitial Magic\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eWhen I spun up  a tdarr node on my desktop, the tdarr server running on my R610 automatically registered the node, which was freaking amazing.\nThat magic though spoiled me and I thought that I didn\u0026rsquo;t need to read the rest of the docs\u0026hellip;\u003c/p\u003e\n\u003ch1 id=\"initial-fail\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eInitial Fail\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eI setup a transcode cache directory on the R610 locally and a separate transcode cache on my desktop that the remote tdarr node would use.\nHaving them separated led to 2 main issues:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eTranscodes were not being migrated back to my library properly\u003c/li\u003e\n\u003cli\u003eI was running out of disk space on my desktop because tdarr wasn\u0026rsquo;t deleting the completed cache files properly.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1 id=\"the-fix\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eThe Fix\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eMake a transcode cache directory accessible on my network, and give access to that directory to the docker container running my remote tdarr node.\u003c/p\u003e\n",
      "content_text": "\nWhen working with tdarr remote nodes, they need to have access not only to the\nsame libraries but also the same transcode cache as the server otherwise the\ntranscodes will fail...\n\n# Network Setup\n\nTo explain I'll give a brief overview of my home setup  \n\nI have an old Dell PowerEdge R610 as my main server running a live server distribution of Ubuntu.\nI use ZFS for my NAS file system, and most of my datasets are accesible over my home network.\nI have a Tdarr server running in a docker container on the R610.\n\nIn my office I dailyi drive a gaming desktop with an Nvidia 2060 Super running Ubuntu as well.\nOn that desktop I am running a Tdarr node in a docker container. \nThe container has access to the network folders with my media. \n\n# Initial Magic \n\nWhen I spun up  a tdarr node on my desktop, the tdarr server running on my R610 automatically registered the node, which was freaking amazing.\nThat magic though spoiled me and I thought that I didn't need to read the rest of the docs...\n\n# Initial Fail \n\nI setup a transcode cache directory on the R610 locally and a separate transcode cache on my desktop that the remote tdarr node would use.\nHaving them separated led to 2 main issues:\n1. Transcodes were not being migrated back to my library properly\n2. I was running out of disk space on my desktop because tdarr wasn't deleting the completed cache files properly.\n\n# The Fix\n\nMake a transcode cache directory accessible on my network, and give access to that directory to the docker container running my remote tdarr node.\n\n\n\n",
      "summary": "When working with tdarr remote nodes, they need to have access not only to the same libraries but also the same transcode cache as the server otherwise the...",
      "date_published": "2022-05-25T06:36:59Z",
      "date_modified": "2022-05-25T06:36:59Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/local-dns-with-pi-hole/",
      "url": "https://pype.dev/local-dns-with-pi-hole/",
      "title": "Local DNS with Pi-hole",
      "content_html": "\u003ch2 id=\"spoilers\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eSpoilers\u003c/span\u003e \u003ca href=\"#spoilers\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTailscale is way easier than this\u0026hellip; I was doing this local DNS overwrite in\nPi-hole before running tailscale and I haven\u0026rsquo;t just totally \u0026ldquo;kicked the habit\u0026rdquo;\nyet, so for anyone NOT running tailcale, but wanting local HTTPS and using\nPi-Hole this method would work fine\u003c/p\u003e\n\u003ch2 id=\"intro\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eIntro\u003c/span\u003e \u003ca href=\"#intro\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI use \u003ca href=\"https://pi-hole.net/\"\u003epihole\u003c/a\u003e as my DNS server at home. I run unbound as\nwell and have a pretty standard setup from their docs.\u003c/p\u003e\n\u003cp\u003ePi-hole does 2 primary things for me:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003edns sink-hold, the primary use case I believe\u003c/li\u003e\n\u003cli\u003elocal SSL for all my self-hosted apps\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"caveat\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eCaveat\u003c/span\u003e \u003ca href=\"#caveat\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI know for sure there are better ways to do this, but there\u0026rsquo;s also worse\nones\u0026hellip; so for now this has been my pattern, and it\u0026rsquo;s only bitten me in the\nbutt when I\u0026rsquo;ve forgotten to add the final CNAME record\u0026hellip; which\u0026rsquo;ll make sense\nin a sec.\u003c/p\u003e\n\u003ch2 id=\"process\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eProcess\u003c/span\u003e \u003ca href=\"#process\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIt\u0026rsquo;s really quite simple - in pihole I have a DNS record for my domain pointing\nto my primary server\u003c/p\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250706114501_8c34a31e.png\" alt=\"20250706114501_8c34a31e.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003eThen for each service that I want to keep everything resolved locally for I add a CNAME\u003c/p\u003e\n\u003cfigure\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250706114557_916fb4c4.png\" alt=\"20250706114557_916fb4c4.png\"\u003e\n\u003c/figure\u003e\n\u003cp\u003eWith DNS resolving this way for clients using my pihole, the networking all\nstays local and I still get HTTPS for my wildcard cert in cloudflare\u003c/p\u003e\n\u003ch2 id=\"why\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eWhy?\u003c/span\u003e \u003ca href=\"#why\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe reasons I do this are simple:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eI\u0026rsquo;ve been doing it since I started homelabbing and it started out of misunderstanding of how networking works \u003cem\u003eat all\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eI use a home dashboard with https:// links, and it\u0026rsquo;s nice to just use that\nsame dashbaord publically or at home. With local DNS resolution then I can\nwhitelist some services, but conveniently access over the public url with https\nbut routing such that my whitelist let\u0026rsquo;s me in when it wouldn\u0026rsquo;t if I tried to\naccess the service from an external client\u003c/li\u003e\n\u003cli\u003eit\u0026rsquo;s my homelab - I can do what I want\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"it-s-too-complicated\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eIt’s too complicated\u003c/span\u003e \u003ca href=\"#it-s-too-complicated\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHonestly, as simple as this is, it is tedious and kind of complicated\u0026hellip;\nThere\u0026rsquo;s options to make it better\u0026hellip;\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003escript any service deployment to update the pihole /etc/host file\u003c/li\u003e\n\u003cli\u003ejust use tailscale\u0026hellip;\u003c/li\u003e\n\u003c/ol\u003e\n",
      "content_text": "\n## Spoilers\n\nTailscale is way easier than this... I was doing this local DNS overwrite in\nPi-hole before running tailscale and I haven't just totally \"kicked the habit\"\nyet, so for anyone NOT running tailcale, but wanting local HTTPS and using\nPi-Hole this method would work fine\n\n## Intro\n\nI use [pihole](https://pi-hole.net/) as my DNS server at home. I run unbound as\nwell and have a pretty standard setup from their docs.\n\nPi-hole does 2 primary things for me:\n\n1. dns sink-hold, the primary use case I believe\n2. local SSL for all my self-hosted apps\n\n## Caveat\n\nI know for sure there are better ways to do this, but there's also worse\nones... so for now this has been my pattern, and it's only bitten me in the\nbutt when I've forgotten to add the final CNAME record... which'll make sense\nin a sec.\n\n## Process\n\nIt's really quite simple - in pihole I have a DNS record for my domain pointing\nto my primary server\n\n![20250706114501_8c34a31e.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250706114501_8c34a31e.png)\n\nThen for each service that I want to keep everything resolved locally for I add a CNAME\n\n![20250706114557_916fb4c4.png](https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/20250706114557_916fb4c4.png)\n\nWith DNS resolving this way for clients using my pihole, the networking all\nstays local and I still get HTTPS for my wildcard cert in cloudflare\n\n## Why?\n\nThe reasons I do this are simple:\n\n1. I've been doing it since I started homelabbing and it started out of misunderstanding of how networking works _at all_\n2. I use a home dashboard with https:// links, and it's nice to just use that\n   same dashbaord publically or at home. With local DNS resolution then I can\n   whitelist some services, but conveniently access over the public url with https\n   but routing such that my whitelist let's me in when it wouldn't if I tried to\n   access the service from an external client\n3. it's my homelab - I can do what I want\n\n## It's too complicated\n\nHonestly, as simple as this is, it is tedious and kind of complicated...\nThere's options to make it better...\n\n1. script any service deployment to update the pihole /etc/host file\n2. just use tailscale...\n",
      "summary": "Tailscale is way easier than this... I was doing this local DNS overwrite in Pi-hole before running tailscale and I haven't just totally \"kicked the habit\"...",
      "date_published": "2022-05-23T09:40:59Z",
      "date_modified": "2022-05-23T09:40:59Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/configure-bridge-network-on-ubuntu-22-04-with-netplan/",
      "url": "https://pype.dev/configure-bridge-network-on-ubuntu-22-04-with-netplan/",
      "title": "Configure bridge network on Ubuntu 22.04 with Netplan",
      "content_html": "\u003cp\u003eSee 02-\u0026hellip;.yaml in ansible-nas\u003c/p\u003e\n",
      "content_text": "\nSee 02-....yaml in ansible-nas\n",
      "summary": "See 02-....yaml in ansible-nas",
      "date_published": "2022-05-22T14:55:28Z",
      "date_modified": "2022-05-22T14:55:28Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/netplan-change-from-focal-to-jammy/",
      "url": "https://pype.dev/netplan-change-from-focal-to-jammy/",
      "title": "Netplan change from Focal to Jammy",
      "content_html": "\u003cp\u003eI am revamping my home server and bumped myself early up to Jammy Jellyfish\u0026hellip;\nhowever to my peril I reused my netplan config and after hitting my server with\nthe \u0026lsquo;ol \u003ccode\u003enetplan apply\u003c/code\u003e I lost connection\u0026hellip;\nDNS still seemed to kinda work externally, but internally nothing was up\u0026hellip;\u003c/p\u003e\n\u003cp\u003eTurns out Netplan got a little change in how to express the \u003ccode\u003egateway\u003c/code\u003e key in the netplan config!\u003c/p\u003e\n\u003cp\u003eOld Ubuntu 20.04 way\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003enetwork\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eversion\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eethernets\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eenp0s4\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eaddresses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e192.168.1\u003c/span\u003e\u003cspan class=\"l\"\u003e.{Static IP}/24]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003egateway4\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e192.168.1.1\u003c/span\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e# \u0026lt;-- This changes!\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003enameservers\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eaddresses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e192.168.1.1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1.1.1.1\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eNew jammin way for Jammy Jellyfish (\u003cstrong\u003eat least that worked for me\u003c/strong\u003e)\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003enetwork\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eversion\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eethernets\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eenp0s4\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eaddresses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e192.168.1\u003c/span\u003e\u003cspan class=\"l\"\u003e.{Static IP}/24]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eroutes\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e- \u003cspan class=\"nt\"\u003eto\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003edefault\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003evia\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e192.168.1.1\u003c/span\u003e\u003cspan class=\"w\"\u003e \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003enameservers\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eaddresses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e192.168.1.1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1.1.1.1\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e",
      "content_text": "\nI am revamping my home server and bumped myself early up to Jammy Jellyfish...\nhowever to my peril I reused my netplan config and after hitting my server with\nthe 'ol `netplan apply` I lost connection...\nDNS still seemed to kinda work externally, but internally nothing was up... \n\nTurns out Netplan got a little change in how to express the `gateway` key in the netplan config!\n\nOld Ubuntu 20.04 way\n\n```yaml\nnetwork:\n  version: 2\n  ethernets:\n    enp0s4:\n      addresses: [192.168.1.{Static IP}/24]\n      gateway4: 192.168.1.1  # \u003c-- This changes!\n      nameservers:\n        addresses: [192.168.1.1, 1.1.1.1]\n```\n\nNew jammin way for Jammy Jellyfish (__at least that worked for me__)\n```yaml\nnetwork:\n  version: 2\n  ethernets:\n    enp0s4:\n      addresses: [192.168.1.{Static IP}/24]\n      routes:\n        - to: default\n          via: 192.168.1.1 \n      nameservers:\n        addresses: [192.168.1.1, 1.1.1.1]\n```\n",
      "summary": "I am revamping my home server and bumped myself early up to Jammy Jellyfish... however to my peril I reused my netplan config and after hitting my server...",
      "date_published": "2022-05-22T13:23:17Z",
      "date_modified": "2022-05-22T13:23:17Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "linux",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/how-i-use-nextcloud-for-safe-central-storage/",
      "url": "https://pype.dev/how-i-use-nextcloud-for-safe-central-storage/",
      "title": "How I use Nextcloud for safe central storage",
      "content_html": "\u003col\u003e\n\u003cli\u003eSetup admin\u003c/li\u003e\n\u003cli\u003eExternal Storage extension\u003c/li\u003e\n\u003cli\u003eAdd my nas zfs dataset\u003c/li\u003e\n\u003cli\u003echown -R www-data:www-data on anything nextcloud uploads to.\u003c/li\u003e\n\u003c/ol\u003e\n",
      "content_text": "\n1. Setup admin\n2. External Storage extension\n3. Add my nas zfs dataset\n4. chown -R www-data:www-data on anything nextcloud uploads to.\n",
      "summary": "Setup admin 2. External Storage extension 3. Add my nas zfs dataset 4. chown -R www-data:www-data on anything nextcloud uploads to.",
      "date_published": "2022-05-19T21:17:42Z",
      "date_modified": "2022-05-19T21:17:42Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "zfs",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/nextcloud-permissions-with-zfs-and-ansible-nas/",
      "url": "https://pype.dev/nextcloud-permissions-with-zfs-and-ansible-nas/",
      "title": "Nextcloud permissions with ZFS and Ansible-NAS",
      "content_html": "\u003ch1 id=\"tl-dr\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eTL;DR\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eAs the nextcloud docs say\u0026hellip; if you want to write to an external volume that\nlocation has to be writeable by the user/group \u003ccode\u003ewww-data\u003c/code\u003e on the host system\u0026hellip;\nso if that makes sense to you then this TIL probably isn\u0026rsquo;t a ton of value.. if\nnot however, read on :)\u003c/p\u003e\n\u003ch1 id=\"case-study\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eCase Study\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eYou want to self-host your own cloud and use a smart file system for convenience\u0026hellip;\nNextcloud and ZFS are pretty common goto answers for each of those problems.\u003c/p\u003e\n\u003cp\u003eMy home NAS is built on ZFS and among other things I have a \u003ccode\u003ezpool\u003c/code\u003e named\n\u003ccode\u003etank\u003c/code\u003e and nested in there is a \u003ccode\u003etank/nas\u003c/code\u003e dataset with several child zfs\ndatasets under that.\u003c/p\u003e\n\u003cp\u003eI want to use nextcloud mainly for auto-uploading photos from my wife\u0026rsquo;s and my phones for automatic backups.\nThe issue is that the nextcloud application (I run in Docker) is fixed as the\n\u003ccode\u003ewww-data\u003c/code\u003e user and so any volume/folder that you want nextcloud to write to\nneeds to be permissioned such that \u003ccode\u003ewww-data\u003c/code\u003e owns it\u0026hellip; but I don\u0026rsquo;t want\n\u003ccode\u003ewww-data\u003c/code\u003e to own everything in my NAS\u0026hellip; so what\u0026rsquo;s a girl to do?\u003c/p\u003e\n\u003ch1 id=\"solution\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eSolution\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eWell, one way to go is to just utilize docker volumes, write the data in the\ncontainer to \u003ccode\u003e/var/www/html\u003c/code\u003e and let that be the place your data backsup to.\u003c/p\u003e\n\u003cp\u003eI still wanted nextcloud to automatically write right to my NAS so I created a\n\u003ccode\u003enextcloud-upload\u003c/code\u003e directory inside of \u003ccode\u003etank/nas/media/photos\u003c/code\u003e (photos cause\nthat\u0026rsquo;s all that gets automatically uploaded)\u003c/p\u003e\n\u003cp\u003eThen I \u003ccode\u003echown -R www-data:www-data /tank/nas/media/photos/nextcloud-upload\u003c/code\u003e so\nthat just that sub-folder is owned by \u003ccode\u003ewww-data\u003c/code\u003e. Now everyone\u0026rsquo;s happy!\u003c/p\u003e\n",
      "content_text": "\n# TL;DR\n\nAs the nextcloud docs say... if you want to write to an external volume that\nlocation has to be writeable by the user/group `www-data` on the host system...\nso if that makes sense to you then this TIL probably isn't a ton of value.. if\nnot however, read on :)\n\n\n\n# Case Study\n\nYou want to self-host your own cloud and use a smart file system for convenience...\nNextcloud and ZFS are pretty common goto answers for each of those problems.\n\nMy home NAS is built on ZFS and among other things I have a `zpool` named\n`tank` and nested in there is a `tank/nas` dataset with several child zfs\ndatasets under that.\n\nI want to use nextcloud mainly for auto-uploading photos from my wife's and my phones for automatic backups.\nThe issue is that the nextcloud application (I run in Docker) is fixed as the\n`www-data` user and so any volume/folder that you want nextcloud to write to\nneeds to be permissioned such that `www-data` owns it... but I don't want\n`www-data` to own everything in my NAS... so what's a girl to do?\n\n# Solution\n\nWell, one way to go is to just utilize docker volumes, write the data in the\ncontainer to `/var/www/html` and let that be the place your data backsup to.\n\nI still wanted nextcloud to automatically write right to my NAS so I created a\n`nextcloud-upload` directory inside of `tank/nas/media/photos` (photos cause\nthat's all that gets automatically uploaded)\n\nThen I `chown -R www-data:www-data /tank/nas/media/photos/nextcloud-upload` so\nthat just that sub-folder is owned by `www-data`. Now everyone's happy!\n\n\n\n",
      "summary": "As the nextcloud docs say... if you want to write to an external volume that location has to be writeable by the user/group on the host system... so if that...",
      "date_published": "2022-05-19T13:55:20Z",
      "date_modified": "2022-05-19T13:55:20Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "zfs",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/see-zfs-snapshot-disk-usage/",
      "url": "https://pype.dev/see-zfs-snapshot-disk-usage/",
      "title": "See ZFS snapshot disk usage",
      "content_html": "\u003cp\u003eAs I was cleaning up my NAS recently I noticed that I ran out of storage even\nthough my disk usage looked pretty low\u0026hellip; turns out I was keeping a mega-ton of\nZFS snapshots and due to my own ignorance at the time didn\u0026rsquo;t realize the\nstorage cost of this!\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ezfs list-o space tank/home\u003c/code\u003e will show the disk usage of the dataset and snapshots in \u003ccode\u003etank/home\u003c/code\u003e\u003c/p\u003e\n",
      "content_text": "\nAs I was cleaning up my NAS recently I noticed that I ran out of storage even\nthough my disk usage looked pretty low... turns out I was keeping a mega-ton of\nZFS snapshots and due to my own ignorance at the time didn't realize the\nstorage cost of this!\n\n`zfs list-o space tank/home` will show the disk usage of the dataset and snapshots in `tank/home`\n",
      "summary": "As I was cleaning up my NAS recently I noticed that I ran out of storage even though my disk usage looked pretty low... turns out I was keeping a mega-ton of...",
      "date_published": "2022-05-19T06:05:23Z",
      "date_modified": "2022-05-19T06:05:23Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "zfs",
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/remove-zfs-dataset-specific-snapshots/",
      "url": "https://pype.dev/remove-zfs-dataset-specific-snapshots/",
      "title": "Remove ZFS Dataset Specific Snapshots",
      "content_html": "\u003cp\u003eI started my homelab journey being super naive about ZFS and how to manage the\nfilesystem\u0026hellip; that bit me in the butt when transfering a ton of files out of\nfolders and into datasets because ZFS is copy on write so I was essentially\nduplicating my storage until I got a hair smarter about removing files after\nthey\u0026rsquo;re moved (rsync \u0026ndash;remove-source-file ftw). But I had a ton of snapshots of\nchild datasets with a ton of data that I just never will need, so I learned\n\u003ccode\u003ezfs list -H -o name -t snapshot tank/dataset1/dataset2\u003c/code\u003e will list just the\nsnapshots for dataset2 and if you pipe that into \u003ccode\u003exargs -n1 zfs destroy\u003c/code\u003e then\nyou have a way to clear out some snapshots you don\u0026rsquo;t need!\u003c/p\u003e\n",
      "content_text": "\nI started my homelab journey being super naive about ZFS and how to manage the\nfilesystem... that bit me in the butt when transfering a ton of files out of\nfolders and into datasets because ZFS is copy on write so I was essentially\nduplicating my storage until I got a hair smarter about removing files after\nthey're moved (rsync --remove-source-file ftw). But I had a ton of snapshots of\nchild datasets with a ton of data that I just never will need, so I learned\n`zfs list -H -o name -t snapshot tank/dataset1/dataset2` will list just the\nsnapshots for dataset2 and if you pipe that into `xargs -n1 zfs destroy` then\nyou have a way to clear out some snapshots you don't need!\n",
      "summary": "I started my homelab journey being super naive about ZFS and how to manage the filesystem... that bit me in the butt when transfering a ton of files out of...",
      "date_published": "2022-05-19T05:49:16Z",
      "date_modified": "2022-05-19T05:49:16Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "linux",
        "zfs",
        "cli",
        "bash",
        "homelab",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/jellyfin-media-players/",
      "url": "https://pype.dev/jellyfin-media-players/",
      "title": "Jellyfin-Media-Players",
      "content_html": "\u003cp\u003eI use Jellyfin at home for serving up most of our media - movies and shows etc.\u003c/p\u003e\n\u003cp\u003eMy dream is to have a GPU capable of transcoding any and all of our media for smooth playback on any device\u0026hellip;\nNow, I thought I\u0026rsquo;d have that by now with my Nvidia Quadro P400 however I have issues left and right with 4k content.\u003c/p\u003e\n\u003cp\u003eWhat can I do to still use Jellyfin but get smooth playback?\u003c/p\u003e\n\u003cp\u003eTHe first answer is figure out why I suck with GPUs, but pausing that there\u0026rsquo;s shorter solutions -\u0026gt; namely, use a media player that\u0026rsquo;s compatabile with the encoded content!\u003c/p\u003e\n\u003ch2 id=\"vlc\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eVLC\u003c/span\u003e \u003ca href=\"#vlc\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI\u0026rsquo;ll keep this one short - VLC is great and if you don\u0026rsquo;t need a netflix like experience, I\u0026rsquo;d recommend just using it to browse your network drives and play whatever you have\u003c/p\u003e\n\u003ch2 id=\"jellyfin-web-player\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eJellyfin Web Player\u003c/span\u003e \u003ca href=\"#jellyfin-web-player\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThis is the reason I\u0026rsquo;m writing this post\u0026hellip; the web player is great but not everything is supported on all devices\u003c/p\u003e\n\u003ch2 id=\"jellyfin-mpv-shim\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eJellyfin MPV Shim\u003c/span\u003e \u003ca href=\"#jellyfin-mpv-shim\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThis cross-platform cast client is my answer now.\nYou can find the project \u003ca href=\"https://github.com/jellyfin/jellyfin-mpv-shim/blob/master/README.md#linux-installation\"\u003ehere\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eThe installation instrauctions are super straightforward for Windows, Mac OS, or Linux.\u003c/p\u003e\n\u003cp\u003eI\u0026rsquo;m on Linux and so my install went like this:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt update\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install mpv \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003epipx install jellyfin-mpv-shim\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003epipx inject jellyfin-mpv-shim pystray\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e#profit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eI used \u003ccode\u003epipx\u003c/code\u003e to install the player as I prefer it for stand alone utilities over pip installing anything globally.\u003c/p\u003e\n\u003cp\u003eAfer that I just start the player at the terminal with \u003ccode\u003ejellyfin-mpv-shim\u003c/code\u003e\nThen in the web browser I can cast my content to the player and bypass the web player (and thus solve much of my transcoding issues) trivially!\u003c/p\u003e\n",
      "content_text": "\n\nI use Jellyfin at home for serving up most of our media - movies and shows etc.\n\nMy dream is to have a GPU capable of transcoding any and all of our media for smooth playback on any device...\nNow, I thought I'd have that by now with my Nvidia Quadro P400 however I have issues left and right with 4k content.\n\nWhat can I do to still use Jellyfin but get smooth playback?\n\nTHe first answer is figure out why I suck with GPUs, but pausing that there's shorter solutions -\u003e namely, use a media player that's compatabile with the encoded content!\n\n## VLC\n\nI'll keep this one short - VLC is great and if you don't need a netflix like experience, I'd recommend just using it to browse your network drives and play whatever you have\n\n## Jellyfin Web Player\n\nThis is the reason I'm writing this post... the web player is great but not everything is supported on all devices\n\n## Jellyfin MPV Shim\n\nThis cross-platform cast client is my answer now.\nYou can find the project [here](https://github.com/jellyfin/jellyfin-mpv-shim/blob/master/README.md#linux-installation)\n\nThe installation instrauctions are super straightforward for Windows, Mac OS, or Linux.\n\nI'm on Linux and so my install went like this:\n\n```bash\n\nsudo apt update\nsudo apt install mpv \n\npipx install jellyfin-mpv-shim\npipx inject jellyfin-mpv-shim pystray\n\n#profit\n\n```\n\nI used `pipx` to install the player as I prefer it for stand alone utilities over pip installing anything globally.\n\nAfer that I just start the player at the terminal with `jellyfin-mpv-shim`\nThen in the web browser I can cast my content to the player and bypass the web player (and thus solve much of my transcoding issues) trivially!\n",
      "summary": "I use Jellyfin at home for serving up most of our media - movies and shows etc.",
      "date_published": "2022-04-17T00:00:00Z",
      "date_modified": "2022-04-17T00:00:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/self-hosted-media/",
      "url": "https://pype.dev/self-hosted-media/",
      "title": "self-hosted-media",
      "content_html": "\u003cp\u003eSelf-hosting 1 or several media servers is another common homelab use-case.\nGetting content for your media servers is up to you, but I\u0026rsquo;ll show a few ways here to get content somewhat easily!\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eYouTube Disclaimer at Bottom\u003c/strong\u003e\u003c/p\u003e\n\u003ch2 id=\"you-get\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eyou-get\u003c/span\u003e \u003ca href=\"#you-get\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eyou-get\u003c/code\u003e is a nice cli for grabbing media content off the web.\u003c/p\u003e\n\u003ch3 id=\"installation\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eInstallation\u003c/span\u003e \u003ca href=\"#installation\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003epip install you-get\u003c/code\u003e or use ad-hoc with \u003ccode\u003epipx run you-get \u0026lt;url\u0026gt;\u003c/code\u003e\u003c/p\u003e\n\u003ch3 id=\"usage\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eUsage\u003c/span\u003e \u003ca href=\"#usage\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eFor example if I wanted to catch up on ancient Chinese military tactics I may go for \u003ccode\u003eThe Art of War\u003c/code\u003e off the Internet Archive\u0026hellip;\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esandbox  🌱 main 🗑️  ×3🛤️  ×6via 🐍 v3.8.11 \u003cspan class=\"o\"\u003e(\u003c/span\u003esandbox\u003cspan class=\"o\"\u003e)\u003c/span\u003e  took 15s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e❯ you-get https://archive.org/details/art_of_war_librivox -i\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eSite:       Archive.org\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eTitle:      The Art of War : Sun Tzu : Free Download, Borrow, and Streaming : Internet Archive\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eType:       MP3 \u003cspan class=\"o\"\u003e(\u003c/span\u003eaudio/mpeg\u003cspan class=\"o\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eSize:       3.87 MiB \u003cspan class=\"o\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e4055167\u003c/span\u003e Bytes\u003cspan class=\"o\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003ethe \u003ccode\u003e-i\u003c/code\u003e is showing me the info of what would be downloaded without the flag (it\u0026rsquo;s like a dry run)\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esandbox  🌱 main 🗑️  ×3🛤️  ×6via 🐍 v3.8.11 \u003cspan class=\"o\"\u003e(\u003c/span\u003esandbox\u003cspan class=\"o\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e❯ you-get https://archive.org/details/art_of_war_librivox\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eSite:       Archive.org\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eTitle:      The Art of War : Sun Tzu : Free Download, Borrow, and Streaming : Internet Archive\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eType:       MP3 \u003cspan class=\"o\"\u003e(\u003c/span\u003eaudio/mpeg\u003cspan class=\"o\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eSize:       3.87 MiB \u003cspan class=\"o\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e4055167\u003c/span\u003e Bytes\u003cspan class=\"o\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eDownloading The Art of War : Sun Tzu : Free Download, Borrow, and Streaming : Internet Archi.mp3 ...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 100% \u003cspan class=\"o\"\u003e(\u003c/span\u003e  3.9/  3.9MB\u003cspan class=\"o\"\u003e)\u003c/span\u003e ├████████████████████████████████████████████████████████████┤\u003cspan class=\"o\"\u003e[\u003c/span\u003e1/1\u003cspan class=\"o\"\u003e]\u003c/span\u003e  \u003cspan class=\"m\"\u003e917\u003c/span\u003e kB/s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eNow I can toss that mp3 onto my \u003ccode\u003ebooksonic\u003c/code\u003e server and study for world domination while I do the dishes!\u003c/p\u003e\n\u003ch2 id=\"pytube\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003epytube\u003c/span\u003e \u003ca href=\"#pytube\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003epytube\u003c/code\u003e is a python implementation of a \u003ca href=\"##YouTube\"\u003eyoutube downloader \u003c/a\u003e that works at the command line or in python!\u003c/p\u003e\n\u003ch3 id=\"installation-1\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eInstallation\u003c/span\u003e \u003ca href=\"#installation-1\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003ca href=\"https://pytube.io/en/latest/\"\u003edocs\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003epip install pytube\u003c/code\u003e\u003c/p\u003e\n\u003ch3 id=\"usage-1\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eUsage\u003c/span\u003e \u003ca href=\"#usage-1\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003epytube\u003c/code\u003e has a lot of functionality, but a quick one would be the \u003ccode\u003e--list\u003c/code\u003e so you can see what qualities are available\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esandbox   main ️  ×3️  ×7via  v3.8.11 \u003cspan class=\"o\"\u003e(\u003c/span\u003esandbox\u003cspan class=\"o\"\u003e)\u003c/span\u003e  took 2m49s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e❯ pytube https://www.youtube.com/watch\u003cspan class=\"se\"\u003e\\?\u003c/span\u003ev\u003cspan class=\"se\"\u003e\\=\u003c/span\u003eLDU_Txk06tM  --list\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eLoading video...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;17\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/3gpp\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;144p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;8fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4v.20.3\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4a.40.2\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;True\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;18\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;360p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.42001E\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4a.40.2\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;True\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;22\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;720p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.64001F\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4a.40.2\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;True\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;313\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;2160p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;401\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;2160p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.12M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;271\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1440p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;400\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1440p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.12M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;137\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1080p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.640028\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;248\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1080p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;399\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1080p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.08M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;136\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;720p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.4d401f\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;247\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;720p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;398\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;720p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.05M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;135\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;480p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.4d401f\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;244\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;480p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;397\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;480p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.04M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;134\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;360p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.4d401e\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;243\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;360p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;396\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;360p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.01M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;133\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;240p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.4d4015\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;242\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;240p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;395\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;240p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.00M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;160\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;144p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.4d400c\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;278\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;144p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;394\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;144p\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.00M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;139\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eabr\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;48kbps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4a.40.5\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;140\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eabr\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;128kbps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4a.40.2\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;249\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eabr\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;50kbps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;opus\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;250\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eabr\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;70kbps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;opus\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;Stream: \u003cspan class=\"nv\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;251\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eabr\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;160kbps\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;opus\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003epytube \u0026lt;url\u0026gt; --itag \u0026lt;\u0026gt;\u003c/code\u003e will download the specific \u003ccode\u003eitag\u003c/code\u003e from the list.\u003c/p\u003e\n\u003cp\u003eNotice that some \u003ccode\u003eitags\u003c/code\u003e are videos and others audio - so you can download just the music of a YT video.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003epytube\u003c/code\u003e also works in python\u0026hellip;\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esandbox\u003c/span\u003e \u003cspan class=\"err\"\u003e↪\u003c/span\u003e \u003cspan class=\"n\"\u003emain\u003c/span\u003e \u003cspan class=\"n\"\u003ev3\u003c/span\u003e\u003cspan class=\"mf\"\u003e.8.11\u003c/span\u003e \u003cspan class=\"n\"\u003eipython\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e❯\u003c/span\u003e \u003cspan class=\"kn\"\u003efrom\u003c/span\u003e \u003cspan class=\"nn\"\u003epytube\u003c/span\u003e \u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"n\"\u003eYouTube\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esandbox\u003c/span\u003e \u003cspan class=\"err\"\u003e↪\u003c/span\u003e \u003cspan class=\"n\"\u003emain\u003c/span\u003e \u003cspan class=\"n\"\u003ev3\u003c/span\u003e\u003cspan class=\"mf\"\u003e.8.11\u003c/span\u003e \u003cspan class=\"n\"\u003eipython\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e❯\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003ex\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003eYouTube\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;https://www.youtube.com/watch?v=LDU_Txk06tM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estreams\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;17\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/3gpp\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;144p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;8fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4v.20.3\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4a.40.2\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;True\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;18\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;360p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.42001E\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4a.40.2\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;True\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;22\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;720p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.64001F\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4a.40.2\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;True\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;313\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;2160p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;401\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;2160p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.12M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;271\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1440p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;400\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1440p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.12M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;137\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1080p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.640028\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;248\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1080p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;399\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1080p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.08M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;136\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;720p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.4d401f\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;247\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;720p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;398\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;720p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.05M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;135\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;480p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.4d401f\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;244\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;480p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;397\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;480p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.04M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;134\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;360p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.4d401e\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;243\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;360p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;396\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;360p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.01M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;133\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;240p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.4d4015\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;242\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;240p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;395\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;240p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.00M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;160\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;144p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;avc1.4d400c\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;278\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;144p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;vp9\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;394\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eres\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;144p\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003efps\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;30fps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003evcodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;av01.0.00M.08\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;video\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;139\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eabr\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;48kbps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4a.40.5\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;140\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio/mp4\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eabr\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;128kbps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;mp4a.40.2\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;249\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eabr\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;50kbps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;opus\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;250\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eabr\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;70kbps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;opus\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eStream\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eitag\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;251\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003emime_type\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio/webm\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eabr\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;160kbps\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eacodec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;opus\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eprogressive\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;False\u0026#34;\u003c/span\u003e \u003cspan class=\"nb\"\u003etype\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;audio\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"youtube-frontends\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eYouTube Frontends\u003c/span\u003e \u003ca href=\"#youtube-frontends\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThere\u0026rsquo;s 2 really good options for self-hosting a YT front-end\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/bbilly1/tubearchivist\"\u003eTube Archivist\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/Tzahi12345/YoutubeDL-Material\"\u003eYouTubeDL-Material\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eThey have their pros and cons.\nYou can also build yourself with the above utilities and use Plex or Jellyfin to serve up videos\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eYour self-hosting journey is up to you!\u003c/strong\u003e\u003c/p\u003e\n\u003ch2 id=\"youtube\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eYouTube\u003c/span\u003e \u003ca href=\"#youtube\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eDownloading YouTube videos is a bit of a sore topic\u0026hellip; Mainly you don\u0026rsquo;t to hurt creators who rely on YT ad revenue for their livlihood.\u003c/p\u003e\n\u003cp\u003eThen again, maybe you\u0026rsquo;re a vigilante who knows that YT also monetizes videos for their \u003cem\u003eown\u003c/em\u003e gain and that the creators don\u0026rsquo;t see that money either!\u003c/p\u003e\n\u003cp\u003eThe solution is pretty easy and is 2-fold\u0026hellip;\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eDownload YT videos\u003c/li\u003e\n\u003cli\u003ePersonally support the content creators you follow via paypall, patreon, or whatever else they might have set-up\u0026hellip;. even a buck or two a month is more than they\u0026rsquo;d get from your ad revenue explicitly plus it all goes to them!\u003c/li\u003e\n\u003c/ol\u003e\n",
      "content_text": "\nSelf-hosting 1 or several media servers is another common homelab use-case.\nGetting content for your media servers is up to you, but I'll show a few ways here to get content somewhat easily!\n\n__YouTube Disclaimer at Bottom__\n\n\n## you-get\n\n`you-get` is a nice cli for grabbing media content off the web. \n\n### Installation\n\n`pip install you-get` or use ad-hoc with `pipx run you-get \u003curl\u003e`\n\n\n### Usage\n\nFor example if I wanted to catch up on ancient Chinese military tactics I may go for `The Art of War` off the Internet Archive...\n\n```bash\nsandbox  🌱 main 🗑️  ×3🛤️  ×6via 🐍 v3.8.11 (sandbox)  took 15s\n❯ you-get https://archive.org/details/art_of_war_librivox -i\nSite:       Archive.org\nTitle:      The Art of War : Sun Tzu : Free Download, Borrow, and Streaming : Internet Archive\nType:       MP3 (audio/mpeg)\nSize:       3.87 MiB (4055167 Bytes)\n\n```\n\nthe `-i` is showing me the info of what would be downloaded without the flag (it's like a dry run)\n\n```bash\nsandbox  🌱 main 🗑️  ×3🛤️  ×6via 🐍 v3.8.11 (sandbox)\n❯ you-get https://archive.org/details/art_of_war_librivox\nSite:       Archive.org\nTitle:      The Art of War : Sun Tzu : Free Download, Borrow, and Streaming : Internet Archive\nType:       MP3 (audio/mpeg)\nSize:       3.87 MiB (4055167 Bytes)\n\nDownloading The Art of War : Sun Tzu : Free Download, Borrow, and Streaming : Internet Archi.mp3 ...\n 100% (  3.9/  3.9MB) ├████████████████████████████████████████████████████████████┤[1/1]  917 kB/s\n\n```\n\nNow I can toss that mp3 onto my `booksonic` server and study for world domination while I do the dishes!\n\n\n## pytube\n\n`pytube` is a python implementation of a [youtube downloader ](##YouTube) that works at the command line or in python!\n\n### Installation\n\n[docs](https://pytube.io/en/latest/)\n\n`pip install pytube`\n\n\n### Usage\n\n`pytube` has a lot of functionality, but a quick one would be the `--list` so you can see what qualities are available\n\n```bash\nsandbox   main ️  ×3️  ×7via  v3.8.11 (sandbox)  took 2m49s\n❯ pytube https://www.youtube.com/watch\\?v\\=LDU_Txk06tM  --list\nLoading video...\n\u003cStream: itag=\"17\" mime_type=\"video/3gpp\" res=\"144p\" fps=\"8fps\" vcodec=\"mp4v.20.3\" acodec=\"mp4a.40.2\" progressive=\"True\" type=\"video\"\u003e\n\u003cStream: itag=\"18\" mime_type=\"video/mp4\" res=\"360p\" fps=\"30fps\" vcodec=\"avc1.42001E\" acodec=\"mp4a.40.2\" progressive=\"True\" type=\"video\"\u003e\n\u003cStream: itag=\"22\" mime_type=\"video/mp4\" res=\"720p\" fps=\"30fps\" vcodec=\"avc1.64001F\" acodec=\"mp4a.40.2\" progressive=\"True\" type=\"video\"\u003e\n\u003cStream: itag=\"313\" mime_type=\"video/webm\" res=\"2160p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"401\" mime_type=\"video/mp4\" res=\"2160p\" fps=\"30fps\" vcodec=\"av01.0.12M.08\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"271\" mime_type=\"video/webm\" res=\"1440p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"400\" mime_type=\"video/mp4\" res=\"1440p\" fps=\"30fps\" vcodec=\"av01.0.12M.08\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"137\" mime_type=\"video/mp4\" res=\"1080p\" fps=\"30fps\" vcodec=\"avc1.640028\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"248\" mime_type=\"video/webm\" res=\"1080p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"399\" mime_type=\"video/mp4\" res=\"1080p\" fps=\"30fps\" vcodec=\"av01.0.08M.08\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"136\" mime_type=\"video/mp4\" res=\"720p\" fps=\"30fps\" vcodec=\"avc1.4d401f\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"247\" mime_type=\"video/webm\" res=\"720p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"398\" mime_type=\"video/mp4\" res=\"720p\" fps=\"30fps\" vcodec=\"av01.0.05M.08\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"135\" mime_type=\"video/mp4\" res=\"480p\" fps=\"30fps\" vcodec=\"avc1.4d401f\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"244\" mime_type=\"video/webm\" res=\"480p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"397\" mime_type=\"video/mp4\" res=\"480p\" fps=\"30fps\" vcodec=\"av01.0.04M.08\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"134\" mime_type=\"video/mp4\" res=\"360p\" fps=\"30fps\" vcodec=\"avc1.4d401e\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"243\" mime_type=\"video/webm\" res=\"360p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"396\" mime_type=\"video/mp4\" res=\"360p\" fps=\"30fps\" vcodec=\"av01.0.01M.08\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"133\" mime_type=\"video/mp4\" res=\"240p\" fps=\"30fps\" vcodec=\"avc1.4d4015\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"242\" mime_type=\"video/webm\" res=\"240p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"395\" mime_type=\"video/mp4\" res=\"240p\" fps=\"30fps\" vcodec=\"av01.0.00M.08\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"160\" mime_type=\"video/mp4\" res=\"144p\" fps=\"30fps\" vcodec=\"avc1.4d400c\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"278\" mime_type=\"video/webm\" res=\"144p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"394\" mime_type=\"video/mp4\" res=\"144p\" fps=\"30fps\" vcodec=\"av01.0.00M.08\" progressive=\"False\" type=\"video\"\u003e\n\u003cStream: itag=\"139\" mime_type=\"audio/mp4\" abr=\"48kbps\" acodec=\"mp4a.40.5\" progressive=\"False\" type=\"audio\"\u003e\n\u003cStream: itag=\"140\" mime_type=\"audio/mp4\" abr=\"128kbps\" acodec=\"mp4a.40.2\" progressive=\"False\" type=\"audio\"\u003e\n\u003cStream: itag=\"249\" mime_type=\"audio/webm\" abr=\"50kbps\" acodec=\"opus\" progressive=\"False\" type=\"audio\"\u003e\n\u003cStream: itag=\"250\" mime_type=\"audio/webm\" abr=\"70kbps\" acodec=\"opus\" progressive=\"False\" type=\"audio\"\u003e\n\u003cStream: itag=\"251\" mime_type=\"audio/webm\" abr=\"160kbps\" acodec=\"opus\" progressive=\"False\" type=\"audio\"\u003e\n\n```\n\n`pytube \u003curl\u003e --itag \u003c\u003e` will download the specific `itag` from the list.\n\nNotice that some `itags` are videos and others audio - so you can download just the music of a YT video.\n\n\n`pytube` also works in python...\n\n```python\nsandbox ↪ main v3.8.11 ipython\n❯ from pytube import YouTube\n\nsandbox ↪ main v3.8.11 ipython\n❯ [x for x in YouTube(\"https://www.youtube.com/watch?v=LDU_Txk06tM\").streams]\n\n[\n    \u003cStream: itag=\"17\" mime_type=\"video/3gpp\" res=\"144p\" fps=\"8fps\" vcodec=\"mp4v.20.3\" acodec=\"mp4a.40.2\" progressive=\"True\" type=\"video\"\u003e,\n    \u003cStream: itag=\"18\" mime_type=\"video/mp4\" res=\"360p\" fps=\"30fps\" vcodec=\"avc1.42001E\" acodec=\"mp4a.40.2\" progressive=\"True\" type=\"video\"\u003e,\n    \u003cStream: itag=\"22\" mime_type=\"video/mp4\" res=\"720p\" fps=\"30fps\" vcodec=\"avc1.64001F\" acodec=\"mp4a.40.2\" progressive=\"True\" type=\"video\"\u003e,\n    \u003cStream: itag=\"313\" mime_type=\"video/webm\" res=\"2160p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"401\" mime_type=\"video/mp4\" res=\"2160p\" fps=\"30fps\" vcodec=\"av01.0.12M.08\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"271\" mime_type=\"video/webm\" res=\"1440p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"400\" mime_type=\"video/mp4\" res=\"1440p\" fps=\"30fps\" vcodec=\"av01.0.12M.08\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"137\" mime_type=\"video/mp4\" res=\"1080p\" fps=\"30fps\" vcodec=\"avc1.640028\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"248\" mime_type=\"video/webm\" res=\"1080p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"399\" mime_type=\"video/mp4\" res=\"1080p\" fps=\"30fps\" vcodec=\"av01.0.08M.08\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"136\" mime_type=\"video/mp4\" res=\"720p\" fps=\"30fps\" vcodec=\"avc1.4d401f\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"247\" mime_type=\"video/webm\" res=\"720p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"398\" mime_type=\"video/mp4\" res=\"720p\" fps=\"30fps\" vcodec=\"av01.0.05M.08\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"135\" mime_type=\"video/mp4\" res=\"480p\" fps=\"30fps\" vcodec=\"avc1.4d401f\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"244\" mime_type=\"video/webm\" res=\"480p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"397\" mime_type=\"video/mp4\" res=\"480p\" fps=\"30fps\" vcodec=\"av01.0.04M.08\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"134\" mime_type=\"video/mp4\" res=\"360p\" fps=\"30fps\" vcodec=\"avc1.4d401e\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"243\" mime_type=\"video/webm\" res=\"360p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"396\" mime_type=\"video/mp4\" res=\"360p\" fps=\"30fps\" vcodec=\"av01.0.01M.08\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"133\" mime_type=\"video/mp4\" res=\"240p\" fps=\"30fps\" vcodec=\"avc1.4d4015\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"242\" mime_type=\"video/webm\" res=\"240p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"395\" mime_type=\"video/mp4\" res=\"240p\" fps=\"30fps\" vcodec=\"av01.0.00M.08\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"160\" mime_type=\"video/mp4\" res=\"144p\" fps=\"30fps\" vcodec=\"avc1.4d400c\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"278\" mime_type=\"video/webm\" res=\"144p\" fps=\"30fps\" vcodec=\"vp9\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"394\" mime_type=\"video/mp4\" res=\"144p\" fps=\"30fps\" vcodec=\"av01.0.00M.08\" progressive=\"False\" type=\"video\"\u003e,\n    \u003cStream: itag=\"139\" mime_type=\"audio/mp4\" abr=\"48kbps\" acodec=\"mp4a.40.5\" progressive=\"False\" type=\"audio\"\u003e,\n    \u003cStream: itag=\"140\" mime_type=\"audio/mp4\" abr=\"128kbps\" acodec=\"mp4a.40.2\" progressive=\"False\" type=\"audio\"\u003e,\n    \u003cStream: itag=\"249\" mime_type=\"audio/webm\" abr=\"50kbps\" acodec=\"opus\" progressive=\"False\" type=\"audio\"\u003e,\n    \u003cStream: itag=\"250\" mime_type=\"audio/webm\" abr=\"70kbps\" acodec=\"opus\" progressive=\"False\" type=\"audio\"\u003e,\n    \u003cStream: itag=\"251\" mime_type=\"audio/webm\" abr=\"160kbps\" acodec=\"opus\" progressive=\"False\" type=\"audio\"\u003e\n]\n\n\n```\n\n## YouTube Frontends\n\nThere's 2 really good options for self-hosting a YT front-end...\n\n[Tube Archivist](https://github.com/bbilly1/tubearchivist)\n\n[YouTubeDL-Material](https://github.com/Tzahi12345/YoutubeDL-Material)\n\nThey have their pros and cons.\nYou can also build yourself with the above utilities and use Plex or Jellyfin to serve up videos...\n\n__Your self-hosting journey is up to you!__\n\n\n## YouTube\n\nDownloading YouTube videos is a bit of a sore topic... Mainly you don't to hurt creators who rely on YT ad revenue for their livlihood.\n\nThen again, maybe you're a vigilante who knows that YT also monetizes videos for their _own_ gain and that the creators don't see that money either!\n\nThe solution is pretty easy and is 2-fold...\n\n1. Download YT videos\n2. Personally support the content creators you follow via paypall, patreon, or whatever else they might have set-up.... even a buck or two a month is more than they'd get from your ad revenue explicitly plus it all goes to them!\n",
      "summary": "Self-hosting 1 or several media servers is another common homelab use-case. Getting content for your media servers is up to you, but I'll show a few ways...",
      "date_published": "2022-03-24T00:00:00Z",
      "date_modified": "2022-03-24T00:00:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "python",
        "homelab",
        "tech",
        "series-homelab"
      ]
    },
    {
      "id": "https://pype.dev/truenas-and-wireguard/",
      "url": "https://pype.dev/truenas-and-wireguard/",
      "title": "Truenas-And-Wireguard",
      "content_html": "\u003ch2 id=\"nas\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eNAS\u003c/span\u003e \u003ca href=\"#nas\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eOne of the most common use cases for self-hosting anything is a file share system.\nI have been a fan of \u003ca href=\"https://www.truenas.com/\"\u003eTrueNAS\u003c/a\u003e for a while.\nI currently use TrueNAS Core at home, and plan to consider transitioning to TrueNAS Scale soon.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBlog post forthcoming on that!\u003c/strong\u003e\u003c/p\u003e\n\u003ch2 id=\"vpn\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eVPN\u003c/span\u003e \u003ca href=\"#vpn\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI don\u0026rsquo;t write a ton about homelabbing yet but one of the first things to set up whether you have a massive homelab or a little raspberry pi would be a self-hosted VPN.\nI have notes on wireguard \u003ca href=\"%22/wireguard%22\"\u003ehere\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eI finally have a need to put my TrueNAS box on my wireguard network in order to transfer files to other devices that are outside my LAN.\u003c/p\u003e\n\u003cp\u003eThere is a handy tutorial on setting this up via the GUI \u003ca href=\"https://www.truenas.com/docs/core/network/wireguard/\"\u003ehere\u003c/a\u003e.\nThey walk you through setting up 2 tunables wireguard. One to enable the the connection and one to setup the network interface.\nNext you create a \u003ccode\u003ePost Init\u003c/code\u003e script which will check that the right directories exist and will copy the wireguard config that hasn\u0026rsquo;t been made yet to the proper location and finally starts wireguard.\u003c/p\u003e\n\u003cp\u003eThe above is just copy/paste from the tutorial but the final step, although not super tricky, isn\u0026rsquo;t the same for everyone as it depends on your wireguard config and network setup.\u003c/p\u003e\n\u003cp\u003eThe final step is for you create the relevant wireguard config (see my post but I just use \u003ccode\u003epivpn -a\u003c/code\u003e) and send that config over to your TrueNAS box!\u003c/p\u003e\n\u003cp\u003eFor me this final work flow looked like this:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003essh user@vpn-server\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003epivpn -a\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;follow prompts\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003escp ~/configs/truenas.conf root@\u0026lt;truenas ip\u0026gt;:/root/wg0.conf\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"bug\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eBug?\u003c/span\u003e \u003ca href=\"#bug\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe script in the tutorial for starting the wireguard service is straight forward enough however my TrueNAS box didn\u0026rsquo;t get the wireguard interface up and running on reboot.\u003c/p\u003e\n\u003cp\u003eEasy enough solution:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003essh root@\u0026lt;truenas ip\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e/usr/local/etc/rc.d/wireguard start\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWe can check that the interface is now working with \u003ccode\u003eifconfig\u003c/code\u003e and should see something like the following:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ewg0: \u003cspan class=\"nv\"\u003eflags\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e8051\u0026lt;UP,POINTOPOINT,RUNNING,MULTICAST\u0026gt; metric \u003cspan class=\"m\"\u003e0\u003c/span\u003e mtu \u003cspan class=\"m\"\u003e1420\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nv\"\u003eoptions\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e80000\u0026lt;LINKSTATE\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        inet x.x.x.x --\u0026gt; x.x.x.x netmask 0xffffff00\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        groups: tun\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        nd6 \u003cspan class=\"nv\"\u003eoptions\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e101\u0026lt;PERFORMNUD,NO_DAD\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        Opened by PID \u003cspan class=\"m\"\u003e1325\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"gotcha\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eGotcha!\u003c/span\u003e \u003ca href=\"#gotcha\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHere\u0026rsquo;s another thing I had to navigate when setting this up.\u003c/p\u003e\n\u003cp\u003eMy \u003ccode\u003epivpn\u003c/code\u003e configuration sets the endpoint for my wireguard clients to \u003ccode\u003epaynepride.com:\u0026lt;port forwarded to wireguard server\u0026gt;\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003eWhat this means is that when I check the wireguard config for TrueNAS which is on my home network it resolves \u003ccode\u003epaynepride.com\u003c/code\u003e to the server I have running my reverse proxy.\nHowever! My reverse proxy is not responsible for my vpn traffic and so the traffic was just getting dropped - instead I needed to change the wireguard config just for my truenas box to piont to the local address of my vpn server.\nThis really threw me for a loop today but is just another reminder that if you have network problems it\u0026rsquo;s probably DNS\u0026hellip;\u003c/p\u003e\n\u003cp\u003eGive her the \u0026lsquo;ol reboot and now if I check \u003ccode\u003ewg\u003c/code\u003e I should see some traffic on my wireguard tunnel!\u003c/p\u003e\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/truenas-wireguard.png\" alt=\"TrueNAS Wireguard\" title=\"TrueNAS and Wireguard\" /\u003e\n",
      "content_text": "\n## NAS\n\nOne of the most common use cases for self-hosting anything is a file share system. \nI have been a fan of [TrueNAS](https://www.truenas.com/) for a while. \nI currently use TrueNAS Core at home, and plan to consider transitioning to TrueNAS Scale soon.\n\n__Blog post forthcoming on that!__ \n\n\n## VPN \n\nI don't write a ton about homelabbing yet but one of the first things to set up whether you have a massive homelab or a little raspberry pi would be a self-hosted VPN.\nI have notes on wireguard [here](\"/wireguard\").\n\nI finally have a need to put my TrueNAS box on my wireguard network in order to transfer files to other devices that are outside my LAN.\n\nThere is a handy tutorial on setting this up via the GUI [here](https://www.truenas.com/docs/core/network/wireguard/).\nThey walk you through setting up 2 tunables wireguard. One to enable the the connection and one to setup the network interface.\nNext you create a `Post Init` script which will check that the right directories exist and will copy the wireguard config that hasn't been made yet to the proper location and finally starts wireguard.\n\nThe above is just copy/paste from the tutorial but the final step, although not super tricky, isn't the same for everyone as it depends on your wireguard config and network setup.\n\nThe final step is for you create the relevant wireguard config (see my post but I just use `pivpn -a`) and send that config over to your TrueNAS box!\n\nFor me this final work flow looked like this:\n\n```bash\n\nssh user@vpn-server\n\npivpn -a\n\n\u003cfollow prompts\u003e\n\nscp ~/configs/truenas.conf root@\u003ctruenas ip\u003e:/root/wg0.conf\n\n```\n\n## Bug?\n\nThe script in the tutorial for starting the wireguard service is straight forward enough however my TrueNAS box didn't get the wireguard interface up and running on reboot.\n\nEasy enough solution:\n\n```bash\nssh root@\u003ctruenas ip\u003e\n/usr/local/etc/rc.d/wireguard start\n```\n\nWe can check that the interface is now working with `ifconfig` and should see something like the following:\n\n```bash \nwg0: flags=8051\u003cUP,POINTOPOINT,RUNNING,MULTICAST\u003e metric 0 mtu 1420\n        options=80000\u003cLINKSTATE\u003e\n        inet x.x.x.x --\u003e x.x.x.x netmask 0xffffff00\n        groups: tun\n        nd6 options=101\u003cPERFORMNUD,NO_DAD\u003e\n        Opened by PID 1325\n```\n\n\n## Gotcha!\n\nHere's another thing I had to navigate when setting this up.\n\nMy `pivpn` configuration sets the endpoint for my wireguard clients to `paynepride.com:\u003cport forwarded to wireguard server\u003e`\n\nWhat this means is that when I check the wireguard config for TrueNAS which is on my home network it resolves `paynepride.com` to the server I have running my reverse proxy.\nHowever! My reverse proxy is not responsible for my vpn traffic and so the traffic was just getting dropped - instead I needed to change the wireguard config just for my truenas box to piont to the local address of my vpn server.\nThis really threw me for a loop today but is just another reminder that if you have network problems it's probably DNS...\n\nGive her the 'ol reboot and now if I check `wg` I should see some traffic on my wireguard tunnel!\n\n\u003cimg src=\"https://cdn.statically.io/gh/pypeaday/images.pype.dev/main/blog-media/truenas-wireguard.png\" alt=\"TrueNAS Wireguard\" title=\"TrueNAS and Wireguard\" /\u003e\n",
      "summary": "One of the most common use cases for self-hosting anything is a file share system. I have been a fan of TrueNAS for a while. I currently use TrueNAS Core at...",
      "date_published": "2022-03-23T00:00:00Z",
      "date_modified": "2022-03-23T00:00:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/wireguard/",
      "url": "https://pype.dev/wireguard/",
      "title": "Wireguard",
      "content_html": "\u003ch2 id=\"vpn\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eVPN\u003c/span\u003e \u003ca href=\"#vpn\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eVirtual Private Networks are a big deal, and this shouldn\u0026rsquo;t be considered anything even close to a guide on using them.\nHere are just my notes and some setup for how I use \u003ca href=\"https://www.wireguard.com/\"\u003ewireguard\u003c/a\u003e at home.\u003c/p\u003e\n\u003ch2 id=\"wireguard\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eWireguard\u003c/span\u003e \u003ca href=\"#wireguard\" class=\"heading-anchor\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eWireguard is an awesome peer-to-peer VPN tunnel that makes it really easy for me to get into my home network when I\u0026rsquo;m out and about.\nMy main reasons for this are 1. I don\u0026rsquo;t trust public wi-fi and 2. I want to use pi-hole for ad blocking when I\u0026rsquo;m not at home\u003c/p\u003e\n\u003cp\u003eWireguard can be configured as a \u0026ldquo;peer-to-site\u0026rdquo; VPN tunnel as well.\nMy vpn setup let\u0026rsquo;s me jump to various machines on my network from anywhere!\u003c/p\u003e\n\u003cp\u003eI use \u003ca href=\"https://pivpn.io/\"\u003epivpn\u003c/a\u003e in a VM that\u0026rsquo;s already running \u003ccode\u003epi-hole\u003c/code\u003e to host my wireguard server.\nIt\u0026rsquo;s super easy to setup just by following the instructions on the pivpn site.\u003c/p\u003e\n\u003cp\u003eThe reason I like it is that I have a nice \u003ccode\u003ecli\u003c/code\u003e for managing wireguard configs.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edumbledore@pihole-vpn:~$ pivpn\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e::: Control all PiVPN specific functions!\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e::: Usage: pivpn \u0026lt;command\u0026gt; \u003cspan class=\"o\"\u003e[\u003c/span\u003eoption\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e::: Commands:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::    -a, add              Create a client conf profile\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::    -c, clients          List any connected clients to the server\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::    -d, debug            Start a debugging session \u003cspan class=\"k\"\u003eif\u003c/span\u003e having trouble\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::    -l, list             List all clients\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::   -qr, qrcode           Show the qrcode of a client \u003cspan class=\"k\"\u003efor\u003c/span\u003e use with the mobile app\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::    -r, remove           Remove a client\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::  -off, off              Disable a user\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::   -on, on               Enable a user\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::    -h, \u003cspan class=\"nb\"\u003ehelp\u003c/span\u003e             Show this \u003cspan class=\"nb\"\u003ehelp\u003c/span\u003e dialog\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::    -u, uninstall        Uninstall pivpn from your system!\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::   -up, update           Updates PiVPN Scripts\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e:::   -bk, backup           Backup VPN configs and user profiles\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eWhen I\u0026rsquo;m ready to add a new client to my \u003ccode\u003ewg\u003c/code\u003e network, it\u0026rsquo;s as easy as \u003ccode\u003epivpn add\u003c/code\u003e and follow the instructions.\nThe easiest part here is that you\u0026rsquo;ll be given a QR code in the terminal that you can just scan with the client (like a smart phone) and you\u0026rsquo;ll have your wireguard config handled by the app (oh right, download the wireguard app) in no time!\u003c/p\u003e\n",
      "content_text": "\n## VPN\n\nVirtual Private Networks are a big deal, and this shouldn't be considered anything even close to a guide on using them.\nHere are just my notes and some setup for how I use [wireguard](https://www.wireguard.com/) at home.\n\n## Wireguard\n\nWireguard is an awesome peer-to-peer VPN tunnel that makes it really easy for me to get into my home network when I'm out and about.\nMy main reasons for this are 1. I don't trust public wi-fi and 2. I want to use pi-hole for ad blocking when I'm not at home\n\nWireguard can be configured as a \"peer-to-site\" VPN tunnel as well.\nMy vpn setup let's me jump to various machines on my network from anywhere!\n\nI use [pivpn](https://pivpn.io/) in a VM that's already running `pi-hole` to host my wireguard server.\nIt's super easy to setup just by following the instructions on the pivpn site.\n\nThe reason I like it is that I have a nice `cli` for managing wireguard configs.\n\n```bash\ndumbledore@pihole-vpn:~$ pivpn\n::: Control all PiVPN specific functions!\n:::\n::: Usage: pivpn \u003ccommand\u003e [option]\n:::\n::: Commands:\n:::    -a, add              Create a client conf profile\n:::    -c, clients          List any connected clients to the server\n:::    -d, debug            Start a debugging session if having trouble\n:::    -l, list             List all clients\n:::   -qr, qrcode           Show the qrcode of a client for use with the mobile app\n:::    -r, remove           Remove a client\n:::  -off, off              Disable a user\n:::   -on, on               Enable a user\n:::    -h, help             Show this help dialog\n:::    -u, uninstall        Uninstall pivpn from your system!\n:::   -up, update           Updates PiVPN Scripts\n:::   -bk, backup           Backup VPN configs and user profiles\n```\n\n\nWhen I'm ready to add a new client to my `wg` network, it's as easy as `pivpn add` and follow the instructions.\nThe easiest part here is that you'll be given a QR code in the terminal that you can just scan with the client (like a smart phone) and you'll have your wireguard config handled by the app (oh right, download the wireguard app) in no time!\n",
      "summary": "Virtual Private Networks are a big deal, and this shouldn't be considered anything even close to a guide on using them. Here are just my notes and some setup...",
      "date_published": "2022-03-12T00:00:00Z",
      "date_modified": "2022-03-12T00:00:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "homepage",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/adblock-coverage/",
      "url": "https://pype.dev/adblock-coverage/",
      "title": "Adblock-Coverage",
      "content_html": "\u003cp\u003eI run pi-hole at home for ad blocking and some internal DNS/DHCP handling.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003epi hole posts on the way\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eOne thing I\u0026rsquo;ve never put too much thought in is asking \u0026ldquo;how well am I doing at blocking?\u0026rdquo;\nThere\u0026rsquo;s lots of ways to measure that depending on what you care about but I just learned of \u003ca href=\"https://d3ward.github.io/toolz/adblock\"\u003eadblock tester\u003c/a\u003e.\nIt\u0026rsquo;s awesome and gave me a quick glimpse into how my pi-hole is performing on keeping my webpages clean and my DNS history private!\u003c/p\u003e\n\u003cp\u003eCredits to \u003ca href=\"https://github.com/d3ward/toolz\"\u003ed3ward\u003c/a\u003e for the awesome tool!\u003c/p\u003e\n",
      "content_text": "\n\nI run pi-hole at home for ad blocking and some internal DNS/DHCP handling.\n\n__pi hole posts on the way__\n\nOne thing I've never put too much thought in is asking \"how well am I doing at blocking?\"\nThere's lots of ways to measure that depending on what you care about but I just learned of [adblock tester](https://d3ward.github.io/toolz/adblock).\nIt's awesome and gave me a quick glimpse into how my pi-hole is performing on keeping my webpages clean and my DNS history private!\n\nCredits to [d3ward](https://github.com/d3ward/toolz) for the awesome tool!\n",
      "summary": "I run pi-hole at home for ad blocking and some internal DNS/DHCP handling.",
      "date_published": "2022-03-07T00:00:00Z",
      "date_modified": "2022-03-07T00:00:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "til",
        "tech"
      ]
    },
    {
      "id": "https://pype.dev/webservers-and-indexes/",
      "url": "https://pype.dev/webservers-and-indexes/",
      "title": "Webservers-And-Indexes",
      "content_html": "\u003cp\u003eI host a lot of services in my homelab, but they\u0026rsquo;re mostly dockerized applications so I have never had to care much about how content gets served up.\nToday I had several little concepts click into place regarding webservers, and it was a similar experience to when I started homelabing and didn\u0026rsquo;t know what a \u0026ldquo;server\u0026rdquo; was in the first place.\u003c/p\u003e\n\u003ch1 id=\"servers\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eServers\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eA \u0026ldquo;server\u0026rdquo; can have a lot of different meanings but specifically in my world it was a physical server, like my PowerEdge R610 which acts as my main \u0026ldquo;home server\u0026rdquo;.\nBut then on my server, I have other servers\u0026hellip; Jellyfin is my main media server - but that\u0026rsquo;s obviously not a hardware thing, that\u0026rsquo;s software.\nThis is certainly not a groundbreaking thing but it was a tiny piece to the puzzle that I was missing\u0026hellip; that \u0026ldquo;server\u0026rdquo; is highly contextual.\u003c/p\u003e\n\u003ch1 id=\"webservers\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eWebservers\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eSomething that confused the heck out of me when I first started down the road of having a server was what a webserver even was\u0026hellip;\nI always thought the \u0026ldquo;webserver\u0026rdquo; was just \u0026ldquo;a server that hosts a website\u0026rdquo;\u0026hellip; and yes, that\u0026rsquo;s true, but also it wasn\u0026rsquo;t true in how I understood \u0026ldquo;server\u0026rdquo;.\nIt turns out that across my 40-odd dockerized services I have at home that I must have about 40-odd web servers running, each docker container is spinning up its own!\u003c/p\u003e\n\u003cp\u003eSo something I have wanted to do for a long time is put my theology notes online for my small group to access whenever they might want\u0026hellip; it doesn\u0026rsquo;t need to be fancy or anything.\nMy issue was not knowing what to even Google. I tried \u0026ldquo;How to serve up static html\u0026rdquo; but that kind of search is for people who know what a \u0026ldquo;static\u0026rdquo; site is - I am not one of those people.\nI kept running across nginx and apache things, wordpress and other website building tools, etc.\nIn fact I only recently learned that JavaScript assets cann still be considered static so I am a complete baby in the web-dev space.\u003c/p\u003e\n\u003cp\u003eWhat I really wanted was just a simple landing page with a link to each of my \u0026ldquo;posts\u0026rdquo; which are in the form of a single html file each that I can easily export from my tiddlywiki (I have a post about tiddlywiki \u003ca href=\"/tiddly-wiki\"\u003ehere\u003c/a\u003e)\u003c/p\u003e\n\u003cp\u003eThe first win \u003ccode\u003epython -m http.server\u003c/code\u003e right in the directory I kept my html files in and that got me what I wanted functionally.\nBut then I wanted just a hair more organization\u0026hellip;\nI started looking for a way to dynamically generate an index for a directory of html files but again the verbiage of that Google search just wasn\u0026rsquo;t helping me - I didn\u0026rsquo;t want anything complicated and I knew that what I wanted had to be easy\u0026hellip;\u003c/p\u003e\n\u003ch1 id=\"the-index\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eThe Index\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eLuckily I randomly came across a SO that mentioned a Linux utility called \u003ccode\u003etree\u003c/code\u003e which does exactly what I wanted!\u003c/p\u003e\n\u003cp\u003eSee my TIL on \u003ccode\u003etree\u003c/code\u003e \u003ca href=\"'/tree'\"\u003ehere\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eSo now it goes like this:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eTake notes on X in my tiddlywiki\u003c/li\u003e\n\u003cli\u003eExport that tiddler to a html file\u003c/li\u003e\n\u003cli\u003ePut that html file into a \u003ccode\u003enotes\u003c/code\u003e folder in my github repo for small group notes\u003c/li\u003e\n\u003cli\u003eUse \u003ccode\u003etree\u003c/code\u003e to generate an \u003ccode\u003eindex.html\u003c/code\u003e of each of those files in the \u003ccode\u003enotes\u003c/code\u003e directory\u003c/li\u003e\n\u003cli\u003eUse \u003ccode\u003epython -m http.server\u003c/code\u003e to start a web server that lands me at the \u003ccode\u003eindex.html\u003c/code\u003e and now I can click through to any post!\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIt\u0026rsquo;s not fancy but it\u0026rsquo;s functional\u0026hellip;\nThis site/blog is built with markdown and \u003ca href=\"https://www.markata.dev\"\u003emarkata\u003c/a\u003e and I wanted way more functionality in my tech notes.\nBut for this simple use case I learned a ton about \u003cem\u003ehow\u003c/em\u003e content gets served up on a webpage and my small group benefits from the easy access as well!\u003c/p\u003e\n",
      "content_text": "\nI host a lot of services in my homelab, but they're mostly dockerized applications so I have never had to care much about how content gets served up.\nToday I had several little concepts click into place regarding webservers, and it was a similar experience to when I started homelabing and didn't know what a \"server\" was in the first place.\n\n# Servers\n\nA \"server\" can have a lot of different meanings but specifically in my world it was a physical server, like my PowerEdge R610 which acts as my main \"home server\".\nBut then on my server, I have other servers... Jellyfin is my main media server - but that's obviously not a hardware thing, that's software. \nThis is certainly not a groundbreaking thing but it was a tiny piece to the puzzle that I was missing... that \"server\" is highly contextual.\n\n# Webservers \n\nSomething that confused the heck out of me when I first started down the road of having a server was what a webserver even was...\nI always thought the \"webserver\" was just \"a server that hosts a website\"... and yes, that's true, but also it wasn't true in how I understood \"server\".\nIt turns out that across my 40-odd dockerized services I have at home that I must have about 40-odd web servers running, each docker container is spinning up its own!\n\nSo something I have wanted to do for a long time is put my theology notes online for my small group to access whenever they might want... it doesn't need to be fancy or anything.\nMy issue was not knowing what to even Google. I tried \"How to serve up static html\" but that kind of search is for people who know what a \"static\" site is - I am not one of those people.\nI kept running across nginx and apache things, wordpress and other website building tools, etc.\nIn fact I only recently learned that JavaScript assets cann still be considered static so I am a complete baby in the web-dev space.\n\nWhat I really wanted was just a simple landing page with a link to each of my \"posts\" which are in the form of a single html file each that I can easily export from my tiddlywiki (I have a post about tiddlywiki [here](/tiddly-wiki))\n\nThe first win `python -m http.server` right in the directory I kept my html files in and that got me what I wanted functionally. \nBut then I wanted just a hair more organization...\nI started looking for a way to dynamically generate an index for a directory of html files but again the verbiage of that Google search just wasn't helping me - I didn't want anything complicated and I knew that what I wanted had to be easy...\n\n# The Index \n\nLuckily I randomly came across a SO that mentioned a Linux utility called `tree` which does exactly what I wanted!\n\nSee my TIL on `tree` [here]('/tree')\n\nSo now it goes like this:\n\n* Take notes on X in my tiddlywiki\n* Export that tiddler to a html file \n* Put that html file into a `notes` folder in my github repo for small group notes \n* Use `tree` to generate an `index.html` of each of those files in the `notes` directory\n* Use `python -m http.server` to start a web server that lands me at the `index.html` and now I can click through to any post!\n\nIt's not fancy but it's functional... \nThis site/blog is built with markdown and [markata](https://www.markata.dev) and I wanted way more functionality in my tech notes.\nBut for this simple use case I learned a ton about _how_ content gets served up on a webpage and my small group benefits from the easy access as well!\n",
      "summary": "I host a lot of services in my homelab, but they're mostly dockerized applications so I have never had to care much about how content gets served up. Today I...",
      "date_published": "2022-03-06T00:00:00Z",
      "date_modified": "2022-03-06T00:00:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech",
        "til"
      ]
    },
    {
      "id": "https://pype.dev/traefik/",
      "url": "https://pype.dev/traefik/",
      "title": "Traefik",
      "content_html": "\u003ch1 id=\"traefik\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eTraefik\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eIf you don\u0026rsquo;t know about \u003ca href=\"https://doc.traefik.io/traefik/\"\u003etraefik\u003c/a\u003e and you need a reverse-proxy then you might want to check it out.\nI used to use nginx for my reverse proxy but the config was over my head, and once it was working I was afraid to touch it.\nTraefik brings a lot to the table, my main uses are reverse proxy and ip whitelisting, but it\u0026rsquo;s doing even more under the hood that I don\u0026rsquo;t have a full-grasp of yet.\u003c/p\u003e\n\u003cp\u003eI like Traefik a lot because once I get some basic config up it\u0026rsquo;s incredibly easy to add services into my homelab whether they run on my primary server or not.\nThis will not be exhaustive but I\u0026rsquo;ll outline my simple setup process of traefik and how I add services whether they are in docker or not.\u003c/p\u003e\n\u003ch1 id=\"docker\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eDocker\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eIn 2022 I\u0026rsquo;m still a docker fan-boy and I run my traefik instance in a docker container.\nThis isn\u0026rsquo;t necessary but I love the portability since my homelab is very dynamic at the moment.\nAnd even if it wasn\u0026rsquo;t I\u0026rsquo;d still want to keep traefik in docker because deployment and updating are just so flipping easy\u003c/p\u003e\n\u003cp\u003eA simple docker-compose file for traefik might look like this:\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003etraefik\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eimage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;traefik:v2.4\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003enetwork_mode\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ehost\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003evolumes\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;docker-data/traefik/traefik.toml:/etc/traefik/traefik.toml:ro\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;docker-data/traefik/config.yml:/etc/traefik/config.yml:ro\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;docker-data/traefik/letsencrypt:/letsencrypt:rw\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;/var/run/docker.sock:/var/run/docker.sock:ro\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e# for auto-discovery\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ traefik_environment_variables }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003erestart_policy\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eunless-stopped\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ememory\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1g\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch1 id=\"ansible-deployment\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eAnsible deployment\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003e\u003cstrong\u003eI plan to have more on my homelab and Ansible on this site eventually\u0026hellip;\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eI use Ansible to deploy most of my services at home, including traefik. My main homelab repo is \u003ca href=\"https://github.com/nicpayne713/ansible-nas\"\u003ehere\u003c/a\u003e which is a fork of \u003ca href=\"https://github.com/davestephens/ansible-nas\"\u003eAnsible NAS\u003c/a\u003e.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIf you want my stuff then be sure to go to the \u003ccode\u003euser/nic\u003c/code\u003e branch on my fork\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eYou can see the ansible stuff for traefik \u003ca href=\"https://github.com/davestephens/ansible-nas/tree/master/roles/traefik\"\u003ehere\u003c/a\u003e\u003c/p\u003e\n\u003ch1 id=\"config\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eConfig\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eI use a \u003ccode\u003etraefik.toml\u003c/code\u003e as the main config and it looks something like this.\nWith ansible a lot of this is done through template variables but this is the general idea.\nThis config tells traefik what ports to listen and forward on, and gives the names to be referenced by docker labels (down below).\u003c/p\u003e\n\u003cp\u003eTraefik also has a handy web ui that with this config you can find on port \u003ccode\u003e8080\u003c/code\u003e.\nThere is a \u003ccode\u003eproviders\u003c/code\u003e section - which is one of the biggest selling points of traefik for me.\nI have a docker provider configured  and a static file.\u003c/p\u003e\n\u003cp\u003eThe docker provider lets traefik auto-discover new services that I deploy and automatically handle the routing!\nThe static file lets me easily add non-dockerized service routing, or routing to dockerized services on another host (I think traefik has an easier way to do this automatically but I don\u0026rsquo;t do it often enough to need that kind of automation).\nThen at the bottom is the SSL cert stuff.\nUsing Let\u0026rsquo;s Encrypt is pretty easy and I use Cloudflare as my DNS provider\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eentryPoints\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eentryPoints\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eweb\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eaddress\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;:80\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eentryPoints\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eweb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ehttp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eredirections\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eentryPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eto\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;websecure\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eentryPoints\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ewebsecure\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eaddress\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;:443\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eentryPoints\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ewebsecure\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ehttp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etls\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003ecertResolver\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;letsencrypt\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eentryPoints\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ewebsecure\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ehttp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etls\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edomains\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003emain\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;example.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003esans\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s2\"\u003e\u0026#34;*.example.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eentryPoints\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etraefik\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eaddress\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;:8080\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eproviders\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eprovidersThrottleDuration\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;1s\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eproviders\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edocker\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eexposedbydefault\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eproviders\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003efile\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003efilename\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;/etc/traefik/config.yml\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eapi\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003einsecure\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003edashboard\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003elevel\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;INFO\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eping\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eterminatingStatusCode\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ecertificatesResolvers\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ecertificatesResolvers\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eletsencrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ecertificatesResolvers\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eletsencrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eacme\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eemail\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;my_email@example.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003estorage\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;/letsencrypt/acme.json\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003ecaserver\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://acme-staging-v02.api.letsencrypt.org/directory\u0026#34;\u003c/span\u003e  \u003cspan class=\"c\"\u003e# le staging, not prod\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ecertificatesResolvers\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eletsencrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eacme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ednsChallenge\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003eprovider\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;cloudflare\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch1 id=\"providers-file\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eProviders.file\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eTo my knowledge there isn\u0026rsquo;t much to configure on the docker provider side of things until you deploy a service.\nBut the provider config file should get a little screen time here.\u003c/p\u003e\n\u003cp\u003eThe file defines a traefik http router for each service you define, in this case just \u003ccode\u003epihole\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eHere I am adding my pihole instance which is not run inside docker but is inside a VM on another host.\nI want the \u003ccode\u003eentryPoints\u003c/code\u003e to be set to \u003ccode\u003ewebsecure\u003c/code\u003e which is configured above in the http redirects.\nI want some middlewares, \u003ccode\u003eaddprefix-pihole\u003c/code\u003e and \u003ccode\u003edefault-headers\u003c/code\u003e, which I\u0026rsquo;ll explain below.\nI set letsencrypt as the cert certResolver.\nFinally I name the service \u003ccode\u003epihole\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThen in the \u003ccode\u003eservices\u003c/code\u003e section I configure where pihole is located by just giving the internal IP for traefik to route to.\nFinally I define my middlewares.\nTo get to the pihole homepage you need to use the route \u003ccode\u003e/admin\u003c/code\u003e so I want that added automatically when I go to \u003ccode\u003epihole.example.com\u003c/code\u003e so I come to \u003ccode\u003epihole.example.com/admin\u003c/code\u003e.\nAnd I wanted to restrict access to just my internal network and my wireguard network - this is done with the \u003ccode\u003edefault-whitelist\u003c/code\u003e.\nThe last thing is to configure a chain of middlewares that I called \u003ccode\u003esecured\u003c/code\u003e which is just easier for the docker labels later on.\u003c/p\u003e\n\u003cp\u003eWith this config in play though, traefik will know about the route \u003ccode\u003epihole.example.com\u003c/code\u003e and handle the ip whitelisting and load balancing for me.\u003c/p\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ehttp\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c\"\u003e#region routers \u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003erouters\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003epihole\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eentryPoints\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;websecure\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003erule\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Host(`pihole.example.com`)\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003emiddlewares\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"c\"\u003e# - default-headers\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e- \u003cspan class=\"l\"\u003eaddprefix-pihole\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e- \u003cspan class=\"l\"\u003edefault-whitelist\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003etls\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ecertResolver\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eletsencrypt\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eservice\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003epihole\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e#region services\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eservices\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003epihole\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eloadBalancer\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eservers\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e- \u003cspan class=\"nt\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;http://192.168.1.3:80\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003epassHostHeader\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e#endregion\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003emiddlewares\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eaddprefix-pihole\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eaddPrefix\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eprefix\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;/admin\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ehttps-redirect\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eredirectScheme\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003escheme\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ehttps\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003edefault-headers\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eheaders\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eframeDeny\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003esslRedirect\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ebrowserXssFilter\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003econtentTypeNosniff\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eforceSTSHeader\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003estsIncludeSubdomains\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003estsPreload\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003estsSeconds\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e15552000\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ecustomFrameOptionsValue\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eSAMEORIGIN\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003edefault-whitelist\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eipWhiteList\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003esourceRange\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;10.6.0.0/24\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e# wg\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;192.168.1.0/24\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e# lan\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;172.17.0.0/16\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"c\"\u003e# docker\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003esecured\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003echain\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003emiddlewares\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e- \u003cspan class=\"l\"\u003edefault-whitelist\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e- \u003cspan class=\"l\"\u003edefault-headers\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003ch1 id=\"docker-labels\"\u003e\u003cspan class=\"heading-wear-glyph\"\u003eDocker labels\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eNow the real magic is with Docker.\nHere is an example docker-compose file for spinning up a \u003ca href=\"https://jellyfin.org/\"\u003ejellyfin\u003c/a\u003e server that you want to expose to the world, or at least access at home with \u003ccode\u003ejellyfin.example.com\u003c/code\u003e instead of \u003ccode\u003ehttp://192.168.1.N:8096\u003c/code\u003e\u0026hellip;\u003c/p\u003e\n\u003cp\u003eI left some of the ansible variable stuff in here, but the main part to be concerned with is the \u003ccode\u003elabels\u003c/code\u003e section\u0026hellip;\u003c/p\u003e\n\u003cp\u003eWe define just a few labels to throw onto this docker container which let\u0026rsquo;s traefik discover it automatically and apply any settings necessary (like my \u003ccode\u003eipWhiteList\u003c/code\u003e).\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003etraefik.enable\u003c/code\u003e is either True or False.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etraefik.http.router.jellyfin.rule\u003c/code\u003e defines an http router called jellyfin and sets the url to \u003ccode\u003ejellyfin.example.com\u003c/code\u003e (if example.com was my \u003ccode\u003eansible_nas_domain\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etraefik.http.routers.jellyfin.tls.certresolver\u003c/code\u003e is set to letsencrypt since I use LE for my wildcard certs.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etraefik.http.routers.jellyfin.tls.domains[0].main\u003c/code\u003e will just be \u003ccode\u003eexample.com\u003c/code\u003e -\u0026gt; and this should remind you of the toml file above\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etraefik.http.routers.jellyfin.tls.domains[0].sans\u003c/code\u003e is set to \u003ccode\u003e*.example.com\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etraefik.http.services.jellyfin.loadbalancer.server.port\u003c/code\u003e is set to jellyfin\u0026rsquo;s default http port of 8096, which tells traefik which port to point to for this service.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ejellyfin\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eimage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003elinuxserver/jellyfin\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003evolumes\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_config_directory }}:/config:rw\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_movies_directory }}:/movies:{{ jellyfin_movies_permissions }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_music_directory }}:/music:{{ jellyfin_music_permissions }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_photos_directory }}:/photos:{{ jellyfin_photos_permissions }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_tv_directory }}:/tv:{{ jellyfin_tv_permissions }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_books_directory }}:/books:{{ jellyfin_books_permissions }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_audiobooks_directory }}:/audiobooks:{{ jellyfin_audiobooks_permissions }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eports\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_port_http }}:8096\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_port_https }}:8920\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eenv\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eTZ\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ ansible_nas_timezone }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003ePUID\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_user_id }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003ePGID\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_group_id }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003erestart_policy\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eunless-stopped\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ememory\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003e1g\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003elabels\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003etraefik.enable\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ jellyfin_available_externally }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003etraefik.http.routers.jellyfin.rule\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Host(`jellyfin.{{ ansible_nas_domain }}`)\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003etraefik.http.routers.jellyfin.tls.certresolver\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;letsencrypt\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003etraefik.http.routers.jellyfin.tls.domains[0].main\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;{{ ansible_nas_domain }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003etraefik.http.routers.jellyfin.tls.domains[0].sans\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;*.{{ ansible_nas_domain }}\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003etraefik.http.services.jellyfin.loadbalancer.server.port\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;8096\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eAnd just like that traefik will automagically find your jellyfin container and route \u003ccode\u003ejellyfin.example.com\u003c/code\u003e to it!\u003c/p\u003e\n",
      "content_text": "\n# Traefik\n\nIf you don't know about [traefik](https://doc.traefik.io/traefik/) and you need a reverse-proxy then you might want to check it out.\nI used to use nginx for my reverse proxy but the config was over my head, and once it was working I was afraid to touch it.\nTraefik brings a lot to the table, my main uses are reverse proxy and ip whitelisting, but it's doing even more under the hood that I don't have a full-grasp of yet.\n\nI like Traefik a lot because once I get some basic config up it's incredibly easy to add services into my homelab whether they run on my primary server or not.\nThis will not be exhaustive but I'll outline my simple setup process of traefik and how I add services whether they are in docker or not.\n\n# Docker\n\nIn 2022 I'm still a docker fan-boy and I run my traefik instance in a docker container. \nThis isn't necessary but I love the portability since my homelab is very dynamic at the moment.\nAnd even if it wasn't I'd still want to keep traefik in docker because deployment and updating are just so flipping easy\n\nA simple docker-compose file for traefik might look like this:\n\n```yaml\nname: traefik\nimage: \"traefik:v2.4\"\nnetwork_mode: host\nvolumes:\n  - \"docker-data/traefik/traefik.toml:/etc/traefik/traefik.toml:ro\"\n  - \"docker-data/traefik/config.yml:/etc/traefik/config.yml:ro\"\n  - \"docker-data/traefik/letsencrypt:/letsencrypt:rw\"\n  - \"/var/run/docker.sock:/var/run/docker.sock:ro\"  # for auto-discovery\nenv: \"{{ traefik_environment_variables }}\"\nrestart_policy: unless-stopped\nmemory: \"1g\"\n```\n\n# Ansible deployment\n\n__I plan to have more on my homelab and Ansible on this site eventually...__\n\nI use Ansible to deploy most of my services at home, including traefik. My main homelab repo is [here](https://github.com/nicpayne713/ansible-nas) which is a fork of [Ansible NAS](https://github.com/davestephens/ansible-nas).\n\n\u003e If you want my stuff then be sure to go to the `user/nic` branch on my fork\n\nYou can see the ansible stuff for traefik [here](https://github.com/davestephens/ansible-nas/tree/master/roles/traefik)\n\n# Config\n\nI use a `traefik.toml` as the main config and it looks something like this.\nWith ansible a lot of this is done through template variables but this is the general idea.\nThis config tells traefik what ports to listen and forward on, and gives the names to be referenced by docker labels (down below). \n\nTraefik also has a handy web ui that with this config you can find on port `8080`.\nThere is a `providers` section - which is one of the biggest selling points of traefik for me.\nI have a docker provider configured  and a static file. \n\nThe docker provider lets traefik auto-discover new services that I deploy and automatically handle the routing!\nThe static file lets me easily add non-dockerized service routing, or routing to dockerized services on another host (I think traefik has an easier way to do this automatically but I don't do it often enough to need that kind of automation).\nThen at the bottom is the SSL cert stuff. \nUsing Let's Encrypt is pretty easy and I use Cloudflare as my DNS provider\n\n```toml\n\n[entryPoints]\n[entryPoints.web]\naddress = \":80\"\n\n[entryPoints.web.http.redirections.entryPoint]\nto = \"websecure\"\n\n[entryPoints.websecure]\naddress = \":443\"\n\n[entryPoints.websecure.http.tls]\ncertResolver = \"letsencrypt\"\n\n[entryPoints.websecure.http.tls.domains]\nmain = \"example.com\"\nsans = [\n\"*.example.com\"\n]\n\n[entryPoints.traefik]\naddress = \":8080\"\n\n[providers]\nprovidersThrottleDuration = \"1s\"\n[providers.docker]\nexposedbydefault = false\n[providers.file]\nfilename = \"/etc/traefik/config.yml\"\n\n[api]\ninsecure = true\ndashboard = true\n\n[log]\nlevel = \"INFO\"\n\n[ping]\nterminatingStatusCode = 0\n\n[certificatesResolvers]\n[certificatesResolvers.letsencrypt]\n[certificatesResolvers.letsencrypt.acme]\nemail = \"my_email@example.com\"\nstorage = \"/letsencrypt/acme.json\"\ncaserver = \"https://acme-staging-v02.api.letsencrypt.org/directory\"  # le staging, not prod\n\n[certificatesResolvers.letsencrypt.acme.dnsChallenge]\nprovider = \"cloudflare\"\n```\n\n# Providers.file\n\nTo my knowledge there isn't much to configure on the docker provider side of things until you deploy a service.\nBut the provider config file should get a little screen time here.\n\nThe file defines a traefik http router for each service you define, in this case just `pihole`. \n\nHere I am adding my pihole instance which is not run inside docker but is inside a VM on another host.\nI want the `entryPoints` to be set to `websecure` which is configured above in the http redirects.\nI want some middlewares, `addprefix-pihole` and `default-headers`, which I'll explain below.\nI set letsencrypt as the cert certResolver.\nFinally I name the service `pihole`.\n\nThen in the `services` section I configure where pihole is located by just giving the internal IP for traefik to route to.\nFinally I define my middlewares. \nTo get to the pihole homepage you need to use the route `/admin` so I want that added automatically when I go to `pihole.example.com` so I come to `pihole.example.com/admin`.\nAnd I wanted to restrict access to just my internal network and my wireguard network - this is done with the `default-whitelist`. \nThe last thing is to configure a chain of middlewares that I called `secured` which is just easier for the docker labels later on.\n\nWith this config in play though, traefik will know about the route `pihole.example.com` and handle the ip whitelisting and load balancing for me.\n\n```yaml\nhttp:\n #region routers \n  routers:\n    pihole:\n      entryPoints:\n        - \"websecure\"\n      rule: \"Host(`pihole.example.com`)\"\n      middlewares:\n        # - default-headers\n        - addprefix-pihole\n        - default-whitelist\n      tls: \n        certResolver: letsencrypt\n      service: pihole\n  #region services\n  services:\n    pihole:\n      loadBalancer:\n        servers:\n          - url: \"http://192.168.1.3:80\"\n        passHostHeader: true\n  #endregion\n  middlewares:\n    addprefix-pihole:\n      addPrefix:\n        prefix: \"/admin\"\n    https-redirect:\n      redirectScheme:\n        scheme: https\n\n    default-headers:\n      headers:\n        frameDeny: true\n        sslRedirect: true\n        browserXssFilter: true\n        contentTypeNosniff: true\n        forceSTSHeader: true\n        stsIncludeSubdomains: true\n        stsPreload: true\n        stsSeconds: 15552000\n        customFrameOptionsValue: SAMEORIGIN\n\n    default-whitelist:\n      ipWhiteList:\n        sourceRange:\n        - \"10.6.0.0/24\"  # wg\n        - \"192.168.1.0/24\"  # lan\n        - \"172.17.0.0/16\"  # docker\n\n    secured:\n      chain:\n        middlewares:\n        - default-whitelist\n        - default-headers\n```\n\n\n# Docker labels\n\nNow the real magic is with Docker.\nHere is an example docker-compose file for spinning up a [jellyfin](https://jellyfin.org/) server that you want to expose to the world, or at least access at home with `jellyfin.example.com` instead of `http://192.168.1.N:8096`...\n\nI left some of the ansible variable stuff in here, but the main part to be concerned with is the `labels` section...\n\nWe define just a few labels to throw onto this docker container which let's traefik discover it automatically and apply any settings necessary (like my `ipWhiteList`).\n\n* `traefik.enable` is either True or False. \n* `traefik.http.router.jellyfin.rule` defines an http router called jellyfin and sets the url to `jellyfin.example.com` (if example.com was my `ansible_nas_domain`)\n* `traefik.http.routers.jellyfin.tls.certresolver` is set to letsencrypt since I use LE for my wildcard certs.\n* `traefik.http.routers.jellyfin.tls.domains[0].main` will just be `example.com` -\u003e and this should remind you of the toml file above\n* `traefik.http.routers.jellyfin.tls.domains[0].sans` is set to `*.example.com`\n* `traefik.http.services.jellyfin.loadbalancer.server.port` is set to jellyfin's default http port of 8096, which tells traefik which port to point to for this service.\n\n```yaml\nname: jellyfin\nimage: linuxserver/jellyfin\nvolumes:\n  - \"{{ jellyfin_config_directory }}:/config:rw\"\n  - \"{{ jellyfin_movies_directory }}:/movies:{{ jellyfin_movies_permissions }}\"\n  - \"{{ jellyfin_music_directory }}:/music:{{ jellyfin_music_permissions }}\"\n  - \"{{ jellyfin_photos_directory }}:/photos:{{ jellyfin_photos_permissions }}\"\n  - \"{{ jellyfin_tv_directory }}:/tv:{{ jellyfin_tv_permissions }}\"\n  - \"{{ jellyfin_books_directory }}:/books:{{ jellyfin_books_permissions }}\"\n  - \"{{ jellyfin_audiobooks_directory }}:/audiobooks:{{ jellyfin_audiobooks_permissions }}\"\nports:\n  - \"{{ jellyfin_port_http }}:8096\"\n  - \"{{ jellyfin_port_https }}:8920\"\nenv:\n  TZ: \"{{ ansible_nas_timezone }}\"\n  PUID: \"{{ jellyfin_user_id }}\"\n  PGID: \"{{ jellyfin_group_id }}\"\nrestart_policy: unless-stopped\nmemory: 1g\nlabels:\n  traefik.enable: \"{{ jellyfin_available_externally }}\"\n  traefik.http.routers.jellyfin.rule: \"Host(`jellyfin.{{ ansible_nas_domain }}`)\"\n  traefik.http.routers.jellyfin.tls.certresolver: \"letsencrypt\"\n  traefik.http.routers.jellyfin.tls.domains[0].main: \"{{ ansible_nas_domain }}\"\n  traefik.http.routers.jellyfin.tls.domains[0].sans: \"*.{{ ansible_nas_domain }}\"\n  traefik.http.services.jellyfin.loadbalancer.server.port: \"8096\"\n```\n\n\nAnd just like that traefik will automagically find your jellyfin container and route `jellyfin.example.com` to it!\n",
      "summary": "If you don't know about traefik and you need a reverse-proxy then you might want to check it out. I used to use nginx for my reverse proxy but the config was...",
      "date_published": "2022-03-06T00:00:00Z",
      "date_modified": "2022-03-06T00:00:00Z",
      "authors": [
        {
          "name": "Nic Payne",
          "url": "https://pype.dev"
        }
      ],
      "tags": [
        "homelab",
        "tech"
      ]
    }
  ]
}