ttyd 1.7.7

ttyd: share a terminal in your browser without handing out a shell

ttyd turns any command into a web page: ttyd bash serves a shell at http://SERVER:7681. Since 1.7.4 visitors can only watch unless you pass -W, but ttyd 1.7.7 still listens on every network interface with no password by default. Bind it to 127.0.0.1, add -c user:password with TLS, or put it behind a reverse proxy.

5 min readTerminals and remote servers

At a glance

  • ttyd bash serves a terminal on port 7681, and each browser tab gets its own process.
  • It is read-only by default since 1.7.4; -W lets visitors type.
  • It listens on all interfaces with no password, so use -i 127.0.0.1, -c and TLS.
  • To show a job that is already running, point ttyd at tmux attach -r.

Install ttyd

The current release is ttyd 1.7.7, from March 30, 2024. On macOS run brew install ttyd; on Windows, winget install tsl0922.ttyd or scoop install ttyd.

On Ubuntu, sudo apt install ttyd installs it from universe: Ubuntu 26.04 ships 1.7.7 and 24.04 ships 1.7.4. Debian 13 stable has no ttyd package (testing and unstable do), so use sudo snap install ttyd --classic or a static binary from the GitHub releases page, then check it with ttyd --version.

Share a terminal in the browser

ttyd bash serves bash at http://SERVER:7681, and every browser connection gets a fresh bash of its own: in our test, two tabs got two different process IDs. Port 7681 is the default; -p 8080 picks another and -p 0 a random free one, which ttyd prints at startup.

Since ttyd 1.7.4 (October 2023) the page is read-only by default. Visitors see the output but cannot type, and ttyd logs The --writable option is not set, will start in readonly mode; add -W (--writable) to let them type.

Bash
ttyd bash          # read-only, http://SERVER:7681
ttyd -W bash       # visitors can type
ttyd -p 0 htop     # random free port

ttyd keeps running until you stop it. -o makes it exit after one client disconnects, and -q when the last client leaves.

Lock it down: address, password and TLS

ttyd 1.7.7 listens on all interfaces (0.0.0.0) with no password, so anyone who can reach the port can open the page. ttyd -W bash on a public address hands a shell as your user to whoever finds it, and even read-only mode shows every secret printed to the screen.

Bind it to localhost with -i 127.0.0.1 (or -i lo, or a UNIX socket path) and reach it through an SSH tunnel. -c user:password adds HTTP basic auth and the page returns 401 without it, but basic auth is only base64 encoding, so add TLS with -S, -C and -K.

Bash
ttyd -i 127.0.0.1 bash
ssh -L 7681:127.0.0.1:7681 user@server    # then open http://localhost:7681
ttyd -c alice:s3cret -S -C cert.pem -K key.pem bash

With TLS on, plain HTTP requests got a redirect to HTTPS in our test, and only the right credentials got a 200. -A with a CA file requires client certificates, and -O rejects WebSocket connections from other origins.

FlagWhat it doesDefault
-p, --portPort to listen on; 0 picks a random port7681
-i, --interfaceInterface or address to bind, or a UNIX socket pathAll interfaces
-W, --writableLet visitors typeOff (read-only)
-c, --credentialBasic auth as user:passwordNone
-S, -C, -KTLS on, certificate file, key fileOff
-A, --ssl-caCA file for client certificatesNone
-H, --auth-headerTrust a header set by an authenticating proxyNone
-b, --base-pathPath prefix a proxy passes through, up to 128 charactersNone
-O, --check-originReject WebSocket connections from other originsOff
-m, --max-clientsMaximum number of clients0 (no limit)
-o, --onceAccept one client, exit when it disconnectsOff
-q, --exit-no-connExit when the last client disconnectsOff
-a, --url-argLet the URL pass arguments to the command, risky with a shellOff
-P, --ping-intervalWebSocket ping interval in seconds5

Put ttyd behind a reverse proxy

With nginx or another proxy in front, keep ttyd on 127.0.0.1 and let the proxy handle TLS. This is the ttyd wiki's nginx example; the Upgrade and Connection headers carry the WebSocket the terminal runs over.

Text
location / {
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_pass http://127.0.0.1:7681;
}

If the proxy serves ttyd under a path such as /ttyd/ and passes that path through, start ttyd with -b /ttyd. If the proxy already logs users in, -H X-Auth-User (or whichever header it sets) makes ttyd require that header: in our test requests without it got 407. Anyone who reaches ttyd directly can send the header too, so keep it on 127.0.0.1.

Watch a long job without giving anyone a shell

Because each browser tab gets its own process, ttyd bash cannot show a job you already started. Run the job in tmux and serve a read-only tmux client instead.

Bash
tmux new -d -s train
tmux send-keys -t train 'python3 -u train.py' Enter
ttyd -i 127.0.0.1 tmux attach -r -t train

In our test the browser showed the job's output live, typed input never reached it, and the session kept running after the tab closed. The wiki's ttyd tmux new -A -s ttyd vim shares one session between every tab and your own terminal instead. The tmux detach and attach guide covers the session side, and tmate alternatives compares other ways to share a terminal.

Skip the port, the proxy and the shell

A browser terminal means an open port, a password and a certificate to look after, even when all you want is to see how one job is doing.

FAQ

Is ttyd safe to expose to the internet?

Not with its defaults: ttyd 1.7.7 listens on every interface with no password and no TLS. Keep it on 127.0.0.1 behind a reverse proxy or an SSH tunnel, or turn on -c with -S, -C and -K, and leave -W off unless visitors need to type.

What port does ttyd use by default?

Port 7681. Change it with -p, or pass -p 0 for a random free port, which ttyd prints when it starts.

How do I make ttyd writable?

Start it with -W (--writable), as in ttyd -W bash. Since 1.7.4, ttyd starts read-only unless that flag is set.

Can several people watch the same ttyd terminal?

Not with ttyd bash, because each browser connection starts its own process. Serve a tmux session instead: ttyd tmux attach -r -t train to watch a running job, or ttyd -W tmux new -A -s ttyd to share one writable session.

What is the difference between ttyd and GoTTY?

Both serve a terminal over the web. The original GoTTY (yudai/gotty) has had no commits since December 2017; the maintained fork sorenisanerd/gotty released v1.10.0 in October 2026, listens on port 8080 and is read-only unless you pass -w.

Check on long runs from your phone

Change one import and every tqdm bar prints a link you can open on any device. Get a Discord or Slack message when the run finishes, fails or stalls.

Get a live linkpip install tqdm-live

Sources