iPad as Desktop: Emacs

Lately I’ve been working on a setup such that I can use my iPad as my primary desktop, at least for personal tasks. In this, the first of what I plan as a series of posts about my journey, I’ll outline what I’m currently using to be able to use emacs from my iPad.


For the impatient, and also to serve as an outline for the post, I’ll just list out the tools I’m using to make this happen.

  • Blinkshell
  • Tailscale
  • Mosh
  • An M1 Mac Mini
  • A hardware keyboard

The combination of the above gives me a nearly desktop-native experience running emacs and other terminal applications on my iPad. Note that this setup of course requires network connectivity between the iPad and the Mac Mini, and there are some complications with that, but I’ll try to cover those later in the post.

The finished product: emacs running on a Mac Mini that I’m using Blinkshell to connect to with mosh over a Tailscale VPN connection


I run emacs as my primary editor/IDE/operating system. I’m not one of those old school emacs users, I’m one of the new young punks using someone else’s emacs. In my case, I’m using the doom-emacs package, which provides me with a very comfortable user experience pretty much out of the gate, and since I’ve been a vim user for so long, the adjustment wasn’t that significant.

Emacs is a gui application framework wearing the skin of a text editor. It has support for both terminal ui (tui) or actual native gui (gui) interfaces, and can do so much more than editing text. I primarily use emacs as an editor, however, and I primarily use emacs over other editors because of org-mode and org-roam. I’ll talk about org-roam in another post.

Emacs doesn’t have a native iOS port and it is highly unlikely that it ever will. Largely in part due to application restrictions on iOS making code interpretation not a supported thing, which is fundamental not only to the emacs experience, but fundamental to emacs operation as a whole. I mentioned that emacs is a gui application framework, and it is, but as part of that framework it has its own programming language, emacs lisp, which powers not only custom things, but a lot of emacs’ own built in functionality.

So, as a result, I need a machine somewhere I can run emacs on and have it display on my iPad. And the best experience for that is, in my opinion, a terminal.


Blinkshell is a terminal emulator, ssh, and mosh client for iOS. There’s so much more to it than that, but it has the basic functionality I need: terminal emulation, ability to configure ssh key authentication, ability to do ssh agent forwarding (I won’t be covering this here, as I’m on the lookout for alternatives and it’s been covered elsewhere). It also provides an extremely basic text interface for commands, which is nice, I primarily live in the command line and on my keyboard, not having to tap my way through menus and such to do things is a huge plus.

It’s not a free app, but I’m totally fine with paying for good software. It *is* open source, which is nice, as that allows for auditability and also allows me to try to fix bugs or implement features if I feel up to the challenge.

One thing I discovered recently that it had was support for OSC52 terminal sequences. This is something I only recently discovered, but the general gist of it is that it allows terminal applications to manipulate the clipboard on the client system. If you’ve ever highlighted text on iOS you understand just how hard it can be. Now take things like terminal gui elements into consideration, and it’s basically impossible to copy/paste from the terminal by hand. However, OSC52 allows your terminal application (such as emacs, vim, tmux, etc) to send its own clipboard contents down, so you can use those applications’ native copy/paste functionality to manipulate the clipboard on iOS, making it easy to, say, copy some code from a file and paste it into a discord conversation, or a gist. This is huge, and one of the things that when I first needed to copy something from blink was nearly a deal breaker for me, as I copy things out of my editor all the time, so having that be a bad experience was probably going to prevent me from being able to do this. Fortunately, the problem is mostly solved at this point. There are still some limitations, for instance it doesn’t seem to work with mosh, but there’s a PR waiting to be merged into upstream mosh which hopefully will make its way into blink soon after.


