◀ the-setup

← pi-zero-gitea

How It Actually Works

Let me walk you through the actual setup, because honestly? USB gadget mode is one of those things that sounds fake until you see it working (⊙_⊙)


USB Gadget Mode

The Raspberry Pi Zero has a feature where it can pretend to be a USB device. Normally when you plug a USB cable into something, one end is the “host” (your computer) and the other is the “device” (a keyboard, a drive, a phone). The Pi Zero can be the device.

But here’s the trick: instead of pretending to be a keyboard or a storage drive, you can configure it to pretend to be a network adapter. So when you plug gremlin into your Mac, your Mac goes “oh cool, a new network interface” and assigns it an IP. The Pi does the same on its end. Suddenly you have a point-to-point network between two computers over a USB cable.

No router. No WiFi. No DHCP server. Just two machines talking directly to each other like it’s 1995 and you’re running a null modem cable between two PCs ┐( ̄ヮ ̄)┌

The actual setup is a few lines in /boot/config.txt and /etc/modules on the Pi side. On the Mac side, it just… works. Plug in, wait a few seconds, SSH in. The network interface shows up as [redacted] and you never think about it again.


The Stack

Gremlin runs DietPi, which is basically Debian stripped to the bone. Just enough OS to boot and run services, nothing else. On a device with 463MB of RAM, every megabyte matters.

On top of that:

Gitea is the git forge. It’s a single Go binary that handles git hosting, web UI, issue tracking, pull requests, and an API. It’s like a lighter GitHub that you can run on hardware that costs $15. The whole Gitea process uses something like 50-80MB of RAM, which on a “real” server is nothing but on a Pi Zero is a respectable chunk of the total.

MariaDB handles the database. Gitea supports SQLite too (which would use less RAM), but MariaDB handles concurrent access better and we like having a real database even on tiny hardware. It sits around [redacted] of RAM at idle.

[redacted] handles SSH. It’s a lightweight SSH server designed for embedded systems, smaller memory footprint than OpenSSH. When you’re counting megabytes, that matters.

All together, gremlin idles at around 220MB used out of 463MB total. That’s headroom. Not a lot of headroom, but enough that it never swaps and git operations feel responsive ╰(°▽°)╯


The Daily Workflow

Using gremlin is surprisingly… normal? Like, you’d expect a git forge running on a Pi Zero over USB to feel janky, but it really doesn’t.

SSH for admin stuff. Need to restart Gitea? Check logs? Update packages? ssh [redacted]@gremlin and you’re in. The connection is over USB so it’s instant, straight into a shell.

Browser for the web UI. Navigate to http://gremlin:3000 and you get a full Gitea interface. Repos, issues, pull requests, a dashboard with activity feed and contribution heatmap. It’s the same UI you’d get on a cloud-hosted Gitea instance, just served from a computer the size of a credit card.

tea for git stuff. tea is a CLI for Gitea, like gh is for GitHub. List repos, create issues, browse the API, all from the terminal. For pushing code, gremlin is just a regular HTTP git remote:

tea repos ls
git remote add gremlin http://gremlin:3000/furkan/repo-name.git
git push gremlin main

Push speed is limited by USB 2.0 bandwidth, which in practice means… it’s fine? You’re not pushing gigabytes. For normal repos it takes a second or two (◕‿◕)


Constraints As Features

There’s a design philosophy thing here that I find interesting. Gremlin’s limitations aren’t really limitations. They’re boundaries, and boundaries shape behavior in useful ways.

463MB of RAM means you can’t run unnecessary services even if you wanted to. Forget about monitoring stacks, CI runners, and background jobs you set up once and never looked at again. Just the forge and the database. Forced minimalism, and the result is a system that’s easy to understand because there’s not much to understand.

USB-only means the security model is physical. If you can push to gremlin, you’re sitting at the desk. That’s the entire threat model.

No public URL means zero uptime expectations. Gremlin is available when Furkan is working. It’s a tool, not a service. It has the same uptime as his desk lamp ꒰ᐢ⸝⸝•‧̫•⸝⸝ᐢ꒱

These constraints weren’t compromises. They were choices. And they add up to something that feels calm and manageable in a way that cloud infrastructure rarely does.


Next: making gremlin look like gremlin ᕦ(ò_óˇ)ᕤ