Skip to content

SSH keys, firewalls, and basic server security

8 min read

Why basic server security matters

The moment a server is reachable from the internet, it will be scanned. This isn’t personal—automated bots constantly probe IP ranges looking for weak passwords, exposed services, and outdated software. For beginners running a VPS or dedicated server, a few foundational steps dramatically reduce risk:

  • Use SSH keys instead of passwords
  • Lock down SSH (disable root login, limit users, change defaults carefully)
  • Enable a firewall with only required ports open
  • Add brute-force protection (Fail2ban)
  • Keep the system updated and minimize exposed software
This article focuses on practical, beginner-friendly security measures for typical Linux servers (Ubuntu/Debian examples, with notes for others).

SSH: keys vs passwords

Password authentication (what can go wrong)

Password logins are easy to set up but are vulnerable to:

  • Brute-force attacks: bots try many passwords quickly
  • Credential stuffing: reused passwords from breaches are tried automatically
  • Weak passwords: human-chosen passwords are often guessable
Even with a strong password, automated login attempts create noise and risk.

SSH key authentication (why it’s better)

SSH keys use public-key cryptography:

  • You keep a private key on your computer (never share it)
  • You place the matching public key on the server
  • The server verifies you own the private key without you sending it
Benefits:
  • Not vulnerable to brute-forcing in the same way passwords are
  • Strong security with modern key types (Ed25519)
  • Works well with agents and passphrases for usability
Best practice: Use SSH keys with a passphrase (so a stolen laptop doesn’t automatically grant server access).

Generating SSH keys (client side)

On Linux/macOS (or Windows with PowerShell + OpenSSH), generate an Ed25519 key:

```bash ssh-keygen -t ed25519 -C "your_email@example.com" ```

  • Accept the default file location (usually `~/.ssh/id_ed25519`)
  • Set a strong passphrase when prompted
This creates:
  • `~/.ssh/id_ed25519` (private key — keep secret)
  • `~/.ssh/id_ed25519.pub` (public key — safe to share)

Copy the public key to the server

If password SSH is currently enabled, use:

```bash ssh-copy-id username@server_ip ```

Or manually append it on the server:

1. On your computer: ```bash cat ~/.ssh/id_ed25519.pub ``` 2. On the server, as the user you want to log in as: ```bash mkdir -p ~/.ssh chmod 700 ~/.ssh nano ~/.ssh/authorized_keys ``` Paste the public key, then: ```bash chmod 600 ~/.ssh/authorized_keys ```

Test key login

From your computer:

```bash ssh username@server_ip ```

If it logs in without asking for the account password (it may ask for your key passphrase), key auth is working.

Locking down SSH (sshd) safely

SSH settings are typically in:

  • `/etc/ssh/sshd_config` (or split into `/etc/ssh/sshd_config.d/*.conf` on newer systems)
Before changing anything:
  • Keep a second session open, so you don’t lock yourself out.

Disable root login

Logging in directly as `root` is a common target. Prefer:

  • Log in as a regular user
  • Use `sudo` for admin tasks
In `sshd_config`:

```conf PermitRootLogin no ```

Then reload SSH:

```bash sudo systemctl reload ssh ```

Disable password authentication (after keys work)

Only do this once you’ve confirmed key-based login works.

```conf PasswordAuthentication no KbdInteractiveAuthentication no ```

Reload SSH:

```bash sudo systemctl reload ssh ```

If you later need emergency access, your hosting provider’s console (out-of-band access) can help.

Optional: restrict which users can SSH

This reduces exposure if extra accounts exist:

```conf AllowUsers youruser anotheruser ```

Reload again after editing.

About changing the SSH port

Changing SSH from port 22 can reduce log noise, but it’s security-through-obscurity. It may help against basic scanners, but it does not replace strong authentication and firewalling. If you change the port, remember to update:

  • firewall rules
  • your SSH command: `ssh -p 2222 user@server`

Firewall basics: UFW and iptables

A firewall controls which inbound connections are allowed. Most servers only need a few ports open.

Typical ports:

  • SSH: `22/tcp`
  • HTTP: `80/tcp`
  • HTTPS: `443/tcp`

UFW (Uncomplicated Firewall) on Ubuntu/Debian

UFW is a beginner-friendly frontend to iptables/nftables.

1. Check status: ```bash sudo ufw status verbose ```

2. Set sensible defaults: ```bash sudo ufw default deny incoming sudo ufw default allow outgoing ```

3. Allow SSH (do this before enabling the firewall): ```bash sudo ufw allow OpenSSH ``` Or explicitly: ```bash sudo ufw allow 22/tcp ```

4. Allow web traffic (if you host a website): ```bash sudo ufw allow 80/tcp sudo ufw allow 443/tcp ```

5. Enable: ```bash sudo ufw enable ```