Traditionally, when I’ve wanted to grant access to a machine running on my home network, I have fired up my router configuration web interface, set a static IP for the machine, forwarded a port, etc. This works fine, but has some serious drawbacks. The most important one is that now this port is exposed publicly on the internet. That’s probably not toooooooo bad, especially if I run the service on an alternate port, but it’s still a vulnerability. It’s also a huge pain for the friend who’s hosting the machine for me, as they have to maintain this. And the only way they know if it’s broken is if I call them. Furthermore, it assumes a moderately static IP for the internet connection. When I had my cable connection, this was pretty reasonable to assume, my IP rarely changed. But with my new fiber connection, it seems to change fairly frequently. To solve that I have DNS somewhere and a script to update the dns record on a schedule, but if that breaks then I’m back to calling my friend. It’s all very fragile and troublesome to fix.

So I went on the search for vpn solutions. I thought of having a VM instance somewhere that both my remote shell machine and my iPad could connect to and that would allow me to connect between them. This is fine, and something I almost went with. I would have likely used OpenVPN for this as I’ve done a lot of stuff with OpenVPN in the past, I’m familiar with it, and confident that I could make it do what I wanted. One problem with this, though, is that third party machine. Even the cheapest machine is going to cost me a few bucks a month, and now it’s something I have to maintain. There are third party VPN providers, but I’m not sure how many of them would allow my clients to connect to each other through the VPN, and I’d really rather not use one of those providers anyways, for trust reasons, but also because I really don’t like their ad copy. But that’s another post.

But! I remembered. There’s some new vpn thing built into the linux kernel now, isn’t there? What was that called? Well, it was called Wireguard. I also won’t cover this here because it’s been covered in great detail elsewhere.

Wireguard’s model is point to point VPN. Meaning clients create tunnels directly to each other. Once the connection is established, you can do routing and all sorts of stuff, so I could do the central model with a VM somewhere with wireguard, but it’s still not ideal.

So I went looking for ways to make it so wireguard endpoints could “discover” each other. So I could have my shell machine on a private network with no ports opened, no assumption of a dynamic IP address, etc, and have it just work. I found this article that talks about various scripts and a third machine that updates dns entries and does some cool stuff. Exactly the sort of thing I was looking for. But again, the third box. I thought more about it and thought that would actually make for an interesting service to offer to the world, and thought about how I might implement that.

It seems I’m not the only one who had this idea. Tailscale is *exactly* this. And actually, it’s significantly more. Most importantly for my consideration is that it takes NAT traversal a step further. They will transparently (and securely) proxy your data between your nodes if the NAT needing to be traversed is particularly problematic. On either end. This means that, in theory, no matter where I am, or where my shell box is hosted, I can establish a wireguard tunnel to it.

And the best part: it’s free. At least for single user purposes like mine. They can do this because their service is just providing the discovery for the endpoints, they aren’t actually proxying your data (unless you have the aforementioned troublesome NAT), so their bandwidth needs are relatively low. You install the agent on your machine (they have iOS, Linux, and Mac support at the very least), log in, and your machine is now able to be connected to from the other peers you have set up, as if it’s all local. No ports to open, no dns to configure, no worries about static or dynamic IPs. It all just handles everything smoothly. Wireguard handles when one end or the other changes IP addresses, and tailscale steps in if both sides have changed, or when a new peer comes online and doesn’t know any of its peers. It also handles public key distribution to the peer nodes, and rotation of keys, and and and and and. Seriously well thought out software and service.


Blinkshell support ssh directly, but something else it supports is Mosh, the Mobile Oriented SHell. Mosh has some significant advantages over standard ssh that make it ideal for a client with transient internet connectivity such as a traveling iPad.

Mosh uses SSH for the initial authentication and session establishment, then switches to running on its own port using UDP. The fact that it uses UDP for this is huge, because it allows the client to go offline without having to worry about a TCP session dropping. This means mosh clients can go offline for a practically infinite amount of time without “losing the connection”. In practice what this means is I can pack up my iPad and head out on a trail for a few days without internet access, fire things up when I get back and my connection hasn’t dropped. This may not sound like a big deal, especially when things like tmux exist to allow you to background a terminal session on the remote machine, but it’s pretty big. For the iPad specifically one of the great things about this is that iPadOS times out tcp connections on background processes pretty aggressively to save battery life. So if I switch from my shell to watch a youtube video, say, or read an article, I may come back to my terminal and the connection has dropped, meaning I need to re-establish. This gets really old really quickly, as you might imagine. One extra cool bonus feature of this is, since mosh sessions are inherently resumable, so long as the client keeps the connection information around, a connection can be resumed even after rebooting the client for a software update. Something I recently did! I was pretty blown away!

