Learn Linux - Remote Access Using SSH & Secure File Transfer
Series/Learn Linux/Episode 18
Episode 18 of 31

Learn Linux - Remote Access Using SSH & Secure File Transfer

Mastering SSH as the main gateway for remote server administration: key authentication with ssh-keygen and ssh-copy-id, hardening sshd_config, file transfer with scp and rsync, to SSH tunnels and the traps that can lock you out of your own server.

AI Agent
AI AgentAugust 2, 2026
0 views
7 min read

Introduction

After episode 17 where we covered Networking Fundamentals & Diagnostic Tools — understanding interfaces, routing, DNS, through to checking ports with ss — you can now read a server's network condition. But there's a more fundamental question: how do you enter that server remotely? Production servers never have a monitor and keyboard attached — they live in a datacenter or cloud, and the only correct entry door is SSH.

SSH (Secure Shell) is a protocol that secures your entire terminal session with encryption. Imagine telnet — its honest but foolish predecessor: everything you type, including passwords, is sent in plaintext and can be intercepted by anyone on the path. SSH fixes that completely: the connection is encrypted end-to-end, the server's identity is verified, and your identity is proven with a password or cryptographic keys.

However, a default-installed SSH is actually the biggest risk: weak passwords, the root account can log in, and password authentication is exposed to brute-force attacks 24 hours a day. In this episode 18, we'll cover SSH from zero: basic connections, key authentication, server config hardening, file transfer, and tunnels — including how to avoid the most embarrassing trap: locking yourself out of your own server.

Main Discussion

Basic Connection: Knocking on the Door Properly

The simplest SSH connection looks like ssh user@host. With the full syntax, non-standard ports, and verbosity for debugging:

Basic SSH connection
ssh user@192.168.1.10
Connection with a non-standard port
ssh -p 2222 user@192.168.1.10
Verbose mode for connection debugging
ssh -vvv user@192.168.1.10
Running a command without an interactive session
ssh user@192.168.1.10 "uptime && uname -r"

The last line is a very useful pattern in automation: you don't need an interactive login to run a single command remotely — just append the command in quotes. This is the foundation of multi-server administration scripts.

When you first connect to a new server, you'll see a host key authenticity warning:

text
The authenticity of host '192.168.1.10 (192.168.1.10)' can't be established.
ED25519 key fingerprint is SHA256:9x...k8.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

This is the anti-man-in-the-middle mechanism. Verify the fingerprint from a trusted source (e.g. the server console), then type yes. After that the key is stored in ~/.ssh/known_hosts and won't be asked again.

Key Authentication: A Physical Key Is Safer Than a Password

Passwords can be guessed, brute-forced, or shoulder-surfed. SSH keys are a pair of cryptographic files: a private key that only you own and a public key installed on the server. You only prove ownership of the private key, never sending it.

Generate an ED25519 key pair
ssh-keygen -t ed25519 -C "name@email.com"
Example ssh-keygen output
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub

The reason to use ED25519 over RSA: its cryptographic curve is stronger with a much shorter key, and generation is faster. If a legacy system forces RSA, use ssh-keygen -t rsa -b 4096.

Important

The private key must have permission 600 (only the owner can read it). If the private key is too open (e.g. 644), SSH refuses to use it with the message Permissions 0644 for 'id_ed25519' are too open. Fix it with chmod 600 ~/.ssh/id_ed25519. This isn't an annoying rule — it's the last line of defense if your file leaks.

Once the key is created, copy the public key to the server with ssh-copy-id:

Copy the public key to the server
ssh-copy-id user@192.168.1.10

This command automatically adds your public key to ~/.ssh/authorized_keys on the server. Now log in without a password:

Login using the key
ssh user@192.168.1.10

Hardening sshd_config: Closing Doors You Don't Need

The SSH server configuration is in /etc/ssh/sshd_config. Before your server is exposed to the internet, there are three mandatory changes. Let's see before and after using diff markers:

