Only people who are trying to run a Linux server are going to be interested in tmux.
And the only people who don't know the difference between tmux and a terminal are people who don't use Linux — which is the vast majority of the world.
I'm in that majority, slowly making the move to the other side.
(If you want to know the actual difference between tmux and a terminal, that's coming up below — I went on a bit of a tangent.)
Short story long, I had zero interest in this topic until recently. That's because I just built a Linux server last month, and I genuinely can't describe how amazing it is to have my own machine that's always on. It's actually life changing — the possibilities are endless now, especially with AI doing a lot of the heavy lifting for you.
If you're a bit ADHD and very OCD like I am, you might be interested in setting up a personal Linux server just to organize your life.
Anyways. I'm just going to embrace that I've become a real nerd.
Connecting to the Server
Once you have your server up and running, you actually don't want to be anywhere near it.
It's just there, humming along, doing work for you. You send it commands, and it diligently keeps working. So the problem becomes: how do you actually connect to it and send those commands?
The only real way is to SSH into the machine.
Once you know you have to SSH in, there are actually a lot of ways to do it. The most basic is the built-in terminal on macOS or PowerShell on Windows — that's all you need to get started and set things up. That's what I used at first.
Then I moved on to iTerm2, because I wanted to open more windows and customize my view a little.
Next I tried the VS Code Remote-SSH extension, which seemed like everything I needed... until it kept disconnecting.
Every time I stepped away from my laptop for more than ten minutes, my VS Code Remote-SSH connection would just... die.
I'd come back, click into the terminal, and get the dreaded "Connection lost" banner. Whatever was running — a build, a script, a long pip install — gone. Not paused. Gone. I'd have to reconnect, re-navigate to whatever folder I was in, and start over.
At first I thought it was my wifi. Then I thought it was VS Code being VS Code. Turns out it was neither — it was just SSH doing exactly what SSH is designed to do.
The actual problem
SSH connections have idle timeouts. If your connection sits quiet for too long (no keystrokes, no data), the server — or sometimes your network in between — decides nobody's there and closes it. VS Code's Remote-SSH extension rides on top of a normal SSH connection, so when that connection drops, your whole remote session drops with it. Any process running in that integrated terminal dies too, because it was a child of that SSH session.
I tried the obvious fixes first. Adjusting SSH keepalive settings in my config. Closing my laptop lid less aggressively. None of it fully solved the problem — and even when it did help, I still didn't have a way to walk away from my desk, come back later, and find my work exactly where I left it.
That's when I actually looked into tmux.
What tmux fixes that SSH can't
And now I'm back to using iTerm2 — but with tmux.
At first I thought tmux was just another terminal client, an alternative to iTerm2. After spending a couple hours actually learning it, I realized that's wrong — you need both, together. The setup is:
- A terminal app like iTerm2 is your interface — how you see and type into things.
- tmux is software installed on your Linux server that gives you a persistent session, capable of holding multiple windows and panes, that survives even when your terminal app disconnects.
You don't need tmux on your local computer at all — just install it on your server.
That distinction is the whole reason tmux solves the problem VS Code Remote-SSH couldn't:
tmux runs as its own process on the server, completely separate from your SSH connection. When you start a tmux session and your SSH connection drops — whether from a timeout, closing your laptop, or switching wifi networks — the tmux session just keeps running in the background. Your terminal, your running processes, your scrollback, all of it stays alive.
You reconnect, "attach" to that same session, and it's like nothing happened.
This is different from a VS Code terminal tab, which is tied directly to the SSH connection and dies with it.
Why I also switched from VS Code's terminal to iTerm
This part is optional, but it's what made the whole setup click for me. VS Code's Remote-SSH terminal is still just a terminal window living inside an editor — and editors are heavier, slower to reconnect, and not really built around terminal multiplexing.
iTerm (or honestly, any solid terminal app) plus tmux gives you a lighter, faster connection that's purpose-built for exactly this. I still use VS Code for editing files, but for anything long-running — scripts, servers, agents, builds — it goes through iTerm + tmux now.
Setting up tmux: the actual steps
If you've never touched tmux before, here's the minimum you need to get going.
1. Install tmux on your server
# Ubuntu/Debian
sudo apt update && sudo apt install tmux
# macOS (if you're testing locally first)
brew install tmux
Check that it installed correctly:
tmux -V
# should print something like "tmux 3.3a"
2. SSH into your server like normal
ssh your-username@your-server-ip
3. Start a tmux session
tmux new -s mywork
The -s mywork names the session, which matters once you have more than one running.
4. Do your thing
Run whatever you'd normally run — a script, a server, an install. It's just a regular terminal at this point.
5. Detach (don't close your terminal — detach instead)
Ctrl+b, then d
This is the key habit change. Instead of closing the terminal window when you're done for now, you detach. The session keeps running on the server even after you close your laptop or your SSH connection times out.
6. Reconnect later — from anywhere
ssh your-username@your-server-ip
tmux attach -t mywork
Everything is exactly where you left it. Same scrollback, same running processes.
7. If you forget the session name
tmux ls
This lists every active session so you can attach to the right one.
Turning it into a script
Once I had the basic habit down, I didn't want to manually rebuild my session every time I rebooted the server or killed it by accident. So I scripted it.
Here's the layout I landed on, since I'm running a few Docker containers with agents working on different repos:
Session: agents
├── Window 0 "shell" → plain bash
├── Window 1 "agent-1" → docker exec -it agent-1 bash
├── Window 2 "agent-2" → docker exec -it agent-2 bash
├── Window 3 "agent-3" → docker exec -it agent-3 bash
└── Window 4 "logs" → docker logs, one pane per agent
1. Create the script file
mkdir -p ~/scripts
nano ~/scripts/start-agents.sh
2. Paste this in
#!/bin/bash
# Kill existing session if it exists, so we always start clean
tmux kill-session -t agents 2>/dev/null
# Window 0: plain shell
tmux new-session -d -s agents -n shell
# Window 1-3: one per agent
tmux new-window -t agents -n agent-1
tmux send-keys -t agents:agent-1 "docker exec -it agent-1 bash" Enter
tmux new-window -t agents -n agent-2
tmux send-keys -t agents:agent-2 "docker exec -it agent-2 bash" Enter
tmux new-window -t agents -n agent-3
tmux send-keys -t agents:agent-3 "docker exec -it agent-3 bash" Enter
# Window 4: logs, split into 3 panes
tmux new-window -t agents -n logs
tmux send-keys -t agents:logs "docker logs -f agent-1" Enter
tmux split-window -h -t agents:logs
tmux send-keys -t agents:logs "docker logs -f agent-2" Enter
tmux split-window -h -t agents:logs
tmux send-keys -t agents:logs "docker logs -f agent-3" Enter
tmux select-layout -t agents:logs even-horizontal
# Land back on the shell window
tmux select-window -t agents:shell
# Attach
tmux attach -t agents
(Swap agent-1, agent-2, agent-3 for your actual container names.)
3. Make it executable
chmod +x ~/scripts/start-agents.sh
4. Run it
~/scripts/start-agents.sh
That's it — one command rebuilds the entire workspace, every window, every pane, every time.
Keyboard shortcuts I actually use
tmux shortcuts all start with a "prefix" — by default Ctrl+b. You press that, release it, then press the next key.
| Action | Shortcut |
|---|---|
| Detach from session | Ctrl+b then d |
| New window | Ctrl+b then c |
| Next window | Ctrl+b then n |
| Previous window | Ctrl+b then p |
| Jump to window by number | Ctrl+b then 0–9 |
| Visual window picker | Ctrl+b then w |
| Rename current window | Ctrl+b then , |
| Split pane vertically | Ctrl+b then % |
| Split pane horizontally | Ctrl+b then " |
| Move between panes | Ctrl+b then arrow keys |
| Close current pane | Ctrl+b then x |
| Auto-even pane sizes | Ctrl+b then E (capital) |
| Cycle pane layouts | Ctrl+b then Space |
| Pop a pane out into its own window | Ctrl+b then ! |
| Scroll up in a pane | Ctrl+b then [ (use arrow keys, q to exit) |
Commands I actually use
These work from a plain terminal (not inside tmux) unless noted:
| What it does | Command |
|---|---|
| Start a new named session | tmux new -s mywork |
| List all sessions | tmux ls |
| Attach to a session | tmux attach -t mywork |
| Attach to most recent, or create one if none exists | tmux attach || tmux new -s mywork |
| Attach using shorthand | tmux a |
| Attach to a specific session by name/index | tmux a -t mywork |
| Kill a session | tmux kill-session -t mywork |
| Create a new window in a session | tmux new-window -t mywork -n windowname |
| Rename a window | tmux rename-window -t mywork:0 newname |
| Send a command into a specific window | tmux send-keys -t mywork:0 "docker stats" Enter |
| Split a window into panes | tmux split-window -h -t mywork:0 |
| Even out pane sizes | tmux select-layout -t mywork:0 even-horizontal |
| Switch sessions (from inside tmux) | tmux switch-client -t mywork |
One gotcha worth knowing: if you're already inside a tmux session and try to run tmux again, you'll get a warning about nesting sessions. Use tmux switch-client instead of tmux attach when you're already inside tmux — attach is meant to be run from a plain shell.
What changed for me
I stopped losing work to idle timeouts. I stopped re-explaining context to myself every time I reconnected. And honestly, I stopped dreading stepping away from my desk for coffee.
It's a small habit change — detach instead of close — but it's the one thing that actually fixed a problem I'd been quietly fighting for weeks.
If you're running anything long-lived on a remote server, even something as simple as a personal project, tmux is worth the twenty minutes it takes to learn.