One of the best features of mosh for actual mobile usage, though, is its predictive local echo. If you’ve ever been ssh’d into a remote machine with a lot of latency, you know just how frustrating an experience typing can be. Mosh makes a great attempt at solving this by guessing what affect your keystrokes are going to have on the remote session and applies those affects locally before getting the result back from the remote system. It’s obviously not perfect at it, it can’t be, but for a lot of cases, it’s a HUGE enhancement to the mobile experience. This will be extremely useful for instances such as camping on a remote mountain top in Japan using my LTE connection to connect to my shell box on a cable connection in Portland. Something that absolutely will happen.

A downside to mosh is it doesn’t support ssh agent forwarding. SSH agent forwarding is a troublesome topic. It’s one of those things you really want to have, but it’s implemented in such a way that you really shouldn’t use it. There are alternatives, but they aren’t widespread, and they aren’t currently supported by blinksh. I think my solution for this in the long term is to have an ssh agent start on login on my shell box, then I’ll enter my ssh passphrase on first use to add it to the agent. Since the client would be running with mosh anyways, I shouldn’t have to type my password very often, and it should provide adequate protection for my private key.

Mac Mini

Throughout this I’ve talked a lot about my “remote shell box”. In my case, I’m choosing to go with a Mac Mini. Currently I’m using an M1 Mac Mini with 16GB of ram and 512GB of storage. This should be completely adequate me for a very long time, especially when just using it as a shell box.

But why the Mac mini? Why not a raspberry pi? Or a linux box? Maybe even a linux box hosted in the cloud somewhere so I don’t have to worry about VPNs and firewalls and port forwarding and all of that.

There are a couple of reasons. First and foremost, cost. A virtual machine that has those sorts of specs is quite an expensive proposition. I mean, the absolute cost of the Mac mini being factored in means I can buy a lot of VM hours before reaching the cost of the Mini, especially if I do some optimizations like turning the VM off when I’m not using it, etc. So it’s only a moderately important consideration for me.

Another major consideration for me is storage. I currently use iCloud Drive for my cloud storage stuff. I use this primarily because I’ve leaned very hard into the Apple ecosystem, so all of my devices have native support for it. I also pay for other Apple services, so the storage I use with iCloud Drive is pretty much free. I could use dropbox or something else, or even something like syncthing and roll it myself, but I like the safety net of a cloud backed storage mechanism, and my cloud backed storage mechanism of choice is iCloud Drive.

Furthermore, despite being out for a long time, despite “mobile devices” being a lot of folks’ primary experience with the web, there are lots of web interfaces that just don’t work well on the iPad, be it in Safari (my browser of choice) or Chrome. Oddly, one of the biggest offenders is the AWS console. It is literally unusable on safari for some functions, and only just works on Chrome for some things. And I’m not talking about the obscure things nobody uses, I’m talking about first class fundamental features like Route53 or S3. So having easy access (via VNC) to a full desktop web browser is very handy. This is something I could certainly do through other means, but having it be on the Mac Mini means I get things like my 1password database for free without having to load it onto some third party machine (and good luck trying to do U2F via some sort of remote desktop connection, which I need for my 1password authentication)

And finally, there’s part of me that still would really like to figure out iOS app development. I have some ideas for things I’d like to implement, and at the moment, iOS has no native support for XCode. I can’t imagine it’s not in the works somehow, as it would be great to be able to write software for the iPad, y’know, on the iPad, but there’s probably going to be some cloud component to it for compilation and simulation before that can happen, and it’s just one of many projects Apple has in flight. So having a Mac desktop I can VNC into and do some iOS development on while I’m on the road is great.

Hardware keyboard

