<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>micheal@ecliptik.com</title>
    <description>Professional Website of Micheal Waltz</description>
    <link>https://www.ecliptik.com/</link>
    <atom:link href="https://www.ecliptik.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Thu, 16 Jul 2026 20:44:55 +0000</pubDate>
    <lastBuildDate>Thu, 16 Jul 2026 20:44:55 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Vibe Coding a Fluxbox Inspired Wayland Compositor</title>
        <description>&lt;p&gt;Everything after this paragraph was written with AI. I had &lt;a href=&quot;https://www.anthropic.com/claude/code&quot;&gt;Claude Code&lt;/a&gt; generate this post from it’s memories, git logs, shell history and interview after working on this project.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;Written by Claude:&lt;/p&gt;

&lt;p&gt;I used &lt;a href=&quot;http://fluxbox.org/&quot;&gt;Fluxbox&lt;/a&gt; for fourteen years. Starting around 2000, it lived on every system I owned. In college, my desktop was Fluxbox with &lt;a href=&quot;https://en.wikipedia.org/wiki/XMMS&quot;&gt;xmms&lt;/a&gt;, &lt;a href=&quot;http://gkrellm.srcbox.net/&quot;&gt;gkrellm&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Aterm&quot;&gt;aterm&lt;/a&gt;, and the rest of the classic X11 toolkit.&lt;/p&gt;

&lt;p&gt;I loved the simplicity — it was fast, stayed out of your way, and used almost no resources. But what really got me was the ａｅｓｔｈｅｔｉｃ. You could customize every pixel of the decorations, the toolbar, the menus. You could make a desktop that just &lt;em&gt;looked cool&lt;/em&gt;. Sitting in front of that setup felt like living in the future.&lt;/p&gt;

&lt;p&gt;If you were running Linux in the early 2000s, you know &lt;a href=&quot;/blog/2008/Screenshots-Over-the-Years/&quot;&gt;exactly what I mean&lt;/a&gt;. The last machine I ran it on was a work-issued ThinkPad X61s around 2014. I even had a Fluxbox t-shirt.&lt;/p&gt;

&lt;p&gt;Then the world moved on. X11 gave way to Wayland. Fluxbox stayed behind. I moved through GNOME, then Cinnamon and macOS, but nothing felt the same.&lt;/p&gt;

&lt;p&gt;In February 2026, I built Fluxbox again — for Wayland — in 6 active development days. I directed every decision, reviewed every output, triaged every bug, and managed the entire process. But I didn’t write a single line of code. Claude did.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Scale&lt;/th&gt;
      &lt;th&gt;Scope&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;35,000 lines of C&lt;/td&gt;
      &lt;td&gt;93 source files&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;30+ Wayland protocols&lt;/td&gt;
      &lt;td&gt;110+ window manager actions&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;81% test coverage&lt;/td&gt;
      &lt;td&gt;175 tests (38 C + 137 Python)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;5 man pages&lt;/td&gt;
      &lt;td&gt;5 packaging targets&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;6 active development days&lt;/td&gt;
      &lt;td&gt;153 commits&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The project is called &lt;a href=&quot;https://github.com/ecliptik/fluxland&quot;&gt;fluxland&lt;/a&gt;, and it was 100% vibe coded using &lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code&quot;&gt;Claude Code&lt;/a&gt; with &lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/teams&quot;&gt;Claude Code Teams&lt;/a&gt; orchestration. This is the story of how it was built and what I learned about agentic software development along the way.&lt;/p&gt;

&lt;h2 id=&quot;why-a-wayland-compositor&quot;&gt;Why a Wayland compositor?&lt;/h2&gt;

&lt;p&gt;Let me be clear about what this project was really for: I wanted to understand agentic development. Not by building a TODO app or a CRUD API, but by throwing something genuinely hard at it and seeing what happened.&lt;/p&gt;

&lt;p&gt;My background is operations, not software development. I was a LISA sysadmin managing 80,000+ systems across global data centers. Then DevOps — AWS, GCP, Kubernetes. Now I lead a cloud center of excellence, which in practice means spreadsheets and financial tools, not writing code. My C experience was minimal. My Wayland knowledge was zero.&lt;/p&gt;

&lt;p&gt;That was the point. If I could get AI agents to build a working Wayland compositor — a real piece of systems software with protocol implementations, rendering pipelines, and input handling — it would tell me something meaningful about where this technology actually is.&lt;/p&gt;

&lt;p&gt;A compositor turned out to be an ideal test case for agentic development:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Specific purpose&lt;/strong&gt; with clear success criteria. Does it composite windows? Do decorations render? Can you type?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Genuinely complex&lt;/strong&gt; but not impossibly large. Systems programming, protocol negotiation, text rendering, input handling — the kind of work that requires understanding library internals.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No existing solution.&lt;/strong&gt; Fluxbox doesn’t work on Wayland. This wasn’t reinventing a solved problem.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Visual output.&lt;/strong&gt; You can take a screenshot and &lt;em&gt;see&lt;/em&gt; if it works. This matters more than you’d think.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I considered porting the Fluxbox codebase directly, but a cleanroom implementation on &lt;a href=&quot;https://gitlab.freedesktop.org/wlroots/wlroots&quot;&gt;wlroots&lt;/a&gt; was a purer test of what agentic development can actually do — not translating existing code, but building something from an idea.&lt;/p&gt;

&lt;h2 id=&quot;the-build&quot;&gt;The build&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Day 1&lt;/strong&gt; — 26 commits, 68 new files, ~26,000 lines of C. The entire compositor architecture — core, rendering, window management, protocols, IPC, menus, decorations, XWayland — in one day. I described what I wanted and watched code appear; Claude organized the work into sprints, researched wlroots patterns, then implemented module by module.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/fluxland/01_single_window.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/fluxland/01_single_window.png&quot; alt=&quot;Fluxland single window&quot; width=&quot;90%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;First successful window — Fluxland running after Day 1.&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Day 2&lt;/strong&gt; — 35 commits. Slit, toolbar, touch/tablet support, five man pages, example configs, first unit tests. Renamed from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wm-wayland&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fluxland&lt;/code&gt;. Feature-complete.&lt;/p&gt;

&lt;p&gt;Then I left for a two week vacation. It turned out to be the right rhythm — the build phase is about velocity, the hardening phase is about correctness, and the gap between them lets you see the project with fresh eyes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day 3&lt;/strong&gt; — Twelve bugs found in live testing. Two categories: AI mistakes (plausible code with subtle errors, like using the wrong Pango measurement function — menu titles showed “flu” instead of “fluxland”) and genuine complexity (a SIGCHLD race where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIG_IGN&lt;/code&gt; caused the kernel to auto-reap XWayland, requiring a double-fork rewrite across all five exec paths). Claude diagnosed both classes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day 4&lt;/strong&gt; — Security audit surfaced 36 findings, all fixed. Packaging for three distros. Two WCAG AAA accessibility themes. i18n scaffolding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day 5&lt;/strong&gt; — Test coverage from 35% to 81% in one day — 42,349 lines of test code across 10 phases. Theoretical max is ~84% due to unreachable hardware error paths.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day 6&lt;/strong&gt; — 137 Python end-to-end tests, documentation polish, final bug fixes. Version 1.0.0 tagged.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/fluxland/04_menu.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/fluxland/04_menu.png&quot; alt=&quot;Fluxland desktop with Great Wave theme&quot; width=&quot;90%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Fluxland running with the Great Wave theme — server-side decorations, toolbar, slit, and root menu.&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/fluxland/06_grid.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/fluxland/06_grid.png&quot; alt=&quot;Fluxland grid layout&quot; width=&quot;90%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Multiple windows in a grid layout — snap zones and tiling working as expected.&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;the-moment-it-clicked-team-orchestration&quot;&gt;The moment it clicked: team orchestration&lt;/h2&gt;

&lt;p&gt;Everything above could have been done with a single Claude Code session. What changed the game was &lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/teams&quot;&gt;Claude Code Teams&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The breakthrough wasn’t Claude writing code — it was running 4-5 agents simultaneously in tmux, filling the role of engineering manager rather than developer. I’ve been a tmux user for years (old sysadmin habits), so I already had a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.tmux.conf&lt;/code&gt; that made navigation between panes natural. Watching AI agents take over those familiar panes and start working in parallel was the moment agentic development stopped being a novelty and started feeling like a real workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/fluxland/claude-teams.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/fluxland/claude-teams.png&quot; alt=&quot;Claude Code Teams — 5 agents working simultaneously in tmux&quot; width=&quot;90%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Five Claude Code agents working in parallel: team lead coordinating in one pane, dev and QA agents building, testing, and fixing in others.&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h3 id=&quot;the-team-structure&quot;&gt;The team structure&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Team Lead (me) — triages bugs, assigns work, reviews
  |
  +-- qa-agent-1 — tests feature areas via keyboard simulation + screenshots
  +-- qa-agent-2 — tests different feature areas
  +-- dev-agent  — fixes bugs, deploys, commits
  +-- research agents (as needed) — read-only codebase exploration
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This mirrors how real engineering teams work, because it &lt;em&gt;is&lt;/em&gt; how real engineering teams work. I’m not a software developer, but I’ve spent my career managing systems at scale. The skills transferred directly: triage, prioritize, delegate, verify. The “systems” were AI agents instead of Linux boxes, and the “infrastructure” was a codebase instead of a data center, but the management patterns were the same.&lt;/p&gt;

&lt;h3 id=&quot;the-qadev-feedback-loop&quot;&gt;The QA/dev feedback loop&lt;/h3&gt;

&lt;p&gt;QA agents tested the live compositor running in the same VM. The VM ran two users: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;claude&lt;/code&gt; for development and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;micheal&lt;/code&gt; for the compositor session, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lightdm&lt;/code&gt; auto-login. Agents used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wtype&lt;/code&gt; for keyboard simulation and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grim&lt;/code&gt; for screenshots, running commands as the session user. They’d work through feature areas — menus, window decorations, workspaces, key chains — and report PASS/FAIL for each one. I’d triage the failures, prioritize by severity, and send bug batches to the dev agent. The dev agent would fix, build, deploy, and report the root cause. I’d create re-test tasks and assign them back to QA. QA would verify.&lt;/p&gt;

&lt;p&gt;This is not a new process. It’s standard software engineering. What’s new is that every role except mine was filled by an AI agent.&lt;/p&gt;

&lt;h3 id=&quot;the-screenshot-debugging-breakthrough&quot;&gt;The screenshot debugging breakthrough&lt;/h3&gt;

&lt;p&gt;The most useful discovery was realizing I could ask Claude to take a screenshot of the compositor and then &lt;em&gt;look at it&lt;/em&gt;. Claude is multimodal — it can view images. So a QA agent would simulate some keyboard actions, take a screenshot, and visually inspect the result. “The menu title is truncated.” “The toolbar clock shows ‘16:5’ instead of ‘16:51’.” “There’s a pixel gap between tiled windows.”&lt;/p&gt;

&lt;p&gt;A multimodal AI doing visual QA on a graphical application it built. That’s something I didn’t expect to work as well as it did.&lt;/p&gt;

&lt;h3 id=&quot;what-worked&quot;&gt;What worked&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Parallel feature sprints.&lt;/strong&gt; Four agents in isolated worktrees simultaneously building window animations, snap zones, per-output workspaces, and test infrastructure. Independent work, no conflicts, all merged cleanly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Research-then-implement.&lt;/strong&gt; Read-only Explore agents investigated feature categories first, wrote findings to temporary files. Those findings were synthesized into sprint plans. Then implementation agents executed against the plan. This prevented agents from going off-track or making uninformed architectural decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Persistent memory.&lt;/strong&gt; Claude Code’s memory system — a directory of markdown files that persists across sessions — became the institutional knowledge of the project. Bug patterns, architectural decisions, gotchas, and lessons learned were all captured. Without this, every session would have started from zero. With it, Claude remembered that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pango_layout_get_pixel_size()&lt;/code&gt; can’t be trusted, that decorations are scene buffers not wl_surfaces, and that child processes need double-fork.&lt;/p&gt;

&lt;p&gt;An interesting side effect: the project didn’t have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; file (the standard project instruction file for Claude Code) until the very end. It didn’t need one. The memory system had organically accumulated everything a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt; would contain — build commands, architecture notes, convention guides, known pitfalls — just written by the AI for itself across dozens of sessions rather than curated upfront by a human. The memory files &lt;em&gt;became&lt;/em&gt; the project documentation, growing as the project grew. By the time we wrote a proper &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt;, it was mostly a matter of distilling what the memory system already knew.&lt;/p&gt;

&lt;h3 id=&quot;what-didnt-work&quot;&gt;What didn’t work&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Worktree cleanup.&lt;/strong&gt; Git worktrees used for agent isolation sometimes got cleaned up between turns, losing work. We learned to avoid worktree isolation when agents touched different files and could safely share the main branch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concurrent keyboard simulation.&lt;/strong&gt; Two QA agents sending &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wtype&lt;/code&gt; commands simultaneously caused chaos. Virtual keyboard inputs from different agents would interleave unpredictably. We had to space out testing or assign non-overlapping feature areas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agents forgetting to commit.&lt;/strong&gt; Dev agents would edit files, build, deploy, test — and never run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit&lt;/code&gt;. I had to explicitly instruct commits after each fix. Agents are great at solving problems but mediocre at housekeeping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token limits.&lt;/strong&gt; I hit them often. In traditional development, the constraint is developer time. In agentic development, it’s tokens. You learn to scope work tightly, parallelize efficiently, and avoid wasting context on dead ends — the same skills a good engineering manager uses with human developers, just with a different budget.&lt;/p&gt;

&lt;h2 id=&quot;what-id-tell-someone-starting-their-first-agentic-project&quot;&gt;What I’d tell someone starting their first agentic project&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pick the right project.&lt;/strong&gt; This matters more than anything else. A TODO app won’t teach you much. Something impossible won’t finish. The sweet spot is a project that’s genuinely complex but verifiable — you can look at it, run it, test it, and know whether it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Own the manager role.&lt;/strong&gt; The breakthrough isn’t writing better prompts. It’s thinking like a team lead. You’re not pair programming — you’re running a team. Triage, prioritize, delegate, verify. Set up the processes (QA feedback loops, bug tracking, re-testing) and let the agents execute within them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build verification loops early.&lt;/strong&gt; Tests, screenshots, IPC queries, smoke checks. The AI will write plausible-looking code with subtle bugs. Your job isn’t to read every line — it’s to build the systems that catch problems. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--check-config&lt;/code&gt; validator, the 137 Python UI tests, the screenshot-based QA workflow — these all existed to catch things I couldn’t see by reading code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invest in memory.&lt;/strong&gt; Persistent context files (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CLAUDE.md&lt;/code&gt;, memory directories) are the institutional knowledge of your AI team. Document bug patterns, architectural decisions, gotchas. A single line in a memory file can save a future session from re-discovering a bug that took hours to diagnose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accept the token budget.&lt;/strong&gt; You’ll hit limits. Plan sessions around this. Batch related work together. Parallelize independent tasks. Don’t waste context re-explaining things the memory system should handle. Think of tokens the way you think of sprint capacity — scope accordingly.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Fluxland is genuinely functional. It reads Fluxbox config files, supports key chains and keymodes, renders server-side decorations with the same theming system, runs the slit for dockable apps, and implements 30+ Wayland protocols. You could use it as a daily driver. It has features Fluxbox never had — snap zones, window animations, IPC event subscriptions, WCAG AAA high-contrast themes.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/fluxland/desktop_wave.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/fluxland/desktop_wave.png&quot; alt=&quot;Fluxland desktop wave theme&quot; width=&quot;90%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Fluxland with the desktop_wave theme — a compositor that didn&apos;t exist eight days before this screenshot.&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;It’s also, proudly, 100% vibe coded. Every line generated by Claude Code. But the methodology underneath — sprints, parallel agents, QA feedback loops, persistent memory, visual verification — is real engineering process. “Vibe coded” doesn’t mean unstructured. It means the human’s role shifted from writing code to directing intelligence.&lt;/p&gt;

&lt;p&gt;If I had to start over, I might clone the Fluxbox repo and ask Claude to port it. That would probably have been more efficient. But I like the cleanroom approach. It proves something different: you don’t need to start with existing code. You can start with an idea and a memory of a desktop that looked cool twenty years ago.&lt;/p&gt;

&lt;p&gt;The source is at &lt;a href=&quot;https://github.com/ecliptik/fluxland&quot;&gt;github.com/ecliptik/fluxland&lt;/a&gt;. Try it, break it, file issues.&lt;/p&gt;
</description>
        <pubDate>Fri, 27 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2026/Vibe-Coding-a-Fluxbox-Inspired-Wayland-Compositor/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2026/Vibe-Coding-a-Fluxbox-Inspired-Wayland-Compositor/</guid>
        
        <category>linux</category>
        
        <category>ai</category>
        
        <category>claude</category>
        
        <category>desktop</category>
        
        <category>wayland</category>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>Three Days with Claude Code</title>
        <description>&lt;p&gt;Everything after this paragraph was written with AI. I had &lt;a href=&quot;https://www.anthropic.com/claude/code&quot;&gt;Claude Code&lt;/a&gt; generate this post since I was curious what it would come up with and to give me a summary of what was done to help redesign this blog.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;Written by Claude:&lt;/p&gt;

&lt;p&gt;Over the past three days I’ve been working with &lt;a href=&quot;https://www.anthropic.com/claude/code&quot;&gt;Claude Code&lt;/a&gt; to modernize this 20+ year old Jekyll blog. This post covers what we accomplished, the challenges we faced, and what it’s like pairing with an AI on a real codebase. Claude wrote this post based on our work together.&lt;/p&gt;

&lt;h2 id=&quot;what-is-claude-code&quot;&gt;What is Claude Code?&lt;/h2&gt;

&lt;p&gt;Claude Code is Anthropic’s CLI tool that brings their Claude AI directly into your terminal. Unlike browser-based AI assistants or IDE plugins, it works through conversation while having direct access to your filesystem, git, and development tools. You describe what you want to accomplish, and it can read files, make edits, run commands, and manage the entire workflow.&lt;/p&gt;

&lt;h2 id=&quot;the-starting-point&quot;&gt;The Starting Point&lt;/h2&gt;

&lt;p&gt;This blog has been around since 2004, accumulating 20+ years of technical debt: duplicate CSS, hardcoded colors, no progressive enhancement, bloated dependencies, and inconsistent patterns. I recently added support for small web protocols like &lt;a href=&quot;/blog/2025/gopher-is-still-relevant/&quot;&gt;Gopher&lt;/a&gt; and &lt;a href=&quot;/blog/2025/gemini-a-quieter-place-on-the-internet/&quot;&gt;Gemini&lt;/a&gt;, but the main site needed attention.&lt;/p&gt;

&lt;h2 id=&quot;performance-wins&quot;&gt;Performance Wins&lt;/h2&gt;

&lt;p&gt;The first priority was reducing page weight and improving load times. We tackled this systematically:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Removed animate.css&lt;/strong&gt; - The 57KB library was only used for a subtle header animation. We replaced it with a few lines of CSS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lazy-loaded search&lt;/strong&gt; - The 114KB search.json file was loading on every page load, even though search was rarely used. We moved it to load only when the search input is focused, cutting initial page weight significantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimized fonts&lt;/strong&gt; - Added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;font-display: swap&lt;/code&gt; to prevent invisible text during font loading and reduce cumulative layout shift.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consolidated CSS&lt;/strong&gt; - This was a big one. The site had Terminal.css (908 lines) plus console.css (718 lines) with override conflicts and duplicate declarations. We merged them into a single consolidated stylesheet (~1150 lines), removing unused components like forms, buttons, progress bars, and timelines that were never used.&lt;/p&gt;

&lt;p&gt;The results: ~60KB reduction in page weight and 30-40% faster initial load times.&lt;/p&gt;

&lt;h2 id=&quot;progressive-enhancement&quot;&gt;Progressive Enhancement&lt;/h2&gt;

&lt;p&gt;A major oversight was the site’s complete dependency on JavaScript. If JS was disabled or blocked, the theme toggle was visible but broken, search was displayed but non-functional, and tables had hardcoded colors that didn’t respect system preferences.&lt;/p&gt;

&lt;p&gt;We implemented proper progressive enhancement:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Site defaults to dark mode (TokyoNight-Storm) when JS is disabled&lt;/li&gt;
  &lt;li&gt;System &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prefers-color-scheme&lt;/code&gt; media query respected for light mode&lt;/li&gt;
  &lt;li&gt;Theme toggle and search hidden when JS is disabled&lt;/li&gt;
  &lt;li&gt;Tables use CSS variables consistently (no hardcoded colors)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.js-enabled&lt;/code&gt; class added via inline script for feature detection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the site works cleanly for users without JavaScript.&lt;/p&gt;

&lt;h2 id=&quot;social-media-previews&quot;&gt;Social Media Previews&lt;/h2&gt;

&lt;p&gt;Getting social media previews right turned out to be more challenging than expected. The goal was compact, mobile-friendly link previews in apps like Signal and Slack.&lt;/p&gt;

&lt;p&gt;After several iterations we settled on:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;400x300 grayscale thumbnail (30KB) of my Raspberry Pi setup&lt;/li&gt;
  &lt;li&gt;Simple Open Graph and Twitter Card meta tags&lt;/li&gt;
  &lt;li&gt;Text-focused layout (title, description, small image)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The challenge was Slack’s aggressive caching - previews can take 24-48 hours to refresh. We learned to test with Signal and LinkedIn first, which update immediately.&lt;/p&gt;

&lt;h2 id=&quot;accessibility-improvements&quot;&gt;Accessibility Improvements&lt;/h2&gt;

&lt;p&gt;We improved mobile readability, added proper semantic HTML, and fixed color contrast issues:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Increased mobile font sizes for better readability&lt;/li&gt;
  &lt;li&gt;Aligned header logo and menu to the left on mobile&lt;/li&gt;
  &lt;li&gt;Improved table row contrast in dark mode&lt;/li&gt;
  &lt;li&gt;Fixed heading colors to use cyan for better TokyoNight theme consistency&lt;/li&gt;
  &lt;li&gt;Removed hardcoded colors throughout&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;small-web-protocol-generation&quot;&gt;Small Web Protocol Generation&lt;/h2&gt;

&lt;p&gt;The site generates content for both Gopher and Gemini protocols. We refined the generation scripts significantly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gopher improvements:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;RFC1436-compliant gophermaps with correct host/port&lt;/li&gt;
  &lt;li&gt;30 markdown posts converted to plaintext (70 columns)&lt;/li&gt;
  &lt;li&gt;63 tag pages with gophermaps&lt;/li&gt;
  &lt;li&gt;Year archives for 2011, 2015, 2017, 2021-2025&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Gemini enhancements:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Native gemtext format (not plaintext)&lt;/li&gt;
  &lt;li&gt;Footnote-style text links with inline references&lt;/li&gt;
  &lt;li&gt;Standalone image links on their own lines&lt;/li&gt;
  &lt;li&gt;Internal blog links automatically converted to gemini paths&lt;/li&gt;
  &lt;li&gt;Site map navigation on all pages&lt;/li&gt;
  &lt;li&gt;Docker testing configured for Tailscale hostname&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key difference: Gopher uses plaintext with line wrapping, while Gemini uses native gemtext format without wrapping (clients handle it).&lt;/p&gt;

&lt;h2 id=&quot;security-and-seo&quot;&gt;Security and SEO&lt;/h2&gt;

&lt;p&gt;We added security headers and improved SEO:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Content Security Policy and HSTS headers&lt;/li&gt;
  &lt;li&gt;Schema markup improvements with BlogPosting structured data&lt;/li&gt;
  &lt;li&gt;Sitemap priorities adjusted&lt;/li&gt;
  &lt;li&gt;Tag pages now indexed (removed noindex, added descriptions)&lt;/li&gt;
  &lt;li&gt;All posts have proper meta descriptions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;working-with-claude-code&quot;&gt;Working with Claude Code&lt;/h2&gt;

&lt;p&gt;The development workflow was surprisingly natural. I’d describe what I wanted to accomplish, and Claude would:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Read relevant files to understand the current state&lt;/li&gt;
  &lt;li&gt;Make surgical edits to implement changes&lt;/li&gt;
  &lt;li&gt;Run tests or validation&lt;/li&gt;
  &lt;li&gt;Commit changes with detailed commit messages&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The challenging parts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context matters&lt;/strong&gt; - Claude needed to read files before editing them. When I’d describe a change without pointing to specific files, we’d sometimes start down the wrong path. Learning to say “check the CSS first” or “read the current implementation” helped.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Progressive iteration&lt;/strong&gt; - Complex changes worked best when broken into steps. Rather than “redesign social media previews,” it was better to iterate: create image, add meta tags, test, adjust size, optimize, test again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Git workflow&lt;/strong&gt; - Claude creates commits automatically with co-authored attribution, but never pushes or merges without explicit permission. This worked well for reviewing changes before they went live.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tag management&lt;/strong&gt; - The blog has ~78 canonical tags (lowercase, standardized names like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;512ke&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;macos&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smolweb&lt;/code&gt;). Claude learned to check the tag list and ask before creating new ones, preventing tag sprawl.&lt;/p&gt;

&lt;p&gt;What impressed me most was Claude’s ability to maintain consistency. When we established patterns (like using CSS variables instead of hardcoded colors), it would apply them throughout without being reminded.&lt;/p&gt;

&lt;h2 id=&quot;challenges-and-limitations&quot;&gt;Challenges and Limitations&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No time estimates&lt;/strong&gt; - Claude deliberately avoids giving ETAs for tasks. This is probably good practice (time estimates are usually wrong), but it took adjustment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Background knowledge gaps&lt;/strong&gt; - Occasionally Claude would need reminders about project-specific patterns. We solved this by creating a CLAUDE.md file documenting project rules, which it references automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overly cautious&lt;/strong&gt; - Sometimes Claude would ask for confirmation on straightforward changes. I preferred this to the opposite problem, but found myself saying “yes, go ahead” frequently.&lt;/p&gt;

&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;

