A Rust port of Eternal Terminal — a remote shell that automatically reconnects without interrupting the session.
Wire-compatible with upstream protocol version 6: an et.rs client can talk to a C++ etserver, and a
C++ et client can talk to an et.rs server, in both terminal and port-forwarding modes.
How we track upstream (Rust rewrite, not a C++ git fork): docs/upstream-factory.md.
Windows is a first-class target. Upstream has no native server there, so hosting a session on
Windows meant running the POSIX server inside WSL and landing in a WSL shell. et.rs runs the server
and the per-session terminal natively on Windows using ConPTY, so et gives you a real cmd.exe or
PowerShell — no WSL involved.
brew install minpeter/tap/et-rsInstalls et plus the etserver, etterminal, htm, and htmd role symlinks. The formula
conflicts with the upstream et formula — et.rs is a drop-in replacement, so uninstall one before
installing the other. Upgrade later with brew upgrade et-rs.
yay -S et-rs-bin
# or
paru -S et-rs-binInstalls the prebuilt release binary (x86_64, aarch64) with the role symlinks. Conflicts with the
eternal-terminal package for the same drop-in-replacement reason.
Every release ships archives (with .sha256
checksums) for Linux (gnu/musl, x86_64/aarch64), macOS (x86_64/aarch64), and Windows (x86_64).
The tarballs already contain the role symlinks:
curl -LO "https://github.com/minpeter/et.rs/releases/latest/download/et-VERSION-TARGET.tar.gz"
sudo tar -xzf et-VERSION-TARGET.tar.gz -C /usr/local/bin --strip-components=1To run the server on boot (Linux):
# /etc/systemd/system/et.service
[Unit]
Description=EternalTerminal server (et.rs)
After=network.target
[Service]
ExecStart=/usr/local/bin/etserver
Restart=on-failure
[Install]
WantedBy=multi-user.targetsudo systemctl enable --now et # and open 2022/tcp in your firewallcargo build --release # host
cargo build --release --target x86_64-pc-windows-gnu -p et # et.exeRequires protoc (Protocol Buffers compiler) on the build host.
One binary provides every role, selected by argv[0] (busybox-style symlinks) or by a leading
subcommand:
| Upstream binary | et.rs invocation | Windows |
|---|---|---|
et |
et <host> / et client <host> |
yes |
etserver |
etserver / et server |
yes |
etterminal |
etterminal / et terminal |
yes |
htm |
htm / et htm |
yes |
htmd |
htmd / et htmd |
yes |
ln -s et etserver && ln -s et etterminal && ln -s et htm && ln -s et htmdet user@host
et -c 'uptime' user@host:2022
et -t 8080:80 -r 9000:9000 user@host # forward and reverse tunnels
et -f user@host # forward the ssh-agent socket
et --jumphost jump.example --jport 2022 \
--jserverfifo /tmp/etserver.fifo1 dst:2022 # ET-native jumphost relay
etserver --daemon --pidfile /var/run/etserver.pid
htm # headless terminal multiplexer# on the Windows machine (needs Windows 10 1809+ for ConPTY)
et.exe server --daemon --port 2022 --pidfile "%LOCALAPPDATA%\etserver\etserver.pid"
netsh advfirewall firewall add rule name="et" dir=in action=allow protocol=TCP localport=2022# from anywhere
et user@windows-host:2022 # auto-detects cmd.exe login shell
et --winserver user@windows-host:2022 # explicitly force cmd.exe bootstrap
et --remote-shell powershell user@windows-host:2022 # PowerShell sessionBare clients run a credential-free %ComSpec% SSH probe before bootstrap. An expanded cmd.exe
path selects the Windows bootstrap (no printf, CRLF lines, & separator) and defaults
--terminal-path to et.exe; a literal %ComSpec% preserves POSIX behavior. --winserver
remains the explicit override. The session shell follows %COMSPEC%, or ET_SHELL if set on the
server. OpenSSH on Windows must be reachable.
Ghostty identifies itself as TERM=xterm-ghostty, but many remote hosts do not have that terminfo
entry and stock shell profiles may not recognize it as color-capable. ET sends
TERM=xterm-256color for Ghostty clients so remote prompts and applications retain broadly
supported 256-color behavior. Ghostty's standard COLORTERM=truecolor hint is also forwarded to
POSIX sessions so applications that use it for 24-bit color detection do not downgrade. Other
terminal types are forwarded unchanged.
- Protocol v6 handshake,
crypto_secretbox(XSalsa20-Poly1305) framing, sequence numbers, and catch-up buffers, pinned to upstream bytes by golden fixtures infixtures/wire.json. - Reconnecting client and server sessions with backed reader/writer replay.
- SSH bootstrap (
IDPASSKEYhandshake), remote PTY, window resize, keepalives,--commandexecution, and--no-terminalmode. - Forward, reverse, Unix-socket, port-range, environment-variable named-pipe, and ssh-style
(
bind_address:port:host:hostport, bracketed IPv6) tunnels. - SSH-agent forwarding via a server-created socket exported as
SSH_AUTH_SOCK. - ET-native jumphost relay (client,
etserverJUMPHOST_INITdispatch, andetterminal --jump). etserverINI configuration, daemon mode with pid file, log files honouring--logdir,--logtostdout,--silent,--verbose, and log rollover.- Headless terminal multiplexer (
htm/htmd) with upstream's base64 IPC framing, JSON state, tabs/splits/panes, and pane buffer replay. - Native Windows server and terminal: ConPTY shells, a loopback router authenticated with a per-server token, job-object breakaway so sessions survive the bootstrap ssh, and a console client that maps keys (including navigation keys upstream drops) to ANSI sequences.
- No telemetry:
--telemetryis accepted for compatibility and ignored. #![forbid(unsafe_code)]across every crate.
- The router is a loopback TCP listener; its address and a CSPRNG token live in the
--serverfifoendpoint file under%LOCALAPPDATA%\etserver, which takes the place of Unix socket permissions. - HTM runs native ConPTY panes on Windows 10 1809+; use
et.exe htmfrom an HTM-capable terminal emulator. It is a protocol relay, not a standalone pane UI. The pane shell isSHELL, thenCOMSPEC, thencmd.exe; its home isUSERPROFILE. - HTM IPC uses an authenticated loopback endpoint at
%LOCALAPPDATA%\et-htm\htm.ipc. The endpoint inherits the user-private application directory ACL, like the router.--socketon both HTM roles selects an isolated endpoint; on Windows it must remain below that user'sLOCALAPPDATAtree, without junctions or parent traversal. Do not grant other users access to this directory or its token files.htm -xshuts down only the selected authenticated daemon, not named fleet processes. - HTM first requests Windows job breakaway. If the host denies it, HTM reports the
restriction and starts a detached, handle-isolated daemon within the host job.
It survives the launching
htmclient, but not termination of that host job. The stricteretserver/etterminalSSH-bootstrap breakaway policy is unchanged. - Unix-socket tunnels remain POSIX-only.
- Inbound connections need a firewall rule; the server does not modify firewall state itself.
cargo test --workspaceApache-2.0