How I Built a Remote Dev Server (to code from my iPad)

My 11″ 2020 iPad Pro is one of the best devices I’ve ever used; it might even just be my most favorite Device. It’s sleek, it’s portable, it’s modular, it’s beautiful, and it’s fast. However, it’s held back by the limiting nature of iPadOS; since most of the limitations I’ve run into are merely software problems, and the A12Z chip in my iPad is more than capable of handling what I want it to do (this is the same processor that was used in Apple’s Developer Transition Kit, so it was plenty powerful to run Mac apps), I’ve been on a search to contort this touch-first device into something able to accommodate my diverse set of needs.

One of these needs is coding, and specifically, coding for WordPress web development. The iPad is not nearly as flexible when it comes to this type of work, mostly because of its filesystem. Being a modern device, the iPad has done its best to abstract the filesystem away (which is fine, since normal people don’t think like that anyway), making it harder for me to manage projects thanks to app sandboxing and other genuinely good features. Just, not good for me. But hey, since it’s all software, there’s always solutions to be found.

There are many tutorials online on how to code from an iPad. Some suggest setting up a code-server instance, some suggest using Google Cloud to run a virtual machine, and other people I found have created a workflow using native iPad apps. All of these were too complicated for my taste, or didn’t accommodate for my particular workflow. So, before I introduce to you my own complicated workflow, let me first discuss my needs.

The Needs

My needs are (theoretically) simple:

  • I want to be able to access my projects, dependencies, and workspaces from any device I touch.
  • I want to access these projects from any location.
  • I want to use Visual Studio Code.
  • I want to focus on web development technologies like PHP and React.
  • I want to code from my iPad!
  • Oh, and I would like to do this for free or using stuff I already have.

These are all reasonable needs, albeit complex to set up, and a vanilla setup using Visual Studio Code and code tunnels would probably be enough. However, since I develop primarily for WordPress (both PHP and React), this means I need to build out some additional infrastructure.

The biggest issue would be building a solution that allowed me to access my code and development sites across the web. Since WordPress hard-codes the URL into its database, it’s not like I can access a site assigned to localhost on a server somewhere using a random IP address, since it would just redirect back to localhost. And, unfortunately, WordPress Playground isn’t mature enough to develop on.

WordPress’ hard-coded URLs can really screw you up if you even switch https to http

So, I know what my needs are. How should I go about building this system?

The Stack

Here are the tools I chose to go with:

  • My old Windows laptop
  • Visual Studio Code
  • Tailscale
  • LocalWP
  • Tmux
  • Ubuntu
  • Hyper-V

If you have old hardware lying around (preferably x86-based, but that’s for another article), the rest of what you need should presumably be free! You might not even need to use a VM or Hyper-V, but I wanted to just for fun.

The Server

I have an old Windows laptop I store in my closet. It’s always running, but outside of acting as a fileshare, it doesn’t do much. This is the device I chose to run my development server on. However, I prefer working in a *NIX environment, and I still need my OS to run Windows for some other services, so I decided to take advantage of the hardware’s Hyper-V support and run Ubuntu virtually.

This isn’t something I recommend doing, and it adds so much more complexity to the setup. However, I like it, since I can run all my utilities and have a familiar terminal experience as I do on my Mac. I also get the benefits that Hyper-V has, such as snapshots and backup. Also also, theoretically there’s a sandbox layer that should protect me if my VM gets compromised.

Visual Studio Code Server

In my research I remember seeing something about a Visual Studio Code server, but I remember it being limited: it was an open-source project by a 3rd party and it did not have access to VSCode’s Extensions library. These were limitations I was willing to accept.

Weirdly enough, it took me a while to re-find code-server. That’s because something else kept appearing in my Google results, seemingly throwing me off the trail. This something else was Visual Studio Code Server, which is a set of extensions that are built into VSCode and integrate with vscode.dev, the online version of VSCode hosted by Microsoft. This is basically a way to host your own VSCode instance, but without tons of configuration (you install VSCode and run code tunnel from a terminal). Since it was developed by Microsoft, it also supports Microsoft’s marketplace of extensions.

VSCode also integrates with GitHub, and even offers remote tunneling and port forwarding built in. The tunneling allows me to access the server from anywhere, the port forwarding means that I can forward my localhost ports from my local computer to my remote computer (or is it vice-versa?). You can learn more about VSCode’s Remote Tunnels here:

Tailscale

VSCode got me 90% of the way there. However, I found out in my testing that port-forwarding doesn’t really work for WordPress sites, at least when using VSCode from an iPad.

On a laptop, I can SSH into my server and actually forward ports from the host to the client, and the client takes the ports on as its own. Not so on an iPad; due to there being no hosts file on an iPad, Microsoft instead sets up a proxy URL that tunnels into the host computer. This is a great solution, and it would work in any other instance; however, due to WordPress’ hard-coded database URL, the tunnel sends me to a local IP address that doesn’t work. I can’t change the WordPress site URL to the tunnel’s URL either, since the tunnel URL is assigned at random and changes every time the tunnel is closed and re-opened.