Not just because I’ve gotten into custom mechanical keyboards during the pandemic, in order to use my iPad as a desktop, I need a hardware keyboard. There’s just no way at all I can type on the iPad screen. Not even a little bit. I can do some mild hunt and peck if my keyboard isn’t handy or if I’m mostly browsing the internet or youtube and need to type in a url or a search term, but for the most part, I need a physical keyboard.

There are many options for this, but I did say I’ve gotten into custom mechanical keyboards lately, so I’m currently using a caseless Corne Chocolate v2.1 keyboard with a pair of nice!nano controllers for wireless bluetooth connectivity. I made it into the group by for the Corne-ish Zen keyboard and am probably going to make that my primary travel board next, and am looking into building some other types of boards to see if I like one or the other better for travel purposes. I’ll probably talk about my keyboard use cases in another post, but I also distinguish between keyboards for “long term travel” (backpacking and traveling mostly on foot) and “short term travel” or “heavy travel” (traveling mostly by not-foot, such as work travel or “heading out to the coast for the weekend” sort of travel)


That’s a whole lot of words, and if you’re reading this, thanks for reading along. I have other things I want to cover about this journey toward using an iPad as a primary desktop, there will be some things that are “this is the definitive way to do this” and stuff like “I’m trying a new thing and wanted to share”. I am enjoying this little experiment so far, and getting more and more confident that I’ll be able to use just my iPad for my future planned “long term travel” (more about that at some point as well).

One thing I do want to say is that it’s unlikely that I’ll be able to use just an iPad for work purposes any time soon. I’m still very much bound to a shell of some sort, and then there’s consideration of device and credential management from employer, consideration of ergonomics of using effectively a tiny laptop display for all of my work, etc, but I would like to eventually give it a solid try! Maybe in a few years once Apple has further converged the iPadOS and MacOS experiences.

Bonus action shot of me working on this post at East Side Coffee

Emacs: a new chapter

I previously wrote about my first month with org-mode. I’m pleased to say that all of that went right out the window and I barely look at Org anymore. But that’s fine. It’s the way of things. Especially with me!

However, today I just did something wild and crazy. I deleted my .vimrc and all associated settings. Emacs is now my primary editor. I’ll of course still be using vim for one-off things, especially on remote servers where I don’t have, nor want my full emacs setup on, and don’t feel like bothering with tramp, but it’ll just be whatever stock config is there. And that’s all I really need out of vim anymore.

Last week I also did something wild and crazy. I switched from using Spacemacs as my base to using Doom Emacs. With that I also switched actual Emacs versions, as Doom recommends emacs-plus on MacOS, where previously I was using emacsformacosx.com.

I’d previously tried switching to Doom Emacs, but reverted my changes. I don’t remember all of the issues I ran into, but definitely enough that it wasn’t a super wonderful experience. However, I think a lot of that had to do with emacs-plus vs emacsformacosx, where the former is recommended and the latter is explicitly called out as being problematic with Doom. This time, I actually read the getting started instructions, and am much happier.

There was a bit of an adjustment period, many of the key bindings are different, configuring doom is *much* different than Spacemacs, etc. But now that I’m settled in it’s starting to feel more like home.

I did this mostly because I wanted to try out Doom and see what all the fuss was about. I don’t really see it as a “better” sort of thing, just different. There are definitely some things I like, and some things that I miss from Spacemacs, but for the most part it’s just a different thing, and now I’m getting more comfortable with it.

Anywho, I’m excited that Emacs is now my standard editor. Like I said, I’ll still use vim quite a bit, but really only in its stock installation form, for quick one-off things or in situations where I don’t want to (or can’t) set up my full Emacs environment.

A month with Org-mode

People have sang to me the praises of Org-mode for years and years and years. But every time I’ve sat down to try to learn enough Emacs to be able to use Org-mode I’ve nearly had to go see a doctor for the pain in my left hand. I just can’t use the ctrl key that much.

Recently, however, I’ve been working with my shrink on a lot of things, and one of the things she asked about is if I’d tried any task management tools. That opened a whole can of worms and we talked a lot about it, but the long story short of it is that I went home that evening, bought Things for all of the platforms I use, and promptly stopped using it.

