SSH keys, firewalls, and basic server security
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
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
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
- 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
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
- `~/.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)
- 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
```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)
- Allow established connections so replies work
- Allow SSH from trusted sources (optional)
- Allow web ports
- Drop everything else
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)
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:
Updates and packages
- [ ] Apply security updates regularly:
- [ ] Enable unattended security upgrades (optional but helpful on Ubuntu/Debian):
- [ ] Remove unused software/services
Intrusion and abuse mitigation
- [ ] Install and configure Fail2ban for SSH (and possibly web auth logs)
- [ ] Check logs periodically:
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.