SSH Remote Access with Keys, Client Config, and tmux
I standardized remote access to managed Linux hosts using SSH key authentication, a maintained ~/.ssh/config, and persistent tmux sessions. Host aliases and ProxyJump turned multi-hop logins into a single short command that survives dropped connections.
Objective & Context
SSH is the primary control channel for every server in the homelab. This lab builds reliable, low-friction access with key auth, named host entries, jump-host routing, and tmux for session persistence, the entry point for the hardening lab.
Learning Objectives
- Generate Ed25519 key pairs and deploy public keys with ssh-copy-id.
- Define host aliases with per-host users, keys, and ProxyJump in ssh_config.
- Connect through a bastion host with a single command.
- Keep sessions alive across disconnects with tmux.
- Harden the client side: key passphrases, agent, and known_hosts hygiene.
Environment & Prerequisites
Prerequisites
- OpenSSH client installed (standard on Linux and macOS; Windows via OpenSSH feature).
- Two reachable hosts for the ProxyJump step (a bastion plus a target, or simulate with one).
- tmux installed:
sudo apt install -y tmux. - Existing SSH keys are fine; generate fresh ones if you have none.
Step-by-Step Execution
1. Generate an Ed25519 key pair and deploy the public key
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" && ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]Expected output:
Generating public/private ed25519 key pair.
Your public key has been saved in ~/.ssh/id_ed25519.pub
Number of key(s) added: 1
What this teaches: ssh-keygen -t ed25519 creates the modern small, fast key type; -N "" sets an empty passphrase for lab convenience (use a real passphrase on production keys and load them with ssh-agent). ssh-copy-id appends the public key to the server's ~/.ssh/authorized_keys over one password-authenticated login, after which the key does the authenticating. Skip -f if you already have a key: ssh-keygen prompts before overwriting.
2. Define a host alias with ProxyJump
Host nas
HostName 192.168.20.10
User taki
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
Expected output (config file content):
(~/.ssh/config created with 600 permissions)
$ ssh -G nas | grep -E "^(hostname|user|proxyjump)"
hostname 192.168.20.10
user taki
proxyjump bastion
What this teaches: ssh_config turns repeated flags into a named host: ProxyJump chains through the bastion transparently, and ssh -G prints the effective config for debugging.
3. Connect with one command
ssh nasWhat this teaches: The alias resolves user, key, and jump host automatically; key-based auth means no password prompt. One short word replaces a long fragile command line.
4. Start a persistent session
tmux new -s work; tmux attach -t workExpected output:
Last login: Wed Jun 17 2026 from 192.168.10.5
[work] taki@nas:~$
What this teaches: tmux new -s work creates a named session; the server keeps it alive if your connection drops, and tmux attach -t work rejoins it. Long jobs survive network flakiness. In practice you detach with Ctrl-b d and reattach later; the second command here just demonstrates the reattach half.
How It Works
SSH multiplexes an encrypted channel over TCP: the handshake negotiates ciphers, the server proves its identity via host keys (checked against known_hosts), and the client authenticates, ideally with a public key challenge the server verifies against authorized_keys. Ed25519 keys are the modern default: small, fast, and secure.
ssh_config is a per-user policy file where Host blocks set options for matching names. ProxyJump composes connections: your client opens a channel to the bastion, then tunnels the second SSH session through it, so the target never needs a public address. IdentityFile pins which key each host uses, avoiding agent key-spray.
tmux adds persistence above SSH. The tmux server runs on the remote host independent of your connection; your terminal merely attaches to it. Detaching (Ctrl-b d) leaves everything running, which is why long transfers and builds belong inside tmux rather than a bare SSH session.
Validation & Testing
Disconnect mid-task and reconnect to confirm the tmux session resumes intact, and verify login uses the key (no password prompt). Pass criteria: one-command access through the jump host and a session that survives network drops.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Permission denied (publickey) | Server rejected all offered keys | Confirm the public key is in the server's ~/.ssh/authorized_keys, with 700 on ~/.ssh and 600 on authorized_keys; sshd in StrictModes ignores the file when permissions are looser |
| Host key verification failed | The server key changed or a different host answers | Investigate before deleting; remove the stale line with ssh-keygen -R hostname only when expected |
| ProxyJump hangs with no error | The bastion is unreachable or its SSH is down | Test ssh bastion alone first, then add -v to see where the chain stalls |
| tmux attach says no sessions | The session name was mistyped or the server was killed | List with tmux ls; sessions die if the host rebooted |
| Too many authentication failures | The agent offered many keys before the right one | Set IdentitiesOnly yes and pin IdentityFile per host |
| Connection freezes on idle | NAT or firewall drops idle TCP | Add ServerAliveInterval 60 to keep the channel active |
Advanced: Troubleshooting
- Password prompt: confirm the public key is in remote
~/.ssh/authorized_keyswith 600 perms. - ProxyJump fails: the bastion host entry must itself be reachable and keyed.
- Lost work on disconnect: always run long tasks inside tmux or screen.
Key Results
- Reduced multi-hop logins to a single aliased command.
- Eliminated password prompts via key-based authentication.
- Preserved 100% of long-running sessions across disconnects with tmux.
- Centralized host definitions in one maintained ssh config.
Key Takeaways
- Ed25519 keys plus ssh_config aliases make logins one word long.
- ProxyJump reaches private hosts through a bastion transparently.
- ssh -G reveals the effective config when behavior surprises you.
- tmux sessions survive disconnects; long jobs belong inside them.
- 600 on keys and 700 on ~/.ssh are mandatory, not cosmetic.
Practice Challenges
Challenge 1: Key-only lockdown
Goal: configure a test VM so password auth is disabled and only your key works, then verify a password login fails.
Hint: PasswordAuthentication no in sshd_config plus systemctl reload sshd.
Challenge 2: Detach survival
Goal: start a 10-minute task in tmux, kill your SSH client entirely, reconnect, and reattach to find it still running.
Hint: Ctrl-b d detaches cleanly first.