telnet and rsh, which transmitted passwords in plain text.Your Machine → (encrypted tunnel) → Remote Server
22 by default.~/.ssh/authorized_keys.ssh-keygen -t ed25519 -C "your_email@example.com"
id_ed25519 the private key and id_ed25519.pub the public key.-t rsa may be used, but ed25519 is recommended for better security and performance.ssh username@hostname
ssh ubuntu@54.23.11.222 # AWS EC2 instance
ssh user@myserver.com # domain
ssh root@192.168.1.10 # LAN server
ssh -i mykey.pem ubuntu@<public-ip>
ssh -p 2222 user@host
The authenticity of host 'example.com (54.x.x.x)' can't be established.
Are you sure you want to continue connecting (yes/no)?
~/.ssh/known_hosts.~/.ssh/:~/.ssh/
id_ed25519 # private key
id_ed25519.pub # public key
authorized_keys # keys allowed to log in (on server)
known_hosts # server fingerprints
config # optional config file
~/.ssh/config to store shortcuts and settings:Host my-ec2
HostName 54.23.11.222
User ubuntu
IdentityFile ~/.ssh/mykey.pem
Port 22
ssh my-ec2
scp (Secure Copy) or rsync over SSH.scp file.txt user@host:/remote/path/
scp user@host:/remote/path/file.txt ./
scp -r ./myfolder user@host:/var/www/
rsync example (faster, syncs changes only):rsync -avz ./site/ user@host:/var/www/site/
ssh -L 8080:localhost:3000 user@host
localhost:8080 on your machine → localhost:3000 on the remote server.ssh -R 9000:localhost:3000 user@host
eval "$(ssh-agent)"
ssh-add ~/.ssh/id_ed25519
AllowUsers/etc/ssh/sshd_config.ssh client options.| Option | Description | Example |
|---|---|---|
-p <port> |
Connect to the remote host on the specified TCP port (default is 22). | ssh -p 2222 user@example.com |
-i <identity_file> |
Use this private key file for authentication (instead of the default ~/.ssh/id_*). |
ssh -i ~/.ssh/mykey.pem ubuntu@host |
-l <user> |
Specify the remote login user (same as user@host). |
ssh -l ubuntu 1.2.3.4 |
-F <configfile> |
Use an alternative SSH config file instead of ~/.ssh/config. |
ssh -F ./ssh_config my-alias |
-4, -6 |
Force use of IPv4 (-4) or IPv6 (-6). |
ssh -4 user@example.com |
-C |
Enable compression on the SSH connection (useful on slow links). | ssh -C user@example.com |
-q |
Quiet mode: suppress most warnings and diagnostic messages. | ssh -q user@example.com |
| Option | Description | Example |
|---|---|---|
-i <identity_file> |
Use specified private key file (repeated here because it is so common). | ssh -i ~/.ssh/id_ed25519 user@host |
-A |
Enable SSH agent forwarding (forward your local agent to the remote host). | ssh -A user@jumphost |
-a |
Disable SSH agent forwarding (explicitly turn it off). | ssh -a user@host |
-K |
Enable GSSAPI-based authentication (Kerberos etc.), if configured. | ssh -K user@host |
-o PreferredAuthentications=<methods> |
Specify which authentication methods to try (e.g., publickey,password). |
ssh -o PreferredAuthentications=publickey user@host |
-o IdentitiesOnly=yes |
Use only the explicitly specified identities (not every key from the agent). | ssh -i ~/.ssh/work_rsa -o IdentitiesOnly=yes user@host |
| Option | Description | Example |
|---|---|---|
-o StrictHostKeyChecking=yes|no|ask |
Control behavior when a host key changes or is unknown: yes = refuse; no = accept automatically; ask = prompt. |
ssh -o StrictHostKeyChecking=ask user@host |
-o UserKnownHostsFile=<file> |
Use a particular known-hosts file instead of ~/.ssh/known_hosts. |
ssh -o UserKnownHostsFile=./known_hosts user@host |
-o VerifyHostKeyDNS=yes|no |
Check host keys via DNS (SSHFP records), if configured. | ssh -o VerifyHostKeyDNS=yes user@host |
-o HostKeyAlgorithms=<list> |
Specify which host key algorithms to accept (useful when dealing with older servers). | ssh -o HostKeyAlgorithms=ssh-ed25519 user@oldhost |
| Option | Description | Example |
|---|---|---|
-L <local_port>:<host>:<host_port> |
Local port forward: listen on local port and forward to host:host_port from the remote side.
|
ssh -L 8080:localhost:3000 user@server |
-R <remote_port>:<host>:<host_port> |
Remote port forward: listen on remote port and forward back to host:host_port on your local side.
|
ssh -R 9000:localhost:3000 user@server |
-D <local_port> |
Dynamic port forwarding (SOCKS proxy) on the given local port. Useful for tunneling arbitrary traffic through SSH. |
ssh -D 1080 user@server |
-N |
Do not execute a remote command; only forward ports (no shell). | ssh -N -L 5432:db.internal:5432 user@bastion |
-f |
Run SSH in the background (after asking for passwords / passphrases). | ssh -f -N -L 8080:localhost:3000 user@server |
-g |
Allow remote hosts to connect to local forwarded ports (for -L / -D). |
ssh -g -L 8080:localhost:3000 user@server |
| Option | Description | Example |
|---|---|---|
-J <user@jump>[,<user@jump2>...] |
Use one or more jump hosts (proxy jumps). SSH will connect through these hosts to reach the final destination. |
ssh -J jumphost user@target |
-o ProxyCommand=<command> |
Use a custom command to connect to the server (legacy way to implement jump hosts). | ssh -o ProxyCommand="ssh jumphost nc %h %p" user@target |
-o ProxyJump=<host> |
Same as -J, for use in config files. |
ssh -o ProxyJump=jumphost user@target |
| Option | Description | Example |
|---|---|---|
-X |
Enable X11 forwarding (trusted or untrusted based on server config; sometimes restricted). | ssh -X user@remote |
-Y |
Enable trusted X11 forwarding (less restricted, but requires caution). | ssh -Y user@remote |
-t |
Force pseudo-tty allocation (useful when running interactive commands like top or sudo). |
ssh -t user@remote "sudo journalctl -f" |
-T |
Disable pseudo-tty allocation (never allocate a terminal). | ssh -T git@github.com |
| Option | Description | Example |
|---|---|---|
-v, -vv, -vvv |
Increase verbosity of logging (more v = more detailed).Useful for debugging handshake/auth problems. |
ssh -vv user@host |
-E <logfile> |
Append debug logs to the specified file. | ssh -vvE ssh.log user@host |
-M |
Place the SSH connection into "master" mode for connection sharing (ControlMaster). | ssh -M -S /tmp/ssh-sock user@host |
-S <ctl_socket> |
Specify the control socket path used for ControlMaster/ControlPath connections. Allows subsequent SSH calls to reuse the same TCP connection. |
ssh -S /tmp/ssh-sock user@host |
-O check|forward|exit |
Send control commands to an existing master connection (check status, request port forwarding, or close it). | ssh -O check -S /tmp/ssh-sock user@host |
-o Option (Config Key = Value)-o lets you specify any SSH config directive on the command line. Common patterns:Example -o usage |
Meaning |
|---|---|
-o ConnectTimeout=5 |
Fail if connection cannot be established within 5 seconds. |
-o ServerAliveInterval=30 |
Send keepalive messages every 30 seconds to avoid idle disconnections. |
-o ServerAliveCountMax=3 |
After 3 unanswered keepalives, SSH will terminate the connection. |
-o LogLevel=ERROR |
Show only error messages (less verbose than the default). |
-o Compression=yes |
Enable compression (same effect as -C). |
ssh-keygen is the standard tool (from OpenSSH) for creating and managing SSH key pairs.ssh-keygen is usually installed by default together with ssh.ssh-keygen -t ed25519 -C "your_email@example.com"
~/.ssh/id_ed25519~/.ssh/id_ed25519 → private key~/.ssh/id_ed25519.pub → public key~/.ssh/authorized_keys).-t:| Type | Option | Notes |
|---|---|---|
| Ed25519 | -t ed25519 |
Modern, fast, short keys, recommended default if supported. |
| RSA | -t rsa |
Widely supported, use 3072 or 4096 bits for security. |
| ECDSA | -t ecdsa |
Elliptic curve, okay, but ed25519 is often preferred. |
| DSA | -t dsa |
Deprecated/insecure, do not use. |
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
| Option | Meaning | Example |
|---|---|---|
-t <type> |
Key type (rsa, ed25519, ecdsa, ...). | ssh-keygen -t ed25519 |
-b <bits> |
Key size (mainly for RSA). | ssh-keygen -t rsa -b 4096 |
-C <comment> |
Add a comment (often an email or label). | ssh-keygen -C "laptop key" |
-f <filename> |
Specify output file (private key path). | ssh-keygen -f ~/.ssh/myserver_ed25519 |
-N <passphrase> |
Set passphrase non-interactively (be careful with shell history). | ssh-keygen -N "mySecret" ... |
-p |
Change the passphrase of an existing key. | ssh-keygen -p -f ~/.ssh/id_ed25519 |
-y |
Read a private key and print the corresponding public key. | ssh-keygen -y -f ~/.ssh/id_ed25519 > id_ed25519.pub |
-l |
Show fingerprint of a key. | ssh-keygen -l -f ~/.ssh/id_ed25519.pub |
-E <hash> |
Specify hash for fingerprints (e.g., md5, sha256). |
ssh-keygen -l -E sha256 -f id_ed25519.pub |
~/.ssh/:~/.ssh/
id_ed25519 ← default ed25519 private key
id_ed25519.pub ← its public key
id_rsa ← default RSA private key
id_rsa.pub ← its public key
~/.ssh/id_github~/.ssh/id_company~/.ssh/id_personal_server-f when generating to pick a non-default name:ssh-keygen -t ed25519 -f ~/.ssh/id_github -C "github key"
ssh-keygen -p -f ~/.ssh/id_ed25519
-y).pub file but still have the private key, you can regenerate the public key:ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub
-y reads the private key, extracts the matching public key, and prints it to stdout.-l, -E)ssh-keygen -l -f ~/.ssh/id_ed25519.pub
-E sha256 or -E md5 to specify hash algorithm:ssh-keygen -l -E sha256 -f ~/.ssh/id_ed25519.pub
known_hosts Entriesssh-keygen can also manipulate the ~/.ssh/known_hosts file (where host keys are stored).| Command | Meaning |
|---|---|
ssh-keygen -F hostname |
Find and print host keys for hostname in known_hosts. |
ssh-keygen -R hostname |
Remove all keys for hostname from known_hosts (useful if the remote host changed its key). |
ssh-keygen -R example.com
# 1) Generate key
ssh-keygen -t ed25519 -f ~/.ssh/id_github -C "github-email@example.com"
# 2) Print the public key
cat ~/.ssh/id_github.pub
# 3) Copy the printed key into GitHub > Settings > SSH and GPG keys
# 4) Use in SSH config
cat >> ~/.ssh/config <<EOF
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_github
EOF
ssh-keygen -t ed25519 -f ~/.ssh/id_server -C "server key"
# copy public key to server (if ssh-copy-id is available)
ssh-copy-id -i ~/.ssh/id_server.pub user@server
# or manually:
cat ~/.ssh/id_server.pub # copy this line
# then paste it into server's ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519
ssh-agent + ssh-add) to avoid entering the passphrase every time.~/.ssh/authorized_keys?~/.ssh/authorized_keys.authorized_keys for the target user.authorized_keys is basically the allow list of public keys for that Unix account.~/.ssh/authorized_keys can contain many public keys.ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMyKeyForLaptop laptop
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAnotherKeyForPC desktop
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDemoKey... old-server
authorized_keys<key-type> <base64-key-data> [<comment>]
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBlaBlaBla... my-laptop
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDemo... old-key
<key-type> could be:
ssh-ed25519ssh-rsa (legacy)ecdsa-sha2-nistp256<base64-key-data> is a long base64 string representing the public key.<comment> is free text, commonly:
id_ed25519.pub (laptop)work_ed25519.pub (work machine)authorized_keys:cat id_ed25519.pub >> ~/.ssh/authorized_keys
cat work_ed25519.pub >> ~/.ssh/authorized_keys
authorized_keys might look like:ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAALaptopKeyBase64... laptop
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAASomeWorkKeyBase64... work
ssh-copy-id to Add Keysssh-copy-id, which:
~/.ssh/authorized_keys,ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
authorized_keys.authorized_keys can optionally start with options that restrict what the key is allowed to do.<options> <key-type> <base64-key> <comment>
command="/usr/local/bin/backup-script.sh" ssh-ed25519 AAAAC3Nz... backup-key
from="1.2.3.4" – allow only from certain IPs.no-port-forwardingno-X11-forwardingno-agent-forwardingpermitopen="host:port"authorized_keys of the target user.authorized_keys.chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
~/.ssh/config?~/.ssh/config (user-level) or /etc/ssh/ssh_config (system-wide).ssh my-server),Match).~/.ssh/config
chmod 600 ~/.ssh/config
Host ALIAS_OR_PATTERN
Option1 value
Option2 value
...
Host block apply only to matching hosts.Host my-server
HostName 203.0.113.42
User ubuntu
IdentityFile ~/.ssh/id_myserver
ssh my-server
ssh -i ~/.ssh/id_myserver ubuntu@203.0.113.42
ssh_config:| Directive | Meaning | Example |
|---|---|---|
Host |
Start a block of settings for a host alias or pattern. | Host my-server |
HostName |
Real DNS name or IP to connect to. | HostName 203.0.113.42 |
User |
Remote login user (same as ssh user@host). |
User ubuntu |
Port |
Port number (default 22). | Port 2222 |
IdentityFile |
Path to the private key to use. | IdentityFile ~/.ssh/id_myserver |
IdentitiesOnly |
If yes, use only the keys listed here, not all from ssh-agent. |
IdentitiesOnly yes |
ForwardAgent |
Forward your local ssh-agent to the remote host (yes/no). |
ForwardAgent yes |
ProxyJump |
Jump host (bastion) for connecting to another host. | ProxyJump bastion.example.com |
LocalForward |
Set up local port forwarding (local_port host:host_port). |
LocalForward 8080 localhost:3000 |
RemoteForward |
Set up remote port forwarding. | RemoteForward 9000 localhost:3000 |
ServerAliveInterval |
Send keepalive every N seconds. | ServerAliveInterval 30 |
ServerAliveCountMax |
Number of unanswered keepalives allowed before disconnect. | ServerAliveCountMax 3 |
StrictHostKeyChecking |
How to handle unknown/changed host keys (yes/no/ask). |
StrictHostKeyChecking ask |
Host:
* matches any string? matches any single characterHost github.com
User git
IdentityFile ~/.ssh/id_github
Host *.example.com
User deploy
IdentityFile ~/.ssh/id_company
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
Host entries before generic ones like Host *.# 1) GitHub SSH
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_github
IdentitiesOnly yes
# 2) Personal VPS
Host vps
HostName 198.51.100.10
User root
Port 22
IdentityFile ~/.ssh/id_vps
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 3
# 3) Internal server via jump host (bastion)
Host bastion
HostName bastion.mycompany.com
User ubuntu
IdentityFile ~/.ssh/id_company
Host internal-app
HostName internal.app.local
User ubuntu
ProxyJump bastion
IdentityFile ~/.ssh/id_company
ssh github.com
ssh vps
ssh internal-app
Include to Split ConfigsInclude path_or_pattern~/.ssh/
config
config.d/
github.conf
work.conf
personal.conf
~/.ssh/config:Include ~/.ssh/config.d/*.conf
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
*.conf file can hold host blocks grouped by purpose (e.g., work vs personal).Match BlocksMatch allows conditional config based on:
Match CONDITION1 CONDITION2 ...
Option value
...
Match all
# reset conditions
Match host my-server localaddress 192.168.1.100
Compression yes
ServerAliveInterval 15
Match all
Match user deploy
IdentitiesOnly yes
IdentityFile ~/.ssh/id_deploy
ssh -G my-server
ssh -vvv my-server
~/.ssh and its contents.Host entry for each setting wins.chmod 600 ~/.ssh/id_*ForwardAgent yes (only enable when you trust the remote host).StrictHostKeyChecking no (can open you to MITM attacks).rsync is a fast, incremental file-copying tool.rsync [OPTIONS] SOURCE DEST
| Option | Description | Details |
|---|---|---|
-a |
Archive mode (recommended default) |
Preserves: • permissions • timestamps • symlinks • device files • recursive directories Equivalent to: -rlptgoD
|
-v |
Verbose output | Prints names of files being transferred. |
-z |
Compress data during transfer | Improves transfer speed on slow networks. |
--delete |
Mirror deletions |
Removes files on destination that no longer exist in source. Useful for exact mirroring. Always test with --dry-run first.
|
--dry-run-n |
Simulation mode | Shows what would change without making modifications. |
--progress |
Show per-file transfer progress | Useful for large files, shows speed and ETA. |
-e ssh |
Use SSH as the remote shell | Usually optional, but needed for customizing SSH options (port, key file, etc.). |
rsync -av source_dir/ backup_dir/
source_dir/ → copy contents of source_dir into backup_dir.source_dir (without slash) → copy the directory itself as a subdirectory.rsync -av project/ /mnt/backup/project/
rsync -av project /mnt/backup/
Destination tree becomes: /mnt/backup/project/...rsync -av --dry-run project/ /mnt/backup/project/
rsync -avz SOURCE/ user@remote.host:/path/to/dest/
rsync -avz user@remote.host:/path/to/src/ DEST/
rsync -avz ./app/ user@example.com:/var/www/app/
rsync -avz user@example.com:/var/log/myapp/ ./logs/
rsync -avz -e ssh ./app/ user@example.com:/var/www/app/
rsync -avz -e "ssh -p 2222" ./app/ user@example.com:/var/www/app/
rsync -avz -e "ssh -i ~/.ssh/deploy_key" ./app/ user@example.com:/var/www/app/
~/.ssh/config:Host myserver
HostName example.com
User deploy
Port 2222
IdentityFile ~/.ssh/deploy_key
rsync -avz ./app/ myserver:/var/www/app/
-e then, because SSH picks up config for myserver.rsync -avz --delete ./app/ myserver:/var/www/app/
/var/www/app an exact mirror of ./app.rsync -avz --delete --dry-run ./app/ myserver:/var/www/app/
rsync -av --delete ~/Documents/ /mnt/backup/Documents/
rsync -avz --delete ~/Documents/ backup@backup.example.com:/data/backup/junzhe-docs/
--exclude to skip certain paths:rsync -avz \
--exclude ".git/" \
--exclude "node_modules/" \
./app/ myserver:/var/www/app/
# exclude.txt
.git/
node_modules/
dist/
*.log
rsync -avz --exclude-from=exclude.txt ./app/ myserver:/var/www/app/
-a (archive) already includes:
-p → preserve permissions-o → preserve owner (needs root to work fully)-g → preserve group-t → preserve modification times-H → preserve hard links-A → preserve ACLs-X → preserve extended attributessudo rsync -aHAX --delete / /mnt/backup/rootfs/
-z helps on slow networks, but may be useless or harmful on fast LANs.rsync -avz --bwlimit=2000 ./app/ myserver:/var/www/app/
(limit ~2000 KB/s)
--partial keeps partially transferred files.--partial --progress is common for large files.# from local dev machine:
rsync -avz --delete \
--exclude ".git/" \
--exclude "node_modules/" \
./app/ myserver:/var/www/app/
rsync -avz --delete \
--exclude ".cache/" \
--exclude "Downloads/" \
~/ mybackup:/data/backups/junzhe-home/
rsync -avz \
user1@server1:/data/ \
user2@server2:/mirror/data/
rsync -avz --partial --progress \
largefile.iso myserver:/data/