~ $ man persistent-tmux-sessions

Persistent tmux sessions on a server you SSH into

7 min · updated

A remote dev box is only useful when you can SSH in and immediately pick up where you left off. That means tmux must be running before you arrive, your named session must exist, and reattaching must be a single command. This guide wires all three: a boot-created session via systemd, an attach-or-create alias, and a layout that survives reboots.

The problem with starting tmux manually

If tmux only starts when you SSH in and run tmux new-session, two things go wrong:

The fix is to have tmux create the canonical session at boot, independently of any SSH connection. systemd user services are the right tool for this.

systemd user service

Create the service file at ~/.config/systemd/user/tmux.service:

[Unit]
Description=tmux default session
After=network.target

[Service]
Type=forking
ExecStart=/usr/bin/tmux new-session -d -s main
ExecStop=/usr/bin/tmux kill-session -t main
KillMode=none
Restart=on-failure

[Install]
WantedBy=default.target

Key details:

Enable linger so the service runs without a login session

systemd user services normally only run while the user has an active login session. On a server, that means the service would stop when you disconnect. Linger removes that restriction.

loginctl enable-linger $USER

This is a one-time command. After enabling linger, systemd starts user services at boot and keeps them running even when no one is logged in.

Enable and start the service:

systemctl --user daemon-reload
systemctl --user enable tmux.service
systemctl --user start tmux.service

Verify it is running:

systemctl --user status tmux.service
tmux list-sessions

You should see main: 1 windows (or similar) from list-sessions even before you have attached.

The attach-or-create alias

The -A flag to tmux new-session attaches to an existing session by that name if one exists, and creates it if it does not. Combined with -s main, this gives you a single command that always lands you in your workspace.

alias t='tmux new-session -A -s main'

Add this to your ~/.bashrc or ~/.zshrc. Now t is the only command you need to type after SSHing in. If the systemd service created the session at boot, you attach to it. If the session was somehow absent, a new one is created under the same name.

SSH config for a one-keystroke workflow

On your local machine, add a host entry in ~/.ssh/config:

Host vps
  HostName 203.0.113.10
  User ahmed
  IdentityFile ~/.ssh/id_ed25519

Now ssh vps connects, and if you add tto your shell's login init (or just muscle-memory type it), you are in your workspace in two commands. Some people set RemoteCommand tmux new-session -A -s main in the SSH config to attach automatically, but that prevents interactive SSH commands like ssh vps 'git pull' — it is a tradeoff.

Organizing windows in the boot session

A single tmux session with named windows is enough for most server workflows. You can pre-create windows in the service by chaining tmux commands in ExecStart, but this gets unwieldy. A simpler approach: use a setup script that the service calls on first run, or just create windows manually once and rely on tmux-continuum to restore the layout after reboots.

# example: pre-create named windows at session start
# (add to ExecStart after new-session, or run manually once)
tmux new-window -t main -n code
tmux new-window -t main -n logs
tmux new-window -t main -n ops

With tmux-continuum configured (@continuum-restore 'on'), these windows are automatically restored on the next boot. The systemd service creates the bare session; continuum restores the saved layout on top of it within seconds.

Verifying persistence after a reboot

# reboot the server
sudo reboot

# after reconnecting (wait ~30 seconds)
ssh vps
tmux list-sessions
# should show: main: N windows (created ...) [attached]

If the session is absent after reboot, check linger status and service logs:

loginctl show-user $USER | grep Linger
journalctl --user -u tmux.service --since "5 minutes ago"

The most common failure mode is forgetting loginctl enable-linger. The service file is correct but linger is off, so systemd tears down the user slice — and the service with it — when the last session closes.

Multiple named sessions

If you run more than one project on the same server, separate sessions by project rather than stacking everything into windows on one session. Each session has its own window list and status bar, making context switching clean.

# alias per project
alias t='tmux new-session -A -s main'
alias tc='tmux new-session -A -s care90'
alias td='tmux new-session -A -s dars'

The systemd service only creates main at boot. The other sessions come alive when you first attach and are saved/restored by continuum from that point forward.

For running parallel Claude Code sessions across these sessions, see the tmux + Claude Code layout guide.