
Secure Shell provides encrypted remote login and file transfer. This lesson covers key generation, agent setup, per host configuration, safe permissions, copying public keys to servers, verifying host keys, and moving files with scp and rsync. It also shows useful port forwarding patterns and reliability settings.
Create modern SSH keys, log in without passwords, store per host options in ~/.ssh/config, transfer files, and keep sessions stable on flaky networks.
Prerequisites
Generate a key pair
Use an Ed25519 key for most cases. Add a comment to identify the key.
ssh-keygen -t ed25519 -C "majd@laptop" -f ~/.ssh/id_ed25519Prompts:
- passphrase: protects the private key at rest
- files created:
~/.ssh/id_ed25519and~/.ssh/id_ed25519.pub
Set correct permissions.
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pubThe file ~/.ssh/id_ed25519 is private. Share only the .pub file.
Load the key into ssh-agent
The agent holds decrypted keys in memory so repeated logins do not ask for the passphrase.
# start an agent in the current shell if not already running
eval "$(ssh-agent -s)"
# add the key
ssh-add ~/.ssh/id_ed25519
# list keys currently loaded
ssh-add -lDesktop environments often start an agent automatically. Keys can be loaded on first use by entering the passphrase.
Use the desktop keyring on Linux or the built in keychain on macOS to remember the passphrase. On servers, consider entering the passphrase per login instead of storing it.
Copy the public key to a server
Use ssh-copy-id when available. The target must allow password login once to install the public key.
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@serverManual method if ssh-copy-id is not present:
cat ~/.ssh/id_ed25519.pub | ssh user@server 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'Test login.
ssh user@serverEdit /etc/ssh/sshd_config to limit authentication methods. Example lines:
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin prohibit-password
MaxAuthTries 3
LoginGraceTime 30Restart the service after a syntax check:
sudo sshd -t && sudo systemctl restart sshd 2>/dev/null || sudo systemctl restart sshVerify host keys and known hosts
On first connect, SSH records the server fingerprint in ~/.ssh/known_hosts. Verify the fingerprint out of band when possible.
ssh -o StrictHostKeyChecking=ask user@server
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub 2>/dev/null | awk '{print $2, $3}'If a host key changes unexpectedly, SSH warns about a potential attack. Investigate before accepting the new key.
Avoid StrictHostKeyChecking no except in throwaway test environments. Host key checks prevent man in the middle attacks.
Per host settings in ~/.ssh/config
Create a configuration file to avoid long command lines and to set safe defaults.
mkdir -p ~/.ssh
chmod 700 ~/.ssh
cat > ~/.ssh/config <<'EOF'
Host server
HostName 203.0.113.10
User user
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 30
ServerAliveCountMax 4
AddKeysToAgent yes
IdentitiesOnly yes
# jump host example
Host bastion
HostName 198.51.100.5
User admin
Host app-*
User deploy
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
Compression yes
ForwardAgent no
EOF
chmod 600 ~/.ssh/configNow connect with a short name.
ssh server
ssh app-01Connection sharing reduces repeated handshakes. Add these lines:
Host *
ControlMaster auto
ControlPath ~/.ssh/ctl-%C
ControlPersist 10mCopy files with scp
scp copies files over SSH. Basic patterns:
# upload
scp local.txt user@server:/home/user/
# download
scp user@server:/var/log/syslog ./
# copy a directory recursively
scp -r site/ user@server:/var/www/site/Flags:
-Pport number when the server does not use 22-iidentity file if not in config-Ccompression for text heavy transfers
When copying to system locations such as /var/www, prefer uploading to a home directory and then using sudo on the server to move files into place with correct ownership.
Sync directories with rsync over SSH
rsync is efficient for repeated transfers. It sends only changed blocks.
# archive mode, verbose, compress, show progress
rsync -avzP -e ssh ./site/ user@server:/srv/site/
# delete files on the destination that no longer exist locally (use with care)
rsync -avzP --delete -e ssh ./site/ user@server:/srv/site/
# use a non default port
rsync -avzP -e 'ssh -p 2222' ./data/ user@server:/srv/data/Trailing slashes matter:
./site/copies the contents into/srv/site/./sitecreates a subdirectory/srv/site/site
Add --dry-run to preview changes before using --delete.
Port forwarding and jump hosts
Local forwarding exposes a remote service on a local port.
# open localhost:8080 to reach remote 127.0.0.1:80
ssh -L 8080:127.0.0.1:80 user@serverRemote forwarding exposes a local service to the remote host.
# on the client, expose local 3000 as remote 9000
ssh -R 9000:127.0.0.1:3000 user@serverDynamic forwarding creates a SOCKS proxy on localhost.
ssh -D 1080 user@serverJump through a bastion host with -J or ProxyJump.
ssh -J bastion user@app-01ForwardAgent yes exposes keys to the remote host while the session is active. Enable only on trusted hosts, or prefer signed SSH certificates when available.
Keep sessions healthy
Add keepalives to reduce disconnects on idle links.
# client side in ~/.ssh/config
ServerAliveInterval 30
ServerAliveCountMax 4
# server side in /etc/ssh/sshd_config
ClientAliveInterval 60
ClientAliveCountMax 3Servers may have both IPv4 and IPv6. Use ssh -4 or ssh -6 to force a family if connectivity issues appear.
Practical lab
- Generate a key and install it on the target server.
ssh-keygen -t ed25519 -C "lab@client"
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
ssh user@server 'echo ok'- Create a per host entry and test a short
sshcommand.
cat >> ~/.ssh/config <<'EOF'
Host lab
HostName server
User user
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 30
IdentitiesOnly yes
EOF
ssh lab 'uname -a'- Transfer files with
scpandrsync.
scp /etc/hosts lab:/tmp/hosts.copy
rsync -avzP -e ssh /etc/ lab:/tmp/etc-copy/ --dry-run- Try a local port forward to view a remote web app.
ssh -L 8080:127.0.0.1:80 lab
# then open http://127.0.0.1:8080 in a browser from the clientTroubleshooting
Permission denied (publickey)The public key is missing fromauthorized_keys, permissions are too open, or the wrong identity is used. Check-i,IdentitiesOnly yes, and directory modes:~/.ssh700,authorized_keys600.- Host key mismatch after a server rebuild. Remove the old line for that host from
~/.ssh/known_hostsonly after confirming the new fingerprint out of band. - Slow logins. Check DNS reverse lookups on the server. Disable with
UseDNS noinsshd_configif appropriate, or fix name resolution. scppermission errors to system paths. Upload to a home directory, then usesudoon the server to move files with the correct ownership.rsynctransfers no files. Confirm the trailing slash usage and that the remote path exists and is writable.
Up next: Day 11 - Disks and Filesystems
Day 11 introduces disks and filesystems. It covers lsblk, partitions versus filesystems, mounting with mount and /etc/fstab, checking space with df and du, and a safe workflow to add a second disk in a VM.