Basic connection
ssh user@host # by password or a key from ~/.ssh
ssh -p 2222 user@host # non-standard port
ssh -i ~/.ssh/special_key user@host # a specific private key
ssh -v user@host # verbose: see which key is tried and which algorithm
Key authentication (the right way)
Password auth is unsafe (brute force). Keys are the standard:
ssh-keygen -t ed25519 -C "alice@laptop" # generate a pair (ed25519 is modern)
▸creates ~/.ssh/id_ed25519 (private) and ~/.ssh/id_ed25519.pub (public)
ssh-copy-id user@host # place .pub into ~user/.ssh/authorized_keys on host
▸now ssh user@host works without a password
The file ~/.ssh/authorized_keys on the server holds the public keys
allowed to log in. The permissions are strict, or sshd refuses:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
# see [[file-permissions]]
~/.ssh/config: aliases and options
Host prod
HostName 10.20.30.40
User deploy
Port 2222
IdentityFile ~/.ssh/prod_key
Host bastion
HostName bastion.example.com
User alice
Host internal-*
ProxyJump bastion # go through the bastion automatically
User deploy
Now ssh prod or ssh internal-db1 works without flags.
Port forwarding
# Local forward: localhost:8080 → host:80 THROUGH ssh
ssh -L 8080:localhost:80 user@host
▸now curl http://localhost:8080 reaches the remote :80
# Remote forward: open a port on the server, point it back to me locally
ssh -R 9090:localhost:3000 user@host
▸on the remote machine localhost:9090 = my local :3000
# Dynamic (SOCKS proxy)
ssh -D 1080 user@host
▸SOCKS5 proxy on localhost:1080, all traffic goes through host
Useful for reaching internal services without a VPN.
SSH agent
So you do not type a key's passphrase every time:
eval "$(ssh-agent)" # start the agent
ssh-add ~/.ssh/id_ed25519 # add a key, passphrase is asked once
ssh user@host # now without a password
ssh-add -l # what is in the agent
Agent forwarding (ssh -A) is a risky feature: it forwards the agent
to the remote host. Do not use it on untrusted servers
(root there can sign anything in your name).
scp / sftp / rsync
Copying files over the same channel:
scp file.txt user@host:/path/ # old school, simple
scp -r dir/ user@host:/path/ # recursive
rsync -avzP file.txt user@host:/path/ # modern: incremental, progress, compression
sftp user@host # interactive FTP-like
Use rsync for anything non-trivial: it resumes an interrupted transfer.
Server side
The config is /etc/ssh/sshd_config:
Port 22
PermitRootLogin no # do not let root in directly
PasswordAuthentication no # keys only
PubkeyAuthentication yes
AllowUsers alice bob
After editing:
sudo sshd -t # syntax check
sudo systemctl reload ssh # apply (HUP signal, does not drop current sessions)
Security
- Keys only, not passwords
- No root:
PermitRootLogin no - fail2ban or similar to block brute force
- Non-standard port lowers the noise but does NOT replace real protection
- Known hosts:
~/.ssh/known_hostsverifies the server's fingerprint; a "host key changed" warning is a reason to stop and check