The reason I stopped using it was not because I abandoned the idea or because the software is bad or anything. I’m sure it’s great software, and I’ve been doing *plenty* of task management. The reason I stopped using it is because the very same day I grabbed Emacs for Mac OS X and tried to put the hand pain behind me. I haven’t stopped since.

Of course, the story doesn’t just end there. I’m not using stock Emacs, I’m not even using the default-literally-painful keybindings. I got into work the next day, asked a coworker who is a die-hard Emacs user “what do” and he pointed me at Spacemacs. Spacemacs is an Emacs “distribution” (of sorts) which includes a large number of packages and configuration so as to create a consistent and user friendly Emacs platform. It also happens to be targeted at users of “evil-mode” (Emacs VI Layer), which aims to make a very vim-like experience within Emacs. Their tag line is even “The best editor is neither Emacs nor Vim, it’s Emacs and Vim!”. After a month and change, I think I agree with this.

DOGEMACS. Shut up and take my money. Wow.


Org-mode is at its simplest definition, an outlining system. You have headings, subheadings, sub-subheadings, ordered lists, unordered lists, etc. Folks familiar with Markdown are already quite familiar with this sort of thing, though Markdown and Org are actually 2 distinct formats.

But that’s barely even doing Org justice. The real power of Org lies in the functionality that Org adds to the top of it. You can reorganize these headings and subheadings. You can mark things as TODO, DONE, WAITING, or any arbitrary DONE-ness you’d like. You can make checkboxes that you can check off by hitting a couple of keystrokes. You can query the files semantically to extract things like “what’s on my agenda for today” and “what are the TODO items in my backlog” or “how am I doing on keeping up with that new habit I’m trying to form”.

You can also do really amazing things like embed code snippets that are *executable* and even embed multiple of such snippets and have them extracted out as a file in that language for later execution. This in particular is very popular in the Emacs world where people share their configs readily, and folks will write their main Emacs config file as an Org document, publish the document, and extract the actual config out of the document.

My first month

After a few days of flailing about getting familiar with Emacs, with some peculiarities of Spacemacs, upgrading Spacemacs multiple times (the latest official published release when I started using it was over 2 years old, the master branch was several months behind, so everyone seems to just use develop), and tuning my config to my preferences, I started calling myself an Emacs user and started using it full time for nearly any text editing task (ironically, this post is actually *not* being written in Emacs, despite there being an org2blog plugin, but I haven’t quite gotten that far in my journey yet). After years of poking fun at Emacs whenever it was brought up, I now find myself singing its praises. I still poke plenty of fun at it, the default keybindings really do make my hand (and brain, especially as a long time vim user) hurt, but it’s always been all in good fun and now half of the joke is that I’m making fun of myself since I, too, am an Emacs user.

At first I started putting everything I could possibly think of into Org. I have read numerous task management books and whatnot and revisited Getting Things Done and started implementing a “trusted system” in Org. Mostly, I was just trying to get things out of my head. Organize things, try to accomplish things, but even just writing it down would be plenty useful. And it was. I started using Org-habit to track habits like scooping the litter box, making the bed, taking my medicine, and have slowly added things to it, spotted when I was falling behind on a habit(s). I started compiling a list of many of the books I’m interested in reading in the future. I put together a whole directory of the owners in my HOA and used Org to organize a project which required us to get keys to everyone’s units, so involved chasing people down, tracking which board member had whose keys, etc. I’m using it to keep track of all of the documents I need to collect and give to my accountant for my 2019 tax return. I’m using it for general HOA organizational tasks, though that’s only temporary until I find something better that I can share with the rest of our community.

I’m also using Org-journal to try to keep a diary. I’ve been pretty faithful with it, sometimes writing very little, other times writing very long winded entries. I spent the afternoon of Jan 1, 2020 writing up a bit of a “what I want to get out of 2020” and some “resolutions” for good measure. And I’m using org-habit to make sure I review that document periodically.

