Until this round the gateway ran under nohup from the
shell that last built it — fine on a bench box, awkward across
reboots. An rc.d script and a matching install helper now put
e2b-compat on the same footing as any other FreeBSD
service: a rc.conf knob enables it, service e2b-compat
start starts it, daemon(8) supervises and restarts it on
crash, and the log lands in a known place. Nothing exotic; the point
is to stop reaching for ps and a fresh nohup
every time an operator wants the gateway up.
The rc.d surface
The script lives at tools/rc.d/e2b-compat in this repo and
gets installed to /usr/local/etc/rc.d/e2b-compat. The
wire format is stock FreeBSD: . /etc/rc.subr,
PROVIDE: e2b_compat, REQUIRE: NETWORKING
FILESYSTEMS LOGIN, and run_rc_command “$1” at the
bottom. service e2b-compat {start,stop,restart,status} behave
exactly as you’d expect from any base-system service.
The actual supervision is delegated to daemon(8):
/usr/bin/env $ENV /usr/sbin/daemon \
-p /var/run/e2b_compat.pid \
-P /var/run/e2b_compat.supervisor.pid \
-r -R 2 \
-f -o /var/log/e2b-compat.log \
-T e2b_compat \
/usr/local/bin/e2b-compat --listen ... --zfs-pool ... ...
-r -R 2 respawns the child two seconds after a crash —
cheap crash recovery without standing up a supervisor tree. -f
-o appends the child’s stdout/stderr to the log file, which
newsyslog(8) can rotate. -T e2b_compat
tags the lines into syslog too so boot-time failures show up in
/var/log/messages even before the logfile exists. The
two pidfiles split the roles on purpose: pidfile holds
the child pid so rc.subr’s service
status grep-for-procname path works, and
supervisor_pidfile lets a clean stop reach the
supervisor first so -r doesn’t respawn the child we’re
trying to kill.
rc.conf knobs
The script honours the usual <name>_enable +
per-variable overrides convention. Defaults match honor’s current
layout; override in /etc/rc.conf or
/etc/rc.conf.d/e2b-compat.
| variable | default | note |
|---|---|---|
e2b_compat_enable | NO | Set to YES to bring the service up at boot and allow service e2b-compat start without onestart. |
e2b_compat_listen | 127.0.0.1:3000 | The SDK’s default; keep bound to loopback and front with an SSH tunnel or a proper proxy for anything reachable off-box. |
e2b_compat_zfs_pool | zroot/jails | Parent dataset for per-sandbox clones; must exist before first start. |
e2b_compat_snapshot | zroot/jails/_template@base | The @base snapshot cloned for the empty-templateID path. Bump to the DNS-aware snapshot (…@base-dns-*) on hosts with per-jail resolv.conf plumbing. |
e2b_compat_jails_root | /jails | Mountpoint of the pool — where e2b-<id> clones land. |
e2b_compat_templates_root | /jails | Where the registry scans for <name>-template directories at startup and on POST /templates/reload. |
e2b_compat_ui_dir | /usr/local/share/e2b-compat/ui | Static SPA served under /ui/. The install helper copies e2b-compat/ui/ here so the deployed gateway’s assets live in the base filesystem layout, not /tmp. |
e2b_compat_otel_endpoint | empty | Passes through as OTEL_EXPORTER_OTLP_ENDPOINT. Empty string → the tonic exporter isn’t built (stderr logging only). See tracing. |
e2b_compat_logfile | /var/log/e2b-compat.log | Append-only target for the child’s stdout + stderr. newsyslog.conf can rotate on a cron just like any other base-system log. |
Two more knobs (e2b_compat_otel_service and
e2b_compat_env) let an operator set
OTEL_SERVICE_NAME and arbitrary extra
KEY=VALUE pairs without editing the script;
e2b_compat_restart_delay (default 2)
controls daemon(8)‘s respawn delay.
Installing on honor
tools/install-e2b-compat-service.sh handles the full
copy: the binary to /usr/local/bin/e2b-compat, the UI
tree to /usr/local/share/e2b-compat/ui/, and the rc.d
script to /usr/local/etc/rc.d/e2b-compat. It’s
idempotent — rerun to refresh any of those after a fresh
cargo build —release on the honor side. If
e2b_compat_enable= isn’t already in
/etc/rc.conf it appends e2b_compat_enable=“YES”;
otherwise it leaves the existing line alone.
From the dev machine:
mise run e2b:install-service-honor
That task chains e2b:sync-honor → e2b:build-honor,
scps the rc.d script + install helper to honor’s /tmp,
and invokes the installer under sudo. The service itself
isn’t started — the operator decides when to cut over, usually with
a quick service e2b-compat stop + start
roundtrip to avoid dropping in-flight sandbox API calls.
Day-to-day
sudo service e2b-compat start
sudo service e2b-compat status # expects a PID
sudo service e2b-compat restart # stops, supervisor exits, restart
sudo service e2b-compat stop
tail -f /var/log/e2b-compat.log # the log daemon(8) is appending to
A clean stop kills the supervisor first so -r doesn’t
respawn the child mid-teardown. That’s the reason the rc.d script
tracks two pidfiles — rc.subr’s
stop_postcmd uses supervisor_pidfile to
reach daemon(8) directly.
When it doesn’t start
service e2b-compat statussays “not running” butpsshows the binary → the pidfile drifted from the real child. Checksudo cat /var/run/e2b_compat.pidvs.pgrep -f /usr/local/bin/e2b-compat. A stale pidfile from a previous crash is the usual cause;service e2b-compat stop+ a freshstartfixes it./var/log/e2b-compat.logis empty and the service exits immediately → daemon(8) probably couldn’t exec the binary. Check/var/log/messagesfor a syslog line taggede2b_compat; permissions, a missing/usr/local/bin/e2b-compat, or a typo’de2b_compat_snapshot(nonexistent ZFS snapshot) are the usual shapes.- Gateway binds but
/templatesis empty → the templates-root is wrong or the directory has no*-templatechildren. Fix on disk, thencurl -X POST http://127.0.0.1:3000/templates/reloadto rescan without a restart. - After a GELI-unlock reboot, the service comes up before
coppicenet0does → adjustREQUIRE:(the script already listsNETWORKINGwhich covers the bridge on honor’s currentrc.conf; if you move the bridge setup into a late-boot unit, add it toREQUIRE:too).
Files
tools/rc.d/e2b-compat— the rc.d script, verbatim what gets installed.tools/install-e2b-compat-service.sh— binary + UI + rc.d copy, idempotent..mise.tomltaske2b:install-service-honor— one command from the dev machine./var/log/e2b-compat.logon honor — where child stdout/stderr land, including the tracing lines the gateway emits.