A Systems Lab from an iPad or MacBook

September 20, 2026

AI-generated. This post was generated by AI.

My systems lab lives on an Ubuntu server. I reach it from an iPad or a MacBook, but the lesson files, databases, and tools stay on the same machine. Switching devices means connecting to the workspace again.

The setup has three parts: a remote Linux machine for the experiments, a persistent terminal session, and a command-line tool that puts each lesson next to the tools I use to work through it.

One workspace, two ways in

The lab runs on a DigitalOcean Droplet: an Ubuntu 24.04 virtual machine with four CPUs, about 8 GiB of memory, and a 160 GiB disk. On the iPad, Blink Shell supplies the terminal. I use Mosh to connect from both devices.

Mosh logs in through SSH, then carries terminal traffic over UDP. It tolerates temporary connection loss and changes in the client's IP address. The login and address here are placeholders:

mosh lab-user@droplet.example

Once connected, I use tmux to create or attach to a session on the droplet:

tmux new-session -A -s study
Field notes / diagramTwo devices. One lab.Each device makes its own Mosh connection. Both can attach to the same tmux session on the Ubuntu droplet.
Drawing diagram…
Mermaid source
flowchart TB
    accTitle: Remote access to the systems lab
    accDescr: An iPad running Blink and a MacBook each connect through Mosh to an Ubuntu droplet. A tmux session on the droplet runs the course tools and labs.
    ipad("iPad · Blink Shell") -->|Mosh| session
    mac("MacBook · terminal") -->|Mosh| session
    subgraph droplet[Ubuntu droplet]
      session("tmux · study session")
      session --> courses("tutor + kb")
      session --> labs("CLI tools + labs")
    end

Mosh handles the connection; tmux keeps the shell session on the server so another terminal can attach. With tmux's default keys, Ctrl-b, then d, detaches while the shell keeps running. That session still depends on the droplet staying up.

Coursework in the terminal

I work through self-directed systems courses using tutor, a custom Go command-line tool. A course is an ordered route through a subject, such as PostgreSQL or DuckDB. A lesson is a small experiment focused on one mechanism or practical task.

Each lesson puts the context, setup, commands, expected evidence, and cleanup in one place. I read it in the terminal, do the work with the real tools, and inspect the result. A DuckDB lesson, for example, might ask me to query PostgreSQL and check the result against psql.

tutor duckdb route
tutor duckdb 4 lesson
tutor duckdb status --json

route shows completed, available, and planned lessons. 4 lesson opens lesson four; status reports progress. The CLI reads Markdown lesson files and keeps course progress in SQLite.

Field notes / diagramFrom a lesson to evidenceReading a lesson does not complete it. I run the experiment, inspect the result, and explicitly mark the lesson done.
Drawing diagram…
Mermaid source
flowchart TB
    accTitle: The coursework workflow
    accDescr: Choose a lesson, read its context and setup, run commands with real tools, inspect the evidence, clean up, and explicitly mark it done. Tutor stores progress in SQLite.
    route("Choose a lesson") --> read("Read context + setup")
    read --> run("Run the real tools")
    run --> inspect("Inspect the evidence")
    inspect --> cleanup("Clean up the experiment")
    cleanup --> done("Explicitly mark done")
    done --> progress[(SQLite · course progress)]

Displaying a lesson does not mark it complete. I explicitly use done when finished. The distinction keeps the record tied to the work I have completed.

The tools behind the lessons

PostgreSQL 16 and psql provide the server and client for the PostgreSQL experiments. DuckDB and sqlite3 cover local queries and work across database formats. Go, Git, and Bash support the course tooling and shell work; Node.js and Python are supporting runtimes.

Docker and Firecracker are available for container and microVM lab work. kb holds saved environment notes alongside tutor's lessons and progress. Claude Code, Codex, and Ollama are also installed alongside the coursework.

Installed servers do not need to run continuously. At the time of this writeup, my retained PostgreSQL lab is stopped, and lessons can create and clean up private fixtures.

What I have worked through

As of September 20, 2026, the course records show:

  • PostgreSQL Essentials — lessons 1–25 complete. Visibility, snapshots, vacuum, concurrent writes, locks, retries, query plans, indexes, memory, WAL, and checkpoints.
  • Practical DuckDB — lessons 1–4 complete. Querying PostgreSQL, taking a bounded local extract, reading SQLite, and handling imported types.
  • gRPC and Protocol Buffers — all six lessons complete. Message encoding, field presence, schema changes, service calls, errors, streams, deadlines, and retries.
  • PostgreSQL Systems, the legacy route — lessons 1–7 complete, plus an earlier revision of lesson 8. Cluster setup, psql, extensions, processes, pages, and row versions.

SQLite and Linux appear in those experiments, but their separate courses have no recorded completions. Neither does Firecracker. The completed gRPC course's tools were later removed; repeating it would require reinstalling them.

The device gives me a terminal. The droplet holds the workspace. The lessons give me a concrete experiment to run when I get there.