Practical check: ```bash sudo ufw status numbered ```

If you changed SSH to port 2222: ```bash sudo ufw allow 2222/tcp sudo ufw delete allow 22/tcp ``` (Do this carefully to avoid lockout.)

iptables basics (conceptual overview)

iptables uses rule chains like:

  • `INPUT` (incoming traffic to the server)
  • `OUTPUT` (outgoing traffic)
  • `FORWARD` (routing traffic through the server)
A very simplified view:
  • Allow established connections so replies work
  • Allow SSH from trusted sources (optional)
  • Allow web ports
  • Drop everything else
Many modern distros are moving to nftables, but UFW abstracts that away. For beginners, UFW is usually the best starting point.

Brute-force protection with Fail2ban

Even with SSH keys, attackers may still hammer your SSH service. Fail2ban watches log files and temporarily bans IPs that show suspicious behavior (like repeated failed logins).

Install and enable

On Ubuntu/Debian:

```bash sudo apt update sudo apt install fail2ban sudo systemctl enable --now fail2ban ```

Configure a basic SSH jail

Avoid editing the default config directly. Create:

```bash sudo nano /etc/fail2ban/jail.local ```

Example:

```ini [sshd] enabled = true maxretry = 5 findtime = 10m bantime = 1h ```

Restart:

```bash sudo systemctl restart fail2ban ```

Check status:

```bash sudo fail2ban-client status sudo fail2ban-client status sshd ```

Fail2ban is not a replacement for SSH keys and firewalls, but it’s a useful additional layer.

Common attack vectors beginners should know

SSH brute force and credential attacks

The most common “background noise” on the internet. Mitigations:
  • SSH keys + disable passwords
  • Fail2ban
  • firewall rules (optionally restrict SSH to your IP)

Exposed services you forgot you installed

Databases, admin panels, dashboards, or dev tools bound to `0.0.0.0` (public). Mitigations:
  • Only install what you need
  • Bind internal services to `127.0.0.1` or private interfaces
  • Use the firewall to block public access

Unpatched software and known vulnerabilities

Outdated web apps/CMS/plugins are frequent entry points. Mitigations:
  • regular updates
  • remove unused packages and modules

Web application vulnerabilities

SQL injection, file upload bugs, RCE, leaked API keys. Mitigations:
  • keep frameworks updated
  • validate inputs
  • store secrets safely
  • use least privilege for app/service accounts

Misconfigurations and weak permissions

World-writable directories, exposed `.env` files, permissive cloud firewall rules. Mitigations:
  • review permissions
  • avoid storing secrets in public paths
  • audit firewall/security group rules

A practical server hardening checklist

SSH and access

  • [ ] Create a non-root user with sudo access
  • [ ] Set up SSH keys and verify you can log in
  • [ ] Disable root SSH login (`PermitRootLogin no`)
  • [ ] Disable password authentication (`PasswordAuthentication no`) after testing keys
  • [ ] Consider `AllowUsers` to restrict SSH logins
  • [ ] Consider limiting SSH to your IP in the firewall (if you have a static IP)
Example UFW rule to allow SSH only from your home IP: ```bash sudo ufw allow from 203.0.113.10 to any port 22 proto tcp ```

Firewall

  • [ ] Default deny incoming; allow only required ports
  • [ ] Confirm SSH port is allowed before enabling firewall
  • [ ] Remove rules you no longer need
  • [ ] Periodically review open ports:
```bash sudo ss -tulpn ```

Updates and packages

  • [ ] Apply security updates regularly:
```bash sudo apt update && sudo apt upgrade ```
  • [ ] Enable unattended security upgrades (optional but helpful on Ubuntu/Debian):
```bash sudo apt install unattended-upgrades ```
  • [ ] Remove unused software/services

Intrusion and abuse mitigation

  • [ ] Install and configure Fail2ban for SSH (and possibly web auth logs)
  • [ ] Check logs periodically:
- `/var/log/auth.log` (Debian/Ubuntu) - `journalctl -u ssh`

Service hardening basics

  • [ ] Don’t run internet-facing apps as root
  • [ ] Use least-privilege database/service accounts
  • [ ] Ensure TLS (HTTPS) for web services (e.g., Let’s Encrypt)
  • [ ] Backups: test restores, not just backups

Putting it together: a simple “secure baseline” example

For a new Ubuntu VPS hosting a small website:

1. Create a user, add your SSH key to it. 2. In SSH config: - `PermitRootLogin no` - `PasswordAuthentication no` 3. Enable UFW: - allow SSH - allow 80/443 - deny everything else 4. Install Fail2ban with the `sshd` jail enabled. 5. Keep the system updated and remove unused services.

This baseline won’t make a server “unhackable,” but it blocks the most common automated attacks and prevents simple mistakes from becoming full compromises.