&lt;p&gt;Over three days we closed ~60 commits across multiple branches:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;~60KB reduction in page weight&lt;/li&gt;
  &lt;li&gt;30-40% faster load times&lt;/li&gt;
  &lt;li&gt;Full progressive enhancement (works without JavaScript)&lt;/li&gt;
  &lt;li&gt;Improved accessibility and mobile experience&lt;/li&gt;
  &lt;li&gt;Better SEO with proper meta tags and schema&lt;/li&gt;
  &lt;li&gt;Refined Gopher/Gemini generation&lt;/li&gt;
  &lt;li&gt;Consolidated CSS (908 + 718 → ~1150 lines)&lt;/li&gt;
  &lt;li&gt;Security headers (CSP, HSTS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The blog is faster, more accessible, and works properly across a wider range of browsers and clients.&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;Working with Claude Code felt like pair programming with a detail-oriented colleague who has perfect recall and never gets tired. It excels at systematic refactoring, catching inconsistencies, and maintaining patterns across a codebase.&lt;/p&gt;

&lt;p&gt;The experience changed how I think about AI-assisted development. It’s not about replacing programming knowledge - you still need to understand what you want to build and why. But for execution, maintaining consistency, and handling the tedious parts of refactoring, it’s remarkably effective.&lt;/p&gt;

&lt;p&gt;If you’re maintaining a blog, personal site, or any codebase that could use systematic cleanup, Claude Code is worth trying. The CLI approach feels natural for terminal-focused workflows, and having an AI that can read your entire codebase and maintain context across changes is powerful.&lt;/p&gt;

&lt;p&gt;Now I need to figure out what to tackle next. Maybe those 37 HTML posts from 2006-2011 that still need converting to markdown, or implementing responsive images with WebP/AVIF support. Or perhaps I’ll just enjoy the faster, cleaner site for a while.&lt;/p&gt;
</description>
        <pubDate>Tue, 20 Jan 2026 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2026/three-days-with-claude-code/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2026/three-days-with-claude-code/</guid>
        
        <category>jekyll</category>
        
        <category>claude</category>
        
        <category>smolweb</category>
        
        <category>gemini</category>
        
        <category>gopher</category>
        
        <category>ai</category>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>Surfing GlobalTalk with a Macintosh 512Ke</title>
        <description>&lt;p&gt;While I’ve discussed the &lt;a href=&quot;/blog/2025/A-Macintosh-Story/&quot;&gt;origins of my Macintosh 512Ke&lt;/a&gt; and the &lt;a href=&quot;/blog/2025/Enhancing-my-Macintosh-512Ke/&quot;&gt;enhancements&lt;/a&gt; I’ve done over the past year. What really kicked off my interest in using it more than just Zoom background discussion piece, were all the fediverse posts I saw on &lt;a href=&quot;https://marchintosh.com/globaltalk.html&quot;&gt;GlobalTalk&lt;/a&gt; during &lt;a href=&quot;https://www.marchintosh.com/&quot;&gt;MARCHintosh&lt;/a&gt; 2024.&lt;/p&gt;

&lt;p&gt;I was intrigued that classic Macs like my 512Ke, which I always thought was limited in what it could do, could network with other systems, and not just locally but globally. With this in mind I set a goal for myself to have my 512Ke participate in GlobalTalk for MARCHintosh 2025.&lt;/p&gt;

&lt;h2 id=&quot;localtalk-globaltalk-tashtalk-oh-my&quot;&gt;LocalTalk, GlobalTalk, TashTalk, Oh My&lt;/h2&gt;

&lt;p&gt;A quick aside, as noted in my &lt;a href=&quot;/blog/2025/Enhancing-my-Macintosh-512Ke/&quot;&gt;512Ke enhancements&lt;/a&gt; post,I swapped a Macintosh Plus logic board for the 512Ke board in the original case. By using a PicoPSU, RGB2HDMI, FloppyEMU, an original mouse and PS2 keyboard adapter, I can run the 512Ke in a bareboard cyberpunk fashion.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/512ke/512ke-bareboard.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/512ke/512ke-bareboard.jpg&quot; alt=&quot;Bareboard 512Ke&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Bareboard 512Ke&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;To get my 512Ke onto GlobalTalk, I first physically connected everything using &lt;a href=&quot;https://en.wikipedia.org/wiki/PhoneNET&quot;&gt;PhoneNET&lt;/a&gt; with the following hardware,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ko-fi.com/s/4d01fa5b8a&quot;&gt;TashTalk 2 HAT&lt;/a&gt; on a RaspberryPi 3&lt;/li&gt;
  &lt;li&gt;Original Farrallon PhoneNET adapter connected to the TashTalk 2 HAT&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ko-fi.com/s/ce23779f25&quot;&gt;Tashtari PhoneNET Adapter&lt;/a&gt; connected to the 512Ke&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/512ke/tashtalk2.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/512ke/tashtalk2.jpg&quot; alt=&quot;TashTalk 2 HAT&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;TashTalk 2 HAT on a RaspberryPi 3&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/512ke/farrallon.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/512ke/farrallon.jpg&quot; alt=&quot;Farrallon PhoneNET adapter&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Farrallon PhoneNET&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/512ke/db9adapter.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/512ke/db9adapter.jpg&quot; alt=&quot;Tashtari PhoneNET Adapter&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Tashtari PhoneNET Adapter&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;networking&quot;&gt;Networking&lt;/h2&gt;

&lt;p&gt;With everything physically connected, in order for the TashTalk HAT to see LocalTalk traffic, the networking on the RaspberryPi must be setup with a bridge and tap device. Taking inspiration from a &lt;a href=&quot;https://68kmla.org/bb/index.php?threads/tashrouter-an-appletalk-router.46047/page-5#post-518796&quot;&gt;post on m68kmla&lt;/a&gt; I configured the host networking as follows.&lt;/p&gt;

&lt;p&gt;Install required bridge and tap packages,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;uml-utilities bridge-utils
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Configured &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/network/interfaces&lt;/code&gt; with a bridge, tap and static IP address,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#loopback
auto lo
iface lo inet loopback

# Virtual interface
auto tap2
iface tap2 inet manual
   pre-up tunctl -t tap2 -u root
   up ip link set dev tap2 up
   down ip link set dev tap2 down

# Bridge interface
auto br0
iface br0 inet static
   address 192.168.1.163/24
   gateway 192.168.1.1
   dns-nameservers 192.168.1.1
   bridge_ports eth0 tap2
   bridge_fd 9
   bridge_hello 2
   bridge_maxage 12
   bridge_stp off
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Disabled NetworkManager since I want to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/network/interfaces&lt;/code&gt; for network configuration,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl disable NetworkManager
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After restarting the Pi, the eth0 and tap interfaces will show up on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; bridge,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;brctl show
bridge name     bridge &lt;span class=&quot;nb&quot;&gt;id               &lt;/span&gt;STP enabled     interfaces
br0             8000.ae29d573875f       no              eth0
                                                        tap2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;tashrouter&quot;&gt;TashRouter&lt;/h2&gt;

&lt;p&gt;Using the tap2 device, next is bridging the TashTalk 2 HAT to Ethernet, making &lt;a href=&quot;https://en.wikipedia.org/wiki/LocalTalk&quot;&gt;LocalTalk&lt;/a&gt; traffic visible on the wider network. This is done using &lt;a href=&quot;https://github.com/lampmerchant/tashrouter&quot;&gt;tashrouter&lt;/a&gt; which communicates with the TashTalk 2 HAT on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/ttyAMA0&lt;/code&gt; and passes LocalTalk to LToUDP and &lt;a href=&quot;https://apple.fandom.com/wiki/EtherTalk&quot;&gt;EtherTalk&lt;/a&gt; through the tap2 device.&lt;/p&gt;

&lt;p&gt;Using the example from the tashrouter repo, I created &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gt_router.py&lt;/code&gt; python script, changing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seed_zone_name&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vermilion Sands LT&lt;/code&gt;. This is important, since if LocalTalk devices are in the same Zone as EtherTalk devices it can cause some odd &lt;a href=&quot;https://en.wikipedia.org/wiki/AppleTalk&quot;&gt;AppleTalk&lt;/a&gt; behaviour like file servers not showing up.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gt_router.py&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;logging&lt;/span&gt;                                                                                                                                 &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;signal&lt;/span&gt;                                                                                                                                  &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;tashrouter.netlog&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;tashrouter.port.ethertalk.tap&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TapPort&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;tashrouter.port.localtalk.ltoudp&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LtoudpPort&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;tashrouter.port.localtalk.tashtalk&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TashTalkPort&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;tashrouter.router.router&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Router&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sigterm_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_signo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_stack_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Raises SystemExit(0):
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basicConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DEBUG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;%(asctime)s %(levelname)s: %(message)s&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#tashrouter.netlog.set_log_str_func(logging.debug)  # comment this line for speed and reduced spam
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;router&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;router&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;LtoudpPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seed_network&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;71&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seed_zone_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Vermilion Sands LT&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;TashTalkPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;serial_port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;/dev/ttyAMA0&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seed_network&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seed_zone_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;Vermilion Sands LT&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;TapPort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tap_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;tap2&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hw_addr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xDE\xAD\xBE\xEF\xCA\xFE&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;router away!&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SIGTERM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sigterm_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;SystemExit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This script is run with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo python3 gt_router.py&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;an-on-ramp-to-the-information-superhighway&quot;&gt;An On-ramp to The Information Superhighway&lt;/h2&gt;

&lt;p&gt;With LocalTalk bridged into the Ethernet network, next is getting onto GlobalTalk.&lt;/p&gt;

&lt;p&gt;I first followed the &lt;a href=&quot;https://docs.google.com/document/d/1pXMjrAF5vC08TamkdSt2oFCrDFMP47i5dYcjshn9JzU/edit?tab=t.0&quot;&gt;The Ultimate GlobalTalk Network Guide&lt;/a&gt; to understand how things worked, however this guide uses the older &lt;a href=&quot;https://biosrhythm.com/?p=2767&quot;&gt;AppleTalk Router&lt;/a&gt; software that runs only on a Macintosh system, not Linux.&lt;/p&gt;

&lt;p&gt;The newer &lt;a href=&quot;https://gitea.drjosh.dev/josh/jrouter&quot;&gt;jrouter&lt;/a&gt; project runs on Linux and has features like yaml configuration, logs, and can integrate with tashrouter using the bridge setup.&lt;/p&gt;

&lt;p&gt;My configuration for jrouter uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; bridge device, sets the zone name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vermilion Sands&lt;/code&gt;, a 1970-1971 network range and opens up peering. The list of peers was copied from the GlobalTalk spreadsheet. As mentioned before, it’s important the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zone_name&lt;/code&gt; and network range differ from the LocalTalk zone name.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jrouter.yaml&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;listen_port&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;387&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#AURP default port&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;local_ip&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;XX.XX.XX.XX&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#Public IP to forward traffic from&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;monitoring_addr&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;:9459&quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;ethertalk&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;br0&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;zone_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Vermilion Sands&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;net_start&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1970&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;net_end&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1971&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;open_peering&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;peers&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#peer IPs from GlobalTalk spreadsheet&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By using the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; bridge device as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gt_router.py&lt;/code&gt; script, LocalTalk devices will see GlobalTalk devices and vice versa.&lt;/p&gt;

&lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting it All Together&lt;/h2&gt;

&lt;p&gt;With the hardware and software taken care of, everything was in place to start browsing GlobalTalk on the 512Ke like it was 2024. Through various trial and error, I found there is a specific order-of-operations needed for everything to work as expected.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Turn everything off&lt;/li&gt;
  &lt;li&gt;Physically connect everything&lt;/li&gt;
  &lt;li&gt;Turn on RaspberryPi&lt;/li&gt;
  &lt;li&gt;Start jrouter and wait a few minutes for zone information to populate&lt;/li&gt;
  &lt;li&gt;Start &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gt_router.py&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Turn on clients, like the 512Ke&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When running properly, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gt_router.py&lt;/code&gt; logs will show GlobalTalk traffic and zones and file servers will appear in Chooser on the 512Ke.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/512ke/screenshot-512ke-about.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/512ke/screenshot-512ke-about.png&quot; alt=&quot;512Ke About System showing GlobalTalk Zones&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;512Ke About System with GlobalTalk Zones&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/512ke/screenshot-512ke-chooser.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/512ke/screenshot-512ke-chooser.png&quot; alt=&quot;512Ke Chooser showing GlobalTalk Zones&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;GlobalTalk Zones in Chooser on 512Ke&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;gotchas&quot;&gt;Gotchas&lt;/h2&gt;

&lt;p&gt;Here are a few gotchas I came across when configuring everything.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;If running &lt;a href=&quot;https://netatalk.io/&quot;&gt;netatalk&lt;/a&gt; or a QEMU Macintosh, put them on a different system than jrouter/tashtalk. Having them all share the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;br0&lt;/code&gt; device causes some sort of network loop and can crash a Macintosh connected with LocalTalk.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;When in doubt turn everything off and back on again. AppleTalk is temperamental, zones and file servers will just disappear or stop working even though nothing changed. Sometimes the best course of action is to turn everything off, wait a few minutes and then back on again.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Patience is a virtue. The technologies and bitrates involved as relatively slow, and sometimes it just requires waiting a few extra seconds instead of expecting everything to function immediately.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;stretch-goal&quot;&gt;Stretch Goal&lt;/h2&gt;

&lt;p&gt;A stretch goal I had for this project was seeing if I could transfer files between my 512Ke and a modern Macbook using LocalTalk. I managed to do this by setting up a &lt;a href=&quot;https://netatalk.io/&quot;&gt;netatalk 4.1&lt;/a&gt; server on another RaspberryPi with AppleTalk enabled. Because netatalk is able to join the AppleTalk network, it can see and make available it’s services to all devices, including the 512Ke.&lt;/p&gt;

&lt;p&gt;After setting up a file share on netatalk, the 512Ke can mount it in Chooser over LocalTalk and Finder on MacOS will see it over wifi. Now I can easily copy files (albeit slowly) between systems using this shared folder.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/512ke/512ke-netatalk-macos.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/512ke/512ke-netatalk-macos.png&quot; alt=&quot;Screenshot of 512Ke, netatalk cli and MacOS of the same directory and files&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;File share on a 512Ke, Finder and Linux&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/512ke/globaltalk-diagram.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/512ke/globaltalk-diagram.png&quot; alt=&quot;Rough diagram of how everything is connected&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Rough diagram of how everything is connected&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;references-and-links&quot;&gt;References and Links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://biosrhythm.com/?p=2767&quot;&gt;Pushing AppleTalk Across the Internet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://globaltalk.woodlanddigital.net/qemu/&quot;&gt;GlobalTalk Virtual Router on Debian 12&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://68kmla.org/bb/index.php?threads/tashrouter-an-appletalk-router.46047/&quot;&gt;TashRouter: An AppleTalk Router&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.google.com/document/d/1pXMjrAF5vC08TamkdSt2oFCrDFMP47i5dYcjshn9JzU/edit?tab=t.0&quot;&gt;The Ultimate GlobalTalk Network Guide v1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://marchintosh.com/globaltalk.html&quot;&gt;Welcome to #GlobalTalk!&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.vladovince.com/using-tashtalk-with-mini-vmac-to-participate-in-globaltalk-from-your-emulated-mac/&quot;&gt;Using TashTalk with Mini vMac to participate in #GlobalTalk from your emulated Mac&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.vladovince.com/my-globaltalk-setup-1-apple-internet-router-configuration/&quot;&gt;My GlobalTalk Setup: Apple Internet Router configuration&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://biosrhythm.com/?p=2791&quot;&gt;Building a Classic Mac Support Server&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://midnightcheese.com/2025/03/notes-setting-up-globaltalk-qemu-ubuntu/&quot;&gt;Notes From Setting up GlobalTalk Using QEMU on Ubuntu&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://midnightcheese.com/2025/03/notes-setting-up-globaltalk-qemu-ubuntu/&quot;&gt;Macintosh Networking Bookmark Collection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 10 Mar 2025 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2025/Surfing-GlobalTalk-with-a-Macintosh-512Ke/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2025/Surfing-GlobalTalk-with-a-Macintosh-512Ke/</guid>
        
        <category>marchintosh</category>
        
        <category>globaltalk</category>
        
        <category>macintosh</category>
        
        <category>localtalk</category>
        
        <category>512ke</category>
        
        <category>appletalk</category>
        
        
        <category>macintosh</category>
        
      </item>
    
      <item>
        <title>Live, Laugh, Localtalk with Basilisk II</title>
        <description>&lt;p&gt;As I mentioned in my &lt;a href=&quot;/Enhancing-my-Macintosh-512Ke/&quot;&gt;Enhancing my Macintosh 512Ke&lt;/a&gt; post, I use the &lt;a href=&quot;https://basilisk.cebix.net/&quot;&gt;Basilisk II&lt;/a&gt; Macintosh 68k emulator alongside my Macintosh Plus to facilitate downloading software, sharing files with &lt;a href=&quot;https://en.wikipedia.org/wiki/AppleShare&quot;&gt;AppleShare&lt;/a&gt;, playing &lt;a href=&quot;https://www.macintoshrepository.org/4937-myst&quot;&gt;Myst&lt;/a&gt; and many other things. It does take a bit of setup to get working though, especially with configuring the network to work with &lt;a href=&quot;https://en.wikipedia.org/wiki/AppleTalk&quot;&gt;AppleTalk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below is a short guide on how I installed and setup Basilisk II on my &lt;a href=&quot;https://linuxmint.com/&quot;&gt;Linux Mint&lt;/a&gt; laptop to work with my Macintosh Plus over the network.&lt;/p&gt;

&lt;h2 id=&quot;installing-basilisk-ii&quot;&gt;Installing Basilisk II&lt;/h2&gt;

&lt;p&gt;Basilisk II is available in the main Ubuntu, Linux Mint and Debian repos and I assume other Linux distros probably have it too. There are other Macintosh emulators out there like &lt;a href=&quot;https://sheepshaver.cebix.net/&quot;&gt;SheepShaver&lt;/a&gt;, &lt;a href=&quot;https://github.com/friedkiwi/minivmac&quot;&gt;Mini vMac&lt;/a&gt; and even the entirely online &lt;a href=&quot;https://infinitemac.org/&quot;&gt;Infinite Mac&lt;/a&gt; but I like Basilisk since it provides a nice settings manager and works well.&lt;/p&gt;

&lt;p&gt;It is quickly installed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt; on a Debian based distro,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt update
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; basilisk2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;setting-up-basilisk&quot;&gt;Setting Up Basilisk&lt;/h2&gt;

&lt;p&gt;Basilisk requires a few things to setup, most notable a &lt;a href=&quot;https://en.wikipedia.org/wiki/Old_World_ROM&quot;&gt;system ROM&lt;/a&gt; and disk image. It also can mount a shared folder with the host called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unix&lt;/code&gt; that makes copying files in/out of the VM relatively easy.&lt;/p&gt;

&lt;p&gt;Start by creating directories for ROMs, disks and file sharing,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; ~/Documents/basilisk
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/Documents/
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;roms unix disks
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Find and copy a ROM file into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/Documents/basilisk/roms&lt;/code&gt;, for my setup I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PERFORMA.ROM&lt;/code&gt; for no particular reason.&lt;/p&gt;

&lt;p&gt;In the Memory/Misc tab, configure the machine with the following,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;MacOS RAM Size (MB): 128 (or higher)&lt;/li&gt;
  &lt;li&gt;Mac Model ID: Mac IIci (MacOS 7.X)&lt;/li&gt;
  &lt;li&gt;CPU Type: 68040&lt;/li&gt;
  &lt;li&gt;ROM File: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/Documents/basilisk/roms/PERFORMA.ROM&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/basilisk-settings.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/basilisk-settings.png&quot; alt=&quot;Basilisk II Memory/Misc Tab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Basilisk II Memory/Misc Tab&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;A full Install of System 7.5.5 is required in order to use AppleShare and do anything really useful. Disk images are available various places online or you can follow &lt;a href=&quot;https://www.savagetaylor.com/2018/09/02/setting-up-your-vintage-classic-68k-macintosh-installing-the-full-version-of-system-7-5-5-or-6-0-8/&quot;&gt;a guide&lt;/a&gt; to make your own, which is what I did.&lt;/p&gt;

&lt;h2 id=&quot;using-basilisk&quot;&gt;Using Basilisk&lt;/h2&gt;

&lt;p&gt;With system configuration complete and a 7.5.5 disk image ready, turn on the VM which will load a  default desktop containing few icons like the disk drive and trash.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/basilisk-755-desktop.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/basilisk-755-desktop.png&quot; alt=&quot;Default 7.5.5 Desktop in Basilisk&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Default 7.5.5 Desktop in Basilisk&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;wireless-localtalk&quot;&gt;Wireless LocalTalk&lt;/h2&gt;

&lt;p&gt;Getting AppleTalk to work on a 7.5.5 in Basilisk and communicate with other Macintosh devices over LocalTalk using the hosts wireless networking requires a custom kernel module call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sheep_net&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The module is available in the &lt;a href=&quot;https://github.com/cebix/macemu&quot;&gt;macemu&lt;/a&gt; repository and must be built your system and kernel version. This also means that every time there is a kernel upgrade, you will need to re-build the module.&lt;/p&gt;

&lt;p&gt;To build the kernel module,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/cebix/macemu.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;macemu/BasiliskII/src/Unix/Linux/NetDriver
make
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;make &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Load the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sheep_net&lt;/code&gt; kernel module and update it’s permissions so users other than root can use it. This must also be done on every reboot and I have on my to-do list to write a script and add it to something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rc.local&lt;/code&gt; so it loads with the correct permissions across reboots.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;modprobe sheep_net
&lt;span class=&quot;nb&quot;&gt;sudo chmod &lt;/span&gt;777 /dev/sheep_net
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, in the Serial/Network tab of Basilisk, change the Ethernet Interface to your wireless or wired Ethernet device that’s connected to your LAN.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/basilisk-networking.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/basilisk-networking.png&quot; alt=&quot;Basilisk Network Tab&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Basilisk Network Tab&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;After starting the VM will see other devices using AppleTalk on your local network, and if you have a &lt;a href=&quot;https://github.com/lampmerchant/tashtalk&quot;&gt;TashTalk&lt;/a&gt; and &lt;a href=&quot;https://github.com/lampmerchant/tashrouter/&quot;&gt;TashRouter&lt;/a&gt;, older LocalTalk devices like a &lt;a href=&quot;/Enhancing-my-Macintosh-512Ke/&quot;&gt;Macintosh Plus&lt;/a&gt; are also available.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The biggest benefit I have from this setup is I can write blog posts in &lt;a href=&quot;https://en.wikipedia.org/wiki/MacWrite&quot;&gt;MacWrite&lt;/a&gt; on the Macintosh Plus completely distraction free and save them easily to a shared folder in Basilik on my laptop over wifi.&lt;/p&gt;

&lt;p&gt;Previously I would save the file to a virtual floppy disk on the FloppyEMU or use the &lt;a href=&quot;https://bluescsi.com/toolbox&quot;&gt;BlueSCSI Toolbox&lt;/a&gt; to export the file to the SD card. Saving directly to Basilisk and then copying the file to the laptop through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unix&lt;/code&gt; shared folder is faster and closer to the original way Macintosh file sharing worked.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/basilisk-appleshare.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/basilisk-appleshare.png&quot; alt=&quot;AppleShare in Basilisk&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;AppleShare in Basilisk&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;This setup makes me appreciate how impressive that AppleTalk is as almost entirely zero-configuration. Just plug systems into the same physical (or wireless) network and they’re immediately available for use, even today there are very few products that can claim to do that.&lt;/p&gt;
</description>
        <pubDate>Mon, 10 Feb 2025 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2025/Live-Laugh-Localtalk-with-Basilisk-II/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2025/Live-Laugh-Localtalk-with-Basilisk-II/</guid>
        
        <category>basilisk</category>
        
        <category>localtalk</category>
        
        <category>appletalk</category>
        
        <category>macintosh</category>
        
        <category>macplus</category>
        
        <category>system7</category>
        
        <category>retrocomputing</category>
        
        
        <category>macintosh</category>
        
      </item>
    
      <item>
        <title>Enhancing my Macintosh 512Ke</title>
        <description>&lt;p&gt;This is the second in a series of posts on my Macintosh 512Ke. In my &lt;a href=&quot;/A-Macintosh-Story/&quot;&gt;first post&lt;/a&gt; I went over the history of how I obtained this machine, initial exploration and repairs over the years.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/macplus-enhanced.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/macplus-enhanced.jpg&quot; alt=&quot;Macintosh 512Ke Enhanced&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;My Macintosh 512Ke Enhanced in all its glory&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;This post will go over the enhancements I’ve done to &lt;a href=&quot;https://en.wikipedia.org/wiki/Macintosh_512Ke#Official_upgrades&quot;&gt;my Macintosh 512Ke&lt;/a&gt; over the last six months. Getting it to the point where it can do useful, and modern day things, like writing blog posts in &lt;a href=&quot;https://en.wikipedia.org/wiki/MacWrite&quot;&gt;MacWrite&lt;/a&gt;, surfing &lt;a href=&quot;https://en.wikipedia.org/wiki/Gopher_(protocol)&quot;&gt;Gopher&lt;/a&gt;, &lt;a href=&quot;https://jcs.org/wallops&quot;&gt;chatting on IRC&lt;/a&gt; or &lt;a href=&quot;https://www.telnetbbsguide.com/bbs/captains-quarters-ii/&quot;&gt;cruising a BBS&lt;/a&gt; over WiFi and sharing files with modern Linux system. All of these enhancements are completely reversible and non-destructive if I ever want to to bring the machine back to its original stock state.&lt;/p&gt;

&lt;h2 id=&quot;floppyemu&quot;&gt;FloppyEMU&lt;/h2&gt;

&lt;p&gt;A &lt;a href=&quot;https://www.bigmessowires.com/floppy-emu/&quot;&gt;FloppyEMU&lt;/a&gt; let’s me use floppy images directly from an SD card, eliminating the need to use a floppy drive. The original 800k internal floppy drive suffered from &lt;a href=&quot;https://youtu.be/ia513LCN7jY&quot;&gt;cheese-wheel-of-death&lt;/a&gt; which I repaired, cleaned and lubricated for whenever I want to use real floppies, but I almost always prefer the FloppyEMU.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/floppyemu-close.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/floppyemu-close.jpg&quot; alt=&quot;FloppyEMU&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;FloppyEMU displaying some disks&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;usb4vc&quot;&gt;USB4VC&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/dekuNukem/USB4VC&quot;&gt;USB4VC&lt;/a&gt; allows me to use modern USB mice/keyboards on the machine, solving the problem I had of lacking the original M0110 keyboard. My usual keyboard of choice is a transparent blue &lt;a href=&quot;https://www.monsgeek.com/product/ice75-fully-assembled/#&quot;&gt;Monsgeek ICE75&lt;/a&gt; wireless keyboard and a clear blue wireless mouse because I feel it adds to the overall ａｅｓｔｈｅｔｉｃ.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/usb4vc.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/usb4vc.jpg&quot; alt=&quot;usb4vc&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;USB4VC&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;macintosh-plus-logic-board&quot;&gt;Macintosh Plus Logic Board&lt;/h2&gt;

&lt;p&gt;I replaced the 512Ke logic board with a &lt;a href=&quot;https://en.wikipedia.org/wiki/Macintosh_Plus&quot;&gt;Macintosh Plus&lt;/a&gt; logic board providing 4MiB of memory (8x what the 512Ke has) and external SCSI port. This upgrade opens up many more use cases, such as running &lt;a href=&quot;https://en.wikipedia.org/wiki/MacTCP&quot;&gt;MacTCP&lt;/a&gt; which was impossible on a 512Ke.&lt;/p&gt;

&lt;p&gt;Technically this also makes it no longer a 512Ke, and due to the port differences on the boards I had to replace the back case with Macintosh Plus case. Because of the case swap, the rear case is “Platinum” and the front “beige”, giving it a slight two-tone look when viewed from the side. It also lacks the “Macintosh Plus” case badge on the front, making this machine a chimera of sorts. I also did a &lt;a href=&quot;https://tinkerdifferent.com/resources/mac-plus-scsi-term-power-mod.123/&quot;&gt;SCSI term power mod&lt;/a&gt; to the board to power the BlueSCSI without requiring an external power source.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/macplus-logicboard.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/macplus-logicboard.jpg&quot; alt=&quot;MacPlus logic board&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;MacPlus logic board pre SCSI term mod&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;bluescsi&quot;&gt;BlueSCSI&lt;/h2&gt;

&lt;p&gt;A &lt;a href=&quot;https://bluescsi.com/&quot;&gt;BlueSCSI&lt;/a&gt; hangs off the external SCSI port on the back of the MacPlus logic board, booting a System 7.0.1 image from its SD card. Because I splashed the extra $ and built it with a &lt;a href=&quot;https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html&quot;&gt;RaspberryPi Pico W&lt;/a&gt;, it has the ability to emulate a &lt;a href=&quot;https://bluescsi.com/docs/WiFi-DaynaPORT&quot;&gt;DynaPort&lt;/a&gt; EtherTalk device and connect to The Internet using WiFi.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/bluescsi.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/bluescsi.jpg&quot; alt=&quot;BlueSCSI&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;BlueSCSI&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;picorc&quot;&gt;PicoRC&lt;/h2&gt;

&lt;p&gt;A &lt;a href=&quot;https://github.com/dekuNukem/PicoRC&quot;&gt;PicoRC&lt;/a&gt; provides power to the logic board and CRT portion of the analog board with a &lt;a href=&quot;https://www.mini-box.com/picoPSU-80&quot;&gt;PicoPSU&lt;/a&gt; ATX power supply and common AC power brick. It also allows easy access to the pinouts for Signal, H-Sync, V-Sync and GND pins from the logic board wiring harness.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/picorc.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/picorc.jpg&quot; alt=&quot;PicoRC&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;PicoRC connected to MacPlus logic board&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;cooling&quot;&gt;Cooling&lt;/h2&gt;

&lt;p&gt;Original Classic Macintoshs were notorious for failing over time due to heat issues, and using the fan header on the PicoRC, I strapped a &lt;a href=&quot;https://www.amazon.com/dp/B00NEMGCIA&quot;&gt;Noctua NF-A4x10 Fan&lt;/a&gt; to the inside of the case with a zip tie. It doesn’t move a ton of air and adds some noise to a previously silent machine, and it should add a few more hours of life.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/fan.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/fan.jpg&quot; alt=&quot;Fan inside case&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Fan zip-tied to inside the case&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;rgb2hdmi&quot;&gt;RGB2HDMI&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/hoglet67/RGBtoHDMI&quot;&gt;RGB2HDMI&lt;/a&gt; can display the video output of the Macintosh over HDMI to any modern LCD monitor or video capture device. By soldering wires to the Signal, H-Sync, V-sync and Ground pinouts on the PicoRC I can tap into the video signal and use the internal CRT and an external display at the same time.&lt;/p&gt;

&lt;p&gt;This is also my backup plan to continue using the machine if/when the CRT fails, as the logic board and rest of these enhancements (USB4VC and PicoRO) will still be able to display to any monitor that supports HDMI.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/rgb2hdmi.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/rgb2hdmi.jpg&quot; alt=&quot;RGB2HDMI&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Displaying Finder on an both an external LCD and the internal CRT&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;tashtalk-2&quot;&gt;TashTalk 2&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://ko-fi.com/s/60b561a0e3&quot;&gt;TashTalk 2&lt;/a&gt; is a RaspberryPi HAT that lets me connect my Macintosh using &lt;a href=&quot;https://en.wikipedia.org/wiki/PhoneNET&quot;&gt;PhoneNET&lt;/a&gt; adaptors to other devices with &lt;a href=&quot;https://en.wikipedia.org/wiki/AppleTalk&quot;&gt;AppleTalk&lt;/a&gt; networking. With this setup I can use &lt;a href=&quot;https://en.wikipedia.org/wiki/AppleShare&quot;&gt;AppleShare&lt;/a&gt; to share files and printers between other Macintoshes on the network. As an example I’m writing this post on the Macintosh Plus and saving it remotely over AppleShare, then copy it into this blog and publish it.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/tashtalk2.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/tashtalk2.jpg&quot; alt=&quot;TashTalk2 HAT on a RaspberryPi 3&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;TashTalk2 HAT on RaspberryPi 3&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;basilisk-ii&quot;&gt;Basilisk II&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://basilisk.cebix.net/&quot;&gt;Basilisk II&lt;/a&gt; is not a modification, but a Macintosh 68k emulator for MacOS and Linux. I run System 7.5 Basilisk VM to download applications, extract files, and do things in a similar Macintosh environment but on faster hardware. The TashTalk2 RaspberryPi runs a &lt;a href=&quot;https://github.com/lampmerchant/tashrouter/&quot;&gt;TashRouter&lt;/a&gt; that and share files between Basilisk II and the Macintosh over AppleShare.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/basilisk.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/basilisk.jpg&quot; alt=&quot;Basilisk II running on my Linux laptop&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Basilisk II and video out from the Macintosh Plus&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;rominator&quot;&gt;ROMinator&lt;/h2&gt;

&lt;p&gt;The most recent modification to my Macintosh is a &lt;a href=&quot;https://jcm-1.com/product/rominator-v1-for-macintosh-plus/&quot;&gt;ROMinator&lt;/a&gt; that replaces the original system ROM that shipped with the Plus. It provides all the features of the original ROM, but has extra features like changing the startup icon, startup sound and holding down R will boot into &lt;a href=&quot;https://en.wikipedia.org/wiki/System_6&quot;&gt;System 6&lt;/a&gt; from ROM.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/rominator.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/rominator.jpg&quot; alt=&quot;ROMinator&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;ROMinator on the MacPlus logic board&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;thoughts&quot;&gt;Thoughts&lt;/h2&gt;

&lt;p&gt;Over the last six months I am surprised by how much I’ve learned about classic Macintoshs. I went from  booting 40 year old floppies, to connecting to Gopher sites and modern Linux systems and can use my Macintosh 512Ke (Plus) as I would a modern machine. The retro community around these systems is extremely impressive, creating tools and hardware that up until a few years ago didn’t exist and I am grateful for the dedication and enthusiasm that others have for this platform.&lt;/p&gt;

&lt;p&gt;There are still a few things I would like to do (&lt;a href=&quot;https://jetkvm.com/&quot;&gt;remote access…&lt;/a&gt;?) machine, but I am extremely happy with this setup and use it on a weekly basis, writing blog posts like this one, playing games, or just enjoying computing from when times were simpler and more optimistic.&lt;/p&gt;
</description>
        <pubDate>Wed, 05 Feb 2025 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2025/Enhancing-my-Macintosh-512Ke/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2025/Enhancing-my-Macintosh-512Ke/</guid>
        
        <category>macintosh</category>
        
        <category>512ke</category>
        
        <category>macplus</category>
        
        <category>system6</category>
        
        <category>system7</category>
        
        <category>retrocomputing</category>
        
        
        <category>macintosh</category>
        
      </item>
    
      <item>
        <title>A Macintosh Story</title>
        <description>&lt;p&gt;This is the first post in what I am hoping a series of how I took my &lt;a href=&quot;https://en.wikipedia.org/wiki/Macintosh_512Ke&quot;&gt;512Ke “Fat Mac”&lt;/a&gt; and enhanched it to the state it is today.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/my-macintosh.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/my-macintosh.jpg&quot; alt=&quot;Vintage Macintosh 512Ke computer running MacWrite word processor on classic CRT display&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;My Macintosh editing this blog post in MacWrite&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;releasing-the-magic-smoke&quot;&gt;Releasing the Magic Smoke&lt;/h2&gt;

&lt;p&gt;Our story begins a dozen years ago when I inherited the 512Ke Mac from a nursery school. I had at one point turned it on to check if it worked and test out a few of the floppies it came with, but it wasn’t until years later when I thought the kids would like to see it in action during COVID that I did anything else with it. I booted up &lt;a href=&quot;https://www.mobygames.com/game/200750/dinosaur-discovery-kit/&quot;&gt;Dinosaur Discovery Kit&lt;/a&gt; for them to play, which they enjoyed, but 5 minutes later there was a loud pop and a lot of smoke coming out of the case. After quickly moving the kids to a safe distance and bringing it outside, I realized it was still functioning normally right up until I powered it off.&lt;/p&gt;

&lt;p&gt;Researching into what happened, I learned older macs like many systems from the 1980s used RIFA capacitors that were &lt;a href=&quot;https://www.eevblog.com/forum/chat/old-rifa-capacitors-and-a-disaster-story/&quot;&gt;notorious for failing in a spectacular manner&lt;/a&gt; and there were inexpensive modern day replacements. In addition to replacing the RIFA, I decided to recap the entire “analog” board, as the capacitors over time could leak and cause all sorts of issues.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/rifa.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/rifa.jpg&quot; alt=&quot;Failed RIFA capacitor from vintage Macintosh 512Ke showing thermal damage and burn marks&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Blown RIFA capacitor&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;A few online purchases and days later I had replacement capacitors and slowly went through desoldering the old ones and soldering the new ones onto the analog board. Learning about proper CRT discharge procedures as the analog board could provide quite a shock due to the high voltage running through it even after it was powered off. Once everything was replaced, the 512Ke worked just fine and Dinosaur Discovery Kit and other software booted off the floppy without issue.&lt;/p&gt;

&lt;p&gt;I used the machine a bit more, but found it limited in what it could do, especially with many of the floppies I had not working at all. I shelved the system again, satisfied it “worked” but didn’t have much use for it other than looking nice on a shelf in the garage behind me during Zoom meetings..&lt;/p&gt;

&lt;h2 id=&quot;floppyemu&quot;&gt;FloppyEMU&lt;/h2&gt;

&lt;p&gt;Sometime in 2024 while watching retro computer youtube videos I saw a someone use a &lt;a href=&quot;https://www.bigmessowires.com/floppy-emu/&quot;&gt;FloppyEMU&lt;/a&gt; to emulate an external floppy drive and run Macintosh programs downloaded from websites like &lt;a href=&quot;https://macintoshgarden.org/&quot;&gt;Macintosh Garden&lt;/a&gt; and &lt;a href=&quot;https://www.macintoshrepository.org/&quot;&gt;Macintosh Repository&lt;/a&gt; directly off an SD card. It could even emulate a &lt;a href=&quot;https://en.wikipedia.org/wiki/Hard_Disk_20&quot;&gt;Hard Disk 20 &lt;/a&gt; with a 20MiB storage capacity.&lt;/p&gt;

&lt;p&gt;Reading more about the FloppyEMU opened up many possibilities, no more would I be limited to the floppy disks I had, but could run practically any Macintosh software that the 512Ke would run, just find it, copy to an SD card and boot. The possibilities were endless.&lt;/p&gt;

&lt;p&gt;I ordered one and after a few days it arrived, it was relatively easy to assemble and soon I was able to boot off of it, trying out all sorts of software and it completely changed how I could use the machine. It also greatly increased my knowledge of how early Macintoshes worked. Most of my computing experience has involved operating systems installed to permanent storage, like a hard drive, booting off of it and then running programs. Where with the Macintosh there was an Operating System, but you mostly booted into programs directly, they still had a Finder but were very limited and you would have to switch disks if you wanted to do something else.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/macintosh/floppyemu.jpg&quot;&gt;&lt;img src=&quot;/assets/images/posts/macintosh/floppyemu.jpg&quot; alt=&quot;FloppyEMU floppy disk emulator connected to Macintosh 512Ke running Dark Castle retro game&quot; width=&quot;60%&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;FloppyEMU running Dark Castle&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;While the FloppyEMU made this easier, it was starting to show some of it’s own flaws, such as “File not contiguous” errors. After a lot of reading, I found that copying files from my modern Macbook via Finder to the SD card wouldn’t write them in a single stream of data, confusing the FloppyEMU. Copying disk images from my Linux system worked better, but depending on the file format, download site and many other options this was a continuous challenge.&lt;/p&gt;

&lt;h2 id=&quot;hd20&quot;&gt;HD20&lt;/h2&gt;

&lt;p&gt;My frustrations with booting the FloppyEMU as a floppy drive lead to using it’s feature of &lt;a href=&quot;https://www.savagetaylor.com/2020/03/29/booting-a-macintosh-plus-with-floppyemus-hd20-support/&quot;&gt;emulating a Hard Disk 20&lt;/a&gt;. This resolved the problems I was having with continually removing the SD card, copying the disk images to it, booting up the 512Ke and then hoping it would work. Now I could copy almost as many disk images as I wanted to the HD20 and have it boot into the System 6 operating system directly, using it more or less like a modern computer.&lt;/p&gt;

&lt;p&gt;While using this technique, I ended up keeping notes of what all software worked and what didn’t with the error messages on those that didn’t. One that kept repeating itself was the 512Ke simply running out of memory. In my solution of booting to System 6 on the HD20, I inadvertently used up much of the precious 512Ke of memory for the OS, further limiting what software I could run unless I booted directly too it from the FloppyEMU, bringing me back to square one.&lt;/p&gt;

&lt;h2 id=&quot;no-keyboard-detected&quot;&gt;No Keyboard Detected&lt;/h2&gt;

&lt;p&gt;As an aside, while doing all of this, I was still missing one major component - a keyboard. Because the original Macintosh was so focused on using a mouse, I was able to do all of the above with the original &lt;a href=&quot;https://en.wikipedia.org/wiki/Apple_pointing_devices#Macintosh_Mouse_(M0100)&quot;&gt;M0100 mouse&lt;/a&gt; it came with, but I didn’t have a &lt;a href=&quot;https://en.wikipedia.org/wiki/Apple_keyboards#Macintosh_Keyboard_(M0110)&quot;&gt;M0110 keyboard&lt;/a&gt; to use with the system. There were some on Ebay, but they were almost, if not more, expensive than the 512Ke itself and I would need to start looking for alternative options.&lt;/p&gt;

&lt;h2 id=&quot;inputoutput&quot;&gt;Input/Output&lt;/h2&gt;

&lt;p&gt;Up until this point I was really enjoying using the 512Ke, and the software I could run with only the mouse was a lot of fun to use, but I wanted to do more. After watching some videos about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Macintosh_SE/30&quot;&gt;SE/30&lt;/a&gt; the &lt;a href=&quot;https://jcs.org/system6c&quot;&gt;series of videos JCS had done on their 512Ke&lt;/a&gt; programming new System 6 software on the system itself, I knew the system was capable of much more.&lt;/p&gt;

&lt;p&gt;I knew there was a big enough &lt;a href=&quot;https://68kmla.org/bb/index.php&quot;&gt;vintage Macintosh community&lt;/a&gt; to support something like the FloppyEMU, so that must mean there are other projects out there right? How else could I push the system; avoid memory issues, use a modern keyboard, and maybe even getting it online? That rabbit hole was much deeper than I was expecting.&lt;/p&gt;
</description>
        <pubDate>Tue, 28 Jan 2025 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2025/A-Macintosh-Story/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2025/A-Macintosh-Story/</guid>
        
        <category>macintosh</category>
        
        <category>512ke</category>
        
        <category>macplus</category>
        
        <category>system6</category>
        
        <category>system7</category>
        
        <category>retrocomputing</category>
        
        
        <category>macintosh</category>
        
      </item>
    
      <item>
        <title>Switching to Ghostty</title>
        <description>&lt;h2 id=&quot;ghostty-&quot;&gt;Ghostty 👻&lt;/h2&gt;

&lt;p&gt;In December 2024 the new terminal emulator &lt;a href=&quot;https://ghostty.org/&quot;&gt;ghostty&lt;/a&gt; created by mitchellh&lt;a href=&quot;https://mitchellh.com/&quot;&gt;&lt;/a&gt; (founder of &lt;a href=&quot;https://www.hashicorp.com/&quot;&gt;Hashicorp&lt;/a&gt;) was released.&lt;/p&gt;

&lt;p&gt;I originally had the (incorrect) assumption that it was similar to other “new” terminal emulators that require a network connection, were built in javascript or had some sort of “AI” features wedged in.&lt;/p&gt;

&lt;p&gt;What caught my eye though when reading &lt;a href=&quot;https://ghostty.org/docs/about&quot;&gt;About Ghostty&lt;/a&gt;, was the focus on the following,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ghostty.org/docs/about#native&quot;&gt;Native application&lt;/a&gt; no Electron&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=cPaGkEesw20&amp;amp;t=3015s&quot;&gt;Fast&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://mitchellh.com/writing/ghostty-is-coming&quot;&gt;Released when Ready&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This quote by mitchellh and finally convinced me to give it a try,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I like to imagine that if stores like CompUSA still existed, Ghostty 1.0 would be boxed, shrink-wrapped, and on the shelf ready for purchase (but also free and open-source).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/ghostty/ghostty-terminal.png&quot; alt=&quot;Ghostty Terminal editing a draft of this post&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Ghostty Terminal editing a draft of this post&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;initial-impressions&quot;&gt;Initial Impressions&lt;/h2&gt;

&lt;p&gt;Installing on my MacOS and Linux laptops was relatively straightforward, although for my &lt;a href=&quot;https://linuxmint.com/&quot;&gt;Linux Mint&lt;/a&gt; laptop I had to install a .deb from a &lt;a href=&quot;https://github.com/mkasberg/ghostty-ubuntu&quot;&gt;3rd party repo&lt;/a&gt;. What I first noticed was it’s sane defaults, it just worked out-of-the-box and I could just start using it. It was snappy too, especially compared to Terminal.app on MacOS.&lt;/p&gt;

&lt;p&gt;What really hooked me was finding the &lt;a href=&quot;https://ghostty.org/docs/features/theme&quot;&gt;built-in themes&lt;/a&gt;, including my current favorite, &lt;a href=&quot;https://github.com/tokyo-night/tokyo-night-vscode-theme&quot;&gt;Tokyo Night&lt;/a&gt;. Not only were these built into ghostty, but there was an interactive preview feature with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ghostty +list-themes&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/ghostty/ghostty-preview.png&quot; alt=&quot;Ghostty Theme Preview&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Ghostty Theme Preview&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;It was a lot of fun previewing themes with zero friction of trying them out, unlike other terminal emulators where you have to change a config and then reload it. In addition, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;theme&lt;/code&gt; options can set a theme for both light and dark modes, dynamically switching depending on your OS setting. I like to have a “light” OS theme during the day and a “dark” theme during the night and this was a feature I haven’t seen in other terminal emulators.&lt;/p&gt;

&lt;h2 id=&quot;customizing-the-config&quot;&gt;Customizing the Config&lt;/h2&gt;

&lt;p&gt;My ghostty configuration is relatively small, with a few changes for how I like my terminal emulator,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://usgraphics.com/products/berkeley-mono&quot;&gt;TX-02&lt;/a&gt;(Berkeley Mono) Font&lt;/li&gt;
  &lt;li&gt;Semi-transparent blurred background&lt;/li&gt;
  &lt;li&gt;Block style blinking cursor&lt;/li&gt;
  &lt;li&gt;Inverted selection&lt;/li&gt;
  &lt;li&gt;Easy to read&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/ghostty/config&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#Font
font-family = &quot;TX-02&quot;
font-size = &quot;16&quot;

#Terminal settings
term = &quot;xterm-256color&quot;

#Visuals
theme = &quot;light:tokyonight-day,dark:tokyonight&quot;
background-opacity = .9
background-blur-radius = 20
selection-invert-fg-bg = true
bold-is-bright = true
minimum-contrast = 2

#Cursor
cursor-style = block
cursor-style-blink = true
cursor-invert-fg-bg = true
cursor-opacity = .8
shell-integration-features = no-cursor
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;graphics&quot;&gt;Graphics&lt;/h2&gt;

&lt;p&gt;I’ve always though it was cool that some terminals could display graphics using &lt;a href=&quot;https://en.wikipedia.org/wiki/Sixel&quot;&gt;sixels&lt;/a&gt;, but support in Terminal.app was never there. Ghostty doesn’t support sixels either, but does support the &lt;a href=&quot;https://sw.kovidgoyal.net/kitty/graphics-protocol/&quot;&gt;Kitty Graphics Protocol&lt;/a&gt;, which is even better as it’s a modern library and in active development.&lt;/p&gt;

&lt;p&gt;This lets terminals tools like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;timg&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mpv&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;neofetch&lt;/code&gt; display graphics right in the terminal.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/ghostty/ghostty-graphics.png&quot; alt=&quot;Ghostty Graphics&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Ghostty Graphics with neofetch&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;after-two-weeks&quot;&gt;After Two Weeks&lt;/h2&gt;

&lt;p&gt;I’ve been using ghostty for the past two weeks on all my systems and I’ve really enjoyed it. It performs much better than Terminal.app on MacOS, which feels extremely sluggish in comparison now.&lt;/p&gt;

&lt;p&gt;That’s not to say I haven’t had any issues,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Somehow Super+Shift+V makes it impossible in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim&lt;/code&gt; to switch out of insert mode&lt;/li&gt;
  &lt;li&gt;Background blur was just recently added for Linux, but isn’t in an official release yet&lt;/li&gt;
  &lt;li&gt;On MacOS the cursor will not change depending on the context (issue &lt;a href=&quot;https://github.com/ghostty-org/ghostty/discussions/3257&quot;&gt;3257&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren’t enough to keep from using ghostty, and I am looking forward to what future releases have in store.&lt;/p&gt;
</description>
        <pubDate>Thu, 23 Jan 2025 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2025/Switching-to-Ghostty/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2025/Switching-to-Ghostty/</guid>
        
        <category>terminal</category>
        
        <category>linux</category>
        
        <category>macos</category>
        
        <category>zsh</category>
        
        <category>bash</category>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>DNS Guardrails with dnscrypt-proxy</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;Over the holidays we got our two younger children HP laptops for them to do their school work on and to have a proper computer. While the schools Google Classroom login effectively adds restrictions to Chrome, I still wanted to have some guardrails on their Internet access as well as ad-blocking.&lt;/p&gt;

&lt;p&gt;The first thing I did was replace the Windows S install that came on the laptops with &lt;a href=&quot;https://www.linuxmint.com/&quot;&gt;Linux Mint&lt;/a&gt; as I’ve always enjoyed the &lt;a href=&quot;https://projects.linuxmint.com/cinnamon/&quot;&gt;Cinnamon desktop environment&lt;/a&gt; and it has a low enough learning curve that the kids could easily pick it up. After installing a few apps and games (&lt;a href=&quot;https://openrct2.org/&quot;&gt;OpenRCT2&lt;/a&gt;) from the Software Center and setting their own passwords, they were up and running and surfing the world-wide-web.&lt;/p&gt;

&lt;p&gt;Finally I added &lt;a href=&quot;https://tailscale.com/&quot;&gt;Tailscale&lt;/a&gt; to both laptops to put them on my &lt;a href=&quot;https://tailscale.com/kb/1136/tailnet&quot;&gt;tailnet&lt;/a&gt;. This has benefits of accessing tailnet-only services, easier remote access, and leveraging the &lt;a href=&quot;/blog/2021/Running-dnscrypt-proxy-on-OpenBSD/&quot;&gt;dnscrypt-proxy on OpenBSD&lt;/a&gt; I setup a few years ago for DNS.&lt;/p&gt;

&lt;h2 id=&quot;guardrails&quot;&gt;Guardrails&lt;/h2&gt;

&lt;p&gt;My original DNS config worked well, but I wanted to add some guardrails specifically for the kids laptops,&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.cloudflare.com/introducing-1-1-1-1-for-families/&quot;&gt;Cloudflare for Families&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Public-blocklist&quot;&gt;Ad Blocking&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://support.google.com/a/answer/6212415&quot;&gt;YouTube Restricted Mode&lt;/a&gt; via &lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Public-blocklist&quot;&gt;Cloaking&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Accessible only from the Tailscale&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First I tried using the existing &lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy&quot;&gt;dnscrypt-proxy&lt;/a&gt; to provide a different set of DNS resolvers depending on the source IP, but this wasn’t possible. Eventually I came up with a seperate DNS infrastructure in a container for the laptops to use instead.&lt;/p&gt;

&lt;h2 id=&quot;container-stack&quot;&gt;Container Stack&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; is used for building a container including &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnscrypt-proxy&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; debian:trixie-slim&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; DEBIAN_FRONTEND noninteractive&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;apt update &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    apt &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; dnscrypt-proxy &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;      ca-certificates &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt clean

&lt;span class=&quot;k&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; /tmp&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [ &quot;/usr/sbin/dnscrypt-proxy&quot; ]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [ &quot;-config&quot;, &quot;/etc/dnscrypt-proxy/dnscrypt-proxy.toml&quot; ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;docker compose&lt;/a&gt; is used to bring up the stack, which includes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tailscale&lt;/code&gt; container to provide network and access to other devices on the tailnet. Configuration files are monted read-only from the current directly and some volumes to maintain state across restarts.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose.yml&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3.9&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;tailscale&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;tailscale-dnscrypt&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dnscrypt-proxy&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ghcr.io/tailscale/tailscale&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;stdin_open&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TS_AUTH_KEY=${TS_AUTH_KEY}&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TS_USERSPACE=true&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TS_STATE_DIR=/var/lib/tailscale&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TS_SOCKET=/var/run/tailscale/tailscaled.sock&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dnscryptvarlib:/var/lib&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;unless-stopped&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;dnscrypt-proxy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;stdin_open&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./dnscrypt-proxy.toml:/etc/dnscrypt-proxy/dnscrypt-proxy.toml:ro&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./blocklist.txt:/etc/dnscrypt-proxy/blocklist.txt:ro&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./cloaking-rules.txt:/etc/dnscrypt-proxy/cloaking-rules.txt:ro&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./domains-allowlist.txt:/etc/dnscrypt-proxy/domains-allowlist.txt:ro&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;keys:/etc/dnscrypt-proxy/keys&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;network_mode&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;service:tailscale&apos;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;dnscryptvarlib&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;dnscrypt-proxy&quot;&gt;dnscrypt-proxy&lt;/h2&gt;

&lt;p&gt;The dnscrypt-proxy configuration uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cloudflare-family&lt;/code&gt; source and ad-blocking using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blocklist.txt&lt;/code&gt; generated with &lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Combining-Blocklists&quot;&gt;generate-domains-blocklist.py&lt;/a&gt;. All logs go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/stdout&lt;/code&gt; so they appear in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker compose logs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnscrypt-proxy.toml&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#Use cloudflare DNS&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;server_names&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;[&apos;cloudflare-family&apos;]&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Listen on local and LAN addresses for DNS&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;listen_addresses&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;[&apos;127.0.0.1:53&apos;]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;max_clients&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;250&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;user_name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;_dnscrypt-proxy&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Enable ipv4 and ipv6&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ipv4_servers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ipv6_servers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Allow TCP and UDP&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;force_tcp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2500&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;keepalive&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Logging&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;log_level&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;use_syslog&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Certs&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;cert_refresh_delay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;240&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dnscrypt_ephemeral_keys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;tls_disable_session_tickets&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Cache&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;cache&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Cloaking&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;cloaking_rules&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/etc/dnscrypt-proxy/cloaking-rules.txt&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Query logging, commented out unless for troubleshooting&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[query_log]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/dev/stdout&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;tsv&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Sources for resolvers and relays&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[sources]&lt;/span&gt;
  &lt;span class=&quot;nn&quot;&gt;[sources.&apos;public-resolvers&apos;]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;https://download.dnscrypt.info/resolvers-list/v3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
/public-resolvers.md&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;]&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;  &lt;span class=&quot;py&quot;&gt;minisign_key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;cache_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/var/tmp/public-resolvers.md&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;refresh_delay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Blocking configuration&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[blocked_names]&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;## Path to the file of blocking rules (absolute, or relative to the same directory as the executable file)&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;blocked_names_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/etc/dnscrypt-proxy/blocklist.txt&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;log_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/dev/stdout&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;log_format&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;tsv&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Allow configuration&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[allowed_names]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;allowed_names_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/etc/dnscrypt-proxy/domains-allowlist.txt&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Public-blocklist&quot;&gt;Cloaking&lt;/a&gt; is used so all YouTube requests resolve to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;restrict.youtube.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cloaking-rules.txt&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;www.youtube.com restrict.youtube.com
m.youtube.com  restrict.youtube.com
youtubei.googleapis.com restrict.youtube.com
youtube.googleapis.com restrict.youtube.com
www.youtube-nocookie.com restrict.youtube.com
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;exposing-via-tailscale&quot;&gt;Exposing via Tailscale&lt;/h2&gt;

&lt;p&gt;Since I only want DNS available to devices on my tailnet, and not publicly available, there’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tailscale&lt;/code&gt; container in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose.yml&lt;/code&gt; that provides networking to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnscrypt-proxy&lt;/code&gt; container using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;network_mode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Set this up by creating an &lt;a href=&quot;https://tailscale.com/kb/1085/auth-keys&quot;&gt;auth key&lt;/a&gt; for your tailnet and then putting it into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file that docker compose will source in and set as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TS_AUTH_KEY&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;TS_AUTH_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;tskey-auth-xxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;enabling-on-linux-mint&quot;&gt;Enabling on Linux Mint&lt;/h2&gt;

&lt;p&gt;My tailnet uses &lt;a href=&quot;https://tailscale.com/kb/1081/magicdns&quot;&gt;Magic DNS&lt;/a&gt; which sets the nameserver for all devices on a tailnet to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;100.100.100.100&lt;/code&gt;, but since this is a DNS server specific to a subset of systems we want to use the IP of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnscrypt-proxy&lt;/code&gt; device instead.&lt;/p&gt;

&lt;p&gt;After bringing up the stack with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker compose up&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tailscale&lt;/code&gt; container will authenticate to the tailnet and have an Tailscale IP (eg &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;100.112.129.40&lt;/code&gt;). This IP is then added to the laptops &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/resolv.conf&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nameserver 100.112.129.40
search tailnet-3831.ts.net
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Tailscale will keep trying to revert this, so to keep the settings permanent, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/resolv.conf&lt;/code&gt; is set to immutable with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chattr +i /etc/resolv.conf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To test DNS is working, looking for more “adult” content on youtube will give a message similar to “your Google workspace administrator has restricted some content”.&lt;/p&gt;

&lt;p&gt;Verify in container logs with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dig m.youtube.com  @100.76.233.91&lt;/code&gt; (where the IP is your Tailscale container IP) and check the logs for messages similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1       m.youtube.com   A       CLOAK   0ms     -&lt;/code&gt;.&lt;/p&gt;
</description>
        <pubDate>Tue, 23 Jan 2024 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2024/DNS-Guardrails-with-dnscrypt-proxy/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2024/DNS-Guardrails-with-dnscrypt-proxy/</guid>
        
        <category>linux</category>
        
        <category>dns</category>
        
        <category>containers</category>
        
        <category>docker</category>
        
        <category>networking</category>
        
        <category>tailscale</category>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>Tailscale on the DevTerm R-01</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;Recently I assembled a &lt;a href=&quot;https://www.clockworkpi.com/product-page/devterm-kit-r01&quot;&gt;ClockworkPi DevTerm R-01&lt;/a&gt;, a cyberdeck-like terminal with a &lt;a href=&quot;https://en.wikipedia.org/wiki/RISC-V&quot;&gt;RISC-V&lt;/a&gt; compute module. While the retro-future design of the DevTerm really appealed to me, and I’ve also been wanting to work with RISC-V for a while to learn a new architecture making the R-01 a perfect esoteric project platform.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/devtermtailscale/devterm-r01.png&quot; alt=&quot;DevTermR01&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;ClockworkPi DevTerm R-01&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;After trying out a few things like &lt;a href=&quot;https://www.dosbox.com/&quot;&gt;DOSBox&lt;/a&gt;, &lt;a href=&quot;https://git.suckless.org/surf/&quot;&gt;Surf&lt;/a&gt;, and &lt;a href=&quot;https://www.scummvm.org/&quot;&gt;ScummVM&lt;/a&gt;, I found the &lt;a href=&quot;https://linux-sunxi.org/D1&quot;&gt;Allwinner D1&lt;/a&gt; RISC-V chip wasn’t powerful enough to do much other than some basic window management, &lt;a href=&quot;http://www.infocom-if.org/downloads/downloads.html&quot;&gt;Interactive Fiction&lt;/a&gt;, and browsing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gopher://&lt;/code&gt; with &lt;a href=&quot;https://bombadillo.colorfield.space/&quot;&gt;Bombadillo&lt;/a&gt;. However I still wanted to use it as a terminal to access other systems, which lead me to attempting to install &lt;a href=&quot;https://tailscale.com&quot;&gt;Tailscale&lt;/a&gt; to leverage the mesh VPN and other features.&lt;/p&gt;

&lt;p&gt;Installing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tailscale&lt;/code&gt; was un-eventful, as it’s had &lt;a href=&quot;https://github.com/tailscale/tailscale/issues/2119&quot;&gt;RISC-V support&lt;/a&gt; for a while, and following the install guide did what was expected. The problem is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tailscaled&lt;/code&gt; fails due to the required &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tun&lt;/code&gt; kernel module missing in the 5.4.61 kernel running on the DevTerm.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Jan 26 02:25:17 localhost systemd[1]: Started Tailscale node agent.
Jan 26 02:25:17 localhost tailscaled[1074605]: wgengine.NewUserspaceEngine(tun &quot;tailscale0&quot;) ...
Jan 26 02:25:17 localhost tailscaled[1074605]: Linux kernel version: 5.4.61
Jan 26 02:25:17 localhost tailscaled[1074605]: is CONFIG_TUN enabled in your kernel? `modprobe tun` failed with: modprobe: FATAL: Module tun not found in directory /lib/modules/5.4.61
Jan 26 02:25:19 localhost tailscaled[1074605]: tun module not loaded nor found on disk
Jan 26 02:25:19 localhost tailscaled[1074605]: wgengine.NewUserspaceEngine(tun &quot;tailscale0&quot;) error: tstun.New(&quot;tailscale0&quot;): CreateTUN(&quot;tailscale0&quot;) failed; /dev/net/tun does not exist
Jan 26 02:25:19 localhost tailscaled[1074605]: flushing log.
Jan 26 02:25:19 localhost tailscaled[1074605]: logger closing down
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;building-a-tuntap-kernel-module&quot;&gt;Building a TUN/TAP Kernel Module&lt;/h2&gt;

&lt;p&gt;The first step was finding if the R-01 kernel source was available so re-build the exact kernel version and include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tun&lt;/code&gt; module by setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONFIG_TUN=m&lt;/code&gt;. Looking around the ClockworkPi website, Discord, and Github I eventually found the &lt;a href=&quot;https://github.com/clockworkpi/DevTerm/wiki/Create-DevTerm-R01-OS-image-from-scratch#how-to-compile-kernel&quot;&gt;How to Compile Kernel&lt;/a&gt; documentation. This had links to the original source and the toolchain.&lt;/p&gt;

&lt;p&gt;Since the R-01 isn’t exactly fast, cross-building this on a x86 system was required. My personal Debian server is a bit of mess when it comes to package pinning, so I created a new 8 CPU, 8GiB memory virtual machine in qemu and install &lt;a href=&quot;https://www.releases.ubuntu.com/jammy/&quot;&gt;Ubuntu 22.04 “Jammy Jellyfish”&lt;/a&gt; since that’s what the R-01 is running and what ClockworkPi has in it’s documentation.&lt;/p&gt;

&lt;h3 id=&quot;installing-required-packages&quot;&gt;Installing Required Packages&lt;/h3&gt;

&lt;p&gt;After setting up the VM, install required packages for cross-building the kernel,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;gcc-11-riscv64-linux-gnu binutils-riscv64-linux-gnu qemu-user-static build-essential git wget curl vim libncurses-dev flex automake autoconf bison libssl-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;cloning-clockworkpi-kernel-source&quot;&gt;Cloning ClockworkPi Kernel Source&lt;/h3&gt;

&lt;p&gt;Clone the &lt;a href=&quot;https://github.com/cuu/last_linux-5.4&quot;&gt;kernel source&lt;/a&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/git&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; ~/git
git clone https://github.com/cuu/last_linux-5.4.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setting-up-build-toolchain&quot;&gt;Setting Up Build Toolchain&lt;/h3&gt;

&lt;p&gt;Download the ClockworkPi toolchain from &lt;a href=&quot;https://github.com/cuu/toolchain-thead-glibc&quot;&gt;https://github.com/cuu/toolchain-thead-glibc&lt;/a&gt;, which is a README pointing to a Mega link. While it’s a bit concerning coming from Mega, since it’s a tarball and running in a VM it’s not that risky. There’s also a section on installing the official RISC-V toolchain which is another option, but requires additional building.&lt;/p&gt;

&lt;p&gt;Untar in home directory,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~
&lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xvzf&lt;/span&gt; riscv64-glibc-gcc-thead_20200702.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;existing-kernel-config-from-devterm&quot;&gt;Existing Kernel Config from DevTerm&lt;/h3&gt;

&lt;p&gt;Copy the running kernel config in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc/config.gz&lt;/code&gt; on the DevTerm to the VM. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.gz&lt;/code&gt; contains the configuration for how the running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5.4.61&lt;/code&gt; kernel was configured and is loaded to set everything the exact same way when building the new kernel.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/git/last_linux-5.4
scp cpi@devterm:/proc/config.gz &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;gunzip &lt;/span&gt;config.gz
&lt;span class=&quot;nb&quot;&gt;mv &lt;/span&gt;config .config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;enabling-config_tun&quot;&gt;Enabling CONFIG_TUN&lt;/h3&gt;

&lt;p&gt;There are two ways to enable the TUN/TAP module,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Edit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.config&lt;/code&gt; and set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONFIG_TUN=m&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Interactively run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;menuconfig&lt;/code&gt; and set it in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Device Drivers -&amp;gt; Network device support -&amp;gt; Universal TUN/TAP device driver support &lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~/riscv64-glibc-gcc-thead_20200702/bin/:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
make &lt;span class=&quot;nv&quot;&gt;LOCALVERSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu- &lt;span class=&quot;nv&quot;&gt;ARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;riscv menuconfig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;building-the-kernel&quot;&gt;Building the Kernel&lt;/h3&gt;

&lt;p&gt;Build the kernel using the provided &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m.sh&lt;/code&gt; script, but first edit it to include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATH&lt;/code&gt; for the toolchain and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOCALVERSION=&lt;/code&gt;. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LOCALVERSION=&lt;/code&gt; isn’t set then the kernel version will include a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; at the end and modules will not load due to a version mis-match,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~/riscv64-glibc-gcc-thead_20200702/bin/:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
make &lt;span class=&quot;nv&quot;&gt;LOCALVERSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu- &lt;span class=&quot;nv&quot;&gt;ARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;riscv
make &lt;span class=&quot;nv&quot;&gt;LOCALVERSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu- &lt;span class=&quot;nv&quot;&gt;ARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;riscv &lt;span class=&quot;nv&quot;&gt;INSTALL_MOD_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;/rootfs/ modules_install
make &lt;span class=&quot;nv&quot;&gt;LOCALVERSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu- &lt;span class=&quot;nv&quot;&gt;ARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;riscv &lt;span class=&quot;nv&quot;&gt;INSTALL_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;/boot/ zinstall
&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;/boot/
&lt;span class=&quot;nb&quot;&gt;cp arch&lt;/span&gt;/riscv/boot/dts/sunxi/board.dtb &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;/boot/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./m.sh&lt;/code&gt; and wait a few minutes while it builds.&lt;/p&gt;

&lt;p&gt;When successful, the new kernel and modules are in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test/boot/&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;setting-up-new-modules-on-devterm&quot;&gt;Setting up New Modules on DevTerm&lt;/h2&gt;

&lt;p&gt;Create a tarball of the new modules and copy them to the DevTerm,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~/git/last_linux-5.4/test/rootfs/lib/modules
&lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-cvzf&lt;/span&gt; 5.4.61.modules.tar.gz 5.4.61/
scp 5.4.61.modules.tar.gz cpi@devterm:~
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On the DevTerm, backup original modules directory,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /lib/modules
&lt;span class=&quot;nb&quot;&gt;sudo mv &lt;/span&gt;5.4.61 5.4.61.orig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and untar the new modules directory,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /lib/modules
&lt;span class=&quot;nb&quot;&gt;sudo tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xvzf&lt;/span&gt; ~/5.4.61.modules.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;loading-the-tuntap-module&quot;&gt;Loading the TUN/TAP Module&lt;/h3&gt;

&lt;p&gt;Load the new TUN/TAP Module,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;modprobe tun
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If successfull &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dmesg&lt;/code&gt; will show,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tun: Universal TUN/TAP device driver, 1.6
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setting-up-tailscale&quot;&gt;Setting up Tailscale&lt;/h3&gt;

&lt;p&gt;Now that the TUN/TAP module is loaded, start &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tailscaled&lt;/code&gt; and finish setting up Tailscale,&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;service tailscaled start
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;tailscale up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Wed, 25 Jan 2023 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2023/Tailscale-on-the-DevTerm-R-01/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2023/Tailscale-on-the-DevTerm-R-01/</guid>
        
        <category>devterm</category>
        
        <category>riscv</category>
        
        <category>linux</category>
        
        <category>tailscale</category>
        
        
        <category>devterm</category>
        
      </item>
    
      <item>
        <title>Superhighway84 on FreeBSD</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;A couple of weeks ago I saw &lt;a href=&quot;https://マリウス.com/superhighway84/&quot;&gt;Superhighway84&lt;/a&gt; on &lt;a href=&quot;https://news.ycombinator.com/item?id=29698412&quot;&gt;HackerNews&lt;/a&gt; and started to check it out, but didn’t get very far. I finally spent some time to get it up and running on &lt;a href=&quot;https://www.freebsd.org&quot;&gt;FreeBSD&lt;/a&gt; which works, but requires a few additional steps.&lt;/p&gt;

&lt;p&gt;I wanted to get Superhighway84 on a spare RaspberryPi 3 running FreeBSD 13, primarily used for a &lt;a href=&quot;/blog/2021/Gemini-Capsule-in-a-FreeBSD-Jail/&quot;&gt;Gemini Capsule in FreeBSD&lt;/a&gt;, since it doesn’t have much traffic and is mostly idle.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Superhighway84 is an USENET-inspired decentralized internet discussion system, featuring a retro text user interface and powered by IPFS and OrbitDB.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/superhighway84/superhighway84.png&quot; alt=&quot;Superhighway84&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Superhighway84 in Solarized Dark terminal&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;ipfs-on-freebsd&quot;&gt;IPFS on FreeBSD&lt;/h2&gt;

&lt;p&gt;Superhighway84 uses &lt;a href=&quot;https://ipfs.io&quot;&gt;IPFS&lt;/a&gt; as it’s backend, making it fully decentralized. Reading through the setup docs, an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipfs init&lt;/code&gt; is required to build the initial &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ipfs&lt;/code&gt; filesystem. There is a &lt;a href=&quot;https://www.freshports.org/sysutils/ipfs-go/&quot;&gt;ipfs-go&lt;/a&gt; in FreeBSD ports, but it doesn’t seem to work, at least on arm64.&lt;/p&gt;

&lt;p&gt;To work around this, building &lt;a href=&quot;https://github.com/ipfs/go-ipfs&quot;&gt;ipfs-go&lt;/a&gt; from source is doable in a few steps,&lt;/p&gt;

&lt;p&gt;First, install a few required packages to compile the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go&lt;/code&gt; binaries&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas pkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;gcc gmake go openssl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, clone the source of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go-ipfs&lt;/code&gt; and checkout the latest stable branch, otherwise there might be a version mismatch error on startup,&lt;/p&gt;
&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone https://github.com/ipfs/go-ipfs.git
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;go-ipfs
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git checkout tags/v0.11.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Set a few environment vars to compile with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; and use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;:/usr/local/go/bin
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$GOPATH&lt;/span&gt;/bin
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CGO_ENABLED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GOTAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;openssl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Build from source using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gmake&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas gmake &lt;span class=&quot;nb&quot;&gt;install
&lt;/span&gt;go version go1.17.5 freebsd/arm64
bin/check_go_version 1.15.2
plugin/loader/preload.sh &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; plugin/loader/preload.go
go &lt;span class=&quot;nb&quot;&gt;fmt &lt;/span&gt;plugin/loader/preload.go &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null
go &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-asmflags=all=&apos;-trimpath=&apos;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-gcflags=all=&apos;-trimpath=&apos;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ldflags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-X &quot;&lt;/span&gt;github.com/ipfs/go-ipfs&lt;span class=&quot;s2&quot;&gt;&quot;.CurrentCommit=67220edaa&quot;&lt;/span&gt; ./cmd/ipfs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After the build is finished, copy the binary to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/bin&lt;/code&gt; and export it into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PATH&lt;/code&gt; ,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; ~/go/bin/ipfs ~/bin
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~/bin:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Initialize &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ipfs&lt;/code&gt; and set profile config to lowpower for running on a RaspberryPi&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ipfs init &lt;span class=&quot;nt&quot;&gt;--profile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;lowpower
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;building-superhighway84&quot;&gt;Building Superhighway84&lt;/h2&gt;

&lt;p&gt;With IPFS initialized, build Superhighway84 and copy the binary to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/bin&lt;/code&gt;. There are &lt;a href=&quot;https://github.com/mrusme/superhighway84/releases/tag/v0.0.11&quot;&gt;binary releases&lt;/a&gt; for FreeBSD arm64, but compiling it from source is relatively easy as well.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git clone https://github.com/mrusme/superhighway84.git
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;superhighway84
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go build &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;superhighway64 ~/bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Start up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;superhighway84&lt;/code&gt;, and wait a few minutes to fully sync. Using a “light” terminal theme is not recommened as it’s difficult to read, and I recommended switching to a darker terminal theme.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;superhighway84
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Mon, 17 Jan 2022 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2022/Superhighway84-on-FreeBSD/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2022/Superhighway84-on-FreeBSD/</guid>
        
        <category>freebsd</category>
        
        <category>smolweb</category>
        
        <category>ipfs</category>
        
        
        <category>bsd</category>
        
      </item>
    
      <item>
        <title>Bookmarking and Creating a Local Internet Archive</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;While I’m a heavy user of RSS with &lt;a href=&quot;https://www.newsblur.com&quot;&gt;Newsblur&lt;/a&gt;, I’ve never had a coherent bookmarking solution. Last week I finally setup a proper bookmark manager, and as a bonus, archived bookmarked pages locally in my own personal &lt;a href=&quot;https://archive.org&quot;&gt;Internet Archive&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;bookmarking-with-raindropio&quot;&gt;Bookmarking With Raindrop.io&lt;/h2&gt;

&lt;p&gt;A long time ago I was a user of &lt;a href=&quot;https://en.wikipedia.org/wiki/Delicious_(website)&quot;&gt;del.icio.us&lt;/a&gt;, and first looked into using &lt;a href=&quot;https://pinboard.in&quot;&gt;Pinboard&lt;/a&gt; for bookmarking. While Pinboard had most of the features I wanted - it lacked a native mobile app. I looked into other alternatives, and I ended up subscribing to &lt;a href=&quot;https://raindrop.io&quot;&gt;Raindrop.io&lt;/a&gt; after using it for a few days on a trial basis.&lt;/p&gt;

&lt;p&gt;Raindrop.io had all the features I was looking for,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Free and &lt;a href=&quot;https://help.raindrop.io/premium-features&quot;&gt;Paid Subscription&lt;/a&gt; models&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://help.raindrop.io/mobile-app&quot;&gt;Mobile App&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://help.raindrop.io/backups/#permanent-library&quot;&gt;Permanent Copies&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://help.raindrop.io/using-search/#full-text-search&quot;&gt;Full text search&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://help.raindrop.io/tags&quot;&gt;Tagging&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://help.raindrop.io/backups#backup-to-dropbox&quot;&gt;Dropbox sync&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using the apps or browser extensions is seamless, making it easy to save bookmarks no matter what device or browser I’m using. I also imported all of my Firefox bookmarks which required some cleaning up, but gave a good impression of how the tool looks with content. I’m still experimenting with categories and tagging, but overall there’s some order to the chaos, and with tags and full text search I can quickly find sites without having to resort to a search engine.&lt;/p&gt;

&lt;p&gt;I also setup an &lt;a href=&quot;https://ifttt.com&quot;&gt;IFTTT&lt;/a&gt; automation so whenever a page is bookmarked in Raindrop.io, it will add it to Saved Stories in Newsblur with the tags. While it’s not really that useful, it can act as a sort of backup if needed and maybe in the future Newsblur will add some feature that makes it more useful.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/bookmarking/raindropapp.png&quot; alt=&quot;Raindrop.io Mac App&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Raindrop.io Mac App&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;archiving-locally-with-archivebox&quot;&gt;Archiving Locally with ArchiveBox&lt;/h2&gt;

&lt;p&gt;While researching bookmarking services, I stumbled across &lt;a href=&quot;https://archivebox.io&quot;&gt;ArchiveBox&lt;/a&gt;, which can create a local &lt;a href=&quot;https://archive.org&quot;&gt;Internet Archive&lt;/a&gt; of webpages, media, and other thing from the web. It can also import bookmarks, archiving them locally and sending them to archive.org.&lt;/p&gt;

&lt;p&gt;This got me thinking, the &lt;a href=&quot;https://help.raindrop.io/backups&quot;&gt;Backup feature&lt;/a&gt; in Raindrop.io saves an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Export.html&lt;/code&gt; to &lt;a href=&quot;https://www.dropbox.com/home&quot;&gt;Dropbox&lt;/a&gt;. I could setup Dropboxy sync on my server and have a cronjob import every hour, syncing all new bookmarks from Raindrop.io into ArchiveBox automatically.&lt;/p&gt;

&lt;p&gt;My first attempt at this was successful, but the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Export.html&lt;/code&gt; backup is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;!DOCTYPE NETSCAPE-Bookmark-file-1&amp;gt;&lt;/code&gt; format, and while ArchiveBox can import it, it doesn’t do it all that well - creating archives of parts of pages, not applying tags, and just overall wasn’t very consistent.&lt;/p&gt;

&lt;p&gt;I found that ArchiveBox can also import a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;json&lt;/code&gt; formatted file with a simple array schema with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url:&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tags:&lt;/code&gt; fields, so I wrote a quick script to convert this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Backup.html&lt;/code&gt; into an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import.json&lt;/code&gt; and then import it into ArchiveBox using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose&lt;/code&gt;. Putting this into an hourly cronjob then automatically imports any new bookmarks and archives them.&lt;/p&gt;

&lt;p&gt;This script gets all bookmarked URLs and tags from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Export.html&lt;/code&gt; and creates a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import.json&lt;/code&gt; with a structure of,&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://www.friendlyskies.net/notebook/giving-haiku-os-beta-3-a-try&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;haiku,os&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://github.com/dwmkerr/hacker-laws&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;patterns&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://www.benoakley.co.uk/tartan-asia-extreme&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;korean,japanese,film,movies&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://drodio.com/creating-your-own-remote-workspace-for-under-5k/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;wfh,shed,backyard&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;raindrop-import.sh&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#Imports bookmarks from Raindrop.io&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Backup file from Raindrop sync on Dropbox&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;exportfile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~/Dropbox/Apps/Raindrop.io/Export.html&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;importfile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~/Dropbox/Apps/Raindrop.io/import.json&quot;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;span class=&quot;nv&quot;&gt;delimiter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;,&apos;&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;[&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;importfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Cleanup import to only get raw links&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;url &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-io&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&amp;lt;a href=[&apos;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;&quot;][^&quot;&apos;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;]*[&apos;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;&quot;]&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;exportfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s/^&amp;lt;a href=[&quot;&apos;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;]//i&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s/[&quot;&apos;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;]$//i&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
  &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;A HREF=&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;exportfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-io&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;tags=[&apos;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;&quot;][^&quot;&apos;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;]*[&apos;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;&quot;]&apos;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s/^tags=[&quot;&apos;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;]//i&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s/[&quot;&apos;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;]$//i&apos;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;\n&apos;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;,&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;munged_tags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%?&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;{ &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;munged_tags&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; }&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;delimiter&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;importfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Trim last , in file before finishing array to make it valid JSON&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;$ s/.$//&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;importfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;]&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;importfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Check that JSON is valid before importing&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;jq &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;lt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;importfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Successfully Parsed JSON from &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;importfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Unsuccessfully Parsed JSON from &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;importfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Import exportfile into archivebox using docker-compose&lt;/span&gt;
docker-compose &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; ~/archivebox/docker-compose.yml run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; archivebox add &lt;span class=&quot;nt&quot;&gt;--parser&lt;/span&gt; json &amp;lt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;importfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When imported, only these URLs are archived and the tags are applied properly, creating an complete archived copy of bookmarks saved in Raindrop.io.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/bookmarking/archivebox.png&quot; alt=&quot;ArchiveBox&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;ArchiveBox&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;Since Raindrop.io has preview/live/archive views as well as fulltext search, I probably won’t use ArchiveBox frequently, but it’s good to have a local backup in multiple formats just-in-case. It also automatically sends the page to archive.org, so it’s another guarentee that it is archived somewhere in case the page disappears 10 years from now. By default it will also save a PDF file and text using &lt;a href=&quot;https://github.com/postlight/mercury-parser&quot;&gt;Mercury&lt;/a&gt; and &lt;a href=&quot;https://github.com/mozilla/readability&quot;&gt;Readability&lt;/a&gt; which I may work on setting up to send to my Kindle for offline reading.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I now have a featureful bookmarking service that I can use almost anywhere, and have started making extensive use of it already. I wish I had setup something like this years ago, as there are many sites I’ve come across that I wish I could reference but completely forget how to find them using a search engine. Now can I not only quickly find them in my bookmark manager, but I also have my own local archive I can rely on in the future as well.&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://raindrop.io&quot;&gt;Raindrop.io&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://archivebox.io&quot;&gt;ArchiveBox&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/ArchiveBox/ArchiveBox/wiki/Web-Archiving-Community&quot;&gt;Web Archiving Community&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://parameters.ssrc.org/2018/09/on-the-importance-of-web-archiving/&quot;&gt;On the Importance of Web Archiving&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 04 Jan 2022 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/bookmarking-with-raindrop/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/bookmarking-with-raindrop/</guid>
        
        <category>hack</category>
        
        <category>bookmarks</category>
        
        <category>archiving</category>
        
        
        <category>technology</category>
        
      </item>
    
      <item>
        <title>This Website Is Now Available on IPFS, ENS, and Handshake</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;In the past few months there has been a lot of chatter about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;web3&lt;/code&gt; and what it means and doesn’t mean for the future of the web. There’s a lot of hype around NFTs, mostly because of the money that is exchanging hands, and instead of outright dismissing it I wanted to dive deeper to understand it better.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-an-ens-domain&quot;&gt;Setting up an ENS Domain&lt;/h2&gt;

&lt;p&gt;I first thought about NFTs when I discovered you can buy &lt;a href=&quot;https://ens.domains&quot;&gt;ENS Domains&lt;/a&gt; and then set them up like a standard DNS name with the additional benefit of using them as an identity. I went through the ENS purchase - setting up &lt;a href=&quot;https://www.coinbase.com/wallet&quot;&gt;Coinbase Wallet&lt;/a&gt; - and buying the domain with some ETH. My overall impression was is there’s a lot of fees. Registering the domain and other actions are relatively inexpensive, but the &lt;a href=&quot;https://cryptocurrencysimple.com/all-you-must-know-about-what-are-eth-gas-fees/&quot;&gt;gas fees&lt;/a&gt; are much higher and take up the bulk of the transaction cost. Skipping over all the details, it cost about 400$ to fully setup &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecliptik.eth&lt;/code&gt; - registering, reverse lookup to my wallet address, and setting the metadata.&lt;/p&gt;

&lt;p&gt;The results of setting up the ENS domain are here, &lt;a href=&quot;https://app.ens.domains/name/ecliptik.eth/details&quot;&gt;ecliptik.eth&lt;/a&gt; and it resolves to &lt;a href=&quot;https://ecliptik.eth.limo&quot;&gt;https://ecliptik.eth&lt;/a&gt; on IPFS. This name also includes additional features like setting my &lt;a href=&quot;https://medium.com/the-ethereum-name-service/nft-avatar-support-for-ens-profiles-bd4a5553f089&quot;&gt;Avatar image to an NFT I own&lt;/a&gt; (which is one I created myself and put on &lt;a href=&quot;https://opensea.io&quot;&gt;opensea.io&lt;/a&gt; for free).&lt;/p&gt;

&lt;h2 id=&quot;setting-up-a-handshake-domain&quot;&gt;Setting up a Handshake Domain&lt;/h2&gt;

&lt;p&gt;The next domain setup was &lt;a href=&quot;https://handshake.org&quot;&gt;Handshake&lt;/a&gt; which is a “Decentralized naming and certificate authority” and has an auction process to acquire a Handshake domain. I setup &lt;a href=&quot;https://bobwallet.io&quot;&gt;Bob Wallet&lt;/a&gt; and went through the &lt;a href=&quot;https://github.com/handshake-org/hs-airdrop&quot;&gt;airdrop claim&lt;/a&gt; to get some HNS. Eventually I ended up using &lt;a href=&quot;https://www.namebase.io&quot;&gt;Namebase&lt;/a&gt; to handle the auction and management details and after about 14 days (due to the auction process) I was the new owner of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecliptik&lt;/code&gt; Handshake domain.&lt;/p&gt;

&lt;p&gt;The one interesting thing I noticed is that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecliptik&lt;/code&gt; domain was already up for auction when I checked. After some research I found that if you register an ENS domain name and it’s not claimed on Handshake, there are bots that will automatically start and auction for it.  Because it was a bot and not someone else trying to buy it, I easily outbid and acquired the name with no counter bids. I also acquired a few other names like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amfora&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rawtext&lt;/code&gt; since I had some more HNS.&lt;/p&gt;

&lt;p&gt;Accessing the HNS domain requires some additional software or using DNS servers that support it, the Namebase article &lt;a href=&quot;https://learn.namebase.io/starting-from-zero/how-to-access-handshake-sites&quot;&gt;How to Access Handshake Sites&lt;/a&gt; has how to set this all up.&lt;/p&gt;

&lt;p&gt;Handshake names are also available using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hns.to&lt;/code&gt; domain, and mine is accessible at &lt;a href=&quot;https://ecliptik.hns.to&quot;&gt;https://ecliptik.hns.to&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;mirroring-to-ipfs&quot;&gt;Mirroring To IPFS&lt;/h2&gt;

&lt;p&gt;Now that I had the DNS and Handshake domains I had to figure out how to use them. ENS has a lot of documentation on using &lt;a href=&quot;https://ipfs.io&quot;&gt;IPFS&lt;/a&gt; to point an ENS domain to, and then it’s fully part of the “Distributed Web”. After doing some research I found that &lt;a href=&quot;https://fleek.co&quot;&gt;Fleek.co&lt;/a&gt; provides free Web, IPFS, ENS, and Handshake features. I followed their setup guide and now whenever I push to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; on my &lt;a href=&quot;https://github.com/ecliptik/ecliptik.github.io&quot;&gt;Github Pages repo&lt;/a&gt;, it automatically publishes it to IPFS using InterPlanetary Name System (&lt;a href=&quot;https://docs.ipfs.io/concepts/ipns/&quot;&gt;IPNS&lt;/a&gt;) which resolves the name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecliptik.ens&lt;/code&gt; to the current version of this blog.&lt;/p&gt;

&lt;p&gt;Now whenever I publish to this blog, it’s automatically updated on IPFS and available at &lt;a href=&quot;ipns://ecliptik.eth&quot;&gt;ipns://ecliptik.eth&lt;/a&gt;, and via http at &lt;a href=&quot;https://ecliptik.eth.limo&quot;&gt;https://ecliptik.eth.limo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Accessing ENS and IPFS directly  requires some additional software outside of traditional browsers, but &lt;a href=&quot;https://brave.com&quot;&gt;Brave&lt;/a&gt; has support both for ENS and IPFS.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;Learning about ENS, Handshake, and IPFS was a lot of fun, and while I highly doubt that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;web3&lt;/code&gt; is “the future”, these technologies have a lot of offer for the future of the Internet. I am particularly fond of IPFS as it reminds me of &lt;a href=&quot;https://www.bittorrent.org&quot;&gt;Bittorrent&lt;/a&gt; but without having to setup a torrent/magnet link and seed. Getting started with IPFS is easy, and hosting your own IPFS node locally is a quick and  free way to participate in the distributed web.&lt;/p&gt;

&lt;p&gt;I really understood the power of IPFS when I saw the different ways you could use it as a &lt;a href=&quot;https://docs.ipfs.io/concepts/ipfs-gateway/&quot;&gt;Gateway&lt;/a&gt;, enabling any application that uses http to access content on IPFS. This really shines with git and package repositories, see &lt;a href=&quot;https://dataswamp.org/~solene/2021-05-01-ipfs-openbsd-69.html&quot;&gt;OpenBSD 6.9 packages using IPFS&lt;/a&gt; for a real-world application.&lt;/p&gt;
</description>
        <pubDate>Thu, 30 Dec 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/setting-up-ipfs-ens-and-handshake/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/setting-up-ipfs-ens-and-handshake/</guid>
        
        <category>ipfs</category>
        
        <category>distributed</category>
        
        
        <category>technology</category>
        
      </item>
    
      <item>
        <title>Forwarding gpg-agent Over SSH</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;Basic notes from setting up &lt;a href=&quot;https://wiki.gnupg.org/AgentForwarding&quot;&gt;gpg-agent forwarding&lt;/a&gt; between a MacOS and Debian Linux system.&lt;/p&gt;

&lt;h2 id=&quot;client-system&quot;&gt;Client System&lt;/h2&gt;

&lt;p&gt;Assuming system is running MacOS install &lt;a href=&quot;https://gnupg.org/&quot;&gt;gpg&lt;/a&gt; and pinentry (GPG password prompt tool) using &lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt;,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;gnupg pinentry-mac
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Edit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.gnupg/gpg-agent.conf&lt;/code&gt; and make sure that ${HOME} is the full path to your users home dir, eg &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Users/$USER&lt;/code&gt;, this must match what’s setup in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RemoteForward&lt;/code&gt; later,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;default-cache-ttl 600
max-cache-ttl 7200
enable-ssh-support
pinentry-program /usr/local/bin/pinentry-mac
extra-socket $HOME/.gnupg/S.gpg-agent.extra
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.gnupg/gpg.conf&lt;/code&gt; (where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$GPG_KEY&lt;/code&gt; is the fingerprint of the GPG key to use)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;default-key $GPG_KEY
personal-digest-preferences SHA512
cert-digest-algo SHA512
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
no-emit-version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Edit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/config&lt;/code&gt; and setup a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RemoteForward&lt;/code&gt;, this is important since the forward is required in order to communicate over a socket. Make sure the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$UID&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$USER&lt;/code&gt; on the remote and local system are set accordingly, as these will differ depending on the OS and login.&lt;/p&gt;

&lt;p&gt;Also double check the socket names that they match up from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.gnupg/gpg-agent.conf&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/config&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Host $REMOTE_IP
   ForwardAgent yes
   Compression yes
   ForwardX11 yes
   RemoteForward /run/user/$UID/gnupg/S.gpg-agent /Users/${USER}/.gnupg/S.gpg-agent.extra
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;remote-system&quot;&gt;Remote System&lt;/h2&gt;

&lt;p&gt;Update &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ssh/sshd_config&lt;/code&gt; (or wherever it is depending on your OS) configuration to include &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StreamLocalBindUnlink yes&lt;/code&gt; and restart &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshd&lt;/code&gt; This option will,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Specifies whether to remove an existing Unix-domain socket file for local or remote port forwarding before creating a new one.  If the socket file already exists and StreamLocalBindUnlink is not enabled, ssh will be unable to forward the port to the Unix-domain socket file. This option is only used for port forwarding to a Unix-domain socket file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;troubleshooting-gpg-agent&quot;&gt;Troubleshooting gpg-agent&lt;/h2&gt;

&lt;p&gt;Sometimes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StreamLocalBindUnlink yes&lt;/code&gt; doesn’t work and the client agent needs restarted and sockets removed from the remote system,&lt;/p&gt;

&lt;p&gt;Restart the agent on the client system,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gpg-connect-agent reloadagent /bye
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Remove the socket on the remote system,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rm /run/user/1000/gnupg/S.gpg-agent
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ssh back into the remote system and gpg-agent forwarding should work again.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20190423113837/https://www.isi.edu/~calvin/gpgagent.htm&quot;&gt;Remote gpg-agent Via ssh Forwarding&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 27 Dec 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/Forwarding-gpg-agent-over-SSH/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/Forwarding-gpg-agent-over-SSH/</guid>
        
        <category>ssh</category>
        
        <category>linux</category>
        
        <category>unix</category>
        
        <category>gpg</category>
        
        <category>git</category>
        
        
        <category>unix</category>
        
      </item>
    
      <item>
        <title>Gemini Capsule in a FreeBSD Jail running on a RaspberryPi</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;With the &lt;a href=&quot;https://www.freebsd.org/releases/13.0R/announce/&quot;&gt;recent release of FreeBSD 13&lt;/a&gt;, I wanted to test it out on a spare RaspberryPi 3 that was part of my &lt;a href=&quot;/blog/2017/Raspberry-Pi-Kubernetes-Cluster/&quot;&gt;old Kubernetes cluster&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In particular, &lt;a href=&quot;https://docs.freebsd.org/en/books/handbook/jails/&quot;&gt;FreeBSD Jails&lt;/a&gt; have always interested me, although I’ve never used them in practice. Over the years I’ve managed &lt;a href=&quot;https://en.wikipedia.org/wiki/OS-level_virtualization&quot;&gt;operating system virtualization&lt;/a&gt; through Solaris Zones and Docker containers, and Jails seem like and good middle ground between the two - easier to manage than zones and closer to the OS than Docker.&lt;/p&gt;

&lt;p&gt;I also want to run my own &lt;a href=&quot;https://gemini.circumlunar.space&quot;&gt;Gemini&lt;/a&gt; capsule locally to use some of the features that my other hosted capsules don’t have (like SCGI/CGI) and setting up a capsule in a Jail is a good way to learn both at the same time.&lt;/p&gt;

&lt;h2 id=&quot;installing-freebsd-on-a-raspberrypi&quot;&gt;Installing FreeBSD on a RaspberryPi&lt;/h2&gt;

&lt;p&gt;Installing FreeBSD on a RaspberryPi is relatively easy, &lt;a href=&quot;https://download.freebsd.org/ftp/releases/arm64/aarch64/ISO-IMAGES/13.0/&quot;&gt;downloading the FreeBSD 13 RPI image&lt;/a&gt; and booting from the SD card to get started. Everything will come up automatically, and you can ssh in with the default user:pass of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;freebsd:freebsd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A few post-install things I did to secure the host more,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Add another non-root user other than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;freebsd&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Disable password logins and require ssh-keys&lt;/li&gt;
  &lt;li&gt;Setup &lt;a href=&quot;https://man.openbsd.org/doas&quot;&gt;doas&lt;/a&gt; for new user&lt;/li&gt;
  &lt;li&gt;Remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;freebsd&lt;/code&gt; user with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doas rmuser freebsd&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Set strong root password&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;setting-up-ntp&quot;&gt;Setting up NTP&lt;/h2&gt;

&lt;p&gt;Since the RPI doesn’t have a real-time clock, setting up NTP is crucial for accurate time, which if not set can cause all sorts of issues with TLS and other commands.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Enabe ntpd&lt;/span&gt;
host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;ntpd_enable=&quot;YES&quot;&apos;&lt;/span&gt; | doas &lt;span class=&quot;nb&quot;&gt;tee&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /etc/rc.conf

&lt;span class=&quot;c&quot;&gt;# Force sync time&lt;/span&gt;
host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas ntpdate pool.ntp.org

&lt;span class=&quot;c&quot;&gt;# Start ntpd&lt;/span&gt;
host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas service ntpd onestart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;setting-up-the-jail&quot;&gt;Setting up the Jail&lt;/h2&gt;

&lt;h3 id=&quot;creating-the-jail&quot;&gt;Creating the Jail&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;https://docs.freebsd.org/en/books/handbook/jails/&quot;&gt;Jails guide&lt;/a&gt; is straightforward, but contains two different methods of configuring jails. The built-in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jail&lt;/code&gt; commands or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ezjail&lt;/code&gt;. I ended up &lt;a href=&quot;https://docs.freebsd.org/en/books/handbook/jails/#jails-ezjail&quot;&gt;using ezjail&lt;/a&gt; which seems more robust and featureful.&lt;/p&gt;

&lt;p&gt;Following the instructions first add the second loopback interface,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;cloned_interfaces=&quot;lo1&quot;&apos;&lt;/span&gt; | doas &lt;span class=&quot;nb&quot;&gt;tee&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /etc/rc.conf
host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas service netif cloneup
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then install ezjail and a few other packages we’ll need later on,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas pkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;ezjail ca_root_nss openssl
host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;ezjail_enable=&quot;YES&quot;&apos;&lt;/span&gt; | doas &lt;span class=&quot;nb&quot;&gt;tee&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /etc/rc.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a new jail named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thesours&lt;/code&gt;, using the new second loopback and a new LAN IP on the interface &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;em0&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas ezjail-admin create thesours &lt;span class=&quot;s1&quot;&gt;&apos;lo1|127.0.1.1,em0|192.168.7.223&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This installs a FreeBSD 13 (default version is the host version) jail filesystem in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/jails/thesours/&lt;/code&gt; and will take a while to download and extract.&lt;/p&gt;

&lt;p&gt;Once complete, list the new jail,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas ezjail-admin list
STA JID  IP              Hostname                       Root Directory
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;----&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;---------------&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;------------------------------&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;------------------------&lt;/span&gt;
DR  1    127.0.1.1       thesours                       /usr/jails/thesours
    1    ue0|192.168.7.223
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setting-up-the-jail-1&quot;&gt;Setting up the Jail&lt;/h3&gt;

&lt;p&gt;Now that there’s a running jail, connect to it’s console to start setting it up.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;doas ezjail-admin console thesours
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Many of the directories are shared with the basejail and are immutable, but adding users and packages, configuring services, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc&lt;/code&gt; are all independent of the host OS.&lt;/p&gt;

&lt;p&gt;Add a new non-root user using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;adduser&lt;/code&gt;, install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doas&lt;/code&gt; and set up this user for root privileges. Enabling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshd&lt;/code&gt; also allows ssh sessions into the jail,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;jail&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;sshd_enable=&quot;YES&quot;&apos;&lt;/span&gt; | doas &lt;span class=&quot;nb&quot;&gt;tee&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /etc/rc.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setting-up-a-gemini-capsule&quot;&gt;Setting up a Gemini Capsule&lt;/h3&gt;

&lt;p&gt;Now that the jail is setup, the next step is installing and configuring the Gemini server &lt;a href=&quot;https://tildegit.org/solderpunk/molly-brown&quot;&gt;Molly Brown&lt;/a&gt;, which has a lot of features such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~&lt;/code&gt; support for user gemini folders and SCGI/CGI scripting.&lt;/p&gt;

&lt;h4 id=&quot;building-molly-brown&quot;&gt;Building Molly Brown&lt;/h4&gt;

&lt;p&gt;Molly Brown requires &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go&lt;/code&gt;, which was built in the host and not the jail in order to keep jail packages to a minimum.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas pkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Build Molly Brown,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; ~/go
host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GOPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~/go
host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go get tildegit.org/solderpunk/molly-brown
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Copy the resulting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/go/bin/molly-brown&lt;/code&gt; binary to the jail,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas &lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;molly-brown /usr/jails/thesours/usr/local/sbin/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Also create the TLS certs that molly brown will require later, and copy them to the jail,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /usr/jails/thesours/etc/ssl/gemini/
host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /usr/jails/thesours/etc/ssl/gemini/
host&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;openssl req &lt;span class=&quot;nt&quot;&gt;-x509&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-newkey&lt;/span&gt; rsa:4096 &lt;span class=&quot;nt&quot;&gt;-keyout&lt;/span&gt; key.pem &lt;span class=&quot;nt&quot;&gt;-out&lt;/span&gt; cert.pem &lt;span class=&quot;nt&quot;&gt;-days&lt;/span&gt; 1826 &lt;span class=&quot;nt&quot;&gt;-nodes&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-subj&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/CN=thesours.ecliptik.com&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Go back into the jail and setup a few configurations for Molly Brown with the following assumptions,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Config in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/molly.conf&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Logs in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/log/molly&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;TLS certs in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/jails/thesours/etc/ssl/gemini&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Document root in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/gemini/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Run as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;daemon&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create the required paths, create/copy files and set the proper permissions for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;daemon&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;jail&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /var/log/molly /var/gemini/
jail&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas &lt;span class=&quot;nb&quot;&gt;chown&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; daemon:daemon /var/log/molly /usr/jails/thesours/etc/ssl/gemini /var/gemini/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;molly-brown-configuration&quot;&gt;Molly Brown Configuration&lt;/h4&gt;

&lt;p&gt;Create  configuration in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/molly.conf&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;## Molly basic settings&lt;/span&gt;
Port &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 1965
Hostname &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;thesours.ecliptik.com&quot;&lt;/span&gt;
CertPath &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/etc/ssl/gemini/cert.pem&quot;&lt;/span&gt;
KeyPath &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/etc/ssl/gemini/key.pem&quot;&lt;/span&gt;
DocBase &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/var/gemini/&quot;&lt;/span&gt;
HomeDocBase &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;users&quot;&lt;/span&gt;
GeminiExt &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;gmi&quot;&lt;/span&gt;
DefaultLang &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;en&quot;&lt;/span&gt;
AccessLog &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/var/log/molly/access.log&quot;&lt;/span&gt;
ErrorLog &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/var/log/molly/error.log&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;creating-a-molly-brown-service&quot;&gt;Creating a Molly Brown Service&lt;/h4&gt;

&lt;p&gt;Create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;etc/rc.d/molly&lt;/code&gt; to manage the service and have it start when the jail does. It will run as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;daemon&lt;/code&gt; user to improve security.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# $FreeBSD$&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# PROVIDE: molly&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# REQUIRE: networking&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# KEYWORD: shutdown&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; /etc/rc.subr

&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;molly&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Gemini Protocol daemon&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;rcvar&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;molly_enable&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/sbin/molly-brown&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;command_args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-c /etc/molly.conf&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;molly_brown_user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;daemon&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;pidfile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/var/run/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.pid&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;required_files&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/etc/molly.conf&quot;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;start_cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;molly_start&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;stop_cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;molly_stop&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;status_cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;molly_status&quot;&lt;/span&gt;

molly_start&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        /usr/sbin/daemon &lt;span class=&quot;nt&quot;&gt;-P&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pidfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$molly_brown_user&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$command&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

molly_stop&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pidfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
                &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;kill&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; TERM &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pidfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else
                &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is not running&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

molly_status&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pidfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
                &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is running as pid &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pidfile&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else
                &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; is not running&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

load_rc_config &lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;
run_rc_command &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Enable the service,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;jail&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;molly_enable=&quot;YES&quot;&apos;&lt;/span&gt; | doas &lt;span class=&quot;nb&quot;&gt;tee&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /etc/rc.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add a default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/gemini/index.gmi&lt;/code&gt; file with some basic gemtext and start the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;molly&lt;/code&gt; service,&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;jail&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas service molly start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;running-example&quot;&gt;Running Example&lt;/h3&gt;

&lt;p&gt;The gemini capsule &lt;a href=&quot;gemini://thesours.ecliptik.com&quot;&gt;gemini://thesours.ecliptik.com&lt;/a&gt; is running Molly Brown in a FreeBSD jail.&lt;/p&gt;
</description>
        <pubDate>Sun, 25 Apr 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/Gemini-Capsule-in-a-FreeBSD-Jail/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/Gemini-Capsule-in-a-FreeBSD-Jail/</guid>
        
        <category>freebsd</category>
        
        <category>hack</category>
        
        <category>gemini</category>
        
        <category>100daystooffload</category>
        
        
        <category>hack</category>
        
      </item>
    
      <item>
        <title>Pocket CHIP Terminal Dashboard</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;When I first got my &lt;a href=&quot;/blog/2021/Pocket-CHIP/&quot;&gt;Pocket C.H.I.P.&lt;/a&gt; one of the first thoughts I had was to use it as sort of a mini-desktop terminal to display things like weather, new mail, etc. After doing some &lt;a href=&quot;/blog/2021/CHIP-Serial-Console/&quot;&gt;other tinkering&lt;/a&gt; with it first, it has been on my desk the last couple of weeks displaying the following information,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Latest local toot in &lt;a href=&quot;https://fosstodon.org/web/timelines/public/local&quot;&gt;Fosstodon&lt;/a&gt; using &lt;a href=&quot;https://github.com/ihabunek/toot&quot;&gt;Toot&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Top 10 &lt;a href=&quot;https://news.ycombinator.com&quot;&gt;Hacker News&lt;/a&gt; posts using &lt;a href=&quot;https://github.com/donnemartin/haxor-news&quot;&gt;haxor-news&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Current weather from &lt;a href=&quot;https://wttr.in&quot;&gt;wttr.in&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Current time with &lt;a href=&quot;https://github.com/xorg62/tty-clock&quot;&gt;tty-clock&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Currenly playing track on Spotify using &lt;a href=&quot;https://github.com/ecliptik/walt-grover&quot;&gt;walt-grover&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/chip_terminal/IMG_6909.png&quot; alt=&quot;Pocket C.H.I.P Terminal Dashboard&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Pocket C.H.I.P. Terminal Dashboard&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/tmux/tmux&quot;&gt;Tmux&lt;/a&gt; is the heart of the setup, with each applet in it’s own terminal pane and then borders turned off so it looks like a single seamless screen. Running in tmux has the added benefit of detaching the dashboard, like when you want to watch some &lt;a href=&quot;/blog/2021/CHIP-Vaporwave/&quot;&gt;vaporwave on the framebuffer&lt;/a&gt; or sharing the screen from ssh for remote control.&lt;/p&gt;

&lt;p&gt;The tools used in these panes are a combination of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;watch&lt;/code&gt; to refresh every 60 seconds or a small shell script. I attempted to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;watch&lt;/code&gt; for everything, but some commands didn’t work well with the ASCII escape codes even with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--color&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;It’s using &lt;a href=&quot;https://github.com/tmuxinator/tmuxinator&quot;&gt;tmuxinator&lt;/a&gt; to save the layout and restore the dashboard after a reboot.&lt;/p&gt;

&lt;p&gt;Tmuxinator config in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/tmuxinator/chip.yaml&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;name: chip
root: ~/

windows:
  - CHIP:
      layout: 7bd9,60x33,0,0[60x7,0,0,0,60x13,0,8,3,60x7,0,22{27x7,0,22,4,32x7,28,22,9},60x3,0,30,6]
      panes:
        - watch -n60 -t --color &quot;toot timeline --local --public --count 1 --once | sed &apos;/^$/d&apos; | grep -v &apos;─────────────────&apos; | grep -v &apos;ID &apos; | sed &apos;s/\s\{2,\}/_TOKEN_/&apos; | awk -F_TOKEN_ {&apos;print \$1&apos;}&quot;
        - watch -n60 -t --color &quot;hn top 10 | head -n -3 | sed &apos;s/^[ \t]*//&apos; | grep -v &apos;points by&apos; | awk -F\( {&apos;print \$1&apos;} | sed -e &apos;s/\.\s\s\s/. /g&apos;&quot;
        - /home/chip/bin/weather.sh
        - bin/tty-clock -m -B -D -C 5
        - watch -n120 -t --color &quot;/home/chip/bin/spotify/spotify.rb&quot;
  - amfora:
      - amfora
  - serial:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Additional configuration includes updating the &lt;a href=&quot;https://github.com/aleh/pocketchip-batt&quot;&gt;pocketchip-batt&lt;/a&gt; utility to better display charging and how much battery is remaining and putting it and the CHIPs IP address into the right status of the tmux toolbar.&lt;/p&gt;

&lt;p&gt;Terminal blanking is turned off so the display is always on.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;setterm -blank 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Wifi powersave feature is turned off since there were issues with it losing DNS and occasional loss of network connectivity&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo /sbin/iw dev wlan0 set power_save off
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Tmux config in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.tmux.conf&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#Switch Windows
bind-key n next-window
bind-key m previous-window

#Set 256 colors
set -g default-terminal &quot;screen-256color&quot;

# start window numbering at 1
set -g base-index 1

# start pane numbering at 1
set -g pane-base-index 1

#Update default binding of `Enter` to also use copy-pipe
unbind -T copy-mode-vi Enter

#Clock
set-option -g clock-mode-colour yellow

#Switch panels with vi keybindings
bind k selectp -U # switch to panel Up
bind j selectp -D # switch to panel Down
bind h selectp -L # switch to panel Left
bind l selectp -R # switch to panel Right

set-option -g status on
set-option -g status-interval 1
set-option -g status-keys vi
set-option -g status-position bottom

set-option -g visual-activity on
set-window-option -g status-left &quot;&quot;
set-window-option -g monitor-activity on
set-window-option -g window-status-activity-style &quot;none&quot;
set-option -g status-right &quot;#( ~/bin/right-status.sh )&quot;

#### COLOUR (Solarized light)

# default statusbar colors
set-option -g status-style fg=yellow,bg=black #yellow and base02

# default window title colors
set-window-option -g window-status-style fg=brightblue,bg=default #base0 and default
#set-window-option -g window-status-style dim

# active window title colors
set-window-option -g window-status-current-style fg=brightred,bg=default #orange and default
#set-window-option -g window-status-current-style bright

# pane border
set-option -g pane-border-style fg=black #base02
set-option -g pane-active-border-style fg=black #base01

# message text
set-option -g message-style fg=brightred,bg=black #orange and base01

# pane number display
set-option -g display-panes-active-colour blue #blue
set-option -g display-panes-colour brightred #orange

# clock
set-window-option -g clock-mode-colour green #green

# bell
set-window-option -g window-status-bell-style fg=black,bg=red #base02, red
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Sun, 04 Apr 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/Pocket-CHIP-Terminal-Dashboard/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/Pocket-CHIP-Terminal-Dashboard/</guid>
        
        <category>chip</category>
        
        <category>hack</category>
        
        <category>100daystooffload</category>
        
        
        <category>chip</category>
        
      </item>
    
      <item>
        <title>Vaporwave in Pocket C.H.I.P. Framebuffer</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;In the ever expanding ways to hack &lt;a href=&quot;/blog/2021/Pocket-CHIP/&quot;&gt;my Pocket C.H.I.P.&lt;/a&gt;, and my recent discovery of &lt;a href=&quot;https://en.wikipedia.org/wiki/Vaporwave&quot;&gt;Vaporwave&lt;/a&gt;, I couldn’t help but combine the two and have a looping music video device on my desktop. Note this is not running in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt;, but in the console framebuffer, which gives it more ＡＥＳＴＨＥＴＩＣＳ.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/chip_vaporwave/chip-vaporwave.png&quot; alt=&quot;Vaporwave in Pocket C.H.I.P&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;NEON PALM MALL in C.H.I.P. Framebuffer&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;required-software&quot;&gt;Required Software&lt;/h2&gt;

&lt;p&gt;The C.H.I.P. is fully upgraded to Debian Buster, and there were some oddities with getting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dpkg&lt;/code&gt; sorted out, so the package installs may not work exactly as defined here but are a general guide. It’s also &lt;a href=&quot;http://www.chip-community.org/index.php/Setting_up_text_mode_on_PocketCHIP_4.3&quot;&gt;booting into the console framebuffer&lt;/a&gt; and not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt;, so there’s no desktop environment or window manager running.&lt;/p&gt;

&lt;p&gt;The following tools are used,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://mplayerhq.hu/design7/news.html&quot;&gt;mplayer&lt;/a&gt;, for playback with framebuffer and armhf support&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/alsa-project/alsa-utils&quot;&gt;alsa-utils&lt;/a&gt;, specifically &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alsamixer&lt;/code&gt; to control volume from console&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtube-dl.org/&quot;&gt;youtube-dl&lt;/a&gt;, download video+audio from youtube&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ffmpeg.org/&quot;&gt;ffmpeg&lt;/a&gt;, combine video+audio from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;youtube-dl&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install packages,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; ffmpeg mplayer alsa-utils
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;youtube-dl&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; https://yt-dl.org/downloads/latest/youtube-dl &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; /usr/local/bin/youtube-dl
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo chmod &lt;/span&gt;a+rx /usr/local/bin/youtube-dl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;downloading-videos&quot;&gt;Downloading Videos&lt;/h2&gt;

&lt;p&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;youtube-dl&lt;/code&gt;, download a Vaporwave video. The Pocket C.H.I.P. is very particular about the screen resolution and codec of the video. Anything larger than the C.H.I.P. screen (480×272) will give an error, and some codecs won’t play. I found the following format combination works best for video playback.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;resolution: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;320x240@240p&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;container: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mp4&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;codec: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;avc1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this example we’ll save &lt;a href=&quot;https://www.youtube.com/watch?v=FZUfiW3W1KY&quot;&gt;NEON PALM MALL (Vaporwave Mix + Video)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-F&lt;/code&gt; argument to display the list of available formats and choose the one that best matches,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;youtube-dl &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt; https://www.youtube.com/watch?v&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;FZUfiW3W1KY
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;youtube] FZUfiW3W1KY: Downloading webpage
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;info] Available formats &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;FZUfiW3W1KY:
format code  extension  resolution note
249          webm       audio only tiny   48k , webm_dash container, opus @ 48k &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;48000Hz&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, 18.74MiB
250          webm       audio only tiny   64k , webm_dash container, opus @ 64k &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;48000Hz&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, 24.76MiB
251          webm       audio only tiny  127k , webm_dash container, opus @127k &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;48000Hz&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, 48.90MiB
140          m4a        audio only tiny  129k , m4a_dash container, mp4a.40.2@129k &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;44100Hz&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, 49.55MiB
394          mp4        192x144    144p   51k , mp4_dash container, av01.0.00M.08@  51k, 25fps, video only, 19.82MiB
160          mp4        192x144    144p   53k , mp4_dash container, avc1.4d400b@  53k, 25fps, video only, 20.33MiB
278          webm       192x144    144p   67k , webm_dash container, vp9@  67k, 25fps, video only, 25.81MiB
133          mp4        320x240    240p   93k , mp4_dash container, avc1.4d400d@  93k, 25fps, video only, 35.73MiB
395          mp4        320x240    240p  106k , mp4_dash container, av01.0.00M.08@ 106k, 25fps, video only, 40.57MiB
242          webm       320x240    240p  126k , webm_dash container, vp9@ 126k, 25fps, video only, 48.47MiB
396          mp4        480x360    360p  188k , mp4_dash container, av01.0.01M.08@ 188k, 25fps, video only, 72.01MiB
134          mp4        480x360    360p  221k , mp4_dash container, avc1.4d4015@ 221k, 25fps, video only, 84.73MiB
243          webm       480x360    360p  229k , webm_dash container, vp9@ 229k, 25fps, video only, 87.72MiB
397          mp4        640x480    480p  334k , mp4_dash container, av01.0.04M.08@ 334k, 25fps, video only, 127.98MiB
244          webm       640x480    480p  396k , webm_dash container, vp9@ 396k, 25fps, video only, 151.83MiB
135          mp4        640x480    480p  430k , mp4_dash container, avc1.4d401e@ 430k, 25fps, video only, 164.88MiB
18           mp4        480x360    360p  435k , avc1.42001E, 25fps, mp4a.40.2 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;44100Hz&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, 166.58MiB &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;best&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Find the best format to fit the requirements above, in this example format code &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;133&lt;/code&gt; will work best for video.&lt;/p&gt;

&lt;p&gt;Download the video and audio (use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bestaudio&lt;/code&gt; to automatically choose) and merge into an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mp4&lt;/code&gt; container,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;youtube-dl &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; 133+bestaudio &lt;span class=&quot;nt&quot;&gt;--merge-output-format&lt;/span&gt; mp4  https://www.youtube.com/watch?v&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;FZUfiW3W1KY
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;youtube] FZUfiW3W1KY: Downloading webpage
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;download] NEON PALM MALL &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Vaporwave Mix + Video&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-FZUfiW3W1KY&lt;/span&gt;.f133.mp4 has already been downloaded
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;download] 100% of 35.73MiB
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;download] Destination: NEON PALM MALL &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Vaporwave Mix + Video&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-FZUfiW3W1KY&lt;/span&gt;.f140.m4a
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;download] 100% of 49.55MiB &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;00:19
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;ffmpeg] Merging formats into &lt;span class=&quot;s2&quot;&gt;&quot;NEON PALM MALL (Vaporwave Mix + Video)-FZUfiW3W1KY.mp4&quot;&lt;/span&gt;
Deleting original file NEON PALM MALL &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Vaporwave Mix + Video&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-FZUfiW3W1KY&lt;/span&gt;.f133.mp4 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;pass &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; to keep&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Deleting original file NEON PALM MALL &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Vaporwave Mix + Video&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-FZUfiW3W1KY&lt;/span&gt;.f140.m4a &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;pass &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; to keep&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;playback&quot;&gt;Playback&lt;/h2&gt;