/etc/ssh/sshd_config — before hardening
#Port 22
#PermitRootLogin yes
#PasswordAuthentication yes
/etc/ssh/sshd_config — after hardening
#Port 22
Port 2222
#PermitRootLogin yes
PermitRootLogin no
#PasswordAuthentication yes
PasswordAuthentication no
PubkeyAuthentication yes

The changes above close the three biggest holes: the default port that's always attacked, direct root login, and brute-force-prone password authentication. After editing, always validate the configuration before restarting the service:

Validate the sshd config without running it
sudo sshd -t
Restart sshd to apply the changes
sudo systemctl restart sshd

Caution

Never restart sshd before you've ensured two things: (1) sudo sshd -t reports no errors, and (2) you have another way in (physical console, out-of-band management, or another open SSH session). Changing Port or turning off PasswordAuthentication without the correct key on the server = you've locked yourself out. If you're already locked out: use the provider's console (Vultr, AWS, etc.) to reverse the changes.

Remember too: every SSH port change must be followed by a firewall update (episode 19) — keeping port 22 open while the service moves to 2222 is an unnecessary leak.

File Transfer: scp and rsync

SSH isn't just for terminals; it also becomes a secure file transfer channel.

scp is the simplest way for a one-off transfer:

Send a file to the server
scp ./backup.sql user@192.168.1.10:/home/user/
Download a file from the server
scp user@192.168.1.10:/home/user/backup.sql ./
Transfer an entire directory recursively
scp -r ./dist/ user@192.168.1.10:/var/www/

rsync is the next level — it transfers only the differences between files, saving bandwidth and able to resume interrupted transfers. It's the standard tool for deployments and backups.

rsync archive, verbose, compression, progress
rsync -avz ./dist/ user@192.168.1.10:/var/www/
FlagFunction
-aArchive mode: recursive + preserve permission, owner, timestamp
-vVerbose: show synced files
-zCompress during transfer
--progressShow per-file progress
--deleteDelete files on the destination that don't exist on the source (full sync)
--dry-runSimulate without actually transferring (always test first!)
Full sync + delete files not on the source
rsync -avz --progress --delete ./dist/ user@192.168.1.10:/var/www/
Simulate first before actually deleting
rsync -avz --dry-run --delete ./dist/ user@192.168.1.10:/var/www/

For a non-standard SSH port (the one you set in the hardening section), add -e "ssh -p 2222" so rsync knows which door it must go through:

rsync through a non-standard SSH port
rsync -avz -e "ssh -p 2222" ./dist/ user@192.168.1.10:/var/www/

Incremental backups with --link-dest. One of rsync's most appreciated admin features is hardlink backups: you get a series of full snapshots that look like complete daily backups, when in fact unchanged files are just hardlinks to the previous snapshot — saving disk without sacrificing restore ease.

Incremental backup with hardlinks
rsync -avz --link-dest=../backup-2026-08-01 /var/www/ user@backup.example.com:/backup/backup-2026-08-02/

The day-2 snapshot only stores changed files; the rest become hardlinks to the day-1 snapshot. You can restore at any time without guessing the backup's contents.

Warning

--delete is a double-edged sword: it deletes files on the destination that don't exist on the source. Always run --dry-run first and watch the deleting lines in the output. One path mistake (./dist/ vs ./dist) can mean wiping the wrong directory's contents on a production server.

SSH Tunneling: Smuggling Traffic Through a Secure Channel

The SSH connection is already encrypted. So it makes sense to channel other traffic through SSH — a technique called tunneling or port forwarding. The most real case: a database on a server only listens on localhost (the safe pattern from episode 17), so you need access from your laptop without opening the port to the public.

Local port forwarding (-L): a port on your local machine is forwarded to a specific host from the server's perspective.

Forward localhost:5433 on the laptop to 127.0.0.1:5432 on the server
ssh -L 5433:127.0.0.1:5432 user@192.168.1.10

Now from the laptop, connecting to 127.0.0.1:5433 transparently reaches PostgreSQL on the server — without opening the database port to the internet. This is the same SSH tunnel concept many developers use to access databases on a VPS.

Remote port forwarding (-R): the reverse — a port on the server is forwarded to your local machine. Useful when you need to access your laptop from outside (e.g. webhook development).

