My homelab was already running; the laptop was still the dependency
The problem was not that I lacked a server.
I already run a Proxmox homelab with the usual collection of machines, storage, and services that accumulate when a person decides maintaining infrastructure is a hobby rather than a warning sign. My AI development environment was the odd exception. Orca, the projects, the terminals, and the agent processes still depended on my MacBook Pro.
That arrangement was convenient while AI coding tools were occasional helpers. It became less convenient when Claude Code and OpenAI Codex started doing work that could take a while: inspecting repositories, editing several files, installing dependencies, running tests, and investigating failures.
The Mac was both the interface and the execution host. Closing the lid stopped being a harmless physical action. It became a decision about whether an agent task should remain available.
On 19 October 2026, I moved the environment to a dedicated Ubuntu virtual machine on my Proxmox server. I called it Osaka-Orca. The name is slightly grand for a VM in a cupboard, but it gives the machine a job and makes it easier to talk about the architecture.
Orca describes itself as an agent development environment for Claude Code, Codex, and other coding agents. In my setup, Orca Desktop remains the interface I use on the Mac while the Linux VM hosts the runtime, projects, tools, and agent processes.
The important change was not “I installed Orca on Linux”. It was separating the place where I interact with an agent from the place where the agent works.
The working core of the setup is:
flowchart TB
Mac["MacBook Pro<br/>Orca Desktop"]
iPhone["iPhone<br/>Orca Mobile"]
subgraph Proxmox["Proxmox VE"]
subgraph VM["Osaka-Orca · Ubuntu VM"]
Server["Orca Remote Server<br/>Port 6768"]
Claude["Claude Code"]
Codex["OpenAI Codex"]
Projects[("Shared Project Files")]
Server --> Claude
Server --> Codex
Claude --> Projects
Codex --> Projects
end
end
Mac -->|"Wi-Fi or LAN / WireGuard"| Server
iPhone -->|"Wi-Fi / WireGuard"| ServerThis is the part I have verified. Browser control is deliberately not shown as a working branch because the client-hosted and server-hosted browser paths are still under investigation.
The VM gives the workflow a home
I chose a dedicated VM because it made the boundary explicit without requiring another physical computer or a cloud subscription.
Osaka-Orca has its own operating system, storage, service lifecycle, and development account. It is still part of my home network, so it is not magical isolation. It is an operational boundary: if the agent environment breaks, I can work on it without making the Mac itself the thing I am repairing.
The guest currently runs Ubuntu Server 24.04 LTS. The running image reports 24.04.5, but the point release is less important to the design than having a known Linux environment that I can reproduce and maintain.
The guest exposes two useful storage areas. The root filesystem is roughly 60 GiB, and a separate ext4 volume of roughly 500 GiB is mounted for projects. Those are the sizes I can verify from inside Ubuntu. The migration notes described the virtual disks as approximately 64 GB and 512 GB, but I cannot verify the Proxmox host’s physical storage mapping from inside the VM. I therefore do not present “NVMe operating-system disk” and “HDD project disk” as verified facts in this article.
That distinction sounds fussy until storage becomes part of an outage. A guest can tell me what virtual block devices and filesystems it sees. It cannot, by itself, tell me which physical device on the Proxmox host backs them or what performance characteristics that device has.
The split still makes sense even without the hardware label. Project data has a predictable home, and the operating-system volume is not the only place where important files might be hiding.
The current Orca service is a little different from my first notes
The installation path changed during the work, which is exactly why live configuration deserves more trust than an old setup note.
The running systemd unit is orca-serve.service. When I checked it on 26 October 2026, it was enabled and active. The service currently invokes /opt/Orca/orca-ide in server mode. From a shell, the CLI is available through the user’s local bin directory as ~/.local/bin/orca-ide.
The service is the important part, not the filename. I wanted Orca to behave like a server that returns after a reboot, rather than an application I had to remember to launch in a terminal.
That gives me a familiar operational loop:
- Proxmox starts the VM.
- Ubuntu starts the systemd-managed Orca service.
- Orca Desktop connects from the Mac.
- The remote workspace exposes the project storage.
- Agents run against the Linux environment.
During the initial verification, Orca Desktop connected to the Ubuntu runtime and the service reported an active state. That established that the basic remote path worked. It did not establish that every feature available in a local desktop workspace would work across the same boundary.
That second point became important later.
Remote Orca Server and SSH Host turned out to be different products in practice
I initially explored both connection mechanisms because I wanted to understand how a remote agent might control a browser displayed by Orca Desktop on my Mac.
A Remote Orca Server places the Orca runtime on the remote machine. Osaka-Orca runs the service, and my Mac connects to it.
An SSH Host is a different relationship. It includes an option for the remote host’s Orca CLI to interact with Orca on the desktop, which is interesting for browser work but not interchangeable with the remote-server setup.
I tried to use the same Ubuntu machine in both roles and hit a duplicate Osaka-Orca configuration. Rather than disturb the connection that was already working, I removed the separate SSH Host entry and kept the Remote Orca Server.
This was not a dramatic failure. It was a useful correction to my mental model. “Remote” is not one switch in Orca. The runtime, workspace, CLI, desktop, and browser can sit on different sides of the connection, and each relationship needs to be understood on its own.
Mobile access became a separate pairing problem
Once Osaka-Orca was running, I wanted to check my agents from an iPhone while the MacBook was closed. I assumed moving the runtime to the VM would make the mobile client independent as well. It did not. Orca Mobile was initially paired with the MacBook Pro, so when the laptop was offline the app reported the desktop as unavailable even though the Orca Remote Server on Osaka-Orca was still running.
That was another useful boundary: moving execution to a server does not automatically move every client connection with it.
Orca Mobile can pair with an additional host through a QR code or pairing URL. The installed Orca CLI also exposes --mobile-pairing, which generates a mobile-scoped pairing link rather than the default runtime-environment pairing link. I enabled that option on the existing orca-serve.service instead of starting a second Orca instance.
The service previously started with --pairing-address 192.168.0.122; I added --mobile-pairing, reloaded systemd, and restarted it. The service returned to an active state and its startup logs produced a mobile pairing URL. I retrieved that URL locally and entered it in Orca Mobile. It paired successfully. The URL contains authentication material, so it is not included here.
This gives the remote-access architecture two independent clients: Orca Desktop on the Mac and Orca Mobile on the iPhone, both connecting to Osaka-Orca. It does not yet prove that the mobile client can open existing conversations, show active agent progress, or survive the MacBook going to sleep.
WireGuard is the intended path away from home
I also looked at whether Orca Relay could provide remote access to the headless Ubuntu server. I found relay-related references in the executable, but did not establish that Relay is supported or enabled for this configuration. I therefore kept the design smaller and intend to use my existing WireGuard VPN: the phone connects directly over home Wi-Fi at home, or through WireGuard into the home network when away. That path has not yet been tested from Orca Mobile, so the service is not being presented as publicly reachable.
Pairing is not monitoring
At this point the evidence breaks into three separate claims:
- Mobile connectivity: Orca Mobile paired directly with Osaka-Orca — confirmed.
- Remote monitoring: viewing existing conversations and active agent progress — not verified.
- Unattended execution: confirming Claude Code or Codex completes work while the MacBook sleeps — not verified.
That distinction matters. Successful pairing is a concrete improvement, but it is not proof that the complete unattended workflow works.
Claude and Codex moved first; the rest of the workshop followed
Once the remote runtime was working, I installed and authenticated Claude Code and Codex on Osaka-Orca.
That put the agents next to the projects they were modifying. When an agent reads a file, runs a command, installs a dependency, or starts a test runner, the operation happens in the Ubuntu environment rather than on the Mac.
The practical benefit is consistency. Both agents see the same project directories, shell tools, language runtimes, and supporting services. I do not have to remember which changes happened locally and which happened on the server before I can understand a test result.
The supporting tools were chosen around the work I actually wanted to do:
- Headroom wraps Claude Code and Codex to manage context and tool output.
- Serena MCP provides code-oriented navigation and project understanding.
- Node.js and Python cover the language tooling used by the projects and utilities.
- Additional integrations provide access to Claude documentation and Google Drive.
I also experimented with Recall and Valkey, then removed them. They were interesting, but not necessary for the first version of this environment.
That removal was as important as the installation. A self-hosted environment becomes harder to understand every time another service is added “just in case”. Each service brings updates, configuration, logs, failure modes, and another process an agent might interact with. The useful set is the smallest one that supports the work.
The shell had to become part of the product
The migration did not end when Orca connected. A remote development environment is only pleasant if the terminal is pleasant enough to use.
Osaka-Orca was migrated from Bash to Zsh. The new shell uses Oh My Zsh, keeps NVM and Node.js available, and provides aliases for the development workflow. Claude Code and Codex are wrapped through Headroom, so the commands I type continue to use the same context-management layer as the agent sessions launched elsewhere.
I added a custom blue Powerline-style Starship prompt as well. That sounds cosmetic, but the prompt is part of how I tell which machine and project I am touching. A remote shell should make its context visible before I run a command.
The first version of the Zsh setup introduced severe paste lag through syntax highlighting. That was a good reminder that shell customisation has a failure mode: a feature intended to help typing can make typing unpleasant. I removed syntax highlighting and restored responsive pasting.
Starship also gained a daily systemd update check. It is a small maintenance mechanism, but it reflects the broader goal: keep the useful parts of the environment current without turning every update into a manual ritual.
This work happened after the initial migration, not on 19 October itself. The timeline matters because “the server was built” and “the server became comfortable enough for daily work” were separate milestones.
A remote machine still has ordinary process problems
During later checks I found zombie child processes associated with active Headroom and Orca-related processes. I deliberately left them alone while sessions were running rather than restarting services simply to make the process list look cleaner.
That is not a claim that zombie processes are harmless or that the situation deserves no follow-up. It was a maintenance decision: avoid interrupting work first, investigate cleanup when there is a safe point.
This is the less glamorous part of self-hosting. The architecture diagrams show services and connections. They do not show the moment when a process tree looks untidy and the safest action is to leave it alone until the agent finishes.
The same principle applies to updates, authentication, and storage. A persistent environment needs an operator who can decide when to repair it and when not to disturb a live task.
The browser is where the topology stops being obvious
The main server migration works. Browser control does not yet work the way I wanted.
My first goal was for an agent running on Osaka-Orca to control a browser tab inside Orca Desktop on my Mac. That would be useful for front-end debugging and interactive browser work while keeping the agent’s execution environment remote.
The remote CLI returned desktop_browser_bridge_unavailable. I changed the browser placement from Server (streamed) to This device, but the remote CLI still could not reliably drive the Mac-hosted browser.
The failure is easier to understand when the browser is treated as a separate host. A client-hosted browser lives on the paired desktop that I am looking at. A server-hosted browser lives on the execution machine and may be running without a desktop attached. The CLI needs to know which browser it is addressing, and the client-hosted path depends on the desktop being available.
That is also why “the remote server is connected” is not enough evidence. The runtime connection can work while the browser bridge fails.
When I checked GitHub issue #17634 on 26 October 2026, it was still open. The issue describes remote or SSH agents trying to control client-hosted browsers and asks for that workflow to become a first-class orca-cli path.
The linked work did not provide a verified fix for my error. #17354 and #16502 were still open pull requests when I checked. #14440 was still a draft pull request, and #6701 remained an open feature request about browser support for SSH workspaces and remote Orca servers.
That is useful corroboration, not a diagnosis. The issue describes a related topology and similar placement problems. It does not prove that my desktop_browser_bridge_unavailable error has the same cause or that every Orca version behaves the same way.
The other option is to run a browser on Osaka-Orca. An earlier diagnostic suggested providing a Chromium executable through ORCA_BROWSER_EXECUTABLE. I found no current configuration or successful test that proves the server-side headless browser path is working, so I am keeping it in the “next experiment” category.
Persistent infrastructure is not unattended execution
The reason I started this project was to close the MacBook without making the development environment disappear. The VM now stays online independently, and Orca Desktop can reconnect to the runtime.
The test I still need to run is narrower and more demanding:
- Start a real Codex task in a project on Osaka-Orca.
- Confirm that it has begun executing commands.
- Close the MacBook lid or disconnect the desktop client.
- Wait long enough for the task to reach a useful checkpoint.
- Reconnect and verify the changed files, logs, and test results.
That test can fail for reasons that have nothing to do with whether Ubuntu is still running. The agent may need an approval, an authentication token may expire, a command may wait for input, or the task may depend on a desktop connection.
So the accurate claim is that the architecture supports persistent execution. I have not yet proved unattended completion for every task. A running server is not a completed sleep-and-resume test.
That distinction connects with Writing Code Is No Longer the Hard Part. Agents can perform more of the typing and command execution, but I still need to understand the environment, inspect the result, and decide what is safe to leave running.
The server adds responsibilities I did not have to think about on the laptop
Moving the environment off the Mac reduced one dependency and created several operational responsibilities.
The VM needs a sensible update routine. Project storage needs a recovery plan, not just capacity. Agent credentials need to stay in secure mechanisms rather than project files. Services should run with only the permissions they need.
I have not established and verified a complete backup schedule and restore procedure for Osaka-Orca. Proxmox provides ways to back up a VM, but an available backup feature is not the same as a restore test. I will not describe the environment as recoverable until I have exercised that path.
The private network address, SSH port, account name, VM identifier, pairing address, and service logs are deliberately absent from this article. They are useful in administration notes and unnecessary in a public architecture description. Omitting them is not a security strategy by itself; access controls, credential handling, updates, and recovery matter more.
The VM boundary is helpful, but it is not a magic safety box. Claude Code and Codex can modify files and run commands. If I give an agent access to a project, a network, or a credential, the important question is what that access allows it to change.
Why I kept the work at home
A cloud VM could run the same agents and supporting tools. I chose Proxmox because I already had the infrastructure and the operational context.
Allocating a VM was quicker than designing another cloud deployment. I can decide how the operating system is configured, where project files live, which services run, and how the machine reaches other systems on my local network.
There is also a learning benefit. Self-hosting forces me to understand the service lifecycle, storage choices, authentication boundaries, and failure modes. That work is inconvenient when something breaks, but it is also why I prefer the arrangement. I can see the moving parts instead of treating the development environment as a black box.
The trade-off is maintenance. A managed cloud service would move some of that work elsewhere. Osaka-Orca leaves it with me, which is sensible only because I already run Proxmox and accept the responsibility.
The first milestone is useful, but not finished
| Objective | Current state |
|---|---|
| Create a dedicated Ubuntu VM on Proxmox | Working |
| Separate the guest operating-system and project volumes | Working |
| Run the current Orca runtime through systemd | Working |
| Connect Orca Desktop from the Mac | Working |
| Install and authenticate Claude Code | Working |
| Install and authenticate Codex | Working |
| Configure Headroom wrappers | Working |
| Configure Serena and selected integrations | Working, based on the setup |
| Prepare Node.js and Python tooling | Working |
| Move the development shell from Bash to Zsh | Working |
| Keep the Mac-hosted browser controllable from the remote CLI | Not working reliably |
| Configure a server-hosted headless browser | Not verified |
| Prove a Codex task completes while the Mac sleeps | Pending |
| Establish and test VM backup restoration | Pending |
The central outcome is still useful. The Mac no longer has to host the entire AI development environment. It provides the screen, keyboard, and familiar Orca Desktop workflow, while Osaka-Orca provides a Linux environment that can remain available.
That is the architectural change. The rest of the work is proving how dependable it is.
The next meaningful tests are less exciting than the migration
The next work is mostly verification rather than another collection of tools.
I need to run the sleep-and-resume test, decide whether the client-hosted browser path has a supported configuration, and test a server-side Chromium setup if I still need unattended browser work. I also need to establish a backup schedule and perform an actual restore.
The shell work has already shown me what the next phase looks like. A persistent environment is not finished when the main service starts. It needs a usable terminal, a process policy, updates that do not become surprises, and enough operational discipline to know when not to restart something.
My Mac is now the interface to the development environment. Osaka-Orca is the place where the work runs. That separation is useful, but the promise is still conditional until the pending tests pass.