&lt;p&gt;By default the console will blank after a period of time, turn that off so the screen is always on,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;setterm &lt;span class=&quot;nt&quot;&gt;-blank&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mplayer&lt;/code&gt; to playback the video, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fbdev2&lt;/code&gt; device must be used, trying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;directfb&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fbdev&lt;/code&gt; will result in an mplayer playback error.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mplayer &lt;span class=&quot;nt&quot;&gt;-vo&lt;/span&gt; fbdev2 &lt;span class=&quot;nt&quot;&gt;-fs&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-zoom&lt;/span&gt; NEON&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;PALM&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;MALL&lt;span class=&quot;se&quot;&gt;\ \(&lt;/span&gt;Vaporwave&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Mix&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;+&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;Video&lt;span class=&quot;se&quot;&gt;\)&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-FZUfiW3W1KY&lt;/span&gt;.mp4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If sound is too loud or quiet, ssh into the C.H.I.P. and use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alsamixer&lt;/code&gt; to adjust the volume.&lt;/p&gt;

&lt;p&gt;Keyboard controls for mplayer will work on the C.H.I.P. keyboard, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;q&lt;/code&gt; to quit and arrow keys to browse the video.&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;p&gt;Overall resource usage isn’t bad, about 25% CPU when playing the video back with just a slight audio glitch now and then. If CPU gets stressed, audio and playback will glitch even more. There are ways to tune mplayer to perform better on lower end systems like the C.H.I.P., but I won’t go into detail here as there are many guides out there.&lt;/p&gt;