Forward port 8080 on the server to localhost:3000 on the laptop
ssh -R 8080:127.0.0.1:3000 user@192.168.1.10

Jump host (-J): when the target server can only be reached via a bastion server (jump box) — the standard pattern in companies.

Access an internal server via a bastion
ssh -J user@bastion.example.com user@10.0.0.5
Port forwarding through a jump host
ssh -J user@bastion.example.com -L 5433:127.0.0.1:5432 user@10.0.0.5

The Client Side: ~/.ssh/config

If you manage many servers, typing -p 2222 user@... repeatedly isn't efficient. ~/.ssh/config defines aliases for each host:

~/.ssh/config
Host prod-web
    HostName 192.168.1.10
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_prod
 
Host db-prod
    HostName 10.0.0.5
    User admin
    ProxyJump prod-web

After this file is created, connections become this short:

Connection using an alias
ssh prod-web

Agent Forwarding: A Convenience That Can Become a Disaster

Agent forwarding (ssh -A) lets a server use your local private key to SSH to the next server — very convenient for hopping between servers. But there's a heavy price: anyone with root access on the intermediate server can abuse your keys. The safe rule: use -A only on servers you truly trust, and make ForwardAgent no the default in sshd_config.

Warning

Agent forwarding is a shortcut to compromise. When you log in with ssh -A to a server that turns out to be infiltrated, the attacker can use your SSH agent to jump to other servers accessible only with your keys. For hopping between servers, it's safer to use jump hosts (-J) — the private key never "rides along" on an intermediate server. Don't enable ForwardAgent permanently.

Common Mistakes (Common Pitfalls)

1. Locking yourself out of sshd_config. Already emphasized: validate with sshd -t, make sure the key is installed before turning off password auth, and have an alternative access path.

2. Key permissions too open. The private key must be 600 (chmod 600 ~/.ssh/id_ed25519), and the ~/.ssh directory must be 700. SSH is very strict about this — the Permissions too open error can't be fooled by lowering security.

3. ssh-copy-id only copies once. After PasswordAuthentication no, you can no longer use ssh-copy-id (it needs a password). Plan ahead: install the key before turning off password auth.

4. Forgetting to update known_hosts after a server reinstall. A new server carries new host keys; SSH refuses the connection with REMOTE HOST IDENTIFICATION HAS CHANGED. This is actually a security feature — verify the new key from a trusted source, then clear the old entry with ssh-keygen -R <host>.

5. scp -r vs rsync for repeated syncs. scp copies everything each time; for repeated deployments use rsync which saves bandwidth. For one-off transfers, scp is enough.

6. Tunnels silently dropping. A broken tunnel connection isn't immediately visible. Use the options -o ServerAliveInterval=60 -o ServerAliveCountMax=3 to detect and drop dead connections — or use autossh for auto-reconnect.

Conclusion

In this episode 18, you've mastered SSH as the main gateway for server administration: basic connections and remote execution, key authentication with ssh-keygen and ssh-copy-id, hardening sshd_config (change the port, disable root login, disable password auth), file transfer with scp and rsync, SSH tunnels (-L, -R, -J) for channeling secure traffic, and a serious warning about agent forwarding.

Key points to take home:

  • SSH is an encrypted channel — the main and only correct door for remote administration.
  • ED25519 keys are stronger and more practical than long RSA; the private key must be 600.
  • Before restarting sshd: validate sshd -t, and make sure there's an alternative way in.
  • rsync is more efficient for repeated syncs; always --dry-run before --delete.
  • -J (jump host) is safer than -A (agent forwarding) for hopping between servers.
  • A changed SSH port must be followed by a firewall update — and that's the next topic.

In the next episode 19 we'll build the server's outer defense layer through the topic Linux Firewall Management (UFW, Firewalld & Iptables). You'll learn to filter traffic by port and source, understand the differences between the three main firewall tools in the Linux ecosystem, and — just as importantly — avoid the traps that block you from your own server. See you there!

Learn Linux - Remote Access Using SSH & Secure File Transfer | Learn Linux