So, all that to say, using Tailscale (within the VM) is the way to go here. Every device added to the Tailscale tenant gets assigned an IP address that doesn’t seem to change. Plus, you can access those devices from anywhere, as long as you’re using Tailscale on both the client and the host. It eats more battery, but it works quickly and reliably, and it’s technically safer!

WordPress + LocalWP

LocalWP running on Ubuntu running in Hyper-V running on Windows running on a 2011 Asus laptop

The platform I’m using to host WordPress sites is LocalWP. This is a fantastic app that makes it a breeze to set up multiple local development WordPress instances, something I still have a hard time doing manually. This solution is great since it seems to work in Hyper-V, and comes with another important feature:

As opposed to DevKinsta, my preferred local development tool, LocalWP does not use virtualization or Docker. This means that, 1) I can use this within a virtual container like Hyper-V, and 2) it’s not using some weird virtualized network or hosts proxying.

This means that the websites are acting on the physical network, which means I can manually change the WordPress site address to my local Tailscale IP! LocalWP complains about there being a Site URL mismatch, but simply ignoring the warning is harmless and I’m left with an easy-to-manage set of WordPress instances segmented by port number.

Problems and Troubleshooting

This setup works great. It’s stable, reliable, and accessible. I can access my code environment remotely, my terminal remotely (through VSCode or Tailscale and SSH), and I can access my WordPress sites remotely. However, the one problem I’ve noticed while testing this setup is that iPad multitasking is unreliable.

The iPad is not good at keeping the VSCode instance in state. There are many times I’ve found myself switching between apps and coming back to a blank VSCode window that now has to load from scratch.

ℹ️ Update from the future:

I originally wrote this in April 2023, and since then have noticed some changes. Maybe it’s the iPad OS 17 beta, or something on Microsoft’s side, but the stability of VSCode seems to have significantly gotten better.

While I was editing this post for publishing (on my iPad, duh), I decided to try and go back to VSCode after not using it for a while. Since I had used it last, I had swapped between the Photos app, a Remote Desktop session, Obsidian, and some other apps. All of that and 30 minutes later, and VSCode was still running, still connected to the tunnel, and still responsive! Interesting.

This has a pretty nasty ramification: since I develop with React, I run terminal watchers, like npm start, that forever run until stopped. A lot of those processes build my code. When I switch back to a blank VSCode window on my iPad, or if my Mac loses network connection, VSCode has to reload and any processes that were running are still running. Worse still, the terminal session is lost, which means that my process is running in the background somewhere, unable to be terminated without a complete server restart (or some hardcore terminal process drilling that I’m not familiar enough with).

The solution? I started using tmux, a terminal window manager. This allowed me to create instances of my terminal that I could switch to, even if my session was disconnected. Just a quick tmux attach-session -t name-of-session and boom, I’d be back to where I was! This is such a cool tool, and it has other benefits, such as being able to run VSCode’s code tunnel in the background without leaving a Terminal window open on my dev server.

The iPad

So, this infrastructure allows me to work remotely from almost anything, which is great. But how specifically can I work from my iPad?

Unfortunately, my iPad is the generation right before the M1 version, which means I don’t get goodies like multi-window Stage Manager. However, I do get Stage Manager, albeit for just one screen (which can then be mirrored). So, I can get my multi-window fix that way. It’s hard on an 11″ screen, but it’s manageable.

My 11″ iPad Pro is teeny tiny next to my 16″ MacBook Pro

And it works! I can run Tailscale on my iPad and VPN into my server. VSCode can be accessed via vscode.dev, and I can add that to my homescreen to turn it into its own app. Finally, I use a combination of Terminus and ShellFish to SSH into my server if I want to quickly send commands or move files around. If I need to do something with the GUI, I can use Google’s awesome Chrome Remote Desktop web app to make sure my LocalWP instance is up and running.

💪 Random pro-tip:

If you’re using the Magic Keyboard, you should re-assign the Caps Lock key to be the “Escape” key. It’s very useful, especially in VSCode. You can do this by going to the Settings app → General → Keyboard → Hardware Keyboard → Modifier Keys.

Conclusion

Lookit! A whole freaking development setup on my iPad.

That’s my setup in a nutshell: A server running Ubuntu (through Hyper-V), with installs of Tailscale, LocalWP, VSCode, and tmux. This set of software allows me to code on my iPad with ease, and Stage Manager makes it so I can have Tailscale, Safari, VSCode, and an SSH client running on my tablet’s screen at the same time. I can access everything on my server remotely, and it’s fast.

There are some reliability concerns, and the screen can become cramped. However, this solution allows me to switch between devices with ease, which is especially great for testing (since I can also get my local websites on my phone!).

I’ll keep everyone updated on how this process goes and what issues I run into. Hopefully you’ve found this article helpful! Let me know how you’ve approached this problem, or other similar problems, in the comments section.

3 responses to “How I Built a Remote Dev Server (to code from my iPad)”

  1. Moriah Avatar

    It’s so cool you could build something so workable for you from so many pieces!

  2. Moriah Reif Avatar

    Damn. That is crazy. It’s fascinating how you can take what, to me, sounds like a mishmash of programs, and make it work beautifully for you.

  3. […] my last article on coding with an iPad, I wrote about an (admittedly) complicated way to set up a VSCode server to […]

Leave a Reply