I’m also starting to really figure out what I want to use it for at work. We already use Jira, so using it as a general task management tool is probably not super great. And since I don’t have shared storage between my work computer and my personal computer, it’s hard to really have a unified Agenda between them. But what I’ve started doing is keeping a running log of what I’m doing for a certain task, ticket, or in the case of this week, I’m secondary on-call, so I get to deal with business hours questions in slack and also triaging (and trying to keep up with) new toil-like work that comes in via our ticketing mechansim. I plan to publish these logs (in Org format) to share them with my team and also for oncall weeks as a type of handoff document. I’m also using these to track follow-up work within a project, such as updating provisioning documentation when provisioning a new thing, or scheduling work that’s related to the ticket but should be done later such as deleting backups after a certain period of a time for a decommissioned service.

So, yea

I actually had a whole other post partially written that was probably 10x longer than this already and went into great detail about each individual thing. Part of why it’s taken me so long to write this is because I wanted to pare that down a bit before publishing it since there was just too much detail. I may write up individual posts about some of those things in the future, but it was too much to put all in one place.

What’s amazing though is just how much using Org has transformed how I do things. I wake up in the morning, I consult Org. I check off my morning routine tasks, I check to see if there’s anything I need to do during the day from my personal list, go to work, pick up Org there and do more things, etc. It is slowly starting to consume my computer time, and that’s not a bad thing. In fact, if it has the effects I want it to have (feeling more organized, more confident, able to get more things done), then by all means, consume away 🙂

The future

There are a few things I would like to focus on next.

Primarily, I now have way too much stuff in Org. Or at least, way too much stuff in Org to be able to really reason about it all at once. I’ve kinda shoved everything from my brain into a big pile in Org, loosely arranged some of it, and now I have just a big mess again. It’s at least not in my brain, but part of the benefit of not having it in my brain is trusting that I’ll be able to “remember” it later by looking through my Org (this is one of the core components of the GTD “trusted system”). But I’m starting to fall back on old habits. Not consulting Org for “what’s next” sort of stuff. Primarily because it’s just a jumble of mess right now and hard to reason about. Not checking in with Org in the morning as much, primarily because the morning routine habits I wanted to form using Org have mostly formed, so I get up, make my bed, take my medicine, scoop the litter box, etc, and I don’t have to consult Org to remind me to do those things. I just do them. So getting my Org more organized and usable is definitely high up on the list. A lot of this I think is just going to be “reducing work in progress” and axing projects and such, but I want to put them somewhere such that they’ll naturally surface again at some point and not just because I thought about it one day and then feel bad that I “forgot”. I *think* this is the function of the “tickler file” in GTD? But I haven’t gotten back around to that part on this read through.

Now that I’m more comfortable with Emacs and Spacemacs, I kinda want to look into alternatives. I’m subscribed to several Emacs subreddits, and one of the things that keeps coming up is Doom Emacs which is also a vim-oriented Emacs distribution and seems to be pretty popular. Spacemacs is great, but I find it to be rather buggy at times and have run into some issues. So I’m not exactly married to it. But also maybe I’ll just like how Doom Emacs feels better than Spacemacs? I dunno. It doesn’t necessarily have to be one is better than another, just more my style. I may even try to roll my own thing from a stock Emacs config, just to learn some of the building blocks like use-package, which might make it easier for me to hack on Spacemacs or whatever combination of things I end up using.

I also want to learn more about Emacs Lisp in general. I sorta understand Lisp, but right now a lot of it is just cargo culting and I really have no idea what I’m doing. It might also make it easier for me to use one of these larger distributions if I am better able to understand the code I’m reading or how all the parts fit together.

Part of wanting to learn more about Emacs Lisp and hacking on this stuff is so I can do some ham radio things with Emacs. I feel like Org-mode seems like a great place to put things like radiograms, perhaps a winlink client (or, more likely, an api client for pat), maybe some Org functionality for net control stations, I dunno! Could be fun.

Mostly, though, I just want to keep finding more things I can use Emacs and Org-mode for and do those things! Hopefully my “A year of Org-mode” blog post will have been composed entirely within Emacs, somehow or another.