zed devcontainer with ssh
The editor ‘zed’ does not support devcontainer
. However, it does work with ssh
.
Instead of direct support for devcontainers
, ‘zed’ offers the Remote Development feature, which relies on a connection via ssh
.
You can run an ssh server in a Docker container and get something close to a native devcontainer
.
The idea comes from Supercharged Development with Zed.
This requires:
Dockerfile
– Integration of ssh server into thedevcontainer
docker-compose.yaml
– Build and start configuration of thedevcontainer
~/.ssh/config
– SSH client entry for easy access to the container- zed
settings.json
– appropriate remote config entry in the editor settings
Dockerfile
Example based on a small GO project. The image is essentially based on a Debian derivative.
#
# @see https://www.friedrichkurz.me/posts/2025-06-07-zed-devcontainer/
#
FROM docker.io/library/golang:latest
#
# zed didn't ask for a password - leave app user password empty
#
ARG APP_USER="app"
ARG APP_PASSWORD=""
ARG APP_DIR="/app"
ARG APP_UID="1000"
ARG SSH_PORT="2222"
#
# install ssh server and some essential development commands
#
RUN apt update \
&& apt install -y --no-install-recommends \
iproute2 \
net-tools \
procps \
ssh \
sudo \
&& apt clean \
&& echo >/etc/sudoers.d/10-installer "%sudo ALL=(ALL) NOPASSWD: ALL"
#
# basic sshd configuration
# - accept (empty) password authentication
# - listen on custom high port
# - accept some env variables
#
RUN cat <<EOT >/etc/ssh/sshd_config.d/app.conf
AcceptEnv LANG LC_* GIT_*
AllowUsers ${APP_USER}
AuthenticationMethods none
#AuthenticationMethods none,keyboard-interactive,password
KbdInteractiveAuthentication yes
LogLevel VERBOSE
PasswordAuthentication yes
PermitEmptyPasswords yes
Port ${SSH_PORT}
PrintMotd no
Subsystem sftp /usr/lib/openssh/sftp-server
UsePAM yes
EOT
#
# add development group and user
#
RUN groupadd -f -g ${APP_UID} ${APP_USER}
RUN useradd -u ${APP_UID} -g ${APP_UID} -G sudo -p "${APP_PASSWORD}" -m -s /bin/bash ${APP_USER}
#
# check sshd config
#
RUN /usr/sbin/sshd -t -e
#
# clone the relevant docker environment for ssh login
#
RUN env | grep -i go >> /home/${APP_USER}/.bashrc
#
# prepare app
#
USER ${APP_USER}
WORKDIR ${APP_DIR}
COPY --chown=${APP_UID}:${APP_UID} . ${APP_DIR}
RUN go mod vendor
RUN go build
RUN openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/C=DE/ST=Berlin/O=private/CN=devcontainer.local"
VOLUME [ "${APP_DIR}" ]
#
# start sshd
#
USER root
EXPOSE ${SSH_PORT}
CMD ["/usr/sbin/sshd", "-D", "-e"]
Docker Compose
The devcontainer
can be started with docker compose up --build
.
services:
devcontainer:
image: devcontainer:latest
pull_policy: always
build:
context: .
dockerfile: Dockerfile
volumes:
- type: bind
source: .
target: /app
ports:
- name: ssh
protocol: tcp
app_protocol: ssh
target: 2222
published: 2222
- name: http
protocol: tcp
app_protocol: http
target: 80
- name: https
protocol: tcp
app_protocol: https
target: 443
- name: http3
protocol: udp
app_protocol: http3
target: 443
cap_add:
- CAP_NET_BIND_SERVICE
networks:
- localdev
working_dir: /app
tty: true
networks:
localdev:
driver: bridge
driver_opts:
# https://docs.docker.com/network/packet-filtering-firewalls/#setting-the-default-bind-address-for-containers
"com.docker.network.bridge.host_binding_ipv4": "127.0.0.1"
ssh Config
Add a special host entry to ~/.ssh/config
#
# zed devcontainer
#
Host devcontainer
Hostname localhost
User app
Port 2222
StrictHostKeyChecking accept-new
UserKnownHostsFile /dev/null
Settings in »zed«
In ‘zed’, the devcontainer
can be easily opened using ssh devcontainer
.
{
"ssh_connections": [
{
"host": "devcontainer",
"username": "app",
"projects": [
{
"paths": [
"/app"
]
}
]
}
],
}