<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>bisko.be - Dev</title><description>Technology, development, hardware, and experiments.</description><link>https://bisko.be/</link><language>en-us</language><item><title>Running Ollama with older GPUs on CachyOS</title><link>https://bisko.be/posts/dev/running-ollama-with-older-gpus-on-cachyos/</link><guid isPermaLink="true">https://bisko.be/posts/dev/running-ollama-with-older-gpus-on-cachyos/</guid><description>Today I was migrating my Windows 11 VM to Linux, to allow better flexibility of service being ran on it and encountered an issue with Ollama not being able to run on my old GPUs - GTX1070 and GTX970</description><pubDate>Sat, 28 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3 id=&quot;tldr&quot;&gt;TL;DR;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ollama-cuda&lt;/code&gt; on CachyOS comes (at this point in time) with support only for &lt;code&gt;compute &gt;= 7.5&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you have older GPUs with earlier &lt;code&gt;compute&lt;/code&gt;, you HAVE TO do one of 2 things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build &lt;code&gt;ollama-cuda&lt;/code&gt; from source, with support for the older compute targets&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;ollama-vulkan&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I chose &lt;code&gt;ollama-vulkan&lt;/code&gt; and it’s working perfectly!&lt;/p&gt;
&lt;h3 id=&quot;story-time&quot;&gt;Story time&lt;/h3&gt;
&lt;p&gt;Today I had the inspiration to finally shut down my Windows 11 VM and migrate it to Linux.&lt;/p&gt;
&lt;p&gt;The requirements were to be able to run:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ollama - for local model magic&lt;/li&gt;
&lt;li&gt;Docker - for remote development&lt;/li&gt;
&lt;li&gt;Steam - for playing games&lt;/li&gt;
&lt;li&gt;Jellyfin - for home videos archive&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now I am going to focus only on Ollama as it was an interesting experience and it got me wondering why things are not more obvious.&lt;/p&gt;
&lt;p&gt;The machine has 2 GPUs in it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GTX 1070 - 8GB&lt;/li&gt;
&lt;li&gt;GTX 970 - 4GB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I wanted to run Ollama on them, to play around with local models and how I could integrate it in some projects. For example - anonymizing data locally, doing a non-destructive OpenClaw implementation that is fit for my use-cases, local OCR for documents that I scan with my phone, automating some things in the everyday management of a home.&lt;/p&gt;
&lt;p&gt;So naturally I installed &lt;code&gt;ollama&lt;/code&gt; and &lt;code&gt;ollama-cuda&lt;/code&gt; as I have 2 Nvidia GPUs in there, expecting that it would work fine, as it was working on Windows just a few minutes prior.&lt;/p&gt;
&lt;p&gt;I started Ollama, loaded &lt;code&gt;qwen3:8b&lt;/code&gt; for the quick experiment and… it was running on CPU 🤔&lt;/p&gt;
&lt;p&gt;The GPUs were perfectly capable to hold it in VRAM, but for some reason Ollama was choosing to run them on CPU.&lt;/p&gt;
&lt;p&gt;After trying to figure it out from logs, I asked Claude to help out a bit and it came up with the pretty daunting finding:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;The&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; logs&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; tell&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; story&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; clearly.&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Both&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; your&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GPUs&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; are&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; detected&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; but&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; then&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; filtered&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; out&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; because&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; they&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; fail&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; CUDA&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; initialization:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  &quot;filtering device which didn&apos;t fully initialize&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; id=GPU-eb132a13-b9f4-40e3-d85d-60f211dfd21e&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; library=CUDA&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  &quot;filtering device which didn&apos;t fully initialize&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; id=GPU-550263c8-37e2-2a25-c0b6-10cc7511ed20&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; library=CUDA&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  The&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; reason&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; CUDA&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; library&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; bundled&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; with&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Ollama&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0.17.4&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; was&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; compiled&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; these&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; architectures&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; only:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  CUDA.0.ARCHS&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;=750,800,860,870,880,890,900,1000,1030,1100,1200,1210&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  The&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; minimum&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; supported&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; compute&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; capability&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 7.5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Turing &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; RTX&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; 20xx&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; series&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;). Your GPUs are older than that:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  ┌──────────┬────────────────────┬──────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;   GPU&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Compute&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Capability&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Architecture&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  ├──────────┼────────────────────┼──────────────┤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GTX&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1070&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; │&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 6.1&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Pascal&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;       │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  ├──────────┼────────────────────┼──────────────┤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GTX&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 970&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  │&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 5.2&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Maxwell&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  └──────────┴────────────────────┴──────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Neither&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; supported&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; list,&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; so&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; CUDA&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; initialization&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; fails&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; both,&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; and&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Ollama&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; falls&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; back&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; CPU-only&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; inference.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Your&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; options:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  1.&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Downgrade&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Ollama&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; an&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; older&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; version&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; that&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; still&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; included&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Pascal/Maxwell&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; support&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (pre-0.6.x &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;era&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; had&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; broader&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; arch&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; coverage,&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; but&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; check&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; release&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; notes&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; specifics&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  2.&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Build&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Ollama&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; source&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; with&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; CUDA_ARCHITECTURES=&quot;52;61;75;80;86&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; your&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GPU&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; architectures.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  3.&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Upgrade&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GPUs&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; at&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; least&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; an&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; RTX&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2060&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; newer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (compute &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;7.5+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, this was kind of a letdown for me, as I want to use the GPUs as much as possible, before moving on to a new one.&lt;/p&gt;
&lt;p&gt;I didn’t want to actually rebuild Ollama from source, as it should support things out of the box and I was very confused why it would not, even though the Windows install it supported those architectures.&lt;/p&gt;
&lt;p&gt;These cards were also shown on Ollama’s website as supported!&lt;/p&gt;
&lt;p&gt;To cut a long story of Googling short:&lt;/p&gt;
&lt;p&gt;Turns out that &lt;code&gt;ollama-cuda&lt;/code&gt; comes with just the requirements listed above… and the suggestion was to install &lt;code&gt;ollama-vulkan&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After doing that, everything started working very smoothly!&lt;/p&gt;</content:encoded><category>linux</category><category>llm</category><category>ollama</category><category>cachyos</category><category>vulcan</category><category>cuda</category></item><item><title>[Linux] Recovering a disconnected `apt dist-upgrade` session</title><link>https://bisko.be/posts/dev/linux-recovering-a-disconnected-apt-dist-upgrade-session/</link><guid isPermaLink="true">https://bisko.be/posts/dev/linux-recovering-a-disconnected-apt-dist-upgrade-session/</guid><description>Today I was updating my Proxmox install remotely via the built-in console, but forgot what I was doing and closed the tab mid-way. This resulted in me being unable to connect again as the packages were already being updated in the background and the upgrade has asked a question to replace a file and waiting</description><pubDate>Wed, 23 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today I was updating my Proxmox install remotely via the built-in console, but forgot what I was doing and closed the tab mid-way.&lt;/p&gt;
&lt;p&gt;This resulted in me being unable to connect again as the packages were already being updated in the background and the upgrade has asked a question to replace a file and waiting for my input.&lt;/p&gt;
&lt;p&gt;So I could SSH in, but not do anything, as it was still waiting for input on a console that I could not connect to, as it was not opening the UI.&lt;/p&gt;
&lt;p&gt;After a quick look around, I stumbled upon a &lt;a href=&quot;https://serverfault.com/questions/19634/how-to-reconnect-to-a-disconnected-ssh-session&quot;&gt;Serverfault thread&lt;/a&gt; mentioning using &lt;code&gt;reptyr&lt;/code&gt; to take over the terminal session over SSH.&lt;/p&gt;
&lt;p&gt;Adding here what exactly was done, to be able the session back and finish the upgrade:&lt;/p&gt;
&lt;p&gt;From &lt;a href=&quot;https://serverfault.com/questions/19634/how-to-reconnect-to-a-disconnected-ssh-session#comment1506308_979180&quot;&gt;this comment&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; https://github.com/nelhage/reptyr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; reptyr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;make&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This installed &lt;code&gt;reptyr&lt;/code&gt; on the machine.&lt;/p&gt;
&lt;p&gt;Then I looked for all the open sessions with &lt;code&gt;ps ax | grep pts&lt;/code&gt; to find the process I was looking for.&lt;/p&gt;
&lt;p&gt;Then I found the parent-most process in the call tree that has &lt;code&gt;pts&lt;/code&gt; assigned to it and attached to it via it’s PID:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reptyr&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1390511&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I could finish the upgrade! 🎉&lt;/p&gt;</content:encoded><category>Uncategorized</category></item><item><title>[Linux] Syncthing – read-only file system when running as service</title><link>https://bisko.be/posts/dev/linux-syncthing-read-only-file-system-when-running-as-service/</link><guid isPermaLink="true">https://bisko.be/posts/dev/linux-syncthing-read-only-file-system-when-running-as-service/</guid><description>I’ve been using Syncthing for a while to synchronize my working copy with a local dev server for a few months. At first I was using it by logging in and running it manually through the CLI. It was working well, so I didn’t think twice when I moved to run it as a service.</description><pubDate>Wed, 06 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been using &lt;a href=&quot;https://syncthing.net/&quot;&gt;Syncthing&lt;/a&gt; for a while to synchronize my working copy with a local dev server for a few months.&lt;/p&gt;
&lt;p&gt;At first I was using it by logging in and running it manually through the CLI. It was working well, so I didn’t think twice when I moved to run it as a service. It started, it synced some data, everything was fine.&lt;/p&gt;
&lt;p&gt;Until it wasn’t, of course! 🙂&lt;/p&gt;
&lt;p&gt;Turns out that I didn’t notice a bunch of errors cropping up in the logs mentioning that the filesystem on the dev server is read-only and it was causing Syncthing to not sync anything.&lt;/p&gt;
&lt;p&gt;I thought it was a bug and it was just showing &lt;code&gt;Out of Sync&lt;/code&gt; for the folders, but it was actually syncing. Well I was wrong.&lt;/p&gt;
&lt;p&gt;After debugging for a few hours and not finding any clues whatsoever in the forums through a few Google searches, I landed on an &lt;a href=&quot;https://wiki.archlinux.org/title/syncthing#read-only_file_system_error_on_/etc_although_run_as_root&quot;&gt;Syncthing article on the ArchWiki&lt;/a&gt;, mentioning my exact case:&lt;/p&gt;
&lt;p&gt;read-only file system error on /etc although run as root&lt;/p&gt;
&lt;p&gt;This was my exact usecase, apart from the problematic folder not being &lt;code&gt;/etc&lt;/code&gt;, but &lt;code&gt;/usr/local/src&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Well, after reading what it said, it turns out that if you run Syncthing (or anything) via &lt;code&gt;systemd&lt;/code&gt; and you have &lt;code&gt;ProtectSystem&lt;/code&gt; set for the service to &lt;code&gt;full&lt;/code&gt;, it will make some directories read-only by default. &lt;code&gt;/usr&lt;/code&gt; is one of those paths.&lt;/p&gt;
&lt;p&gt;To fix it, you need to add a new line in the service config and restart the service (and &lt;code&gt;daemon-reload&lt;/code&gt;):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ReadWritePaths=/usr/local/src&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;After this Syncthing should work fine.&lt;/p&gt;</content:encoded><category>Homelab</category><category>linux</category><category>permissions</category><category>read-only</category><category>syncthing</category><category>systemd</category></item><item><title>[Linux] Running multiple commands on multiple servers in parallel</title><link>https://bisko.be/posts/dev/linux-running-multiple-commands-on-multiple-servers-in-parallel/</link><guid isPermaLink="true">https://bisko.be/posts/dev/linux-running-multiple-commands-on-multiple-servers-in-parallel/</guid><description>I have a cluster of Raspberry Pi’s at home running Docker Swarm. To keep up with things, they’re using the same configuration – users, Docker versions, etc. Sometimes some of the updates require running the same thing on all the nodes of the cluster – for example – creating a new Docker macvlan network. To</description><pubDate>Mon, 19 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have a cluster of Raspberry Pi’s at home running Docker Swarm. To keep up with things, they’re using the same configuration – users, Docker versions, etc.&lt;/p&gt;
&lt;p&gt;Sometimes some of the updates require running the same thing on all the nodes of the cluster – for example – creating a new Docker macvlan network.&lt;/p&gt;
&lt;p&gt;To do this, one has to either run the same commands on all the nodes manually, by &lt;strong&gt;ssh&lt;/strong&gt;-ing in each and every one, running the commands and moving on to the next one.&lt;/p&gt;
&lt;p&gt;Since I’m trying to reduce my work in the long run and to make things as organized as possible, I started looking into ways to run commands on all the nodes at the same time.&lt;/p&gt;
&lt;h3 id=&quot;iteration-1-custom-python-script&quot;&gt;Iteration 1: Custom Python script&lt;/h3&gt;
&lt;p&gt;The first iteration of doing this was to create a custom Python script. One side of this was to learn Python a bit better, the other side was that I couldn’t find a good way to run commands in more native way.&lt;/p&gt;
&lt;p&gt;As one can expect (hey, still having little experience in the language 🙂 ), it became bloated mess pretty quickly and was very prone to breakage.&lt;/p&gt;
&lt;p&gt;I had to find another way to do this, without having to re-learn what I did 3 weeks ago and what broke the last time.&lt;/p&gt;
&lt;h3 id=&quot;iteration-2-pssh&quot;&gt;Iteration 2: &lt;code&gt;pssh&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Googling around I stumbled upon &lt;code&gt;[pssh](https://linux.die.net/man/1/pssh)&lt;/code&gt; that can run things in parallel via SSH.&lt;/p&gt;
&lt;p&gt;All things considered, it was pretty easy to get it up and running.&lt;/p&gt;
&lt;p&gt;The problem was that to run some of the things I needed to be able to do them via &lt;code&gt;sudo&lt;/code&gt;. Passing passwords around wasn’t the best, so I had to search around again to figure out how to send the &lt;code&gt;sudo&lt;/code&gt; password when the remote server asked for it.&lt;/p&gt;
&lt;p&gt;Turns out it’s pretty easy if you stumble upon the right &lt;a href=&quot;https://unix.stackexchange.com/a/487558/134974&quot;&gt;StackOverflow comment&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-tldr-version-is&quot;&gt;The TL;DR; version is:&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stty&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -echo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Password: &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;read&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; PASS&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stty&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PASS&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pssh&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;HOSTFIL&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /tmp/output&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -I&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;`&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ./commands.sh`&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;-I &quot;`cat ./commands.sh`&quot;&lt;/code&gt; is required to be done like this (surrounded in quotes and backcquotes like this), otherwise it doesn’t properly run the commands. The password is going to be sent as a command separately and not picked up as an input to &lt;strong&gt;sudo&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The other catch is that because of the way this is set up, one needs to run &lt;code&gt;sudo&lt;/code&gt; with the &lt;code&gt;-S&lt;/code&gt; parameter, to pick the password input properly.&lt;/p&gt;</content:encoded><category>Uncategorized</category></item><item><title>Guessing a numeric zip file password only with command-line utilities</title><link>https://bisko.be/posts/dev/guessing-a-numeric-zip-file-password-only-with-command-line-utilities/</link><guid isPermaLink="true">https://bisko.be/posts/dev/guessing-a-numeric-zip-file-password-only-with-command-line-utilities/</guid><description>Today I received my monthly invoice from my internet provider and something struck me as weird. The invoice, contained in the mail was in a ZIP file with a password. Not to say how strange it was to receive an attachment as a ZIP file in these days and times (spam, malware, phishing, etc.), the</description><pubDate>Mon, 14 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today I received my monthly invoice from my internet provider and something struck me as weird.&lt;/p&gt;
&lt;p&gt;The invoice, contained in the mail was in a ZIP file with a password.&lt;/p&gt;
&lt;p&gt;Not to say how strange it was to receive an attachment as a ZIP file in these days and times (spam, malware, phishing, etc.), the password they chose struck me as very weak.&lt;/p&gt;
&lt;p&gt;It’s the account holder birthday in the format &lt;code&gt;YYMMDD&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I ran a very crude calculation in my mind while at the gym and it came out as very few possible combinations. After using an online tool to calculate how many days have passed (since not all combinations would result in a valid date) since 1900-01-01, turns out the combinations are just 44,075 (until 2020-09-14).&lt;/p&gt;
&lt;p&gt;Knowing that optimized tools that use GPU power to crack hashes can make guesses in the millions per second, I wanted to see how quickly the password can be guessed without using them and using just the Linux/macOS CLI (as I only had access to a VPS in the gym).&lt;/p&gt;
&lt;p&gt;I came up with the following code that works on macOS:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;echo {1..44000} | xargs -P 16 -n 1 -I{} date -v &quot;-{}d&quot; +&quot;%y%m%d&quot; | xargs -P 16 -I{} sh -c &apos;unzip -qqoP &quot;{}&quot; 0417160508.zip &amp;#x26;&amp;#x26; echo &quot;{}&quot; &amp;#x26;&amp;#x26; exit 255&apos;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The command is pretty simple in it’s workings, even though it seems complicated.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;echo {1..44000}&lt;/code&gt; generates the numbers from 1 to 44,000 and passes them on to the next step.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;xargs -P 16 -n 1 -I{} date -v &quot;-{}d&quot; +&quot;%y%m%d&quot;&lt;/code&gt; – takes the input from the first step and generates dates in the format &lt;code&gt;YYMMDD&lt;/code&gt; by leveraging &lt;code&gt;date&lt;/code&gt;‘s functionality to “augment” a date with specific amount. In this case it would take out X days from the current date. Where X is the number generated in the first step. This way we can generate dates from today back to 1900s.&lt;/p&gt;
&lt;p&gt;The third step is the more interesting, so I’m going to split it in two parts:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;xargs -P 16 -I{} sh -c &apos;...&apos;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This takes the generated dates from step 2 and runs a command on each of those dates. &lt;code&gt;-P 16&lt;/code&gt; here means that it’s going to run this in 16 parallel processes, to make sifting through the data faster. The same trick is applied to step 2 to speed up the date generation.&lt;/p&gt;
&lt;p&gt;The second part is where the guesses happen:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;unzip -qqoP &quot;{}&quot; 0417160508.zip &amp;#x26;&amp;#x26; echo &quot;{}&quot; &amp;#x26;&amp;#x26; exit 255&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;What this does is it first tries to decompress the zip file using the password generated in step 2. If it’s successful it would print out (&lt;code&gt;echo&lt;/code&gt;) the guessed password and then &lt;code&gt;exit 255&lt;/code&gt; forces &lt;code&gt;xargs&lt;/code&gt; to stop running. We don’t want to continue guessing if the password was found.&lt;/p&gt;
&lt;p&gt;All in all, it was pretty bad decision to choose this as the password for the file, because running the above command takes only about 10 seconds to guess the correct password for my invoice. Not much more for anyone else.&lt;/p&gt;</content:encoded><category>Uncategorized</category></item><item><title>Dealing with spaghetti code in PHP: Using anonymous functions to extract pieces of template code</title><link>https://bisko.be/posts/dev/dealing-with-spaghetti-code-in-php-using-anonymous-functions-to-extract-pieces-of-template-code/</link><guid isPermaLink="true">https://bisko.be/posts/dev/dealing-with-spaghetti-code-in-php-using-anonymous-functions-to-extract-pieces-of-template-code/</guid><description>Recently I’ve been helping out a friend with trying to make sense of some code and how to modify it to work well with asynchronous calls to the backend. A bonus would be to be able to write it in a more modular and reusable way. The code is a WordPress plugin that was written</description><pubDate>Sat, 08 Aug 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I’ve been helping out a friend with trying to make sense of some code and how to modify it to work well with asynchronous calls to the backend. A bonus would be to be able to write it in a more modular and reusable way.&lt;/p&gt;
&lt;p&gt;The code is a WordPress plugin that was written with very legacy approach – mix of business and frontend logic in one place. Data manipulations done in the middle of template code and such.&lt;/p&gt;
&lt;p&gt;Basically what you’ve seen in PHP sites back in the early 2000s before all the awesome OOP additions to the language and bunch of mature frameworks.&lt;/p&gt;
&lt;p&gt;The case I was chipping away on today was the following – you have a table that shows bunch of entries. We needed to add several filters to the table and make it work via AJAX to quickly refresh the UI, without reloading the whole WordPress Admin page.&lt;/p&gt;
&lt;p&gt;Filtering the data was easy – a quick inline &lt;code&gt;array_filter&lt;/code&gt; to filter the data before it was passed down to the template code (to keep the same code style this was also in the template file 😇).&lt;/p&gt;
&lt;p&gt;The problem came when we started working on making the table renderable over AJAX.&lt;/p&gt;
&lt;p&gt;It’s in the middle of a bunch of other template and business code. If we wanted to limit the output via AJAX only to the table we had only a few ways to achieve that.&lt;/p&gt;
&lt;p&gt;The first way would be to wrap the HTML before and after the table in HUGE &lt;code&gt;if&lt;/code&gt; statements to make sure it’s not rendered.&lt;/p&gt;
&lt;p&gt;Another way would be to extract the template in a separate file and to include it in the AJAX action that we would define in plugin’s code.&lt;/p&gt;
&lt;p&gt;Anonymous functions to the rescue!&lt;/p&gt;
&lt;p&gt;Thinking of how to deal with this in the easiest possible way, I tried defining a normal PHP function that would contain the table code, but there was a problem.&lt;/p&gt;
&lt;p&gt;The code runs contained in a class method. There are references to &lt;code&gt;$this&lt;/code&gt; in the table template. If we don’t want to change the code too much, we would want to pass &lt;code&gt;$this&lt;/code&gt; as a function argument. Well that doesn’t quite work as you can’t pass &lt;code&gt;$this&lt;/code&gt; as parameter 🤷‍♂️.&lt;/p&gt;
&lt;p&gt;I was a bit disappointed that we’ll have to rewrite bunch of stuff in the template and there were quite a few references that we wanted to be aware of, so it keeps working.&lt;/p&gt;
&lt;p&gt;Then I remembered that the site doesn’t run on PHP5.2, but PHP7 and anonymous functions would be supported.&lt;/p&gt;
&lt;p&gt;And they have the nifty feature where you can define what variables from the calling scope will be passed down to the function when it’s called. For example:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$table_function &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ( $pages, $current_page, $items ) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // ... Table render code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will allow you to directly reference &lt;code&gt;$pages&lt;/code&gt; or &lt;code&gt;$items&lt;/code&gt; in the function body.&lt;/p&gt;
&lt;p&gt;The awesome feature here is that you can also pass &lt;code&gt;$this&lt;/code&gt; as a variable in the function scope!&lt;/p&gt;
&lt;p&gt;Now we were able to fully extract the table rendering code in a separate function that we can call in isolation during the AJAX call!&lt;/p&gt;
&lt;p&gt;Of course one must be very careful about the variables used inside the function body as they have to be defined, so be careful where the AJAX function can be called.&lt;/p&gt;
&lt;p&gt;For us, this would mean that we will add a tiny action in the main class that would still require the file, but we’ll have more control on disabling all the other outputs that will happen.&lt;/p&gt;</content:encoded><category>Snippets</category><category>lambda-functions</category><category>php</category><category>WordPress</category></item><item><title>Arduino/ESP32: Disabling the task watchdog</title><link>https://bisko.be/posts/dev/arduino-esp32-disabling-the-task-watchdog/</link><guid isPermaLink="true">https://bisko.be/posts/dev/arduino-esp32-disabling-the-task-watchdog/</guid><description>Recently I’ve been playing around with ESP32’s multicore functionality and task pinning to specific cores. I was using AutoConnect to support WiFi connection without storing credentials in the code and provide OTA updates via the web UI. This was for a project that was going to control some CPU 4-pin PWM fans that are in</description><pubDate>Wed, 29 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I’ve been playing around with ESP32’s multicore functionality and task pinning to specific cores.&lt;/p&gt;
&lt;p&gt;I was using &lt;a href=&quot;https://github.com/Hieromon/AutoConnect&quot;&gt;AutoConnect&lt;/a&gt; to support WiFi connection without storing credentials in the code and provide OTA updates via the web UI.&lt;/p&gt;
&lt;p&gt;This was for a project that was going to control some CPU 4-pin PWM fans that are in my server closet, to cool the air inside. For that I wanted to split the logic in two tasks.&lt;/p&gt;
&lt;p&gt;One task to handle API’s, sensor reading, updates, WiFi, etc. and one task to handle the interrupt and PWM control of the fans.&lt;/p&gt;
&lt;p&gt;All was good, tasks were created, but when running the code, if I get the ESP32 in the mode where you need to connect to it to tell it to connect to your WiFi network, it started exhibiting a strange behavior – it started to reset the controller every few seconds and I couldn’t make the connection work.&lt;/p&gt;
&lt;p&gt;That was annoying time, having to unmount the controller from it’s place and connect it to USB to flash a new firmware.&lt;/p&gt;
&lt;p&gt;After doing the above I noticed that the error was coming from the watchdog:&lt;/p&gt;
&lt;p&gt;Task watchdog got triggered. The following tasks did not feed the watchdog in time:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;IDLE (CPU 1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Tasks currently running:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CPU 0: ManageTask&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CPU 1: ControllerTask&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking around, it seems that this is triggered by the ESP32’s Task Watchdog, which makes sure the tasks get their turn to execute on the CPU.&lt;/p&gt;
&lt;p&gt;And it also seemed that AutoConnect wasn’t very flexible when working in a Task context, compared to running outside of one, directly with all the other code and functionality.&lt;/p&gt;
&lt;p&gt;Digging around a bit and trying different things, it seems that the easiest way to get oneself out of this situation is to just disable the watchdog and hope that things get executed in time 🙂 The task is not mission-critical, so it’s fine to wait more time for it to complete what it’s doing.&lt;/p&gt;
&lt;p&gt;To disable the watchdog, you need to do two things:&lt;/p&gt;
&lt;p&gt;First is to Include the &lt;code&gt;esp_task_wdt.h&lt;/code&gt; header. To do that, add &lt;code&gt;#include &amp;#x3C;esp_task_wdt.h&gt;&lt;/code&gt; to your include section&lt;/p&gt;
&lt;p&gt;Second, make the watchdog not reset the controller and wait more time. To do this, you need to add &lt;code&gt;esp_task_wdt_init(30, false);&lt;/code&gt; at the start of your Task code.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;cpp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; manage_core_task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;pv_parameters&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    esp_task_wdt_init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // .... rest of the code ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will set the watchdog timeout to 30 &lt;strong&gt;SECONDS&lt;/strong&gt; and disable the controller reset if it’s triggered.&lt;/p&gt;
&lt;p&gt;If you want to have the controller still reset after the watchdog is triggered, change the second parameter of the function call from &lt;code&gt;false&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;</content:encoded><category>Uncategorized</category><category>arduino</category><category>code</category><category>esp32</category><category>espressif</category><category>multi-core</category><category>multi-threading</category></item><item><title>Setting up a YubiKey for Git commit signing</title><link>https://bisko.be/posts/dev/setting-up-a-yubikey-for-git-commit-signing/</link><guid isPermaLink="true">https://bisko.be/posts/dev/setting-up-a-yubikey-for-git-commit-signing/</guid><description>I’ve been using a YubiKey as a 2-Factor Authentication key and to sign my Git commits. Until a few days ago I’ve been using a YubiKey 4. Since my current computer doesn’t have any USB-A ports, I’ve been juggling a USB-A-to-USB-C adapters in my backpack and using the key has been a hassle for the</description><pubDate>Wed, 08 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been using a YubiKey as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Multi-factor_authentication&quot;&gt;2-Factor Authentication&lt;/a&gt; key and to sign my Git commits. Until a few days ago I’ve been using a YubiKey 4. Since my current computer doesn’t have any USB-A ports, I’ve been juggling a USB-A-to-USB-C adapters in my backpack and using the key has been a hassle for the last year. That’s why I decided it’s time to move to my “new” YubiKey 5C to gain the benefit of not having to juggle those adapters.&lt;/p&gt;
&lt;p&gt;I’ve actually had the key for a while, as I ordered it together with a replacement YubiKey 4 that I got because of the &lt;a href=&quot;https://www.yubico.com/2017/10/infineon-rsa-key-generation-issue/&quot;&gt;Infineon TPM&lt;/a&gt; issue they identified, but only now I decided it’s time to move to the new key.&lt;/p&gt;
&lt;p&gt;The other reason to do it now is because my old GPG keys expired and I had to reissue them, so I can use the key to sign my Git commits.&lt;/p&gt;
&lt;h3 id=&quot;gpg-madness&quot;&gt;GPG madness&lt;/h3&gt;
&lt;p&gt;If you’ve dealt with GPG keys in the past (or currently) you know that it can be pretty hard to get it up and running properly and safely for someone who’s never done it before. Keeping master keys offline, shuffling public keys, reissuing keys after they expire, possibly signing them with previous keys to verify them, revoking keys… It’s not easy to follow the best practices even in theory. When it comes to following them in practice, things get extremely complicated.&lt;/p&gt;
&lt;p&gt;Most tutorials online refer to using the CLI to generate your keys, navigating menus with a non-common design pattern and are general pain to get them up and running. Most tutorials say use an offline machine like a Raspberry PI and/or generate the master keys and sub-keys while offline and keep the master key off your computer.&lt;/p&gt;
&lt;p&gt;🤯&lt;/p&gt;
&lt;p&gt;I’ve been dealing with this each start of January for the past almost 4 years. I dread the moment when I get the following error, noting that my signing keys have expired.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;error: gpg failed to sign the data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fatal: failed to write commit object&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This year I decided it’s time to try to make this process much easier and to use the in-built certificate generation and avoid the whole hassle with dealing with GPG key generations and such.&lt;/p&gt;
&lt;h3 id=&quot;yubikey-on-key-keys-generation&quot;&gt;YubiKey on-key keys generation&lt;/h3&gt;
&lt;p&gt;With this we still have to use the CLI UI, but it’s a bit more obvious as it has fewer steps.&lt;/p&gt;
&lt;p&gt;First we have to set up our card/device.&lt;/p&gt;
&lt;h3 id=&quot;carddevice-setup&quot;&gt;Card/device setup&lt;/h3&gt;
&lt;p&gt;Run &lt;code&gt;gpg --card-status&lt;/code&gt; in the terminal and you should see something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Reader ………..: Yubico Yubikey 4 OTP U2F CCID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Application ID …: &amp;#x3C;Serial number&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Version ……….: 2.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Manufacturer …..: Yubico&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Serial number ….: &amp;#x3C;Device serial number&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Name of cardholder: unspecified&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Language prefs …: en&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Sex …………..: unspecified&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;URL of public key : \[not set\]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Login data …….: &amp;#x3C;e-mail or nothing&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Signature PIN ….: not forced&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Key attributes …: rsa4096 rsa4096 rsa4096&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Max. PIN lengths .: 127 127 127&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;PIN retry counter : 3 0 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Signature counter : 9&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you see something similar and no errors show up, you should be fine to continue.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;gpg --card-edit&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You will land in a CLI UI, showing the same information at the start and then a command prompt at the bottom &lt;code&gt;gpg/card&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Type &lt;code&gt;admin&lt;/code&gt; and press return/enter.&lt;/p&gt;
&lt;p&gt;You can now type &lt;code&gt;help&lt;/code&gt; to figure out how to change the owner information and PINs for the card.&lt;/p&gt;
&lt;p&gt;One thing that you &lt;strong&gt;&lt;em&gt;MUST&lt;/em&gt;&lt;/strong&gt; do is change the default PINs for the card. There are two of those. The first one is the PIN key you use to access the keys on the card. The second one is the “Admin” PIN or PUK (Personal Unblocking Code).&lt;/p&gt;
&lt;p&gt;To do this type &lt;code&gt;passwd&lt;/code&gt; and you will see a menu:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gpg/card&gt; passwd  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gpg: OpenPGP card no. &amp;#x3C;Serial number&gt; detected&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;1 - change PIN  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;2 - unblock PIN  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;3 - change Admin PIN  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;4 - set the Reset Code  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Q - quit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Type &lt;code&gt;1&lt;/code&gt; and follow the prompts to update your pin. The default PIN is &lt;code&gt;123456&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After completing that, choose &lt;code&gt;3&lt;/code&gt; to change the Admin PIN. The default is &lt;code&gt;12345678&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After having both pins changed, go back to the main menu to finish updating the key information.&lt;/p&gt;
&lt;p&gt;The commands you can use are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt; – to change the cardholder name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;login&lt;/code&gt; – to change the cardholder e-mail address or login&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that we can move on to the actual key generation.&lt;/p&gt;
&lt;h3 id=&quot;key-generation&quot;&gt;Key generation&lt;/h3&gt;
&lt;p&gt;Now it’s time to actually generate the keys.&lt;/p&gt;
&lt;p&gt;To do that, type &lt;code&gt;generate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You will be asked &lt;code&gt;Make off-card backup of encryption key? (Y/n)&lt;/code&gt;, but as mentioned in YubiKey’s documentation, this is only a shim backup and it will not create a full backup of the secret keys, so it doesn’t matter if you reply &lt;code&gt;Yes&lt;/code&gt; or &lt;code&gt;No&lt;/code&gt;. I reply with &lt;code&gt;No(n)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If there are stored keys on the card you will be asked if you want to replace them:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gpg: Note: keys are already stored on the card!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Replace existing keys? (y/N)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure you’re not going to replace something important that you don’t have backup of and continue with &lt;code&gt;Y&lt;/code&gt;. If there’s something important, better to quit the whole process with &lt;code&gt;Ctrl+C&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You will be asked for your card PIN you set earlier.&lt;/p&gt;
&lt;p&gt;Then you will have to chose how long the keys will be valid for:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Please specify how long the key should be valid.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        0 = key does not expire&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;n&gt; = key expires in n days&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &amp;#x3C;n&gt;w = key expires in n weeks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &amp;#x3C;n&gt;m = key expires in n months&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &amp;#x3C;n&gt;y = key expires in n years&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; Key is valid for? (0)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want the keys to be valid for only 1 year, type &lt;code&gt;1y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You will be asked to confirm the expiration date. Check if everything is correct and confirm.&lt;/p&gt;
&lt;p&gt;Then you will be asked to enter information about the key owner:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Is this correct? (y/N) y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GnuPG needs to construct a user ID to identify your key.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Real name: &amp;#x3C;Your name&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Email address: &amp;#x3C;Your e-mail&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Comment: &amp;#x3C;Comment is optional&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; You selected this USER-ID:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &quot;&amp;#x3C;Your name&gt; &amp;#x3C;comment&gt; &amp;#x3C;your e-mail&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Type `O` to confirm if everything seems correct.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you will be asked for your Admin PIN or PUK. This is required as it will perform a write action on the card.&lt;/p&gt;
&lt;p&gt;Then if everything is correct, the YubiKey will start blinking and continue to do so for a while (for me it takes about five minutes or so).&lt;/p&gt;
&lt;p&gt;After it’s done you will see the following message&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gpg: key &amp;#x3C;Short ID&gt; marked as ultimately trusted&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gpg: revocation certificate stored as &apos;/Users/bisko/.gnupg/openpgp-revocs.d/&amp;#x3C;LONG ID&gt;.rev&apos; public and secret key created and signed.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Take a note of the &lt;code&gt;&amp;#x3C;Short ID&gt;&lt;/code&gt; as we’ll be using this later.&lt;/p&gt;
&lt;p&gt;At this point you can quit the GPG prompt with &lt;code&gt;quit&lt;/code&gt; or &lt;code&gt;Ctrl+C&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now it’s time to save the public key, so we can reuse the key on another computer.&lt;/p&gt;
&lt;p&gt;To do so, run the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --armor&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Short&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; I&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Short&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; I&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.asc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will export the public key to a file named &lt;code&gt;&amp;#x3C;Short ID&gt;.asc&lt;/code&gt;. This will be used in the future if you want to be able to use the YubiKey on another computer or if you lose your GPG configuration.&lt;/p&gt;
&lt;p&gt;To restore the public key in your keyring, you need to do:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --import&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Short&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; I&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.asc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Short&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; I&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Your Name &amp;#x3C;your@email&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; imported&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Total&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; processed:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; imported:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;A very important note here.&lt;/em&gt;&lt;/strong&gt; If this is a new GPG install or another computer, GPG won’t recognize the keys on the card by itself. You need to run &lt;code&gt;gpg --card-status&lt;/code&gt; so it can read the card and pick up the keys on the card.&lt;/p&gt;
&lt;h3 id=&quot;setting-up-git-for-signing&quot;&gt;Setting up Git for signing&lt;/h3&gt;
&lt;p&gt;To set up Git to sign your commits you need to add the following to your &lt;code&gt;~/.gitconfig&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Under the &lt;code&gt;[user]&lt;/code&gt; section, you need to add (or update) the following line:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;signingkey = 0x&amp;#x3C;Short ID&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Then if you want to sign all your commits, add the following at the end of the file:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;[gpg]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  program&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; = /usr/local/bin/gpg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;[commit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  gpgsign&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; = true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will make Git sign all your commits.&lt;/p&gt;
&lt;p&gt;To set up GitHub, you need to add your public key to your profile. To do so, go to &lt;code&gt;GitHub -&gt; Settings -&gt; SSH and GPG keys -&gt; New GPG key&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then you will see a text box, where you need to paste the whole content of the &lt;code&gt;&amp;#x3C;Short ID&gt;.asc&lt;/code&gt; file we generated above.&lt;/p&gt;
&lt;p&gt;If you want to copy the contents of the file (on macOS) you can do:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cat &amp;#x3C;Short ID&gt;.asc | pbcopy&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will copy the contents of the whole file in the clipboard.&lt;/p&gt;
&lt;p&gt;Paste that into the text box on GitHub and click the &lt;code&gt;Add GPG key&lt;/code&gt; button.&lt;/p&gt;
&lt;p&gt;After that you can try to commit and push to GitHub and you should see the pretty &lt;code&gt;Verified&lt;/code&gt; label.&lt;/p&gt;
&lt;h3 id=&quot;debugging&quot;&gt;Debugging&lt;/h3&gt;
&lt;p&gt;Sometimes things don’t work outright. To be able to gather more information you can try the following:&lt;/p&gt;
&lt;h3 id=&quot;signing-with-gpg&quot;&gt;Signing with GPG&lt;/h3&gt;
&lt;p&gt;First try to sign something with the key:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gpg -s &amp;#x3C;file&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If this fails, try to figure out why it fails, I’m no expert to help there.&lt;/p&gt;
&lt;p&gt;Check out Git’s outputGIT_TRACE=1 git commit -am “test”&lt;/p&gt;
&lt;p&gt;This would give you the exact things Git does while it tries to perform the commit and sign it. It would give you a hint why the signing might fail.&lt;/p&gt;
&lt;p&gt;From this you can also see that Git executes the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;/usr/local/bin/gpg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --status-fd=2&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -bsau&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Key&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; I&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can try running this manually to see if it will give you a better error.&lt;/p&gt;</content:encoded><category>Snippets</category><category>Technology</category><category>git</category><category>github</category><category>gpg</category><category>key</category><category>public-key</category><category>secrets</category><category>sign</category><category>yubikey</category></item><item><title>e1000e  eth0: Detected Hardware Unit Hang</title><link>https://bisko.be/posts/dev/e1000e-device-id-eth0-detected-hardware-unit-hang/</link><guid isPermaLink="true">https://bisko.be/posts/dev/e1000e-device-id-eth0-detected-hardware-unit-hang/</guid><description>Recently my home server and VM host randomly started losing network connectivity. On the outside it seems that it was still working, but I was unable to access it in any remote way. The ethernet adapter seemed to be on, according to the switch, so the issue must have been somewhere in software. It wouldn’t</description><pubDate>Wed, 18 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently my home server and VM host randomly started losing network connectivity. On the outside it seems that it was still working, but I was unable to access it in any remote way. The ethernet adapter seemed to be on, according to the switch, so the issue must have been somewhere in software.&lt;/p&gt;
&lt;p&gt;It wouldn’t be the first time a driver would be the issue of hanging network connection. In the past I’ve been burned by buggy WiFi drivers on Linux and Windows computers.&lt;/p&gt;
&lt;p&gt;After digging a bit into the system logs, I stumbled on the following:&lt;/p&gt;
&lt;p&gt;vmhost kernel: e1000e 0000:00:1f.6 eth0: Detected Hardware Unit Hang:&lt;br&gt;
vmhost kernel:   TDH                  &amp;#x3C;0&gt;&lt;br&gt;
vmhost kernel:   TDT                  &amp;#x3C;1&gt;&lt;br&gt;
vmhost kernel:   next_to_use          &amp;#x3C;1&gt;&lt;br&gt;
vmhost kernel:   next_to_clean        &amp;#x3C;0&gt;&lt;br&gt;
vmhost kernel: buffer_info[next_to_clean]:&lt;br&gt;
vmhost kernel:   time_stamp           &amp;#x3C;10fbc2f81&gt;&lt;br&gt;
vmhost kernel:   next_to_watch        &amp;#x3C;0&gt;&lt;br&gt;
vmhost kernel:   jiffies              &amp;#x3C;10fbc3871&gt;&lt;br&gt;
vmhost kernel:   next_to_watch.status &amp;#x3C;0&gt;&lt;br&gt;
vmhost kernel: MAC Status             &amp;#x3C;40080083&gt;&lt;br&gt;
vmhost kernel: PHY Status             &amp;#x3C;796d&gt;&lt;br&gt;
vmhost kernel: PHY 1000BASE-T Status  &amp;#x3C;7800&gt;&lt;br&gt;
vmhost kernel: PHY Extended Status    &amp;#x3C;3000&gt;&lt;br&gt;
vmhost kernel: PCI Status             &amp;#x3C;10&gt;&lt;br&gt;
vmhost kernel: e1000e 0000:00:1f.6 eth0: Reset adapter unexpectedly&lt;br&gt;
vmhost kernel: vmbr0: port 1(eth0) entered disabled state&lt;/p&gt;
&lt;p&gt;Then it would reset the network adapter and after a bit do it again, until the machine completely goes offline.&lt;/p&gt;
&lt;p&gt;Looking for answers online I stumbled upon &lt;a href=&quot;https://serverfault.com/questions/616485/e1000e-reset-adapter-unexpectedly-detected-hardware-unit-hang&quot;&gt;this ServerFault thread&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cause&lt;/p&gt;
&lt;p&gt;Reading upon different sources and bug reports list, it seems the best way to reproduce the issue is to have high-bandwidth situation on the device, i.e. streaming large amounts of data that would saturate the interface.&lt;/p&gt;
&lt;p&gt;In my case it was usually happening when I’m streaming media from the local Plex server to a device. Due to the way the network is set up, the Windows VM that runs the Plex instance has to fetch the media file from a NFS network share on a separate device, transcode it in the VM and then send it to the playback device.&lt;/p&gt;
&lt;p&gt;This adds up to a lot of network traffic, usually ~40-100mbit/s, depending on the device that plays the media file and the source media file quality.&lt;/p&gt;
&lt;p&gt;The same issue manifested itself when streaming games via Steam Link to our Apple TV. The connection is wired, but it’s not uncommon for the network to drop. I think it’s correlated with the same issue, but will keep an eye for it to see if it will happen in the future after the fix.&lt;/p&gt;
&lt;p&gt;Possible fix&lt;/p&gt;
&lt;p&gt;Seems a possible fix would be to disable &lt;strong&gt;GSO&lt;/strong&gt; &lt;em&gt;(Generic Segmentation Offload)&lt;/em&gt;, &lt;strong&gt;TSO&lt;/strong&gt; &lt;em&gt;(TCP Segmentation Offload)&lt;/em&gt; and &lt;strong&gt;GRO&lt;/strong&gt; &lt;em&gt;(Generic Receive Offload)&lt;/em&gt; on the network interface*:&lt;/p&gt;
&lt;p&gt;ethtool -K eth0 gso off gro off tso off&lt;/p&gt;
&lt;p&gt;I have applied this to my setup and I’m waiting to see if this will actually solve the issue in the long run.&lt;/p&gt;
&lt;p&gt;Footnotes&lt;/p&gt;
&lt;p&gt;* These options are related to offloading package segmentation to the network interface controller to reduce CPU usage on the machine. More details can be found in &lt;a href=&quot;https://en.wikipedia.org/wiki/Large_send_offload&quot;&gt;this Wikipedia article&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>Homelab</category><category>bandwidth</category><category>bug</category><category>network</category><category>nic</category><category>plex</category><category>proxmox</category><category>steam</category><category>streaming</category></item><item><title>Snippets: Running a local/private swarm Docker image registry</title><link>https://bisko.be/posts/dev/snippets-running-a-local-private-swarm-docker-image-registry/</link><guid isPermaLink="true">https://bisko.be/posts/dev/snippets-running-a-local-private-swarm-docker-image-registry/</guid><description>Today I was trying to generate a Docker image from a Node.js project and I wanted to deploy it on my local test swarm. Unfortunately if one builds a local Docker image, this image is stored and accessible only to the node it was created on and the other swarm nodes can’t access it. The</description><pubDate>Fri, 11 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today I was trying to generate a Docker image from a Node.js project and I wanted to deploy it on my local test swarm.&lt;/p&gt;
&lt;p&gt;Unfortunately if one builds a local Docker image, this image is stored and accessible only to the node it was created on and the other swarm nodes can’t access it.&lt;/p&gt;
&lt;p&gt;The way to fix this is to push the image to a Docker registry where it can be pulled from by all the nodes in the swarm.&lt;/p&gt;
&lt;p&gt;Creating the registry&lt;/p&gt;
&lt;p&gt;To instantiate a registry service in the swarm, run:&lt;/p&gt;
&lt;p&gt;docker service create —name registry —publish 5000:5000 registry:latest&lt;/p&gt;
&lt;p&gt;This will create the registry service and run it in the swarm, making it accessible to all the nodes in the swarm.&lt;/p&gt;
&lt;p&gt;Pushing an image to the registry&lt;/p&gt;
&lt;p&gt;To push an image to the registry, you have to do two things – tag and then push the image.&lt;/p&gt;
&lt;p&gt;Here’s an example on how to build and tag the image in one go:&lt;/p&gt;
&lt;p&gt;docker build . -t localhost.localdomain:5000/&lt;image-name&gt;:latest&lt;/image-name&gt;&lt;/p&gt;
&lt;p&gt;And how to push it to the registry:&lt;/p&gt;
&lt;p&gt;docker push localhost.localdomain:5000/&lt;image-name&gt;:latestUsing the image in a service/container/etc&lt;/image-name&gt;&lt;/p&gt;
&lt;p&gt;To use the image in a service or a container, you specify the full path from above, i.e. &lt;code&gt;localhost.localdomain:5000/&amp;#x3C;image-name&gt;:latest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Swarm nodes will have access to the image and will be able to pull and run it.&lt;/p&gt;
&lt;p&gt;Important note about the registry address&lt;/p&gt;
&lt;p&gt;In most tutorials online, the registry URL is given as &lt;code&gt;localhost:5000&lt;/code&gt;. Unfortunately this doesn’t work and usually it times out when trying to use it. If we change this to &lt;code&gt;localhost.localdomain&lt;/code&gt; it will work!&lt;/p&gt;
&lt;p&gt;Not sure why this happens when both &lt;code&gt;localhost&lt;/code&gt; and &lt;code&gt;localhost.localdomain&lt;/code&gt; resolve to &lt;code&gt;127.0.0.1&lt;/code&gt;.&lt;/p&gt;</content:encoded><category>Homelab</category><category>Snippets</category><category>Technology</category><category>docker</category><category>docker-swarm</category><category>registry</category><category>swarm</category></item><item><title>Snippets: Map Apple Keyboard Section sign key to back quote ( § to ` )</title><link>https://bisko.be/posts/dev/snippets-map-apple-keyboard-section-sign-key-to-back-quote-%C2%A7-to/</link><guid isPermaLink="true">https://bisko.be/posts/dev/snippets-map-apple-keyboard-section-sign-key-to-back-quote-%C2%A7-to/</guid><description>I’ve been using the Apple keyboards for a while, but when you live in Europe it’s not easy to source the US layout ones that I’m used to. On macOS there’s an “easy” way to remap the keyboard with just a terminal command: watch -n1 -x hidutil property -m ‘{“ProductID”:592, “VendorID”:1452}’ –set ‘{“UserKeyMapping”:[{“HIDKeyboardModifierMappingSrc”:0x700000035,”HIDKeyboardModifierMappingDst”:0x700000064}]}’ What this</description><pubDate>Wed, 31 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been using the Apple keyboards for a while, but when you live in Europe it’s not easy to source the US layout ones that I’m used to.&lt;/p&gt;
&lt;p&gt;On macOS there’s an “easy” way to remap the keyboard with just a terminal command:&lt;/p&gt;
&lt;p&gt;watch -n1 -x hidutil property -m ’{“ProductID”:592, “VendorID”:1452}’ —set ’{“UserKeyMapping”:[{“HIDKeyboardModifierMappingSrc”:0x700000035,“HIDKeyboardModifierMappingDst”:0x700000064}]}’&lt;/p&gt;
&lt;p&gt;What this piece of code does is to change the mapping of the Section key ( § ) to write out the backquote/tilde ( &lt;code&gt;`/ ~&lt;/code&gt; ) key.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;watch -n1 -x&lt;/code&gt; part does this every second as sometimes macOS likes to lose the setting, usually when the computer goes to sleep or when the keyboard is unplugged and plugged again.&lt;/p&gt;
&lt;p&gt;Please note that on some versions of macOS the &lt;code&gt;watch&lt;/code&gt; utility is not installed and needs to be pulled through something like &lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt; or &lt;a href=&quot;https://www.macports.org/&quot;&gt;MacPorts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The above code works with the Apple External keyboard with USB and European layout with Bulgarian letters. It might need a slight adjustment to the hex values for keys for other types of keyboards.&lt;/p&gt;
&lt;p&gt;A variation of the command works well for the same type of keyboard on the MacBook Pro itself. You just need to swap the position of the &lt;code&gt;0x700000035&lt;/code&gt; and &lt;code&gt;0x700000064&lt;/code&gt; values.&lt;/p&gt;
&lt;p&gt;I’ve been thinking of writing a tool to automatically do that for me, but at this point I think it’s more worth it to invest and get a new keyboard with the proper layout 🙂&lt;/p&gt;</content:encoded><category>Uncategorized</category></item><item><title>Resetting/Restarting Apple TV remote</title><link>https://bisko.be/posts/dev/resetting-restarting-apple-tv-remote/</link><guid isPermaLink="true">https://bisko.be/posts/dev/resetting-restarting-apple-tv-remote/</guid><description>Last night during a guest visit, I managed to submerge our Apple TV remote under water. Lack of sleep and unstable glasses result in accidents. The remote was working well last night, but today it stopped working. Not responding to any actions. I tried bashing it in my hand, shaking water out of it. It</description><pubDate>Sun, 17 Feb 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Last night during a guest visit, I managed to submerge our Apple TV remote under water. Lack of sleep and unstable glasses result in accidents.&lt;/p&gt;
&lt;p&gt;The remote was working well last night, but today it stopped working. Not responding to any actions. I tried bashing it in my hand, shaking water out of it. It didn’t help at all.&lt;/p&gt;
&lt;p&gt;We thought that it’s gone and were looking for the rice pack in the cupboards.&lt;/p&gt;
&lt;p&gt;I went online mostly as a joke to see if I can try to “restart” it.&lt;/p&gt;
&lt;p&gt;A helpful guide pointed me to press and hold the Volume Up and Menu buttons for 2-3 seconds to reset the remote and get it into pairing mode.&lt;/p&gt;
&lt;p&gt;I was really surprised when &lt;strong&gt;it actually&lt;/strong&gt; &lt;strong&gt;worked&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;So if something seems fishy, try to reset the remote first. If it doesn’t work, then you can try the rice and hardware intervention.&lt;/p&gt;
&lt;p&gt;TL;DR;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hold Menu + Volume Up for 2-3 seconds&lt;/li&gt;
&lt;li&gt;Wait a few seconds&lt;/li&gt;
&lt;li&gt;Try to interact with the Apple TV&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Apple</category><category>Technology</category><category>AppleTV</category><category>Have you tried turning it off and on again?</category><category>remote</category><category>reset</category><category>restart</category></item></channel></rss>