&lt;p&gt;Depending on the video, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mp4&lt;/code&gt; output format may not work and give a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ERROR:   Stream #1:0 -&amp;gt; #0:1 (copy)&lt;/code&gt; when trying to merge video+audio, using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkv&lt;/code&gt; for the output format is a workaround.&lt;/p&gt;
</description>
        <pubDate>Fri, 19 Mar 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/CHIP-Vaporwave/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/CHIP-Vaporwave/</guid>
        
        <category>chip</category>
        
        <category>hack</category>
        
        <category>100daystooffload</category>
        
        
        <category>hack</category>
        
      </item>
    
      <item>
        <title>Running dnscrypt-proxy on OpenBSD</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;A couple of weeks ago I took a spare RaspberryPi 3 leftover from my &lt;a href=&quot;/blog/2017/Raspberry-Pi-Kubernetes-Cluster/&quot;&gt;old k3s cluster&lt;/a&gt; and installed &lt;a href=&quot;https://www.openbsd.org/&quot;&gt;OpenBSD&lt;/a&gt; on it using my &lt;a href=&quot;/blog/2021/CHIP-Serial-Console/&quot;&gt;Pocket C.H.I.P.&lt;/a&gt;. While getting it installed was fun, I wanted to do more with it and use it on a more regular basis to continue learning about OpenBSD in general.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/openbsd-rpi/openbsd-rpi.png&quot; alt=&quot;OpenBSD on RaspberryPi&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;OpenBSD 4.9 Sticker on RaspberryPi 3&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;I’ve had a &lt;a href=&quot;https://pi-hole.net/&quot;&gt;Pi-hole&lt;/a&gt; running on an older Raspberry Pi B with Debian for a few years, but wanted a few additional features, notably using &lt;a href=&quot;https://www.dnscrypt.org/&quot;&gt;DNSCRYPT&lt;/a&gt; to encrypt DNS traffic so our ISP wouldn’t be able to use it for anything and/or using &lt;a href=&quot;https://en.wikipedia.org/wiki/DNS_over_HTTPS&quot;&gt;DNS-over-HTTPS&lt;/a&gt;. I originally was going to setup Pi-hole on the new OpenBSD Pi, but quickly found out that Pi-hole doesn’t work on OpenBSD.&lt;/p&gt;

