iTranslated by AI
Building a Local Server with Cloudflare workerd for Browser-Based Program Execution
Summary of Article Content
Achieving local resource operations from a Web browser with the following configuration:
- Create a simple server using the Cloudflare
workerdbinary - Communicate using the WebSocket functionality of
workerd - Browser UI handled by
workerd, local resource operations by the Client app
Overview
The hurdle to creating your own personal utility tools is constantly lowering with the advent of AI coding agents.
As the number of tools increases, you'll want to consolidate them or have an operation UI because managing and running them is a pain to enhance work efficiency.
Implementing a UI in the browser is one of the options, as it is relatively easy to achieve using AI agents.
Necessity of a Server
To implement a UI in a browser, there is a hurdle where access to local resources is restricted for security reasons. A browser alone cannot execute arbitrary local programs or read/write local files.
Therefore, the common approach is to set up a server in the local environment, communicate with that server through the browser, and have programs associated with the server access the local resources.
workerd
workerd is a server runtime for JavaScript/WebAssembly (Wasm) built using the same system of code as the Cloudflare Workers production environment.
It includes web server features such as HTTP processing, and since it (allegedly) has short startup times, I decided to use it, thinking it would be good for running applications only when needed.
Configuration
The server is configured with workerd + hono.
The client is designed to receive instructions from the server and execute functions.
Cloudflare Workers actually supports WebSocket (requires DO: Durable Objects). And workerd also supports WebSocket.
WebSocket allows for maintaining bidirectional communication, so as long as a connection is established, communication can be initiated from either side at any time.
- workerd_server: Delivery functionality
- static_asset: Web Browser UI design and definition of executable functions
- client_worker: Functionality to receive instructions and execute locally defined functions
Issues Encountered
Handling Differences in workerd Paths Across Environments
{path to workerd executable} serve {path to config.capnp} is the required format.
The {workerd executable} has different paths and extensions depending on the environment (Windows/Linux/Mac, AMD64/ARM64), so some handling is required.
This time, I made it manageable via npm with npm install workerd and decided to run it as npx workerd serve {path to config.capnp}.
2. spawn EINVAL Error
Since I used npm functionality to start the server, I set up the configuration to launch workerd_server using child_process.spawn(). However, on Windows, if shell: false is set, a spawn EINVAL error occurs.
This is because it rejects .bat/.cmd files when shell: false is set, and I ran into this because Windows uses a command wrapper called npm.cmd. It can be a surprisingly troublesome issue if you're not aware of it.
Results
So far, I have only confirmed that it can execute shell commands on a local PC from a Web browser and return the results to the Web browser, but the core functionality was implemented in about half a day.
I came up with several applications and identified some challenges along the way, so I will record them here as a memorandum.
Applications
Deployment to Cloudflare Workers
The workerd_server in this configuration can be operated on Cloudflare Workers.
In that case, although security features would need to be fully implemented, it could be advantageous not to have to run the server yourself.
Decentralization of client_worker
While the client_worker was on the local PC this time, the same configuration can be adopted even if it is not on a local PC.
Any environment is fine as long as it can access the workerd_server. With the previously mentioned method of operating on Cloudflare Workers, connections are possible from the cloud, Raspberry Pi, or even smartphones (though the client side might be troublesome for smartphones).
Real-time Information Delivery Infrastructure
The concept this time was to execute programs, but since bidirectional communication is possible while a WebSocket is connected, it can be used as an information collection or delivery infrastructure.
While this configuration can be used as is, it's essentially a basic feature of Cloudflare Workers.
Reception Infrastructure for Webhooks, etc.
Since bidirectional communication is possible during a WebSocket connection, a configuration can be created where Webhook-style triggers are received in a local environment. This is also a basic feature of Cloudflare Workers.
Nevertheless, it seems interesting to build it yourself.
Cloudflare Workflows
There is a service called Cloudflare Workflows, which allows you to build durable multi-step applications on Cloudflare Workers.
By applying this, it seems possible to create multi-step workflows in a local environment, but apparently, it does not work with workerd alone.
It seems to work in a local simulation environment, so if you want to do something similar in a local environment, you would need to run it via miniflare or build similar functionality yourself.
Challenges
Security
Communication
This time, HTTP communication was used on localhost, but HTTPS is required for internal and external networks.
It is said that workerd can also be run with HTTPS by configuring tlsOptions.
When using it on Cloudflare Workers, it automatically becomes HTTPS, so no consideration is needed.
Authentication
This time, a one-time token method was adopted, creating a mechanism where access is impossible without knowing a random string generated at startup, but this is insufficient for use on internal/external networks or Cloudflare Workers.
I think access management using IDaaS would be a good way to balance implementation difficulty and security.
Execution Restrictions
This time, the available functions were limited through a registration system, but besides that, a mechanism to properly restrict executable commands and the scope of access is necessary.
To avoid unintended overwriting or deletion, it might be worth considering measures such as restricting execution to a sandbox environment.
Development Framework
Although the proof of concept was successful, finding an effective way to integrate it with my own tools will likely require some trial and error.
Discussion