Remote SSH Development Server with Zed
This guide sets up a Raspberry Pi as a lightweight remote development server for an IDE running on another computer.
The examples use Zed on Windows, but the same general arrangement can be used with other SSH-capable IDEs including VS Code, although this is not recommended.
Why use a Raspberry Pi as a development server?
A lightweight IDE such as Zed can keep its graphical interface and other desktop work on the main PC while moving the resource-intensive development work to the Raspberry Pi.
This splits the workload:
- IDE PC: Zed’s graphical interface, display, keyboard/mouse interaction and local desktop resources.
- Raspberry Pi: source files, terminal, Git operations, language servers and development web server.
- GitHub: remote Git repository, accessed from the Pi through SSH agent forwarding.
This is particularly useful with a modest computer where a full VS Code Remote-SSH installation can consume substantial CPU, RAM, swap and disk space.
Zed’s Remote Development architecture is specifically designed this way: Zed runs its UI locally while the remote machine runs the source code, terminal, tasks and language servers.
The result is a very lightweight client/server development environment: the PC handles the interface while the Pi does the development work.
Assumptions
This guide assumes you already have:
- Raspberry Pi OS/Raspbian running on the Pi.
- SSH working between the PC and Pi.
- Passwordless SSH public-key authentication.
- An SSH agent on the PC containing the private key.
- An external persistent drive mounted on the Pi.
- Git installed on the Pi.
- Zed installed on the PC.
- A GitHub account with SSH access configured.
The important security principle is:
The private GitHub SSH key stays on the IDE PC. It is never copied to the Raspberry Pi.
The Pi will temporarily use the PC’s SSH agent through SSH agent forwarding.
The resulting architecture
flowchart TD
PC["PC - Windows + Zed + browser - Private SSH key - SSH agent"]
IDE["Zed on PC"]
PI["Raspberry Pi: (Zed remote server, Source files, Git, Python web server)"]
DRIVE[("1 TB external drive - /mnt/1TB/code")]
GH["GitHub, Git repositories"]
BROWSER["Web browser on PC"]
PC --> IDE
PC --> BROWSER
IDE -->|"SSH -A agent forwarding"| PI
BROWSER -->|"SSH port forwarding"| PI
PI --> DRIVE
PI -->|"Git over SSH, forwarded key"| GH
The private key never leaves the IDE PC:
flowchart LR
KEY["Private GitHub SSH key"] --> AGENT["SSH agent<br/>on IDE PC"]
AGENT -->|"forwarded authentication"| PI["Raspberry Pi"]
PI -->|"authentication request"| GH["GitHub"]
KEY -. "never copied" .-> PI
The Pi can therefore authenticate to GitHub without possessing the private key.
Add the public key to GitHub
The SSH key used for GitHub should already exist on the IDE PC because you already use it to connect to the Pi.
Copy the public key in PowerShell or in a text editor:
Get-Content "$HOME\.ssh\name+2026@host.com.pub"
Copy the resulting complete line.
On GitHub:
Profile → Settings → SSH and GPG keys → New SSH key
Give the key a descriptive title, select Authentication Key, and paste the public key.
GitHub requires the public key to be added to your account before it can be used for Git operations over SSH.
Do not copy the corresponding private key to the Pi.
Allow SSH agent forwarding on the Pi
The SSH server must permit agent forwarding.
On the Pi, edit:
sudo nano /etc/ssh/sshd_config
Find:
AllowAgentForwarding
If it is commented out or absent, add:
AllowAgentForwarding yes
Save the file.
Before reloading the SSH server, check the configuration:
sudo sshd -t
If there is no output, the configuration is syntactically valid.
Then reload SSH:
sudo systemctl reload ssh
A full restart also works:
sudo systemctl restart ssh
You do not normally need to restart the Pi.
Connect to the Pi from Zed
Open Zed’s Remote Projects dialog.
Choose Connect New Server.
Enter the SSH command you normally use to connect to the Pi, but add -A:
ssh -A pi@raspberrypi
The -A option enables SSH agent forwarding.
Zed uses the system ssh executable for Remote Development and supports -A as an SSH connection option.
If you already have a suitable SSH configuration entry, you can instead use that host name and add -A to the connection options.
First connection
On the first connection Zed will install its remote server executable on the Pi.
This is normal.
Zed’s remote server is considerably more lightweight than the VS Code Server arrangement, and it is responsible for the remote development components while the Zed interface remains on the PC. Zed stores the remote server under ~/.zed_server on the remote machine.
After the server has been installed, choose the project directory you want to open.
For this setup, that will be somewhere under:
/mnt/1TB/code/
Test GitHub access from Zed
Open Zed’s integrated terminal.
The terminal is running on the Pi, not on the Windows PC.
Check that the forwarded agent is visible:
ssh-add -l
You should see the key that is loaded into the PC’s SSH agent.
Now test GitHub:
ssh -T git@github.com
The first time, SSH may ask you to confirm GitHub’s host key.
After successful authentication, GitHub should respond with a message identifying your account and noting that GitHub does not provide shell access. This is the normal successful result.
If you instead get:
Permission denied (publickey).
check, in order:
- The private key is loaded into the PC’s SSH agent.
- Zed connected using
-A. AllowAgentForwarding yesis present on the Pi.- You reloaded
sshdafter changingsshd_config. - The corresponding public key is present in your GitHub account.
Create a development directory on the external drive
I keep development files on the persistent 1 TB drive rather than the Pi’s SD card:
sudo mkdir -p /mnt/1TB/code
Give your normal user ownership:
sudo chown pi:pi /mnt/1TB/code
Check:
ls -ld /mnt/1TB/code
You should now be able to create files there as pi.
For example:
cd /mnt/1TB/code
mkdir test
Clone a GitHub repository
From Zed’s terminal connected to the Pi:
cd /mnt/1TB/code
Then clone using the GitHub SSH URL:
git clone git@github.com:USERNAME/REPOSITORY.git
For example:
git clone git@github.com:USERNAME/my-website.git
Git on the Pi connects to GitHub using SSH.
The authentication chain is:
sequenceDiagram
participant Z as Zed (on PC)
participant P as Raspberry Pi
participant A as SSH Agent (on PC)
participant G as GitHub
Z->>P: SSH connection (-A)
P->>A: Request authentication
A-->>P: Sign authentication request
P->>G: SSH authentication
G-->>P: Authentication successful
P-->>Z: Git operation succeeds
The private key itself remains on the PC throughout.
Once the repository has been cloned, Zed can open and edit the files directly on the Pi. Git operations such as:
git status
git pull
git add .
git commit
git push
also execute on the Pi.
Run a Python web server on the Pi
For simple HTML/JavaScript development, Python’s built-in HTTP server is sufficient.
From the project directory:
python3 -m http.server 8000
This serves the current directory on port 8000.
However, repeatedly navigating to the correct directory manually is inconvenient. Zed tasks can use information about the file currently being edited, including $ZED_DIRNAME, which is the directory containing the current file.
Create a Zed web-server task
For a project-specific task, create:
.zed/tasks.json
inside the repository.
Add:
[
{
"label": "Start Python web server",
"command": "python3",
"args": [
"-m",
"http.server",
"8000"
],
"cwd": "$ZED_DIRNAME",
"use_new_terminal": true,
"allow_concurrent_runs": false
}
]
The important part is:
"cwd": "$ZED_DIRNAME"
Zed replaces $ZED_DIRNAME with the directory containing the file currently open in the editor.
Therefore, if you have:
/mnt/1TB/code/my-website/
├── index.html
├── css/
│ └── style.css
└── js/
└── app.js
and index.html is the active file, the task starts:
python3 -m http.server 8000
with:
/mnt/1TB/code/my-website/
as its working directory.
If the currently open file is instead:
/mnt/1TB/code/my-website/test/index.html
the server will start in:
/mnt/1TB/code/my-website/test/
This can be useful when testing several independent HTML pages, but if you always want to serve the whole project, replace:
"cwd": "$ZED_DIRNAME"
with:
"cwd": "$ZED_WORKTREE_ROOT"
which starts the server at the root of the Git worktree.
Forward the web-server port to the IDE PC
The Python server is running on the Pi, so localhost:8000 on the Windows PC would normally mean the Windows PC, not the Pi.
Zed can forward a remote port to a local port over its SSH connection. This tunnels your local traffic securely through the SSH connection to the Pi, effectively bypassing firewall restrictions or network accessibility issues. By default, the forwarded port is available only on the IDE PC’s localhost.
On Windows, open Zed’s local settings file:
%APPDATA%\Zed\settings.json
You can open it from Zed using the zed: open settings file command, or edit the file directly.
Add a port_forwards entry to the SSH connection for the Pi.
For example:
{
"ssh_connections": [
{
"host": "raspberrypi",
"args": ["-A"],
"port_forwards": [
{
"local_port": 8000,
"remote_port": 8000
}
]
}
]
}
If you already have an ssh_connections entry for the Pi, add port_forwards to that existing entry rather than creating a second entry.
Likewise, retain any existing projects, username, port or other settings.
Test the website
With the Python task running on the Pi, open the browser on the IDE PC and go to http://localhost:8000.
graph TD
A[IDE PC Browser] -->|localhost:8000| B[Zed SSH Tunnel]
B -->|Encrypted SSH| C[Pi Port 8000]
C --> D[Python HTTP Server]
The browser behaves as though the web server were running locally, even though the files and server are actually on the Pi.
Running the task
With the desired HTML file open in Zed:
- Open the command palette.
- Choose task: spawn.
- Select Start Python web server.
- Zed opens a terminal and runs the server on the Pi.
Zed’s tasks execute on the remote machine during a Remote Development session, so Python, the source files and the HTTP server all remain on the Pi.
Stop the server with:
Ctrl+C
in its terminal.
Final Note
In my testing, Zed remote development, Python Web Server, and BOINC can run concurrently without interfering with each other.