&lt;p&gt;A quick search, turned up  an excellent &lt;a href=&quot;https://bghost.xyz/post/pihole_on_openbsd/&quot;&gt;Pi-hole on OpenBSD&lt;/a&gt; guide, which cleverly uses the &lt;a href=&quot;https://www.openbsd.org/faq/faq16.html&quot;&gt;vmm hypervisor&lt;/a&gt; to run a Linux VM and install Pi-hole there. This however was also a dead-end since the guide was assuming an x86 install and not arm64. Unfortunately it seems that the OpenBSD arm64 port doesn’t have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmm&lt;/code&gt; so installing a VM wouldn’t work, and probably wasn’t a great idea for performance anyway.&lt;/p&gt;

&lt;p&gt;The guide did include a reference to using &lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy&quot;&gt;dnscrypt-proxy&lt;/a&gt;, which is available as a package for OpenBSD arm64. Reading through the features it can do almost everything Pi-hole can and more,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Local DNS caching&lt;/li&gt;
  &lt;li&gt;Filtering for Ads and Malware&lt;/li&gt;
  &lt;li&gt;DNSCRYPT&lt;/li&gt;
  &lt;li&gt;DNS-over-HTTPS&lt;/li&gt;
  &lt;li&gt;Anonymized DNS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only thing that was missing was the nicer GUI interface of Pi-hole, but I rarely used that anyway after initially setting it up and was more eye-candy that utilitarian. I decided to setup &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnscrypt-proxy&lt;/code&gt; to mimic the blocking capabilities of the Pi-hole and enabled some more of the advanced features.&lt;/p&gt;

&lt;h2 id=&quot;installing-dnscrypt-proxy-on-openbsd&quot;&gt;Installing dnscrypt-proxy on OpenBSD&lt;/h2&gt;

&lt;p&gt;Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnscrypt-proxy&lt;/code&gt; is in the OpenBSD package repo, installation was a simple as,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas pkg_add dnscrypt-proxy
quirks-3.442 signed on 2021-03-09T20:09:44Z
dnscrypt-proxy-2.0.44: ok
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This installs version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.0.44&lt;/code&gt; which is slightly older than upstream, which is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.0.45&lt;/code&gt;. Looking in &lt;a href=&quot;https://cdn.openbsd.org/pub/OpenBSD/snapshots/packages/aarch64/&quot;&gt;openbsd snapshots&lt;/a&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.0.45&lt;/code&gt; is packaged in preparation for OpenBSD 6.9 and can install without issue on 6.8.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;wget https://cdn.openbsd.org/pub/OpenBSD/snapshots/packages/aarch64/dnscrypt-proxy-2.0.45.tgz
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas pkg_add dnscrypt-proxy-2.0.45.tgz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;configuring-dnscrypt-proxy-on-openbsd&quot;&gt;Configuring dnscrypt-proxy on OpenBSD&lt;/h2&gt;

&lt;p&gt;The default configuration is in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/dnscrypt-proxy.toml&lt;/code&gt;, and will need to be updated before starting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dnscrypt-proxy&lt;/code&gt; since it will give one of these errors,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;FATAL] Unable to clone file descriptor: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;bad file descriptor]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;FATAL] Duplicated file descriptors are above base
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It also contains deprecated references to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blacklist&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;whitelist&lt;/code&gt; which will needs replacing. A known good configuration to start with is here: &lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml&quot;&gt;https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;cloudflare-dns-over-https&quot;&gt;Cloudflare DNS-over-HTTPS&lt;/h3&gt;

&lt;p&gt;I am using the &lt;a href=&quot;https://1.1.1.1/&quot;&gt;Cloudflare 1.1.1.1&lt;/a&gt; DNS revolvers since they provide DNS-over-HTTPS and their response times are extremely fast. My ISP and network is also setup for IPv6, and that is configured to allow IPv6 clients and lookups. For fallback DNS, &lt;a href=&quot;https://www.quad9.net/&quot;&gt;Quad9&lt;/a&gt; is used since it’s separate from Cloudflare and has a relatively decent privacy and security features.&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#Use cloudflare DNS&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;server_names&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;cloudflare&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;cloudflare-ipv6&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Listen on local and LAN addresses for DNS&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;listen_addresses&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;127.0.0.1:53&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;[::1]:53&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;192.168.7.221:53&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;[fd82:738a:110d:1:2259:a6b:cd78:733b]:53&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;max_clients&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;250&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;user_name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;_dnscrypt-proxy&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Enable ipv4 and ipv6&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ipv4_servers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ipv6_servers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Include resolvers with the following configuration&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dnscrypt_servers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;doh_servers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;require_dnssec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;require_nolog&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;require_nofilter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Allow TCP and UDP&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;force_tcp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2500&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;keepalive&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Logging&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;log_level&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;use_syslog&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Certs&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;cert_refresh_delay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;240&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dnscrypt_ephemeral_keys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;tls_disable_session_tickets&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Fallback to a non CloudFlare DNS if things aren&apos;t happy&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;fallback_resolver&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;9.9.9.9:53&apos;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ignore_system_dns&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;sources&quot;&gt;Sources&lt;/h3&gt;

&lt;p&gt;To reference revolvers and relays, &lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Configuration-Sources&quot;&gt;sources&lt;/a&gt; are used to find publicly resources. These are setup by default in dnscrypt-proxy, but I’ve added a few changes like caching them to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/dnscrypt-proxy&lt;/code&gt; and point to the latest &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v3&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#Sources for resolvers and relays&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[sources]&lt;/span&gt;
  &lt;span class=&quot;nn&quot;&gt;[sources.&apos;public-resolvers&apos;]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;minisign_key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;cache_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/var/dnscrypt-proxy/public-resolvers.md&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;refresh_delay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;

  &lt;span class=&quot;nn&quot;&gt;[sources.&apos;relays&apos;]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/relays.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;https://download.dnscrypt.info/resolvers-list/v3/relays.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;https://ipv6.download.dnscr&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
ypt.&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;inf&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;o/resolvers-list/v&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/relays.md&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;, &apos;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;https://download.dnscrypt.net/resolvers-list/v&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/relays.md&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;]&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;  &lt;span class=&quot;py&quot;&gt;minisign_key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;cache_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/var/dnscrypt-proxy/relays.md&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;refresh_delay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;block-and-allow-lists&quot;&gt;Block and Allow Lists&lt;/h3&gt;

&lt;p&gt;Another powerful features of dnscrypt-proxy are &lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Filters&quot;&gt;filters&lt;/a&gt;, which can take on the role Pi-hole was doing with having a list of domains to block for ads, malware, and other reasons. To generate these lists, the &lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/utils/generate-domains-blocklist/generate-domains-blocklist.py&quot;&gt;generate-domains-blocklist.py&lt;/a&gt; is used.&lt;/p&gt;

&lt;p&gt;I took the blocklists that Pi-hole was using, and created a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;domains-blocklist.conf&lt;/code&gt; configuration to match, which gives it the same blocking sources as the Pi-hole was.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Local additions
file:domains-blocklist-local-additions.txt

# Peter Lowe&apos;s Ad and tracking server list
https://pgl.yoyo.org/adservers/serverlist.php?hostformat=nohtml

# Ads filter list by Disconnect
https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt

# Basic tracking list by Disconnect
https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt

# Sysctl list (ads)
http://sysctl.org/cameleon/hosts

# BarbBlock list (spurious and invalid DMCA takedowns)
https://paulgb.github.io/BarbBlock/blacklists/domain-list.txt

# NoTracking&apos;s list - blocking ads, trackers and other online garbage
https://raw.githubusercontent.com/notracking/hosts-blocklists/master/dnscrypt-proxy/dnscrypt-proxy.blacklist.txt

# Geoffrey Frogeye&apos;s block list of first-party trackers - https://hostfiles.frogeye.fr/
https://hostfiles.frogeye.fr/firstparty-trackers.txt

# Steven Black hosts file
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts

# Pihole Lists
https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist
https://raw.githubusercontent.com/nickspaargaren/pihole-google/master/categories/androidparsed
https://raw.githubusercontent.com/nickspaargaren/pihole-google/master/categories/analyticsparsed
https://raw.githubusercontent.com/anudeepND/blacklist/master/facebook.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This file also references &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;domains-blocklist-local-additions.txt&lt;/code&gt;, which is setup to protect against &lt;a href=&quot;https://en.wikipedia.org/wiki/DNS_rebinding#Protection&quot;&gt;DNS rebinding protection&lt;/a&gt;,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Localhost rebinding protection
0.0.0.0
127.0.0.*

# RFC1918 rebinding protection
10.*
172.16.*
172.17.*
172.18.*
172.19.*
172.20.*
172.21.*
172.22.*
172.23.*
172.24.*
172.25.*
172.26.*
172.27.*
172.28.*
172.29.*
172.30.*
172.31.*
192.168.*
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;generate-domains-blocklist.py&lt;/code&gt; script will also require the files &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;domains-allowlist.txt&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;domains-time-restricted.txt&lt;/code&gt;, which I just created as empty files to allow the blocklist creation to proceed&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;domains-time-restricted.txt
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;domains-allowlist.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Generating the blocklist can be done manually or as a cronjob,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;python3 generate-domains-blocklist.py &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; blocklist.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since I use &lt;a href=&quot;https://www.plex.tv/&quot;&gt;Plex&lt;/a&gt;, work for a Account Based Marketing company, and Google reCaptcha is usually in blocklists, I created an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allowlist.txt&lt;/code&gt; as well,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;plex.direct
demandbase.com
recaptcha.google.com
gc.zgo.a
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Putting this all together into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/dnscrypt-proxy.toml&lt;/code&gt; blocking configuration,&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#Blocking configuration&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[blocked_names]&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;## Path to the file of blocking rules (absolute, or relative to the same directory as the executable file)&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;blocked_names_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/home/micheal/dnscrypt-proxy/blocklist.txt&apos;&lt;/span&gt;

  &lt;span class=&quot;py&quot;&gt;log_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/var/tmp/blocked.log&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;log_format&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;tsv&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Allow configuration&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[allowed_names]&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;## Path to the file of blocking rules (absolute, or relative to the same directory as the executable file)&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;allowed_names_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/home/micheal/dnscrypt-proxy/allowlist.txt&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;anonymized-dns&quot;&gt;Anonymized DNS&lt;/h3&gt;

