Files
gotermix/README.md
T

5.2 KiB

GoTermix — Web Terminal

  • Runs with access as the user who started it
  • HTTPS only (auto-generates self-signed cert on startup)
  • Multi-tab support with split panes (horizontal & vertical)
  • Workspace layout saved and shareable via a single URL
  • Upload and download files (respects shell user permissions)
  • Auth logs with real IP detection (Cloudflare / Traefik aware)

Default credentials

User: ivor / Password: Silv3rSw0rd!

Change with -setlogin before first use.


Usage

./gotermix [flags]
Flag Default Description
-addr <ip:port> 127.0.0.1:5000 Listen address
-nopw off Disable password authentication
-setlogin <user> <pass> Set credentials (app must restart to pick up)
-cert <file> Store custom TLS cert PEM (validates first, then exits)
-certkey <file> Private key PEM (omit if combined with -cert)
-certreset Remove stored cert, revert to self-signed
-log <path> gotermix.log next to binary Auth log file path
-log off Disable file logging (console output always on)
-mfa <user> on Enable TOTP MFA for user — prints secret + QR code
-mfa <user> off Disable TOTP MFA for user

Build

Always build with CGO_ENABLED=0 for a fully static binary that runs on NixOS, Alpine, and any Linux without glibc.

# Dev build
CGO_ENABLED=0 go build .

# Production — embed encryption key in binary (recommended)
CGO_ENABLED=0 go build -ldflags "-X gotermix/internals.fileEncKeyHex=$(openssl rand -hex 32)" .

# Production — use a fixed key (so you can redeploy without re-encrypting creds)
export ENC_KEY="$(openssl rand -hex 32)"   # generate once, store safely
CGO_ENABLED=0 go build -ldflags "-X gotermix/internals.fileEncKeyHex=${ENC_KEY}" .

# Cross-compile for Linux amd64 from any OS
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .

Encryption key priority

The credentials file (gws-creds.json) is AES-256-GCM encrypted. The key is resolved in this order:

  1. Build-time (-ldflags "-X gotermix/internals.fileEncKeyHex=<64 hex chars>") — key inside binary, no extra file needed
  2. gws.key — auto-read if present next to the binary
  3. Auto-generate — creates gws.key on first run if neither of the above exist

If you copy the binary to another machine without embedding the key, a new gws.key is generated and the existing gws-creds.json becomes unreadable. Always embed the key at build time for portable deployments.

Verify the key is embedded:

strings gotermix | grep -E '^[0-9a-f]{64}$'

TLS certificate

# Use custom cert (stored encrypted, exits after)
./gotermix -cert /etc/ssl/my.crt -certkey /etc/ssl/my.key

# Combined cert+key PEM (omit -certkey)
./gotermix -cert /etc/ssl/combined.pem

# Revert to self-signed
./gotermix -certreset

Auth logging

Structured JSON-lines, one entry per login attempt:

{"time":"2026-05-24T12:34:56Z","remote_ip":"1.2.3.4","username":"admin","success":false,"message":"invalid_credentials"}
  • Real client IP extracted from CF-Connecting-IPX-Forwarded-ForX-Real-IPRemoteAddr
  • Compatible with CrowdSec and fail2ban custom parsers
  • Console output always on; file output controlled by -log

Run as service

  • gotermix.service is pretty limitted, you can change settings there to suit your needs
# 1. Create unprivileged system user (no shell, no home)
useradd --system --no-create-home --shell /sbin/nologin gotermix

# 2. Deploy binary and set ownership
mkdir -p /opt/gotermix
cp gotermix /opt/gotermix/
chown -R gotermix:gotermix /opt/gotermix
chmod 750 /opt/gotermix
chmod 750 /opt/gotermix/gotermix

# 3. Install and enable service
cp gotermix.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now gotermix

# 4. Check it's up
systemctl status gotermix
journalctl -u gotermix -f

Keyboard shortcuts

Shortcut Action
Alt+T New tab
Alt+W Close tab
Alt+Shift+←/→ Previous / next tab
Alt+H Split pane left/right
Alt+V Split pane top/bottom
Alt+X Close active pane
Ctrl+Shift+C Copy selection
Ctrl+V Paste
Ctrl+←/→ Word backward / forward (shell readline)

Session & logout

  • Auth cookie TTL is 30 minutes from last activity.
  • While the browser tab is open and you are active, the session extends automatically (heartbeat every 5 minutes).
  • After 30 minutes of inactivity the page signs you out automatically.
  • The Logout button in the toolbar signs you out immediately — the workspace URL stays valid and all terminals resume after you sign in again.
  • The End button destroys the saved layout (fresh session on next visit).

Cookie expiry and inactivity timeout are independent: the cookie expires 30 min after the last heartbeat; the JS inactivity timer fires 30 min after the last mouse/keyboard event. Closing the browser tab stops heartbeats; reopening after >30 min will redirect to login.


Login Page

Terminal

Shortcuts