&lt;p&gt;One of the features I liked about dnscrypt-proxy is it offers is &lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Anonymized-DNS&quot;&gt;Anonymized DNS&lt;/a&gt;, which I setup to test out.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#Anonymized DNS relays
[anonymized_dns]
routes = [
    { server_name=&apos;zackptg5-us-il-ipv4&apos;, via=[&apos;anon-cs-usca&apos;, &apos;anon-cs-usga&apos;] },
    { server_name=&apos;freetsa.org-ipv6&apos;, via=[&apos;anon-zackptg5-us-il-ipv6&apos;, &apos;anon-acsacsar-ams-ipv6&apos;] }
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While this did work well, unfortunately the DNS query times were consistently 200ms+, which can appear as lag when browsing things. Since DNS-over-HTTPS is encrypted and filtering is setup, this was more of a nice-to-have instead of a requirements, so I ended up commenting it out. If/when Cloudflare provides DNSCRYPT I may re-visit it and see if response times have improved.&lt;/p&gt;

&lt;h3 id=&quot;local-dns-over-https&quot;&gt;Local DNS-over-HTTPS&lt;/h3&gt;

&lt;p&gt;Another feature that Pi-hole didn’t support was DNS-over-HTTPS both for resolving and for serving requests locally. This is something built-in to dnscrypt-proxy with &lt;a href=&quot;https://github.com/DNSCrypt/dnscrypt-proxy/wiki/Local-DoH&quot;&gt;Local DoH&lt;/a&gt; that &lt;a href=&quot;https://support.mozilla.org/en-US/kb/firefox-dns-over-https&quot;&gt;Firefox support for DoH&lt;/a&gt; can then use. By default Firefox will use Cloudflare DoH directly and was previously bypassing the Pi-hole, not getting the filtering features the rest of the network was. Now it can use the same filtering and continue to use DoH.&lt;/p&gt;

&lt;p&gt;To setup DoH on dnscrypt-proxy, a self-signed certificate is required,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openssl req -x509 -nodes -newkey rsa:2048 -days 5000 -sha256 -keyout localhost.pem -out localhost.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This certificate is then used to listen on IPv4 and IPv6 addresses for DoH on port &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3000&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#DNS over HTTPS configuration
[local_doh]
  listen_addresses = [&apos;127.0.0.1:3000&apos;, &apos;[::1]:3000&apos;, &apos;192.168.7.221:3000&apos;, &apos;[fd82:738a:110d:1:2259:a6b:cd78:733b]:3000&apos;]
  path = &quot;/dns-query&quot;
  cert_file = &quot;/home/micheal/dnscrypt-proxy/localhost.pem&quot;
  cert_key_file = &quot;/home/micheal/dnscrypt-proxy/localhost.pem&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Firefox is then configured to use dnscrypt-proxy, for example over IPv6, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://fd82:738a:110d:1:2259:a6b:cd78:733b:3000/dns-query&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;enabling-dnscrypt-proxy&quot;&gt;Enabling dnscrypt-proxy&lt;/h3&gt;

&lt;p&gt;Now that the configuration is all setup and dnscrypt-proxy is installed on OpenBSD, enable the service and start it,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas rcctl &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;dnscrypt_proxy
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas rcctl start dnscrypt_proxy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This should start and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/log/messages&lt;/code&gt; will show it starting,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Mar 12 11:15:59 majora dnscrypt-proxy[1888]: dnscrypt-proxy 2.0.45
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Network connectivity detected
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Dropping privileges
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Network connectivity detected
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to 127.0.0.1:53 [UDP]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to 127.0.0.1:53 [TCP]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to [::1]:53 [UDP]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to [::1]:53 [TCP]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to 192.168.7.221:53 [UDP]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to 192.168.7.221:53 [TCP]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to [fd82:738a:110d:1:2259:a6b:cd78:733b]:53 [UDP]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to [fd82:738a:110d:1:2259:a6b:cd78:733b]:53 [TCP]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to https://127.0.0.1:3000/dns-query [DoH]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to https://[::1]:3000/dns-query [DoH]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to https://192.168.7.221:3000/dns-query [DoH]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Now listening to https://[fd82:738a:110d:1:2259:a6b:cd78:733b]:3000/dns-query [DoH]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Source [public-resolvers] loaded
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Source [relays] loaded
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Loading the set of whitelisting rules from [/home/micheal/dnscrypt-proxy/allowlist.txt]
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Firefox workaround initialized
Mar 12 11:15:59 majora dnscrypt-proxy[1888]: Loading the set of blocking rules from [/home/micheal/dnscrypt-proxy/blocklist.txt]
Mar 12 11:16:04 majora dnscrypt-proxy[1888]: [cloudflare-ipv6] OK (DoH) - rtt: 14ms
Mar 12 11:16:04 majora dnscrypt-proxy[1888]: [cloudflare] OK (DoH) - rtt: 83ms
Mar 12 11:16:04 majora dnscrypt-proxy[1888]: Sorted latencies:
Mar 12 11:16:04 majora dnscrypt-proxy[1888]: -    14ms cloudflare-ipv6
Mar 12 11:16:04 majora dnscrypt-proxy[1888]: -    83ms cloudflare
Mar 12 11:16:04 majora dnscrypt-proxy[1888]: Server with the lowest initial latency: cloudflare-ipv6 (rtt: 14ms)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;logging&quot;&gt;Logging&lt;/h3&gt;

&lt;p&gt;Initially to test things are working well, setup the query logs to write to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/tmp/query.log&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#Query logging, commented out unless for troubleshooting
[query_log]
  file = &apos;/var/tmp/query.log&apos;
  format = &apos;tsv&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As requests come in they will show up here. Blocked requests will also show up in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/tmp/blocked.log&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Depending on the number of devices making DNS requests, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;query.log&lt;/code&gt; can get quite large it’s recommended to keep it enabled when initially testing something, and turning it off when not in use. Leaving &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blocked.log&lt;/code&gt; on is a good idea to help know what to add to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allowlist.txt&lt;/code&gt; in case something is blocked that you want to allow.&lt;/p&gt;

&lt;p&gt;Since a Raspberry Pi is most likely using an MicroSD card and by default OpenBSD will mount &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt; as a filesystem, it’s a good idea to to set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt; as a memory filesystem to avoid excessive writes to the SD Card.&lt;/p&gt;

&lt;p&gt;OpenBSD has the &lt;a href=&quot;https://man.openbsd.org/mount_mfs.8&quot;&gt;mfs&lt;/a&gt; filesytem that can be used to mount a filesystem in-memory to help avoid this,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;mount_mfs is used to build a file system in virtual memory and then mount it on a specified node.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Setup &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mfs&lt;/code&gt;, first by unmounting it. This may require killing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sndio&lt;/code&gt; processes and using the console instead of ssh as it will give a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resource busy&lt;/code&gt; error when trying to unmount &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;doas umount /tmp
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chmod &lt;/span&gt;1777 /tmp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/fstab&lt;/code&gt;, comment out the old &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt; mount and add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mfs&lt;/code&gt; mount,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#1400ced5c75f17ee.d /tmp ffs rw,nodev,nosuid 1 2
swap /tmp mfs rw,nodev,nosuid,-s=256M 0 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Reboot, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/tmp&lt;/code&gt; will now show up as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mfs&lt;/code&gt; type,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mount | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; /tmp
mfs:73353 on /tmp &lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;mfs &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;asynchronous, &lt;span class=&quot;nb&quot;&gt;local&lt;/span&gt;, nodev, nosuid, &lt;span class=&quot;nv&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;524288 512-blocks&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;full-configuration&quot;&gt;Full Configuration&lt;/h2&gt;

&lt;p&gt;Here is the full configuration of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/dnscrypt-proxy&lt;/code&gt; combined from all the snippets above,&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#Use cloudflare DNS&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;server_names&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;cloudflare&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;cloudflare-ipv6&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Listen on local and LAN addresses for DNS&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;listen_addresses&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;127.0.0.1:53&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;[::1]:53&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;192.168.7.221:53&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;[fd82:738a:110d:1:2259:a6b:cd78:733b]:53&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;max_clients&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;250&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;user_name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;_dnscrypt-proxy&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Enable ipv4 and ipv6&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ipv4_servers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ipv6_servers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Include resolvers with the following configuration&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dnscrypt_servers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;doh_servers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;require_dnssec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;require_nolog&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;require_nofilter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Allow TCP and UDP&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;force_tcp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2500&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;keepalive&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Logging&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;log_level&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;use_syslog&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Certs&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;cert_refresh_delay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;240&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;dnscrypt_ephemeral_keys&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;tls_disable_session_tickets&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Fallback to a non CloudFlare DNS if things arne&apos;t happy&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;fallback_resolver&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;9.9.9.9:53&apos;&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;ignore_system_dns&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#[query_log]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#  file = &apos;/var/tmp/query.log&apos;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#  format = &apos;tsv&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Sources for resolvers and relays&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[sources]&lt;/span&gt;
  &lt;span class=&quot;nn&quot;&gt;[sources.&apos;public-resolvers&apos;]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;minisign_key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;cache_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/var/dnscrypt-proxy/public-resolvers.md&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;refresh_delay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;

  &lt;span class=&quot;nn&quot;&gt;[sources.&apos;relays&apos;]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/relays.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;https://download.dnscrypt.info/resolvers-list/v3/relays.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;https://ipv6.download.dnscrypt.info/resolvers-list/v3/relays.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;https://download.dnscrypt.net/resolvers-list/v3/relays.md&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;minisign_key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;cache_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/var/dnscrypt-proxy/relays.md&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;refresh_delay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;72&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Blocking configuration&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[blocked_names]&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;## Path to the file of blocking rules (absolute, or relative to the same directory as the executable file)&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;blocked_names_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/home/micheal/dnscrypt-proxy/blocklist.txt&apos;&lt;/span&gt;

  &lt;span class=&quot;py&quot;&gt;log_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/var/tmp/blocked.log&apos;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;log_format&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;tsv&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Allow configuration&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[allowed_names]&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;## Path to the file of blocking rules (absolute, or relative to the same directory as the executable file)&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;allowed_names_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;/home/micheal/dnscrypt-proxy/allowlist.txt&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Anonymized DNS relays&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#[anonymized_dns]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#routes = [&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#    { server_name=&apos;zackptg5-us-il-ipv4&apos;, via=[&apos;anon-cs-usca&apos;, &apos;anon-cs-usga&apos;] },&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#    { server_name=&apos;freetsa.org-ipv6&apos;, via=[&apos;anon-zackptg5-us-il-ipv6&apos;, &apos;anon-acsacsar-ams-ipv6&apos;] }&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#]&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#DNS over HTTPS configuration&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[local_doh]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;listen_addresses&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;127.0.0.1:3000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;[::1]:3000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;192.168.7.221:3000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;[fd82:738a:110d:1:2259:a6b:cd78:733b]:3000&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/dns-query&quot;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;cert_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/home/micheal/dnscrypt-proxy/localhost.pem&quot;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;cert_key_file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/home/micheal/dnscrypt-proxy/localhost.pem&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Fri, 12 Mar 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/Running-dnscrypt-proxy-on-OpenBSD/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/Running-dnscrypt-proxy-on-OpenBSD/</guid>
        
        <category>openbsd</category>
        
        <category>raspberrypi</category>
        
        <category>hack</category>
        
        <category>dns</category>
        
        <category>100daystooffload</category>
        
        
        <category>hack</category>
        
      </item>
    
      <item>
        <title>CHIP Serial Console</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;Since &lt;a href=&quot;/blog/2021/Pocket-CHIP/&quot;&gt;getting a Pocket C.H.I.P&lt;/a&gt;, I’m looking for more ways to use it outside the original configuration, and came across a Hackernoon post on using a &lt;a href=&quot;https://medium.com/hackernoon/turn-your-pocketchip-into-a-badass-on-the-go-hardware-hackers-terminal-84b1edc939f&quot;&gt;CHIP as a serial console&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also wanted to &lt;a href=&quot;https://brainsnapped.com/2020/10/22/openbsd-on-the-raspberry-pi-3-model-b/&quot;&gt;install OpenBSD onto a RaspberryPi 3&lt;/a&gt; - unlike most RaspberryPi installs where a sdcard image is flashed and boots up - OpenBSD requires following the &lt;a href=&quot;https://www.openbsd.org/faq/faq4.html&quot;&gt;full installation procedure&lt;/a&gt; on the console. Sure you could hook up it up to HDMI and a USB keyboard, but what’s the fun in that? So I took the oppurtunity to do both.&lt;/p&gt;

&lt;h2 id=&quot;hardware&quot;&gt;Hardware&lt;/h2&gt;

&lt;p&gt;Following the Hackernoon post, and using the &lt;a href=&quot;https://www.raspberrypi.org/documentation/usage/gpio/&quot;&gt;RPI GPIO documentation&lt;/a&gt;, I soldered some lead pins onto the CHIPs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5V&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GND&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TXD&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RXD&lt;/code&gt; breakout at the top, made some basic GPIO wires and hooked it all up. Using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5V&lt;/code&gt; has the added benefit of powering the RaspberryPi from the CHIP battery, which in makes both of them portable.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/chip-serial-console/pocket-chip-serial.png&quot; alt=&quot;C.H.I.P. Serial Console&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;C.H.I.P. Serial Console&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;software&quot;&gt;Software&lt;/h2&gt;
&lt;p&gt;To connect via serial console, first release &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/ttyS0&lt;/code&gt; from systemd,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl stop serial-getty@ttyS0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Many articles suggest using &lt;a href=&quot;https://salsa.debian.org/minicom-team/minicom&quot;&gt;minicom&lt;/a&gt; as a serial console, but I prefer &lt;a href=&quot;https://www.gnu.org/software/screen/&quot;&gt;screen&lt;/a&gt;, and used it for years when working in datacenters.&lt;/p&gt;

&lt;p&gt;The OpenBSD console uses a baud rate of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;115100&lt;/code&gt; and transmission of eight bits per byte &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cs8&lt;/code&gt;. Connecting requires &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt;, even if your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chip&lt;/code&gt; user is in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tty&lt;/code&gt; group due to some udev/systemd permissions wonkiness.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;screen /dev/ttyS0 115200,cs8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The serial console works well, although occasionally there is missing data, but after remembering how to use the OpenBSD disk partitioner - OpenBSD 6.8 was running on a RaspberryPi 3. Once the installation is complete, if DHCP was setup during install, connecting to it over ssh is trivial and no longer requires the serial console.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While as much fun as this is, it’s not nearly as useful as it could have been years ago when troubleshooting misbehaving &lt;a href=&quot;https://shrubbery.net/~heas/sun-feh-2_1/Systems/Netra_t1_105/spec.html&quot;&gt;Sun Netra&lt;/a&gt; or &lt;a href=&quot;https://shrubbery.net/~heas/sun-feh-2_1/Systems/SunFire280R/SunFire280R.html&quot;&gt;Sun Fire&lt;/a&gt; systems. For now though it’s a good hack, useful in the right circumstances, and just looks cool.&lt;/p&gt;
</description>
        <pubDate>Wed, 03 Mar 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/CHIP-Serial-Console/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/CHIP-Serial-Console/</guid>
        
        <category>chip</category>
        
        <category>openbsd</category>
        
        <category>100daystooffload</category>
        
        <category>hack</category>
        
        <category>raspberrypi</category>
        
        
        <category>chip</category>
        
      </item>
    
      <item>
        <title>Pocket C.H.I.P.</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;Recently I got a &lt;a href=&quot;https://shop.pocketchip.co/&quot;&gt;Pocket C.H.I.P.&lt;/a&gt; with the idea of making it mini terminal on my desk, displaying things like weather, new email, new mastodon toots, etc. It comes pre-loaded with some basic software: terminal, &lt;a href=&quot;https://www.lexaloffle.com/pico-8.php&quot;&gt;pico8&lt;/a&gt;, and a few other utilities. Because it was released in 2017 and the demise of the original Next Thing the software on it is out-of-date, running Debian 8 and an older version of pico8.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/pocket-chip/pocket-chip.png&quot; alt=&quot;Pocket C.H.I.P.&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Pocket C.H.I.P.&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;I wanted to updated it to at least Debian 10, and found a &lt;a href=&quot;https://gist.github.com/luzhuomi/526fbcc30f3522f09eacf20d0f776fa5&quot;&gt;working guide&lt;/a&gt; which follows the basic Debian upgrade process as well as some fixes for common issues like Xorg configs and updating wifi settings.&lt;/p&gt;

&lt;p&gt;Unfortunately this broke a few other things that weren’t listed in the guide, like the FN keys no longer working on the built-in keyboard and pico8 failing to start. I spent some time tackling these issues and now have a fully working Debian 10 Pocket C.H.I.P. with pico8 and a functioning keyboard.&lt;/p&gt;

&lt;h2 id=&quot;fixing-fn-keys&quot;&gt;Fixing FN Keys&lt;/h2&gt;

&lt;p&gt;After upgrading to Debian 10, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FN&lt;/code&gt; keys on the C.H.I.P. build-in keyboard will no longer work. Fix this by sourcing the keymap in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/home/chip/.xinitrc&lt;/code&gt; and restarting C.H.I.P. for xorg to load the xmodmap every time.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /home/chip/.Xmodmap &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; xmodmap /home/chip/.Xmodmap
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For reference &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/home/chip/.Xmodmap&lt;/code&gt; is,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;keycode 10 = 1 exclam F1 exclam
keycode 11 = 2 at F2 at
keycode 12 = 3 numbersign F3 numbersign
keycode 13 = 4 dollar F4 dollar
keycode 14 = 5 percent F5 percent
keycode 15 = 6 asciicircum F6 asciicircum
keycode 16 = 7 ampersand F7 ampersand
keycode 17 = 8 asterisk F8 asterisk
keycode 18 = 9 parenleft F9 parenleft
keycode 19 = 0 parenright F10 parenright
keycode 22 = BackSpace BackSpace KP_Delete BackSpace
keycode 29 = y Y braceleft Y
keycode 30 = u U braceright U
keycode 31 = i I bracketleft I
keycode 32 = o O bracketright O
keycode 33 = p P bar P
keycode 36 = Return NoSymbol KP_Enter
keycode 43 = h H less H
keycode 44 = j J greater J
keycode 45 = k K apostrophe K
keycode 46 = l L quotedbl L
keycode 56 = b B grave b
keycode 57 = n N asciitilde n
keycode 58 = m M colon M
keycode 59 = comma less semicolon less
keycode 60 = period comma semicolon comma
keycode 61 = slash question backslash question
keycode 82 = KP_Subtract underscore F11 KP_Subtract
keycode 86 = KP_Add KP_Equal F12 KP_Add
keycode 108 = Mode_switch Meta_R Alt_R Meta_R
keycode 111 = Up NoSymbol Prior
keycode 113 = Left NoSymbol Home
keycode 114 = Right NoSymbol End
keycode 116 = Down NoSymbol Next
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;updating-pico8&quot;&gt;Updating Pico8&lt;/h2&gt;

&lt;p&gt;Downloaded latest Pico8 for the C.H.I.P. from &lt;a href=&quot;https://www.lexaloffle.com/bbs/?tid=34009&quot;&gt;lexaloffle.com&lt;/a&gt; and follow the instructions on installing it.&lt;/p&gt;

&lt;p&gt;The binary was built against an old version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libcurl&lt;/code&gt; and will give error about not finding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CURL_OPENSSL_3&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./pico8: /usr/lib/arm-linux-gnueabihf/libcurl.so.4: version &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;CURL_OPENSSL_3&lt;span class=&quot;s1&quot;&gt;&apos; not found (required by ./pico8)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To fix this, download the older &lt;a href=&quot;https://downloads.raspberrypi.org/raspbian/images/raspbian-2017-09-08/&quot;&gt;Raspian Stretch image&lt;/a&gt; and mount it locally&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mount &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;48234496 &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; ext4 2017-09-07-raspbian-stretch.img /mnt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create the directory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/share/libcurlhack&lt;/code&gt; and copy the files &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mnt/usr/lib/arm-linux-gnueabihf/{libcrypto.so.1.0.2,libcurl.so.4,libssl.so.1.0.2}&lt;/code&gt; from the Raspbian Stretch image to the C.H.I.P.&lt;/p&gt;

&lt;p&gt;When finished the C.H.I.P. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/share/libcurlhack/&lt;/code&gt; will look like this,&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chip@chip:~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; /usr/local/share/libcurlhack/
total 2208
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 root staff 1493272 Feb 24 02:20 libcrypto.so.1.0.2
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 root staff  439956 Feb 24 02:15 libcurl.so.4
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 root staff  320924 Feb 24 02:19 libssl.so.1.0.2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a shell script &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/bin/pico8&lt;/code&gt; that will include this new path in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;LD_LIBRARY_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/local/share/libcurlhack:/usr/lib/arm-linux-gnueabihf/
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;LD_LIBRARY_PATH

/usr/lib/pico8/pico8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running Pico8 from the Pocket C.H.I.P. launcher will now work.&lt;/p&gt;

&lt;h2 id=&quot;changing-the-window-manager&quot;&gt;Changing the Window Manager&lt;/h2&gt;

&lt;p&gt;By default the C.H.I.P. will run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pocket-wm&lt;/code&gt;, which is a modified version of &lt;a href=&quot;https://dwm.suckless.org/&quot;&gt;dwm&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chip@chip:/usr/share/xsessions&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pocket-wm &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;
dwm-6.0, © 2006-2011 dwm engineers, see LICENSE &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;details
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This in turn runs &lt;a href=&quot;https://tools.suckless.org/dmenu/&quot;&gt;dmenu&lt;/a&gt; and to launch the “home” screen with the applications Iceweasel, pico8, urxvt, and aeabi.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chip@chip:~$ strings /usr/bin/pocket-wm | grep dmenu_run -A4
dmenu_run
Iceweasel
pico8
urxvt
aeabi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I looked a bit to see how all this was configured, but need to spent more time on reading up on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dwm&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dmenu_run&lt;/code&gt; to know what I’m looking at.&lt;/p&gt;

&lt;p&gt;To run a different window manager or session we’ll need to configure &lt;a href=&quot;https://github.com/canonical/lightdm&quot;&gt;Lightdm&lt;/a&gt; to use something other than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pocket-wm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example to run &lt;a href=&quot;http://fluxbox.org/&quot;&gt;Fluxbox&lt;/a&gt;, install it using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt;,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; fluxbox
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which creates &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fluxbox.desktop&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/share/xsessions&lt;/code&gt;. This directory contains all available window managers that Lightdm can launch.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chip@chip:~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; /usr/share/xsessions
total 24
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 root root  188 Feb 26  2019 awesome.desktop
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 root root  222 Feb 24  2014 fluxbox.desktop
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 root root   86 Feb 22  2019 lightdm-xsession.desktop
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 root root  118 Apr 27  2016 pocket-wm.desktop
&lt;span class=&quot;nt&quot;&gt;-rw-r--r--&lt;/span&gt; 1 root root 5465 Oct 21  2017 xfce.desktop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chip&lt;/code&gt; users home directory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.dmrc&lt;/code&gt; and set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Session=&lt;/code&gt; to the window manager lightdm should launch automatically. This will match what’s in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/share/xessions&lt;/code&gt; but without the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.desktop&lt;/code&gt; extension This will match what’s in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/share/xessions&lt;/code&gt; but without the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.desktop&lt;/code&gt; extension.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[Desktop]
Language=en_US.utf8
Session=fluxbox
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Restart &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lightdm&lt;/code&gt; and it will restart the C.H.I.P. with the new window manager.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo systemctl restart lightdm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/pocket-chip/fluxbox-chip.png&quot; alt=&quot;Fluxbox on PocketCHIP&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Fluxbox on PocketChip&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h3 id=&quot;right-click&quot;&gt;Right Click&lt;/h3&gt;
&lt;p&gt;Right click is heavily used on Fluxbox but doesn’t work out-of-the-box with the Pocket C.H.I.P., and setting a button override in Xmodmap or mouse keys in Xorg doesn’t work (it even seems to break the FN keys). To enable right click by holding down on the touch screen build and setup &lt;a href=&quot;https://github.com/PeterCxy/evdev-right-click-emulation&quot;&gt;evdev-right-click-emulation&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Clone the repoistory&lt;/span&gt;
git clone https://github.com/PeterCxy/evdev-right-click-emulation

&lt;span class=&quot;c&quot;&gt;# Install required dependencies to build&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; libevdev-dev libevdev2

&lt;span class=&quot;c&quot;&gt;# Build evdev-rce&lt;/span&gt;
make all

&lt;span class=&quot;c&quot;&gt;# Move evdev-rce to a system path and chown the owner group&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo mv &lt;/span&gt;out/evdev-rce /usr/local/bin
&lt;span class=&quot;nb&quot;&gt;sudo chown &lt;/span&gt;root:staff /usr/local/bin/evdev-rce

&lt;span class=&quot;c&quot;&gt;# Have evdev-rce start on boot&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/bin/evdev-rce &amp;amp;&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sudo tee&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /etc/rc.local
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;the Pocket C.H.I.P. is a lot of fun, even with some of these issues the troubleshooting process gave me a way to explore the system and understand how it works. This is valuable as I continue to tinker with it to make it a true desk mini-terminal.&lt;/p&gt;
</description>
        <pubDate>Wed, 24 Feb 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/Pocket-CHIP/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/Pocket-CHIP/</guid>
        
        <category>debian</category>
        
        <category>chip</category>
        
        <category>hack</category>
        
        <category>100daystooffload</category>
        
        
        <category>hack</category>
        
      </item>
    
      <item>
        <title>Custom Keyboards, Sully and Pok3r</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;Working in the tech industry and having geeky hobbies; I’ve always taken my tools, both hardware and software, seriously. For some reason I never thought about the keyboard itself though, and was content with using the bundled membrane boards. A few years ago though this all changed which I discovered the deep rabbit hole that is both utilitarian and vain world of custom keyboards.&lt;/p&gt;

&lt;h2 id=&quot;sully&quot;&gt;Sully&lt;/h2&gt;

&lt;p&gt;Back in 2013 I convinced my boss that I needed a high-end mechanical keyboard to help with some recent hand pain (almost entirely due to Starbound at the time). I purchased a Coolermaster CM Storm with Cherry MX Green switches. It was my first “small” keyboard in a sense that it was a ten-key-less (TKL) and the green switches were clicky and stiff, exactly what I wanted in a keyboard since it reminded me of the electric typewriters I learned to touch-type on.&lt;/p&gt;

&lt;p&gt;After spending some time on &lt;a href=&quot;https://www.reddit.com/r/MechanicalKeyboards/&quot;&gt;r/MechanicalKeyboards&lt;/a&gt; I got the itch to customize it and bought some blank PBT DSA keys in teal and purple, calling it “Sully”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/custom-keyboards-sully-and-pok3r/sully.jpg&quot; alt=&quot;Sully&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Sully&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;Sully was a fantastic board and I used it up until 2019 when I discovered even smaller form factors like 60%. It’s still used in our house, but mostly as a kids toy, demostrating just how well-built it is.&lt;/p&gt;

&lt;h2 id=&quot;vortex-pok3r&quot;&gt;Vortex Pok3r&lt;/h2&gt;

&lt;p&gt;The idea of a smaller, 60% board was appealing in with having the same functionality but in a more compact form. Removing some of the less used keys to provide more desk space and limit finger stretch. I also just liked the way it looked, more compact and different than the standard 101 keyboards. I put the Pok3r on my wishlist because it was “programmable” and I had all sorts of ideas on ways I could customize shortcuts and other functions.&lt;/p&gt;

&lt;p&gt;It came as a Christmas present in 2019, with Cherry MX blue switches and stock keycaps. I immediately started using the programmable PCB, but found it was much more difficult to do since it involves putting it into programming mode and then keying in what you want to setup. Just remapping some keys, like making CAPS-LOCK -&amp;gt; Escape was an exercise in frustration, but it did what I wanted eventually, with the process meticulously detailed in a .txt file. It also has different layers that could hold different keymaps, but I just stuck with a single layer.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;## Caps-lock as ESC&lt;/span&gt;
FN+R_control
CAPS_LOCK
ESC
PN
FN+R_control

&lt;span class=&quot;c&quot;&gt;## HJKL Navigation&lt;/span&gt;
FN+R_Control
FN+H FN+J
FN+J FN+K
FN+K FN+I
PN
FN+R_Control
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;figure&gt;&lt;figcaption&gt;Sample of how to program the stock pok3r firmware&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;pok3r-revived&quot;&gt;Pok3r Revived&lt;/h2&gt;

&lt;p&gt;Eventually I started getting annoyed with the default keycaps, which were a thin cheap ABS plastic and would squeak. Just over a month of use the legends also starting to wear off. This started me down a dark path, first looking into how to stop the squeaking, but then lead to going back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r/MechanicalKeyboards&lt;/code&gt; and following the white rabbit, and making a wish list to customize the board and make it fully mine.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Thick PBT Keycaps&lt;/li&gt;
  &lt;li&gt;Tactile Switches&lt;/li&gt;
  &lt;li&gt;Keyboard Foam&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://qmk.fm&quot;&gt;QMK Programming Support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;devtty&quot;&gt;/dev/tty&lt;/h3&gt;

&lt;p&gt;The first item on the list was easy enough to do, just scour keyboard stores and find a keycap set. I went through various postings, storefronts, and group buys, eventually landing on &lt;a href=&quot;https://matt3o.com/about-mt3-profile-and-devtty-set/&quot;&gt;/dev/tty by matt3o&lt;/a&gt;. These were particularly attractive because of their story; inspired by &lt;a href=&quot;https://deskthority.net/viewtopic.php?t=8539/&quot;&gt;IBM Beamspring terminals&lt;/a&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/tty&lt;/code&gt; name.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;MT3 is inspired by old terminal keyboards; TTY was used to refer to “teletype” or “teletypewriter” but it has come to refer to any type of text terminal. As a linux user the temptation to call the set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/tty&lt;/code&gt; was simply too strong to resist.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The MT3 profile is also extremely high, and the deep dish and feel of PBT makes the keys almost “cuddle” your fingertips. Typing on them is an absolutely joy and because of their thickness they sound amazing even on just a stock board.&lt;/p&gt;

&lt;h3 id=&quot;holy-pandas&quot;&gt;Holy Pandas&lt;/h3&gt;

&lt;p&gt;Next on the list was replacing the switches with something less clicky and more tactile. The original “Sully” board had MX Greens which were extremely clicky and I wanted something different with MX blues in the pok3r, but wanted a change of pace from the last few years. While reading through keyboard sites, the phrase “Holy Panda” kept coming up and how they were fantastic tactile switches. Eventually I came across one of the original post that described the &lt;a href=&quot;https://topclack.com/textclack/2018/12/19/holy-panda-switches-new-and-old-by-quakemz&quot;&gt;origins of the Holy Panda&lt;/a&gt; and found that it was an entirely custom switch, made from two different switches.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Holy Panda switch is the combination of the stem of a Halo True and the housing of a Invyr Panda. The result is the Holy Panda hybrid, one of the snappiest tactile mechanical switches available.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/keyboards/pandas.png&quot; alt=&quot;Pandas&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;YOK Polar Panda(left) Holy Panda(center) Halo True(right)&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;The idea of building my own switches really resonated with me since it gave me, giving me more ownership of what I was building. Holy Pandas also sound amazing when typing, not clicky or loud, but thunky and tactile. Pairing them with a thicker PBT keycap set made perfect sense as well.&lt;/p&gt;

&lt;p&gt;Luckily I found some YOK Polar Panda switches in-stock and ordered them and some Halo Trues from drop, which created “Polar Holy Pandas” with a distinctive blue housing and a salmon stem.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/keyboards/IMG_4665.png&quot; alt=&quot;Building Holy Pandas&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Building Holy Pandas&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;Lubing is also a thing when it comes to building custom switches, and these were lubed with Krytox 205g0, to give them a smoother tactile bump.&lt;/p&gt;

&lt;h3 id=&quot;foam&quot;&gt;Foam&lt;/h3&gt;

&lt;p&gt;Did you know you can put foam in a keyboard to help dampen the sound? I had no idea this was a thing, but it is, and it completely changes the sound profile of a keyboard. So if you’re into how a keyboard sounds, and are willing to spend 15$, foaming a board is a good investment.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/keyboards/IMG_4706.png&quot; alt=&quot;PCB Foam Sandwich&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;PCB Foam Sandwich&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;I opted for foam from &lt;a href=&quot;https://mkultra.click/secret-file-cabinet/60-foam/&quot;&gt;MKUltra&lt;/a&gt;, which I originally thought would go in the bottom of the case. When it arrived I discovered it was plate foam, which goes between the top plate and the PCB, making a sandwich. Even though it wasn’t my original choice, it worked much better since now the entire board is a solid piece with exceptional dampening sounds. Combined with the Holy Panda tactile and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/tty&lt;/code&gt; thickness, it makes a satisfying THUNK with every keypress.&lt;/p&gt;

&lt;h3 id=&quot;qmk-programming&quot;&gt;QMK Programming&lt;/h3&gt;

&lt;p&gt;The last item on the list was improving the programming of the board. I’m planning to write up a more extensive article on &lt;a href=&quot;https://qmk.fm&quot;&gt;QMK&lt;/a&gt;, and the &lt;a href=&quot;https://github.com/pok3r-custom/qmk_pok3r&quot;&gt;pok3r can run QMK&lt;/a&gt;, but requires unlocking the board which is risky and even then will use a fork or QMK and not upstream. While tempted to try this, I found that YMDK makes a drop in replacement &lt;a href=&quot;https://github.com/ecliptik/qmk_firmware/tree/ecliptik/keyboards/ymdk/yd60mq&quot;&gt;YD60MQ PCB&lt;/a&gt; that you can buy for under 30$. This also gave me an excuse to get a de-soldering iron to quickly de-solder the switches and not risk damaging them by using a solder sucker or wick.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/keyboards/IMG_6453.png&quot; alt=&quot;Replacing pok3r PCB&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Replacing old pok3r PCB (red) with new YD60MQ PCB (black)&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;The PCB was replaced about a year after the board was first built, months after I started using QMK on my other boards (more on those in Part 2). The &lt;a href=&quot;https://github.com/ecliptik/qmk_firmware/tree/ecliptik/keyboards/ymdk/yd60mq/keymaps/ecliptik&quot;&gt;custom keymap&lt;/a&gt; flashed on it is similar to the other boards I have, so combos and layers are consistent across all my boards.&lt;/p&gt;

&lt;h2 id=&quot;final-product&quot;&gt;Final Product&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/keyboards/pok3r.jpg&quot; alt=&quot;pok3r Final Form&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;pok3r Final Form&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;With all these features checked off the list, the pok3r is is my daily driver for work and pleasure. It’s a dream to type on with the tactility of the Holy Pandas, and the sound alone is worth the investment. Having the full power of QMK in the board greatly expands it’s capabilities and gives me full ownership and pride in both the hardware and software aspects of it.&lt;/p&gt;

&lt;p&gt;Granted it’s borderline &lt;a href=&quot;https://en.wikipedia.org/wiki/Ship_of_Theseus&quot;&gt;Ship of Thesus&lt;/a&gt;, with the only original parts the aluminum case and stabilizers, but that makes it a fully custom board that no one else has or could come close to replicating.&lt;/p&gt;
</description>
        <pubDate>Mon, 15 Feb 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/Custom-Keyboards-Sully-and-Pok3r/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/Custom-Keyboards-Sully-and-Pok3r/</guid>
        
        <category>keyboards</category>
        
        <category>technology</category>
        
        <category>qmk</category>
        
        <category>hardware</category>
        
        <category>100daystooffload</category>
        
        
        <category>technology</category>
        
      </item>
    
      <item>
        <title>Launching a Gemini Capsule</title>
        <description>&lt;h2 id=&quot;gemawhat&quot;&gt;Gemawhat?&lt;/h2&gt;

&lt;p&gt;Even since I started &lt;a href=&quot;/blog/2021/One-Week-With-Mastodon/&quot;&gt;using Mastodon&lt;/a&gt; a couple of weeks ago, &lt;a href=&quot;https://gemini.circumlunar.space&quot;&gt;Project Gemini&lt;/a&gt; is one of the most exciting new technologies I’ve discovered in my &lt;a href=&quot;https://fosstodon.org/web/timelines/public/local&quot;&gt;local feed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I won’t go into full detail on what Gemini is, but similar to &lt;a href=&quot;/blog/2021/Making-a-Gopherhole-and-Phlog/&quot;&gt;why I made a Gopherhole&lt;/a&gt;, Gemini is a newer Internet protocol that strips away the bloat of the modern web to a core set of concepts, generality, and maximum power-to-weight-ratio.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Gemini is a new, collaboratively designed internet protocol, which explores the space in between gopher and the web, striving to address (perceived) limitations of one while avoiding the (undeniable) pitfalls of the other.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While setting up a Gopherhole was fun and a throwback to an era long gone, Gemini has modern features but still sticks to simplicity,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Encryption by default&lt;/li&gt;
  &lt;li&gt;Gemtext similar to Markdown&lt;/li&gt;
  &lt;li&gt;MIME type support&lt;/li&gt;
  &lt;li&gt;Support for multiple protocols; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gemini://&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gopher://&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;creating-a-capsule&quot;&gt;Creating a Capsule&lt;/h2&gt;

&lt;p&gt;Creating a Gemini Capsule was a much lower barrier than it seems, since it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemtext&lt;/code&gt; is very similar to Markdown and can almost convert 1:1 (with the exception of in-line links). So posts written in Markdown for a static blog (like &lt;a href=&quot;https://www.jekyllnow.com&quot;&gt;Jekyll&lt;/a&gt;) can easily work in Gemini. The tool &lt;a href=&quot;https://github.com/makeworld-the-better-one/md2gemini&quot;&gt;md2gemini&lt;/a&gt; makes this even more seamless by converting Markdown specific things to Gemtext.&lt;/p&gt;

&lt;p&gt;With having content ready to go, hosting is the next challenge. Bringing up your own Gemini server is easy enough, with a &lt;a href=&quot;https://github.com/kr1sp1n/awesome-gemini#servers&quot;&gt;large number of Gemini servers&lt;/a&gt; available. I just went with using my Pubnix account at &lt;a href=&quot;https://rawtext.club&quot;&gt;rawtext.club&lt;/a&gt; which provides a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public_gemini&lt;/code&gt; option. This is also where &lt;a href=&quot;gopher://rawtext.club:70/1~ecliptik&quot;&gt;my gopherhole&lt;/a&gt; is hosted.&lt;/p&gt;

&lt;h2 id=&quot;creating-a-toolset&quot;&gt;Creating a Toolset&lt;/h2&gt;

&lt;p&gt;Manually converting markdown posts, using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scp&lt;/code&gt; to copy them to RTC, and putting together some basic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.gmi&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blog.gmi&lt;/code&gt; files, and I had a live &lt;a href=&quot;gemini://rawtext.club/~ecliptik/&quot;&gt;Gemini capsule&lt;/a&gt; and running. This was nice, but I wanted to publish posts on this blog to both Gopherspace and Geminispace together and needed something that would have some additional features,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Convert Jekyll markdown to Gopher and Gemtext&lt;/li&gt;
  &lt;li&gt;Create a 10 most recent posts page and an archive page of all posts&lt;/li&gt;
  &lt;li&gt;Add tags to posts, group posts by tags, and have all tags listed on the archive page&lt;/li&gt;
  &lt;li&gt;Basic header/footer support&lt;/li&gt;
  &lt;li&gt;Build a &lt;a href=&quot;https://tildegit.org/solderpunk/gemfeed&quot;&gt;gemfeed&lt;/a&gt; to syndicate in Geminispace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Iterating on the &lt;a href=&quot;https://www.ecliptik.com/Making-a-Gopherhole-and-Phlog/&quot;&gt;tools I wrote for Gopher&lt;/a&gt; by including using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;md2gemini&lt;/code&gt; to convert to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemtext&lt;/code&gt; got me partially there, but was still missing some more features. After more iterations, I had &lt;a href=&quot;https://github.com/ecliptik/ecliptik.github.io/blob/master/_scripts/updatesmallweb.sh&quot;&gt;updatesmallweb.sh&lt;/a&gt; that converts Jekyll posts to Gopher and Gemini. Now whenever I publish a post on Jekyll, I can run this script to convert the post to Gopher and Gemini. Doing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git push&lt;/code&gt; to github, then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; on RTC and everything is up-to-date.&lt;/p&gt;

&lt;p&gt;Here’s the script in action building the gopherhole and capsule,&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;micheal &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;git/ecliptik.github.io/_scripts on  master &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$!&lt;/span&gt;?] took 2s
🚀➜ ./updatesmallweb.sh &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; all
Converting post ../_posts/2011-01-22-Vim-rdesktop-external-monitors-and-X-Forwarding-on-a-Google-CR-48.md to gopher
Converting post ../_posts/2015-08-20-Building-a-website-with-Github-and-Jekyll.md to gopher
Converting post ../_posts/2015-08-21-Decompiling-Interactive-Fiction.md to gopher
Converting post ../_posts/2015-08-28-Emulating-ARM64-on-Linux.md to gopher
Converting post ../_posts/2015-08-29-Containerizing-a-Perl-Script.md to gopher
Converting post ../_posts/2015-09-08-Automating-Container-Updates-With-Watchtower.md to gopher
Converting post ../_posts/2017-09-11-Raspberry-Pi-Kubernetes-Cluster.md to gopher
Converting post ../_posts/2017-09-12-ACI-Connector-for-k8s-on-a-Raspberry-Pi-Cluster.md to gopher
Converting post ../_posts/2017-10-02-Cross-Building-and-Running-Multi-Arch-Docker-Images.md to gopher
Converting post ../_posts/2021-01-26-One-Week-With-Mastodon.md to gopher
Converting post ../_posts/2021-01-31-Making-a-Gopherhole-and-Phlog.md to gopher
Converting post ../_posts/2021-02-09-Launching-a-Gemini-Capsule.md to gopher
Creating gophermap: ../_gopher/_posts/gophermap
Converting post ../_posts/2011-01-22-Vim-rdesktop-external-monitors-and-X-Forwarding-on-a-Google-CR-48.md to gemini
Creating tag page ../_gemini/_tags/vim.gmi
Creating tag page ../_gemini/_tags/google.gmi
Creating tag page ../_gemini/_tags/cr-48.gmi
Creating tag page ../_gemini/_tags/linux.gmi
Creating tag page ../_gemini/_tags/blogger.gmi
Converting post ../_posts/2015-08-20-Building-a-website-with-Github-and-Jekyll.md to gemini
Creating tag page ../_gemini/_tags/docker.gmi
Creating tag page ../_gemini/_tags/jekyll.gmi
Creating tag page ../_gemini/_tags/github.gmi
Converting post ../_posts/2015-08-21-Decompiling-Interactive-Fiction.md to gemini
Creating tag page ../_gemini/_tags/zmachine.gmi
Creating tag page ../_gemini/_tags/interactivefiction.gmi
Creating tag page ../_gemini/_tags/zork.gmi
Converting post ../_posts/2015-08-28-Emulating-ARM64-on-Linux.md to gemini
Creating tag page ../_gemini/_tags/operatingsystems.gmi
Creating tag page ../_gemini/_tags/arm.gmi
Creating tag page ../_gemini/_tags/ubuntu.gmi
Converting post ../_posts/2015-08-29-Containerizing-a-Perl-Script.md to gemini
Creating tag page ../_gemini/_tags/perl.gmi
Creating tag page ../_gemini/_tags/containers.gmi
Converting post ../_posts/2015-09-08-Automating-Container-Updates-With-Watchtower.md to gemini
Creating tag page ../_gemini/_tags/watchtower.gmi
Converting post ../_posts/2017-09-11-Raspberry-Pi-Kubernetes-Cluster.md to gemini
Creating tag page ../_gemini/_tags/kubernetes.gmi
Creating tag page ../_gemini/_tags/raspberrypi.gmi
Converting post ../_posts/2017-09-12-ACI-Connector-for-k8s-on-a-Raspberry-Pi-Cluster.md to gemini
Creating tag page ../_gemini/_tags/azure.gmi
Converting post ../_posts/2017-10-02-Cross-Building-and-Running-Multi-Arch-Docker-Images.md to gemini
Converting post ../_posts/2021-01-26-One-Week-With-Mastodon.md to gemini
Creating tag page ../_gemini/_tags/mastodon.gmi
Creating tag page ../_gemini/_tags/fediverse.gmi
Creating tag page ../_gemini/_tags/100daystooffload.gmi
Converting post ../_posts/2021-01-31-Making-a-Gopherhole-and-Phlog.md to gemini
Creating tag page ../_gemini/_tags/gopher.gmi
Converting post ../_posts/2021-02-09-Launching-a-Gemini-Capsule.md to gemini
Creating tag page ../_gemini/_tags/gemini.gmi
Creating tag page ../_gemini/_tags/smallweb.gmi
Creating gemlog index: ../_gemini/gemlog.gmi
Creating archive index: ../_gemini/_posts/index.gmi
Creating tag index page: ../_gemini/_tags/index.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/100daystooffload.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/arm.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/azure.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/blogger.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/containers.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/cr-48.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/docker.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/fediverse.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/gemini.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/github.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/google.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/gopher.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/index.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/interactivefiction.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/jekyll.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/kubernetes.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/linux.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/mastodon.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/operatingsystems.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/perl.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/raspberrypi.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/smallweb.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/ubuntu.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/vim.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/watchtower.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/zmachine.gmi
Adding tag &lt;span class=&quot;nb&quot;&gt;link &lt;/span&gt;gemini://rawtext.club/~ecliptik/_tags/zork.gmi
Generating feed &lt;span class=&quot;s2&quot;&gt;&quot;Gemlog Archive&quot;&lt;/span&gt;, which should be served from gemini://rawtext.club/~ecliptik/_posts/feed.xml
Adding 2021-02-09-Launching-a-Gemini-Capsule.gmi with title &lt;span class=&quot;s1&quot;&gt;&apos;Launching a Gemini Capsule&apos;&lt;/span&gt;...
Adding 2021-01-31-Making-a-Gopherhole-and-Phlog.gmi with title &lt;span class=&quot;s1&quot;&gt;&apos;Making a Gopherhole and Phlog&apos;&lt;/span&gt;...
Adding 2021-01-26-One-Week-With-Mastodon.gmi with title &lt;span class=&quot;s1&quot;&gt;&apos;One Week With Mastodon&apos;&lt;/span&gt;...
Adding 2017-10-02-Cross-Building-and-Running-Multi-Arch-Docker-Images.gmi with title &lt;span class=&quot;s1&quot;&gt;&apos;Cross Building and Running Multi-Arch Docker Images&apos;&lt;/span&gt;...
Adding 2017-09-12-ACI-Connector-for-k8s-on-a-Raspberry-Pi-Cluster.gmi with title &lt;span class=&quot;s1&quot;&gt;&apos;ACI Connector for k8s on a Raspberry Pi Cluster&apos;&lt;/span&gt;...
Adding 2017-09-11-Raspberry-Pi-Kubernetes-Cluster.gmi with title &lt;span class=&quot;s1&quot;&gt;&apos;Raspberry Pi Kubernetes Cluster&apos;&lt;/span&gt;...
Adding 2015-09-08-Automating-Container-Updates-With-Watchtower.gmi with title &lt;span class=&quot;s1&quot;&gt;&apos;Automating Container Updates With Watchtower&apos;&lt;/span&gt;...
Adding 2015-08-29-Containerizing-a-Perl-Script.gmi with title &lt;span class=&quot;s1&quot;&gt;&apos;Containerizing a Perl Script&apos;&lt;/span&gt;...
Adding 2015-08-28-Emulating-ARM64-on-Linux.gmi with title &lt;span class=&quot;s1&quot;&gt;&apos;Emulating ARM64 on Linux&apos;&lt;/span&gt;...
Adding 2015-08-21-Decompiling-Interactive-Fiction.gmi with title &lt;span class=&quot;s1&quot;&gt;&apos;Decompiling Interactive Fiction&apos;&lt;/span&gt;...
Wrote Atom feed to ../_gemini/_posts/feed.xml.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/launching-a-gemini-capsule/gemlog-in-lagrange.png&quot; alt=&quot;Gemlog in Lagrange&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Gemlog in Lagrange&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next&lt;/h2&gt;

&lt;p&gt;Now that I have a better understanding of how Gopher and Gemini work, and have some tooling to make things seamless between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gopher://&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gemini://&lt;/code&gt;, my plans are to improve &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;updatesmallweb.sh&lt;/code&gt; so it’s almost a static site generator. Some of the documentation and examples needs updating as well, so others can use it, and already &lt;a href=&quot;gemini://gemini.lottalinuxlinks.com&quot;&gt;gemini://gemini.lottalinuxlinks.com&lt;/a&gt; has.&lt;/p&gt;

&lt;p&gt;Gemini is one of those things that you either really like or don’t quite understand it. I’m in the former group, as it reminds me of what the Internet was before it turned into what it is today. The phrase “Eternal August” is one that comes to mind, as it’s specification is not meant to really be improved upon and should remain the same for the foreseeable future. This allows creativity to flourish in a restricted environment, like the Demo Scene or modern homebrew Gameboy Games.&lt;/p&gt;

&lt;p&gt;For more on exploring Geminispace, see &lt;a href=&quot;https://github.com/kr1sp1n/awesome-gemini&quot;&gt;awesome-gemini&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Tue, 09 Feb 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/Launching-a-Gemini-Capsule/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/Launching-a-Gemini-Capsule/</guid>
        
        <category>gemini</category>
        
        <category>smolweb</category>
        
        <category>100daystooffload</category>
        
        
        <category>gemini</category>
        
      </item>
    
      <item>
        <title>Making a Gopherhole and Phlog</title>
        <description>&lt;h2 id=&quot;but-why&quot;&gt;But Why?&lt;/h2&gt;

&lt;p&gt;The obvious questions is why make a Gopherhole (what &lt;a href=&quot;https://en.wikipedia.org/wiki/Gopher_(protocol)&quot;&gt;gopher&lt;/a&gt; sites are called) when all the action is on the &lt;a href=&quot;https://en.wikipedia.org/wiki/World_Wide_Web&quot;&gt;World Wide Web&lt;/a&gt; over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;html&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt;? Didn’t those protocols win the Internet two decades ago? I didn’t really think much about Gopher until I started reading more about the newer &lt;a href=&quot;https://gemini.circumlunar.space&quot;&gt;Gemini&lt;/a&gt; protocol on my foray &lt;a href=&quot;/blog/2021/One-Week-With-Mastodon/&quot;&gt;into Mastodon&lt;/a&gt; last week and figuratively went “down” the Gopherhole.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/making-a-gopherhole-and-phlog/gopher-slides.png&quot; alt=&quot;Slides from 1992 Gopher presentation&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Slides from 1992 Gopher presentation&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;I was suprised to find not only a flourishing community, but was drawn to the simplicity of the protocol and creating for it. No more thinking about CSS oddities, having to learn whole web stacks with the latest-and-greatest toolsets. Most of what Gopher is now is the same as it was in the early 90s and it’s something you can easily start learning about and doing without sinking a lot of time and effort just to get started. It reminds of learning Latin, even though it’s a dead language, it’s still useful and it will never change. It also has the advantages of being almost entirely text based and there’s no tracking, cookies, or any of the risks and privacy concerns associated with the modern web.&lt;/p&gt;

&lt;p&gt;For a much more in-depth look on modern Gopher, I recommend reading &lt;a href=&quot;https://tedium.co/2017/06/22/modern-day-gopher-history/&quot;&gt;Burrowing A Gopher Hole&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;start-burrowing&quot;&gt;Start Burrowing&lt;/h2&gt;

&lt;p&gt;The first thing I needed to to was figure out how to host a Gopherhole. I could run it myself locally, and was thinking of re-purposing one of &lt;a href=&quot;/blog/2017/Raspberry-Pi-Kubernetes-Cluster/&quot;&gt;my numerous raspberrypis&lt;/a&gt; to self-host it over port 70. I even got as far as trying to make a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; to run &lt;a href=&quot;http://www.gophernicus.org&quot;&gt;gophernicus&lt;/a&gt; in a container and maybe even get it to run in Kubernetes! I quickly realized this was missing the point of slowing down and focusing on the simplicity that intially drew me in the first place and scrapped this idea.&lt;/p&gt;

&lt;p&gt;While browsing Gemini capsules (the term for Gemini sites), I came across the &lt;a href=&quot;https://github.com/cwmccabe/pubnixhist&quot;&gt;PubNix&lt;/a&gt; &lt;a href=&quot;https://rawtext.club&quot;&gt;RawText.club&lt;/a&gt;, whose mission fit  with the themes of simplicity and do-it-yourself while offering some basic hosting services for gopher, gemini, and web.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;RTC is a non-profit, do-it-yourself social network that uses a smaller, simpler, user-built toolkit. We are proudly the polar opposite of the big, exploitative, corporate-owned social media mega-sites. Not cool. Not easy. Not big. rawtext.club is what you make it. The point is that you can do a LOT using very minimal resources by stringing together command line tricks on a Linux system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I pondered joining for a few days to make sure I would stick with the commitment and didn’t want to join and then lose interest a few weeks later. Even though RTC is a “slow” social network, I wanted to actively particpate in the community and not just be passive and looking for a free handout. Eventually I sent an invite request and was extended a membership. The first few days I spent checking out RTC from the cli; creating a prescense and reading the man pages for the local tools (which are excellent).&lt;/p&gt;

&lt;p&gt;Finally I started adding things in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~ecliptik/public_gopher&lt;/code&gt; and got to work on making a gohperhole. Creating a gopherhole has been well covered by others in other blog posts, which I heavily referenced when making the site,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://johngodlee.github.io/2019/11/20/gopher.html&quot;&gt;Making a Gopherhole&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://jfm.carcosa.net/blog/computing/hugo-gopher/&quot;&gt;Generating a Gopher site with Hugo&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://petermolnar.net/article/gopher/&quot;&gt;Gopher? Gopher.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On RTC, home directories are world readable, so I poked around in some more well-known users &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public_gopher&lt;/code&gt; dirs and saw how their gopherholes were setup. I used the gopher browser &lt;a href=&quot;https://bombadillo.colorfield.space&quot;&gt;Bombadillo&lt;/a&gt; as my main tool to view Gopherspace, and coincidentally &lt;a href=&quot;https://gmi.skyjake.fi/lagrange/&quot;&gt;Lagrange&lt;/a&gt;, the browser I was using to browse Gemini, also supported gopher and would use it occasionally as a GUI view.&lt;/p&gt;

&lt;p&gt;The resulting gopherhole was relatively simple,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[ecliptik@rawtext public_gopher]$ tree .
.
├── about.txt -&amp;gt; ../.who-is
├── gophermap
└── phlog

1 directory, 2 files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The about page is a symlink to my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.who-is&lt;/code&gt; (which is used on RTC as a profile), a link to the Phlog dir, a web link to the www page, and a link back to the RTC gopherhole. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gophermap&lt;/code&gt; for this was simple.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Welcome to ecliptik&apos;s Gopherhole

Nav:
0About	about.txt
1Phlog	./phlog

Links:
hecliptik.com	URL:https://www.ecliptik.com
1rawtext.club	/       rawtext.club    70
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The most difficulty I had was getting the link identifiers and tabs in the correct places.&lt;/p&gt;

&lt;p&gt;Adding these files made the site live at &lt;a href=&quot;gopher://rawtext.club:70/~ecliptik&quot;&gt;gopher://rawtext.club:70/1~ecliptik&lt;/a&gt;. If you don’t have a gopher browser installed it’s viewable through a &lt;a href=&quot;https://gopher.floodgap.com/gopher/gw?a=gopher%3A%2F%2Frawtext.club%3A70%2F1%7Eecliptik&quot;&gt;gopher proxy&lt;/a&gt; from &lt;a href=&quot;https://www.floodgap.com&quot;&gt;Floodgap&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;           Welcome to ecliptik&apos;s Gopherhole
           
           Nav:
TXT   [1]  About
MAP   [2]  Phlog
           
           Links:
HTM   [3]  ecliptik.com
MAP   [4]  rawtext.club
           ___________________________________________________________________
                              Gophered by Gophernicus/3.1 on Arch/5.10 x86_64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;figure&gt;&lt;figcaption&gt;Viewed in Bombadillo&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/making-a-gopherhole-and-phlog/gopher-lagrange-01.png&quot; alt=&quot;Gopherhole in Lagrange Browser&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Gopherhole in Lagrange Browser&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h2 id=&quot;phlog&quot;&gt;Phlog&lt;/h2&gt;

&lt;p&gt;After getting the basic site up I wanted to update it frequently with a Phlog, which is the gopher equivalent of a Blog. Since I already have this blog with &lt;a href=&quot;/blog/2015/Building-a-website-with-Github-and-Jekyll/&quot;&gt;Jekyll&lt;/a&gt; and uses markdown for posts, I thought I might as well mirror these posts to the Phlog. I also decided to only do the pure markdown posts, as some of the older posts on the blog were converted from &lt;a href=&quot;https://junocake.blogspot.com&quot;&gt;my old blogger site&lt;/a&gt; and are HTML. Having to convert all of those to markdown or writing scripts to also convert HTML was a bit too much for this project.&lt;/p&gt;

&lt;p&gt;A few others have already done this, as referenced above for Jekyll and Hugo already, but I wanted to do my own take on it. Originally I wrote a script that would convert a post to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gophermap&lt;/code&gt;, converting the links to blocks, identifying what type they were and creating item links.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#Convert a jekyll markdown post to a gophermap&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#Will create a sub-directory with the name of the post and a gophermap&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#converted to  70 columns with links. Tries to do basic http or gopher&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#linking. May not work well, but works well enough.&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# usage: ./md2gophermap.sh ../_posts/post-to-convert.md&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Know Bugs&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#Pandoc does not wrap code blocks to the columns length and will get cut&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#off when rendered in the gophermap.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#see: https://github.com/jgm/pandoc/issues/4302#issuecomment-360669013&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Take input and craft output file and directory vars for use later on&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;basename&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;outdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;basename&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; .md &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;converting &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
pandoc &lt;span class=&quot;nt&quot;&gt;--from&lt;/span&gt; markdown &lt;span class=&quot;nt&quot;&gt;--to&lt;/span&gt; markdown &lt;span class=&quot;nt&quot;&gt;--reference-links&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--reference-location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;block &lt;span class=&quot;nt&quot;&gt;--columns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;70 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Do some IFS changes in order to properly parse individual lines after conversion&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;IFSORIG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;IFS&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;IFS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;
&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Create gophermap&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;##HTML link syntax&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#hecliptik.com	URL:https://www.ecliptik.com&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;##Gopher link syntax&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#1rawtext.club	/	rawtext.club	70&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Go through the file line-by-line looking for http or gopher linkes and convert&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;line &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
  &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;IFS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;IFSORIG&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | egrep &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;^.+&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.+&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\]&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:.+&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then

    case&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;http&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;itemname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; |sed &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s/\[(.*)\]/\1/&apos;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;print $1&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; |xargs&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;itemlink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; |awk &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;print $2&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s%:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;%%&quot;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;h&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;itemname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;URL:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;itemlink&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;gopher&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;itemname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; |sed &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s/\[(.*)\]/\1/&apos;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;print $1&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; |xargs&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;itemserver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; |awk &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;/ &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;print $3&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;print $1&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;itemlink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; |awk &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;/ &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;print $4&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;itemname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;itemlink&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;itemserver&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;70&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#Set IFS to new line in order to remove leading spaces&lt;/span&gt;
 &lt;span class=&quot;nv&quot;&gt;IFS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;
&quot;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;#Escape all special chars so they&apos;re replaced in sed&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;linemung&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s`[][\\/.*^$]`\\&amp;amp;`g&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;itemmung&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s`[][\\/.*^$]`\\&amp;amp;`g&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;#Replace markdown blocks with gophermap&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;linemung&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;itemmung&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/g&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;fi
done&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Make the subdirectory&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;outdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Use the top of the original Markdown file to create a basic header&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;layout&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;category&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;outdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/gophermap
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;outdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/gophermap
&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;outdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/gophermap

&lt;span class=&quot;c&quot;&gt;#Convert --- lines to underscore&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s/^--.+&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%.0s_&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0..69&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/g&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;outdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/gophermap
&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s/^==.+&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%.0s_&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0..69&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/g&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;outdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/gophermap

&lt;span class=&quot;c&quot;&gt;#Remove the pandoc output file to clean up&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This worked out well, where a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gophermap&lt;/code&gt; for each post under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_posts&lt;/code&gt; was formatted properly into their own directories, wrapping was done, and the item links worked. However it just looked sort of off, and there was an issue where code blocks would not be wrapped by &lt;a href=&quot;https://pandoc.org/&quot;&gt;pandoc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I decided then to just convert them to plaintext and not do a full &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gophermap&lt;/code&gt;, which preserved the formatting, wrapped text blocks more accurately, and just looked better in general. Most of the links in the posts are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; anyway, so if they were followed they’d open in a web browser anyway.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#Convert a jekyll markdown post to plaintext suitable for gopher,&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#converted to  70 columns&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#usage: ./md2gopher.sh ../_posts/post-to-convert.md&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Take input and craft output file and directory vars for use later on&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;outdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;_posts&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;outdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;basename&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; .md &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.txt&quot;&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;outdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;converting &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; to &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
pandoc &lt;span class=&quot;nt&quot;&gt;--from&lt;/span&gt; markdown &lt;span class=&quot;nt&quot;&gt;--to&lt;/span&gt; plain &lt;span class=&quot;nt&quot;&gt;--reference-links&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--reference-location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;block &lt;span class=&quot;nt&quot;&gt;--columns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;70 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.tmp &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Use the top of the original Markdown file to create a basic header&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-6&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;layout&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;category&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.tmp &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.tmp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These plaintext posts rendered much nicer and I was happy with how they turned out.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/making-a-gopherhole-and-phlog/gopher-phlog-post-01.png&quot; alt=&quot;Phlog post in Bombadillo&quot; /&gt;&lt;/p&gt;
&lt;figure&gt;&lt;figcaption&gt;Phlog post in Bombadillo&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;One final step was automatically generating a Phlog index of posts. The post &lt;a href=&quot;https://johngodlee.github.io/2019/11/20/gopher.html&quot;&gt;Making a Gopherhole&lt;/a&gt; that I used when making my own Gopherhole had a script on taking the last 10 posts and generating a gophermap of them. I took this script and modified it some to include some things like a basic layout template.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Create gophermap of last 10 posts&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#Originally from: https://johngodlee.github.io/2019/11/20/gopher.html&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Use layout file for header on gophermap&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;_layouts/phlog &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; gophermap

&lt;span class=&quot;nv&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=(&lt;/span&gt;_posts/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.txt&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Reverse order of posts array&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${#&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[@]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; i&amp;gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; i-- &lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
  &lt;/span&gt;rev_all[&lt;span class=&quot;k&quot;&gt;${#&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rev_all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[@]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[i]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Get 10 most recent posts&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;recent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rev_all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[@]&lt;/span&gt;:0:10&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Add recent post links to gophermap&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$recent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
  &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 4 &lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;title:&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;print $2&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; | xargs&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;0&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; gophermap
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Append footer with html link&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; gophermap
&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;%.0s_&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0..69&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; gophermap
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; gophermap
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;hecliptik.com	URL:https://www.ecliptik.com&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; gophermap
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The gophermap created while not fancy works well in displaying the latest 10 posts,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;                                  ecliptik&apos;s phlog
           ___________________________________________________________________
           
                 These posts are mirrored from https://www.ecliptik.com
           ___________________________________________________________________
           
           Latest 10 posts
           ___________________________________________________________________
           
TXT   [1]  One Week With Mastodon
TXT   [2]  ACI Connector for k8s on a Raspberry Pi Cluster
TXT   [3]  Raspberry Pi Kubernetes Cluster
TXT   [4]  Cross Building and Running Multi-Arch Docker Images
TXT   [5]  Automating Container Updates With Watchtower
TXT   [6]  Containerizing a Perl Script
TXT   [7]  Emulating ARM64 on Linux
TXT   [8]  Decompiling Interactive Fiction
TXT   [9]  Building a website with Github and Jekyll
TXT  [10]  Vim, rdesktop, external monitors, and X Forwarding on a Google CR-48
           
           ___________________________________________________________________
HTM  [11]  ecliptik.com
           ___________________________________________________________________
                              Gophered by Gophernicus/3.1 on Arch/5.10 x86_64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While writing these tools I initially was creating them on my laptop, putting them into a tarball, scping them to RTC and then untarring them. This added a lot of manual steps into the process, so I took the more modern workflow of checking the converted posts into git, cloning them to RTC, the symlinking them from the gopherhole. This way after writing a post (such as this one), I’ll run the scripts, push and then pull on RTC and my phlog will be updated along with the WWW site.&lt;/p&gt;

&lt;p&gt;These tools and usage are describe more in their &lt;a href=&quot;https://github.com/ecliptik/ecliptik.github.io/blob/master/_gopher/README.md&quot;&gt;README.md&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;While gopher didn’t win against the web in the early 90’s, it’s sense of simplicity really shines in todays modern and complex Internet. I’ve already found a lot of interesting content while browsing gopherspace that I wouldn’t find on the WWW and there is much more a sense of community, similar to what the web was like in the early days before modern social networking.&lt;/p&gt;
</description>
        <pubDate>Sun, 31 Jan 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/Making-a-Gopherhole-and-Phlog/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/Making-a-Gopherhole-and-Phlog/</guid>
        
        <category>gopher</category>
        
        <category>100daystooffload</category>
        
        
        <category>gopher</category>
        
      </item>
    
      <item>
        <title>One Week With Mastodon</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;One week ago I posted &lt;a href=&quot;https://fosstodon.org/@ecliptik/105585397423041642&quot;&gt;my first toot&lt;/a&gt; on &lt;a href=&quot;https://joinmastodon.org&quot;&gt;Mastodon&lt;/a&gt; and I want to document my first weeks experience since it was much more eventful than I was expecting.&lt;/p&gt;

&lt;h2 id=&quot;choosing-an-instance&quot;&gt;Choosing an Instance&lt;/h2&gt;

&lt;p&gt;One of the first things you do when signing up for Mastodon is &lt;a href=&quot;https://joinmastodon.org/communities&quot;&gt;choose an instance&lt;/a&gt;. I didn’t quite understand this at first, but eventually realized it was akin to choosing a Geocities neighborhood in the 90s. The instance you sign up for is like a community, with similar interests and themes that best fit your online identity and personality. After reading about different intances and browsing public timelines of users, I choose &lt;a href=&quot;https://hub.fosstodon.org/about/&quot;&gt;Fosstodon&lt;/a&gt; as my home instance. I was drawn to their focus on &lt;a href=&quot;https://en.wikipedia.org/wiki/Free_and_open-source_software&quot;&gt;Free and Open Source Software&lt;/a&gt;, which fits my style of computing and online interests.&lt;/p&gt;

&lt;h2 id=&quot;trying-things-out&quot;&gt;Trying Things Out&lt;/h2&gt;

&lt;p&gt;The first few days I posted a few toots, followed some users on federated instances, and occasionally checked in on the local and federated timelines. I quickly realized that the federated timeline (a timeline which contains posts from all federated instances outside of Fosstodon) wasn’t really for me, but the local timeline for Fosstodon was interesting. Because Fosstodon is only a few thousand users, there wasn’t a firehose of posts to keep up on, and most users were posting links and comments on things that resonated with me.&lt;/p&gt;

&lt;p&gt;Checking in on the &lt;a href=&quot;https://fosstodon.org/web/timelines/public/local&quot;&gt;local feed&lt;/a&gt; every few hours gave insight into what types of posts would add to the community and I started putting a few things out there just to test out the interface and gain confidence in using the service.&lt;/p&gt;

&lt;h2 id=&quot;gemini-and-gopherspace&quot;&gt;Gemini and Gopherspace&lt;/h2&gt;

&lt;p&gt;The first topic that really caught my eye was I saw the hashtag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#gemini&lt;/code&gt; trending on Fosstodon. I thought maybe it was related to space (which is sort of is), and after following the tag and reading toots from other users I discovered &lt;a href=&quot;https://gemini.circumlunar.space&quot;&gt;Project Gemini&lt;/a&gt;. This in turn lead me to installing the &lt;a href=&quot;https://gmi.skyjake.fi/lagrange/&quot;&gt;Lagrange&lt;/a&gt; and &lt;a href=&quot;https://bombadillo.colorfield.space&quot;&gt;Bombadillo&lt;/a&gt; browsers. From there I started exploring all the sites I could find on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gemini://&lt;/code&gt;, and eventually started browsing &lt;a href=&quot;https://en.wikipedia.org/wiki/Gopher_%28protocol%29&quot;&gt;Gopherspace&lt;/a&gt; (which is very much alive even in 2021). This re-kindled a curiosity of using networked computers that I haven’t felt since using &lt;a href=&quot;https://en.wikipedia.org/wiki/FidoNet&quot;&gt;Fidonet&lt;/a&gt; and browsing my local BBS in the 90s.&lt;/p&gt;

&lt;h2 id=&quot;512kb-club&quot;&gt;512KB Club&lt;/h2&gt;

&lt;p&gt;The next trending hashtag I saw was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#512kbclub&lt;/code&gt;, which is a challenge to &lt;a href=&quot;https://512kb.club&quot;&gt;bring your personal websites homepage under 512KB&lt;/a&gt;. This site came in at 252KB total size without any tuning and I submitted it for inclusion and was added to the Blue team, just missing the Orange team cutoff. Looking more closely at the sites components, much of it was Google Analytics, taking up around 138KB of the sites size. I posted a &lt;a href=&quot;https://fosstodon.org/web/statuses/105600821471040740&quot;&gt;toot&lt;/a&gt; about joining the 512KB club and if there were any replacements for Google Analytics and recieved some helpful replies with alternatives. I replaced Google Analytics with &lt;a href=&quot;https://www.goatcounter.com&quot;&gt;Goat Counter&lt;/a&gt; and saw that the site was including &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jquery&lt;/code&gt; but not using it, that brought the site down to 24.7KB and into Green team (&amp;lt;100KB) territory.&lt;/p&gt;

&lt;h2 id=&quot;100daystooffload&quot;&gt;100DaysToOffload&lt;/h2&gt;

&lt;p&gt;Another trending hastag was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#100daystooffload&lt;/code&gt;, a challenge to &lt;a href=&quot;https://100daystooffload.com&quot;&gt;write 100 personal blog posts in one year&lt;/a&gt;. This post is the first in what I hope will be many to participate in this challenge. I like the idea since it gives a goal to strive for and even if no one reads them it will provide personal growth experience.&lt;/p&gt;

&lt;h2 id=&quot;bitwarden&quot;&gt;Bitwarden&lt;/h2&gt;

&lt;p&gt;About a year ago I started looking into alternative for LastPass as my password manager, as annual pricing had increased since I first started using it years ago and I knew there were better products out there. Inspired by seeing others on Fosstodon taking up tools and learning new things, I finally did the migration to &lt;a href=&quot;https://bitwarden.com&quot;&gt;Bitwarden&lt;/a&gt;, which was a much easier process than I expected.&lt;/p&gt;

&lt;h2 id=&quot;screenshotsunday&quot;&gt;ScreenShotSunday&lt;/h2&gt;

&lt;p&gt;It turns out on Sundays a thing to do on Fosstodon is post screenshots with the tag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#screenshotsunday&lt;/code&gt;. Since I have a post on &lt;a href=&quot;/blog/2008/Screenshots-Over-the-Years/&quot;&gt;screenshots through the years&lt;/a&gt; I tooted an old screenshot from &lt;a href=&quot;https://fosstodon.org/@ecliptik/105611942604393139&quot;&gt;RedHat Linux 6.1 in 2000&lt;/a&gt; and got a lot of positive responses, boosts, and followers leading to my highest “engagement”.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Much more happened than and I was expecting when I first thought about joining Mastodon last week. Because of the level of community and quality of posts, using Mastodon is much more rewarding than using Twitter where it feels overwhelming to keep up and posting is like shouting into a crowd of millions hoping a few will hear. I’m really looking forward to what will come with using Mastodon, and possibly other &lt;a href=&quot;https://fediverse.party&quot;&gt;Fediverse&lt;/a&gt;, in the future.&lt;/p&gt;

&lt;p&gt;The one critique I have of using Mastodon is interacting with other federated instances. When following users on other instances, the standard flow is to pop-up a seperate window and having to copy/paste your account in order to complete the action. I would expect since you’re signed into an instance already that it would somehow automaticaly fill this in or just be more seamless overall. This may just be the way it works since they are federated, but it feels clunkier than it should.&lt;/p&gt;
</description>
        <pubDate>Tue, 26 Jan 2021 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2021/One-Week-With-Mastodon/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2021/One-Week-With-Mastodon/</guid>
        
        <category>mastodon</category>
        
        <category>fediverse</category>
        
        <category>100daystooffload</category>
        
        
        <category>mastodon</category>
        
      </item>
    
      <item>
        <title>Cross Building and Running Multi-Arch Docker Images</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;When running a &lt;a href=&quot;http://www.ecliptik.com/Raspberry-Pi-Kubernetes-Cluster/&quot;&gt;Raspberry Pi cluster&lt;/a&gt;, sometimes there’s just not enough power to build native armhf Docker images in a reasonable amount of time.&lt;/p&gt;

&lt;p&gt;While the recent announcement of &lt;a href=&quot;https://integratedcode.us/2017/09/13/dockerhub-official-images-go-multi-platform/&quot;&gt;Docker Hub Official Multi-platform support&lt;/a&gt; makes it easier to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run&lt;/code&gt; official multi-arch images, building a multi-arch image still requires a cross-build environment to speed up builds on lower powered hardware or when you don’t have the native platform.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Cross-building is defined as building a foreign architecture image different from the hosts architecture, such as building a armhf image on a x86 machine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are three methods of cross-building and running multi-arch Docker images each with different considerations,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#docker-for-mac&quot;&gt;Docker for Mac&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#multiarch-on-linux&quot;&gt;Multiarch on Linux&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#qemu-on-linux&quot;&gt;QEMU on Linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;docker-for-mac&quot;&gt;Docker for Mac&lt;/h2&gt;

&lt;p&gt;Since the original beta, &lt;a href=&quot;https://www.docker.com/docker-mac&quot;&gt;Docker for Mac&lt;/a&gt; has had &lt;a href=&quot;https://en.wikipedia.org/wiki/Binfmt_misc&quot;&gt;binfmt_misc&lt;/a&gt; support &lt;a href=&quot;https://twitter.com/quintus23m/status/713523016836231171&quot;&gt;built-in&lt;/a&gt;, which allows it to execute arm containers on x86 without any additional configuration.&lt;/p&gt;

&lt;p&gt;If you have Docker for Mac you can test this out by running any multi-arch Docker image from Docker Hub such as the official &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arm32v7/debian&lt;/code&gt; image,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;🐳 uname -a
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;Darwin sheik.local 16.7.0 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;root:xnu-3789.70.16~2/RELEASE_X86_64 x86_64 i386 MacBookPro11,3 Darwin
&lt;span class=&quot;go&quot;&gt;
🐳 docker run -it --rm arm32v7/debian /bin/bash
Unable to find image &apos;arm32v7/debian:latest&apos; locally
latest: Pulling from arm32v7/debian
d0e027c48353: Pull complete
Digest: sha256:d74cc69431f03bbfbbf9fd52c1eabd6ca491280a03da267acb63b65b81e30c8a

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;/ #&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;Linux 4372bf9a3462 4.9.41-moby #&lt;/span&gt;1 SMP Wed Sep 6 00:05:16 UTC 2017 armv7l GNU/Linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Building an image is as easy as taking an existing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; and changing it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FROM&lt;/code&gt; to point to a base multi-arch image. Depending on the image, it may fail if non-architecture binaries run, such as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wget&lt;/code&gt; to download and run a non-native binary.&lt;/p&gt;

&lt;p&gt;For example to re-build the &lt;a href=&quot;https://github.com/nodejs/docker-node/blob/c37d5e87fa6d46c0e387f73161b056bbf90b83aa/8.6/stretch/Dockerfile&quot;&gt;NodeJS Debian Image&lt;/a&gt; for arm32v7.&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;🐳 curl -sSL https://raw.githubusercontent.com/nodejs/docker-node/c37d5e87fa6d46c0e387f73161b056bbf90b83aa/8.6/stretch/Dockerfile | sed &quot;s/buildpack-deps:stretch/arm32v7\/buildpack-deps:stretch/g&quot; &amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;Dockerfile.nodejs.armhf
&lt;span class=&quot;go&quot;&gt;
🐳 docker build -f Dockerfile.nodejs.armhf -t nodejs:armhf .
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;considerations&quot;&gt;Considerations&lt;/h3&gt;

&lt;p&gt;This is the easiest and quickest way to build an run any 32-bit or 64-bit Docker images. Disadvantages are you must be running macOS and are limited by the hardware macOS will run on, this isn’t an option for large multi-cpu cloud instance types that run Linux.&lt;/p&gt;

&lt;h2 id=&quot;multiarch-on-linux&quot;&gt;Multiarch on Linux&lt;/h2&gt;

&lt;p&gt;Most major Linux distributions have a way of setting up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binfmt_misc&lt;/code&gt; using qemu and other cross-architecture tools. These can be quite complicated to setup and rely on distribution specific knowledge. The &lt;a href=&quot;https://github.com/multiarch&quot;&gt;Multiarch Project&lt;/a&gt; makes setting up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binfmt_misc&lt;/code&gt; much easier by wrapping the whole process in a Docker image itself called &lt;a href=&quot;https://github.com/multiarch/qemu-user-static&quot;&gt;qemu-user-static&lt;/a&gt;. This will install and setup the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-*-static&lt;/code&gt; configurations for all architectures excluding the native hardware.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Installing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-user-static&lt;/code&gt; using a container requires privileged mode since it will register binaries in the host systems &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc&lt;/code&gt; space&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To setup &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-user-static&lt;/code&gt;, follow the &lt;a href=&quot;https://github.com/multiarch/qemu-user-static/blob/master/README.md&quot;&gt;README&lt;/a&gt;, which basically consists of,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;🐳 docker run --rm --privileged multiarch/qemu-user-static:register
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-user-static&lt;/code&gt; setup, test &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-user-static&lt;/code&gt; support works with a Multiarch image,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;🐳 uname -a
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;Linux jezebel 4.9.0-3-amd64 #&lt;/span&gt;1 SMP Debian 4.9.30-2+deb9u2 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;2017-06-26&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; x86_64 GNU/Linux
&lt;span class=&quot;go&quot;&gt;
🐳 docker run -it --rm multiarch/alpine:aarch64-edge /bin/sh
Unable to find image &apos;multiarch/alpine:aarch64-edge&apos; locally
aarch64-edge: Pulling from multiarch/alpine
ee62da588733: Pull complete
c782b02d60f2: Pull complete
Digest: sha256:17a50d7864c2e052d1c48892252356c1ce9eea26d0a61236072d6c900e5bd6a6
Status: Downloaded newer image for multiarch/alpine:aarch64-edge
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;/ #&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;Linux 62670af32738 4.9.0-3-amd64 #&lt;/span&gt;1 SMP Debian 4.9.30-2+deb9u2 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;2017-06-26&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; aarch64 Linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Building an image is similiar to Docker For Mac, take an existing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; and replace it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FROM&lt;/code&gt; with a corresponding &lt;a href=&quot;https://hub.docker.com/u/multiarch/&quot;&gt;Multiarch Docker Hub image&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example to re-build the &lt;a href=&quot;https://raw.githubusercontent.com/nodejs/docker-node/c37d5e87fa6d46c0e387f73161b056bbf90b83aa/8.6/alpine/Dockerfile&quot;&gt;NodeJS Alpine Image&lt;/a&gt; for aarch64,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;🐳 curl -sSL https://raw.githubusercontent.com/nodejs/docker-node/c37d5e87fa6d46c0e387f73161b056bbf90b83aa/8.6/alpine/Dockerfile | sed &quot;s/alpine:3.6/multiarch\/alpine:aarch64-v3.6/g&quot; &amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;Dockerfile.nodejs.aarch64
&lt;span class=&quot;go&quot;&gt;
🐳 docker build -f Dockerfile.nodejs.aarch64 -t nodejs:aarch64 .
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;considerations-1&quot;&gt;Considerations&lt;/h3&gt;

&lt;p&gt;While not as cookie cutter as Docker for Mac, using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-user-static&lt;/code&gt; makes setting up cross-build environments on Linux much easier than it used to be. This also allows you to use much more powerful x86 hardware (either bare metal or cloud) to quickly build Docker images for other architectures than x86.&lt;/p&gt;

&lt;p&gt;The only disadvantage is this method relies on images from Docker Hub that have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-*-static&lt;/code&gt; binaries added, this makes re-building images more difficult since you’ll need to track down a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu&lt;/code&gt; enabled image.&lt;/p&gt;

&lt;p&gt;Known repos that have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu&lt;/code&gt; enabled images,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://hub.docker.com/u/multiarch/&quot;&gt;https://hub.docker.com/u/multiarch/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hub.docker.com/u/resin/&quot;&gt;https://hub.docker.com/u/resin/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;qemu-on-linux&quot;&gt;QEMU on Linux&lt;/h2&gt;

&lt;p&gt;Both Debian and Ubuntu include the &lt;a href=&quot;https://packages.debian.org/sid/qemu-user-static&quot;&gt;qemu-user-static&lt;/a&gt; package that includes statically built emulation binaries for &lt;a href=&quot;https://wiki.qemu.org/Main_Page&quot;&gt;QEMU&lt;/a&gt;. Installing the package on a host x86 architecture and bind mounting a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-*-static&lt;/code&gt; binary will allow the image to run a foreign architecture.&lt;/p&gt;

&lt;p&gt;To setup &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-user-static&lt;/code&gt; using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt; on Debian or Ubuntu,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;🐳 apt update
🐳 apt install -y qemu qemu-user-static qemu-user binfmt-support
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Any architecture that is supported on Docker Hub and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-*-static&lt;/code&gt; should run by bind mounting the correct &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu&lt;/code&gt; binary and using the appropriate Docker image.&lt;/p&gt;

&lt;h3 id=&quot;qemu-examples&quot;&gt;QEMU Examples&lt;/h3&gt;

&lt;p&gt;Run a &lt;a href=&quot;https://hub.docker.com/r/arm32v7/debian/&quot;&gt;arm32v7/debian&lt;/a&gt; image, bind mount the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/bin/qemu-arm-static&lt;/code&gt; binary into the container,&lt;/p&gt;
&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;🐳 uname -a
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;Linux jezebel 4.9.0-3-amd64 #&lt;/span&gt;1 SMP Debian 4.9.30-2+deb9u2 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;2017-06-26&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; x86_64 GNU/Linux
&lt;span class=&quot;go&quot;&gt;
🐳 docker run -it --rm -v /usr/bin/qemu-arm-static:/usr/bin/qemu-arm-static arm32v7/debian /bin/bash
Unable to find image &apos;arm32v7/debian:latest&apos; locally
latest: Pulling from arm32v7/debian
d0e027c48353: Pull complete
Digest: sha256:d74cc69431f03bbfbbf9fd52c1eabd6ca491280a03da267acb63b65b81e30c8a
Status: Downloaded newer image for arm32v7/debian:latest
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;root@7d91bbe1e01b:/#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;Linux 7d91bbe1e01b 4.9.0-3-amd64 #&lt;/span&gt;1 SMP Debian 4.9.30-2+deb9u2 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;2017-06-26&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; armv7l GNU/Linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run a &lt;a href=&quot;https://hub.docker.com/r/s390x/debian/&quot;&gt;s390x/debian&lt;/a&gt; image, bind mount the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/bin/qemu-s390x-static&lt;/code&gt; binary into the container,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;🐳 uname -a
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;Linux jezebel 4.9.0-3-amd64 #&lt;/span&gt;1 SMP Debian 4.9.30-2+deb9u2 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;2017-06-26&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; x86_64 GNU/Linux
&lt;span class=&quot;go&quot;&gt;
🐳 docker run -it --rm -v /usr/bin/qemu-s390x-static:/usr/bin/qemu-s390x-static s390x/debian /bin/bash
Unable to find image &apos;s390x/debian:latest&apos; locally
latest: Pulling from s390x/debian
2f25bc6ba506: Pull complete
Digest: sha256:b01d35a1891549568b1f5fb66b329dded1e9cd45d6cb74f0c02aeb4c72a1417f
Status: Downloaded newer image for s390x/debian:latest
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;root@ad7f1fd946fa:/#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;Linux ad7f1fd946fa 4.9.0-3-amd64 #&lt;/span&gt;1 SMP Debian 4.9.30-2+deb9u2 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;2017-06-26&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; s390x GNU/Linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;considerations-2&quot;&gt;Considerations&lt;/h3&gt;

&lt;p&gt;Using the apt package for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-user-static&lt;/code&gt; is much more powerful and flexible than the Multiarch method, however it requires more knowledge and configuration when running a container since each architecture will require it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-*-static&lt;/code&gt; binary bind mounted and a corresponding architecture Docker image.&lt;/p&gt;

&lt;p&gt;A disadvantage of this method is it’s only useful for running a container, not building a new image since that would require the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FROM&lt;/code&gt; image to include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-*-static&lt;/code&gt; binary and it’s not possible to bind mount the binary when using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker build&lt;/code&gt;. For detailed information on cross-building images see the &lt;a href=&quot;https://github.com/docker-library/official-images&quot;&gt;Docker Libary Official Images&lt;/a&gt; documentation.&lt;/p&gt;

&lt;p&gt;Known official Docker multi-arch images,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://hub.docker.com/u/arm32v6/&quot;&gt;arm32v6&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hub.docker.com/u/arm32v7/&quot;&gt;arm32v7&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hub.docker.com/u/arm64v8/&quot;&gt;arm64v8&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hub.docker.com/r/s390x/&quot;&gt;s390x&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hub.docker.com/u/ppc64le/&quot;&gt;ppc64le&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;final-considerations&quot;&gt;Final Considerations&lt;/h2&gt;

&lt;p&gt;Cross-building Docker images is different than the recent Docker Hub Multi-arch support announcement in September 2017. That announcement is a feature of Docker Hub where a repository can have a single image name and include multiple architectures in a manifest. This means that when running Docker on any supported hardware with a multi-arch enabled image, Docker will know to use the proper image for the architecture&lt;/p&gt;

&lt;p&gt;Before, repositories would either maintain seperate images (eg https://hub.docker.com/u/arm64v8/) or tag images with specific architectures (eg multiarch/debian-debootstrap:arm64-jessie). Now most of this is abstracted away and running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run -it --rm debian /bin/bash&lt;/code&gt; on x86, armhf, or s390x will automatically know what to do without additional configuration.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.hypriot.com/post/setup-simple-ci-pipeline-for-arm-images/&quot;&gt;https://blog.hypriot.com/post/setup-simple-ci-pipeline-for-arm-images/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.debian.org/RaspberryPi/qemu-user-static&quot;&gt;https://wiki.debian.org/RaspberryPi/qemu-user-static&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 02 Oct 2017 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2017/Cross-Building-and-Running-Multi-Arch-Docker-Images/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2017/Cross-Building-and-Running-Multi-Arch-Docker-Images/</guid>
        
        <category>docker</category>
        
        <category>arm</category>
        
        <category>raspberrypi</category>
        
        
        <category>containers</category>
        
      </item>
    
      <item>
        <title>ACI Connector for k8s on a Raspberry Pi Cluster</title>
        <description>&lt;h2 id=&quot;intro&quot;&gt;Intro&lt;/h2&gt;

&lt;p&gt;Running the &lt;a href=&quot;https://web.archive.org/web/20171104111735/https://github.com/azure/aci-connector-k8s&quot;&gt;Azure Container Instances Connector for Kubernetes&lt;/a&gt; on a Raspberry Pi Cluster.&lt;/p&gt;

&lt;p&gt;One of the most interesting features of &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/container-instances/&quot;&gt;Azure Container Instances&lt;/a&gt; is the &lt;a href=&quot;https://web.archive.org/web/20171104111735/https://github.com/azure/aci-connector-k8s&quot;&gt;Azure Container Instances Connector for Kubernetes&lt;/a&gt;. This adds an ACI “node” to an existing &lt;a href=&quot;https://kubernetes.io&quot;&gt;Kubernetes&lt;/a&gt; cluster and allows you to deploy pods to it. This “node” will run pods in ACI without having to create or manage and additional Azure VMs, just point-and-shoot a pod at it and it will run with no additional setup required.&lt;/p&gt;

&lt;p&gt;By using the ACI Connector for Kubernetes on a Raspberry PI, a cluster can run homogenous ARM containers on-prem, but still have the ability to deploy and manage x86 containers to a cloud provider.&lt;/p&gt;

&lt;p&gt;Read more about Azure Container Instances,&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://thenewstack.io/azure-container-instances-mean-cheaper-agile-container-tools-way/&quot;&gt;https://thenewstack.io/azure-container-instances-mean-cheaper-agile-container-tools-way/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/container-instances/&quot;&gt;https://docs.microsoft.com/en-us/azure/container-instances/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/blog/announcing-azure-container-instances/&quot;&gt;https://azure.microsoft.com/en-us/blog/announcing-azure-container-instances/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;creating-an-aci-connector-k8s-arm-image-for-raspberry-pi&quot;&gt;Creating an aci-connector-k8s ARM Image for Raspberry Pi&lt;/h2&gt;
&lt;p&gt;The upstream aci-connector-k8s image is x86 only, but since it’s written in typescript it can easily be run on different architectures. To run on a Raspberry Pi k8s cluster, all that is required is building an armhf Docker image.&lt;/p&gt;

&lt;h3 id=&quot;building-a-nodejs-arm-docker-image&quot;&gt;Building a Nodejs ARM Docker Image&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: As of 9/12/2017 &lt;a href=&quot;https://integratedcode.us/2017/09/13/dockerhub-official-images-go-multi-platform/&quot;&gt;Docker Hub Official Images support multi-platform&lt;/a&gt; and re-building an image for armhf (or arm64, ppc64le, and s390x) is no longer required if using a supported image (currently Debian based only, Alpine based like below still need to be re-built).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The aci-connector-k8s &lt;a href=&quot;https://web.archive.org/web/20211229050703/https://github.com/Azure/aci-connector-k8s/blob/master/Dockerfile&quot;&gt;Dockerfile&lt;/a&gt; uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node:8.4.0-alpine&lt;/code&gt; as it’s base image. While there are some “unofficial” node ARM images, lets create one from a somewhat official repository. This involves finding an armhf Alpine 3.6 image, copying/pasting the &lt;a href=&quot;https://github.com/nodejs/docker-node/blob/17c50cb300581280805a4183524fbf57840f3a7e/8.4/alpine/Dockerfile&quot;&gt;node:8.4-alpine Dockerfile&lt;/a&gt;, replacing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FROM&lt;/code&gt; with the armhf version of alpine, and building the image.&lt;/p&gt;

&lt;p&gt;There are two ways to build an armhf image,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Build on Raspberry Pi
    &lt;ul&gt;
      &lt;li&gt;100% native build, less likely to run into bugs&lt;/li&gt;
      &lt;li&gt;Painfully slow due to Raspberry Pi hardware&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Cross-build using &lt;a href=&quot;https://docs.docker.com/docker-for-mac/multi-arch/&quot;&gt;Docker for Mac&lt;/a&gt; or &lt;a href=&quot;https://github.com/multiarch&quot;&gt;Multiarch&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;Dramatically speed up builds&lt;/li&gt;
      &lt;li&gt;Could have unforseen issues due to running in an emulated environment&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After first attempting option 1, two hours later and losing the ability to ssh into the Raspberry Pi, option 2 is a much faster approach. Building on a MacBook Pro using the built-in multiarch features of Docker for Mac works well, but is still slow even on a 4 core system. Fortunately Using up a 24-core &lt;a href=&quot;https://www.packet.net&quot;&gt;Packet.net&lt;/a&gt; Type 2 bare-metal instance to cross-compile using Multiarch is easy to do too.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: The official Docker images for armhf are &lt;a href=&quot;https://hub.docker.com/r/arm32v6/&quot;&gt;arm32v6&lt;/a&gt; and &lt;a href=&quot;https://hub.docker.com/r/arm32v7/&quot;&gt;arm32v7&lt;/a&gt;. These will work natively on a Raspberry Pi, Docker for Mac, Multiarch, and a Linux system with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;qemu-*-static support&lt;/code&gt;. For full details on these see &lt;a href=&quot;http://www.ecliptik.com/Cross-Building-and-Running-Multi-Arch-Docker-Images/&quot;&gt;my post on cross-building Docker images&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A armhf multiarch nodejs &lt;a href=&quot;https://github.com/ecliptik/dockerfiles/blob/master/node/Dockerfile.alpine.armhf&quot;&gt;Dockerfile&lt;/a&gt; was built on the Packet.net Type 2 instance and pushed to Docker hub as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecliptik/node:8.4.0-alpine-armhf&lt;/code&gt;. This only took a few minutes using the Type 2 instance, much faster than Raspberry Pi or Macbook Pro.&lt;/p&gt;

&lt;p&gt;Example Using Multiarch to re-build a node armhf alpine image,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;curl -sSL https://raw.githubusercontent.com/nodejs/docker-node/c044d61e6d02756bb8ed1557b2f0c7a0d7fead6f/8.4/alpine/Dockerfile | sed &quot;s/alpine:3.6/multiarch\/alpine:armhf-v3.6/&quot; &amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;Dockerfile.node.armhf
&lt;span class=&quot;go&quot;&gt;
docker build -f Dockerfile.node.armhf -t ecliptik/node:8.4.0-alpine-armhf .
docker push ecliptik/node:8.4.0-alpine-armhf
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;building-an-aci-connector-k8s-arm-docker-image&quot;&gt;Building an aci-connector-k8s ARM Docker Image&lt;/h3&gt;
&lt;p&gt;Once a nodejs arm-alpine image is created, clone the &lt;a href=&quot;https://web.archive.org/web/20171104111735/https://github.com/azure/aci-connector-k8s&quot;&gt;aci-connector-k8s&lt;/a&gt; repositoriy, and update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecliptik/node:8.4.0-alpine-armhf&lt;/code&gt; image. Additionaly, use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockefile&lt;/code&gt; below to use multi-stage builds for improved image size.&lt;/p&gt;

&lt;div class=&quot;language-dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;### Base Image&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Setup up a base image to use in Build and Runtime images&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ecliptik/node:8.4.0-alpine-armhf&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;base&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; /app&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; package.json .&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;### Build Image&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Installs build dependencies and npm packages&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Creates artifacts to copy into Runtime image&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;build&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Install build OS packages&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;        &lt;span class=&quot;nv&quot;&gt;buildDeps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;                make &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;                gcc &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;                g++ &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;                python &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;                py-pip &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;                curl &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;                openssl &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;        &apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    apk add &lt;span class=&quot;nt&quot;&gt;--no-cache&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;       &lt;span class=&quot;nt&quot;&gt;--virtual&lt;/span&gt; .build-deps &lt;span class=&quot;nv&quot;&gt;$buildDeps&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#Copy application into build image&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; . .&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Install npm packages&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--silent&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;       gulp-cli &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;       typescript

&lt;span class=&quot;c&quot;&gt;# Compile typescript sources to javascript artifacts&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;tsc &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt; es5 connector.ts

&lt;span class=&quot;c&quot;&gt;### Runtime Image&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Copy artifacts from Build image and setups up entrypoint/cmd to run app&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;runtime&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Copy artifacts from Build Image&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; --from=build /app/node_modules ./node_modules&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; --from=build /app/*.js ./&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; --from=build /app/LICENSE ./&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Runtime command&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;node&quot;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;connector.js&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With an updated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; in the cloned repo, build the aci-connector-k8s image &lt;em&gt;on&lt;/em&gt; a Raspberry Pi,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;docker build -t ecliptik/aci-connector-k8s:alpine-armhf .
docker push ecliptik/aci-connector-k8s:alpine-armhf
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: Trying to build the image on non-native armhf platform like Docker for Mac or Multiarch may result in errors like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;SyntaxError: Unexpected end of JSON input&quot;&lt;/code&gt;. The image only seems to build on native Raspberry Pi or ARM hardware.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;running-the-aci-connector&quot;&gt;Running the ACI Connector&lt;/h2&gt;
&lt;p&gt;Now that we have a armhf image capable of running on a Raspberry Pi, we can deploy the pod to a &lt;a href=&quot;http://www.ecliptik.com/Raspberry-Pi-Kubernetes-Cluster/&quot;&gt;Raspberry Pi Kubernetes cluster&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First clone the &lt;a href=&quot;https://github.com/Azure/aci-connector-k8s&quot;&gt;aci-connector-k8s&lt;/a&gt; repository onto the Raspberry Pi cluster master,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;git clone https://github.com/Azure/aci-connector-k8s.git
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Edit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;examples/aci-connector.yaml&lt;/code&gt; and update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;image&lt;/code&gt; to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecliptik/aci-connector-k8s:alpine-armhf&lt;/code&gt; image.&lt;/p&gt;

&lt;p&gt;Next, if you used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm&lt;/code&gt; to create your cluster and RBAC is enabled, you’ll need to create a role and set it up for the connector. This is discussed in &lt;a href=&quot;https://github.com/Azure/aci-connector-k8s/issues/26#issuecomment-326809041&quot;&gt;this Github issue&lt;/a&gt; that includes creating a RBAC role and updating the service to use it.&lt;/p&gt;

&lt;p&gt;Create the RBAC role for the connector,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;curl -sSL https://raw.githubusercontent.com/alexjmoore/aci-connector-k8s-arm/master/aci-connector-rbac.yaml | kubectl create -f -
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spec&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;examples/aci-connector.yaml&lt;/code&gt; add the RBAC role,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;serviceAccountName: aci-connector-sa
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally after the connector is setup to use the armhf image and RBAC, follow the rest of the &lt;em&gt;Quickstart&lt;/em&gt; guide in the aci-connector-k8s &lt;a href=&quot;https://github.com/Azure/aci-connector-k8s/blob/master/README.md&quot;&gt;README&lt;/a&gt; to set up everything else required to run the connector (Azure keys, deployment of service, etc).&lt;/p&gt;

&lt;h2 id=&quot;working-example&quot;&gt;Working Example&lt;/h2&gt;

&lt;p&gt;Updated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;examples/aci-connector.yaml&lt;/code&gt; with RBAC role and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ecliptik/aci-connector-k8s:alpine-armhf&lt;/code&gt; image&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;extensions/v1beta1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Deployment&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;aci-connector&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;default&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;replicas&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;aci-connector&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;serviceAccountName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;aci-connector-sa&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;containers&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;aci-connector&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ecliptik/aci-connector-k8s:alpine-armhf&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;imagePullPolicy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Always&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;AZURE_CLIENT_ID&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;00000-000-00000-0000-0000&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;AZURE_CLIENT_KEY&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;00000-000-00000-0000-0000&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;AZURE_TENANT_ID&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;00000-000-00000-0000-0000&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;AZURE_SUBSCRIPTION_ID&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;100000-000-00000-0000-0000&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ACI_RESOURCE_GROUP&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;aci-test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Deploy the aci-connector pod,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;kubectl create -f examples/aci-connector.yaml
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Wait a few minutes while the pod comes into service (mostly waiting for the image to pull) on a worker node.&lt;/p&gt;

&lt;p&gt;Verify aci-connector pod has started,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;kubectl get pods
NAME                             READY     STATUS    RESTARTS   AGE
aci-connector-1252680567-b88w6   1/1       Running   0          3m
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Verify aci-connector node is added,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;kubectl get nodes -o wide
NAME            STATUS    AGE       VERSION   EXTERNAL-IP   OS-IMAGE                        KERNEL-VERSION
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;aci-connector   Ready     2m        v1.6.6    &amp;lt;none&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&amp;lt;unknown&amp;gt;                       &amp;lt;unknown&amp;gt;
&lt;span class=&quot;gp&quot;&gt;navi            Ready     1h        v1.7.5    &amp;lt;none&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;Raspbian GNU/Linux 8 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;jessie&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   4.4.50-hypriotos-v7+
&lt;span class=&quot;gp&quot;&gt;tael            Ready     1h        v1.7.5    &amp;lt;none&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;Raspbian GNU/Linux 8 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;jessie&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   4.4.50-hypriotos-v7+
&lt;span class=&quot;gp&quot;&gt;tatl            Ready     1h        v1.7.5    &amp;lt;none&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;Raspbian GNU/Linux 8 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;jessie&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   4.4.50-hypriotos-v7+
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Deploy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;example/nginx-pod.yaml&lt;/code&gt; pod from aci-connector-k8s repo,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;kubectl create -f examples/nginx-pod.yaml
pod &quot;nginx&quot; created
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Verify pod deployed and is running in ACI,&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;kubectl get pods -o wide
 NAME                             READY     STATUS    RESTARTS   AGE       IP               NODE
 aci-connector-1696751608-tcjcq   1/1       Running   0          24m       10.244.2.4       tael
 nginx                            1/1       Running   0          10s       104.42.235.280   aci-connector
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;general-docker-on-arm-links&quot;&gt;General Docker on ARM Links&lt;/h2&gt;
&lt;p&gt;While researching and setting this up I came across many good resources on running Docker on ARM,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://help.packet.net/armv8/docker-on-armv8&quot;&gt;https://help.packet.net/armv8/docker-on-armv8&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/docker-library/official-images#architectures-other-than-amd64&quot;&gt;https://github.com/docker-library/official-images#architectures-other-than-amd64&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.hypriot.com/post/first-touch-down-with-docker-for-mac/&quot;&gt;https://blog.hypriot.com/post/first-touch-down-with-docker-for-mac/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/&quot;&gt;https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ARM Docker Image Repositories&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://hub.docker.com/u/arm32v6/&quot;&gt;arm32v6&lt;/a&gt; - Works on RPI 3 with &lt;a href=&quot;https://blog.hypriot.com/downloads/&quot;&gt;HypriotOS&lt;/a&gt; 32-bit&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hub.docker.com/u/arm32v7/&quot;&gt;arm32v7&lt;/a&gt; - Works on RPI 3 with &lt;a href=&quot;https://blog.hypriot.com/downloads/&quot;&gt;HypriotOS&lt;/a&gt; 32-bit&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hub.docker.com/u/arm64v8/&quot;&gt;arm64v8&lt;/a&gt; - Currently no 64-bit version of HypriotOS, but will work on &lt;a href=&quot;https://www.packet.net/bare-metal/servers/type-2a/&quot;&gt;Packet.net Type 2A Instances&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 12 Sep 2017 00:00:00 +0000</pubDate>
        <link>https://www.ecliptik.com/blog/2017/ACI-Connector-for-k8s-on-a-Raspberry-Pi-Cluster/</link>
        <guid isPermaLink="true">https://www.ecliptik.com/blog/2017/ACI-Connector-for-k8s-on-a-Raspberry-Pi-Cluster/</guid>
        
        <category>docker</category>
        
        <category>azure</category>
        
        <category>arm</category>
        
        <category>kubernetes</category>
        
        <category>raspberrypi</category>
        
        
        <category>containers</category>
        
      </item>
    
  </channel>
</rss>
