Securing Your Home Server: Essential Steps Every Self-Hoster Should Take

Running a home server gives you control over your data and services, but it also makes you responsible for security. Unlike managed cloud services, you are the sysadmin. One misconfiguration could expose your personal data, family photos, or entire network to attackers.

The good news? Securing a home server isn’t rocket science. Follow these essential steps and you’ll be miles ahead of most self-hosters.

1. Harden SSH Access

SSH is your primary gateway to manage the server remotely. It’s also the #1 target for automated attacks.

Change the Default Port

Attackers scan port 22 constantly. Moving SSH to a non-standard port dramatically reduces automated attacks.

sudo nano /etc/ssh/sshd_config

Change this line:

Port22

To something like:

Port2299

Then restart SSH:

sudo systemctl restart sshd

Remember: Update your firewall rules and client configs to use the new port.

Disable Password Authentication

Passwords can be brute-forced. SSH keys cannot (within reasonable timeframes).

First, set up SSH keys on your client:

ssh-keygen -t ed25519 -C "[email protected]"
ssh-copy-id -p 2299 user@your-server

Then disable password auth:

sudo nano /etc/ssh/sshd_config

Set:

PPPauesbrskmweioytrARduoAtouhtteLhnoetgniitcniactnaiotoinonyenso

Restart SSH:

sudo systemctl restart sshd

Test Before Logging Out

Critical: Open a second terminal and test SSH before closing your current session. If something broke, you’ll still have access to fix it.

2. Configure a Firewall

Linux includes ufw (Uncomplicated Firewall), which makes firewall management simple.

Enable UFW

sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing

Allow Only What You Need

# SSH (use your custom port)
sudo ufw allow 2299/tcp

# HTTP/HTTPS (if running web services)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Plex (example media server)
sudo ufw allow 32400/tcp

Enable the Firewall

sudo ufw enable
sudo ufw status

You should see:

ST284to204a9/3t9t/u/ctstpc:cppactiveAAAAcLLLtLLLiOOOoWWWnFAAArnnnoyyymwwwhhheeerrreee

Rate Limit SSH

Prevent brute-force attacks:

sudo ufw limit 2299/tcp

This blocks IPs that attempt 6+ connections in 30 seconds.

3. Keep Software Updated

Unpatched vulnerabilities are low-hanging fruit for attackers.

Enable Automatic Security Updates

On Ubuntu/Debian:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

This installs security patches automatically while leaving major updates for manual review.

Update Regularly

Even with automatic updates, manually update weekly:

sudo apt update && sudo apt upgrade -y

For Docker containers (if you use them):

docker compose pull
docker compose up -d

4. Use Reverse Proxy with SSL

Exposing individual services directly is risky and messy. A reverse proxy centralizes access and encrypts traffic.

Install Nginx Proxy Manager

The easiest option for beginners:

mkdir -p ~/nginx-proxy-manager
cd ~/nginx-proxy-manager
wget https://github.com/NginxProxyManager/nginx-proxy-manager/raw/main/docker-compose.yml
docker compose up -d

Access at http://your-server:81 (default login: [email protected] / changeme).

Get Free SSL Certificates

Nginx Proxy Manager integrates Let’s Encrypt:

  1. Add a domain pointing to your server’s public IP
  2. Create a proxy host in NPM
  3. Enable “Force SSL” and “HTTP/2”
  4. NPM handles certificate renewal automatically

Result: Your services are accessible via https://service.yourdomain.com with valid certificates.

5. Implement Fail2Ban

Fail2Ban monitors logs and bans IPs after repeated failed login attempts.

Install Fail2Ban

sudo apt install fail2ban

Configure SSH Protection

sudo nano /etc/fail2ban/jail.local

Add:

[sshd]
enabled = true
port = 2299
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

This bans IPs for 1 hour after 3 failed attempts in 10 minutes.

Start Fail2Ban:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Check status:

sudo fail2ban-client status sshd

6. Secure Docker Containers

If you use Docker, container security matters.

Don’t Run Containers as Root

Add this to your docker-compose.yml:

services:
  app:
    image: myapp
    user: "1000:1000"  # Your user/group ID

Find your UID/GID:

id

Use Read-Only Filesystems When Possible

services:
  app:
    image: myapp
    read_only: true
    tmpfs:
      - /tmp

Keep Images Updated

docker image prune -a  # Remove old images
docker compose pull     # Update to latest
docker compose up -d    # Restart with new images

7. Monitor Logs

You can’t fix what you don’t see.

Check Auth Logs Regularly

sudo tail -f /var/log/auth.log

Look for patterns like repeated failed logins from unfamiliar IPs.

Set Up Log Monitoring (Optional)

Tools like Grafana + Loki or Uptime Kuma can alert you to issues.

Simple option for uptime monitoring:

docker run -d \
  -p 3001:3001 \
  -v uptime-kuma:/app/data \
  --name uptime-kuma \
  louislam/uptime-kuma:1

Access at http://your-server:3001 and configure service checks.

8. Network Segmentation (Advanced)

Isolate your server from your home network using VLANs or a dedicated subnet.

Why It Matters

If your server gets compromised, segmentation prevents attackers from pivoting to other devices (laptops, phones, IoT devices).

How to Implement

  1. Configure VLANs on your router/switch (if supported)
  2. Place server in VLAN 10, trusted devices in VLAN 20
  3. Set firewall rules to allow only necessary traffic between VLANs

Alternative: Use a dedicated Raspberry Pi as a firewall running OPNsense or pfSense.

9. Backup and Test Restores

Security includes disaster recovery.

Automate Backups

Use tools like Restic or Duplicati:

# Install restic
sudo apt install restic

# Initialize backup repo
restic init --repo /mnt/backup

# Backup important directories
restic -r /mnt/backup backup /home /etc /var/www

# Set up cron job
echo "0 2 * * * restic -r /mnt/backup backup /home /etc /var/www" | sudo crontab -

Test Restores Monthly

A backup is worthless if you can’t restore it:

restic -r /mnt/backup restore latest --target /tmp/restore-test

10. Know When You’re Exposed

Use tools to check your attack surface.

Scan Your Ports

From an external network (phone LTE, friend’s house):

nmap -p 1-65535 your-public-ip

You should only see ports you explicitly opened.

Check for Vulnerabilities

sudo apt install lynis
sudo lynis audit system

Lynis audits your system and suggests hardening steps.

Security Checklist

  • SSH on non-standard port, key-only auth, root disabled
  • Firewall enabled with minimal open ports
  • Automatic security updates enabled
  • Reverse proxy with SSL (Let’s Encrypt)
  • Fail2Ban monitoring SSH and web services
  • Docker containers not running as root
  • Regular log reviews
  • Automated backups tested monthly
  • Port scan confirms no unexpected open ports
  • Lynis audit score >70

What About VPNs?

Many self-hosters avoid exposing services entirely by accessing them only via VPN (WireGuard or Tailscale).

Pros:

  • No public attack surface
  • Encrypted access from anywhere
  • Simpler than reverse proxy setup

Cons:

  • Must connect to VPN before accessing services
  • Can’t share services with non-VPN users

Recommendation: Use VPN for admin access (SSH, Portainer) and reverse proxy for services you share (Jellyfin, Nextcloud).

Final Thoughts

Security is a process, not a one-time task. Threat landscapes change, software gets updated, and configurations drift.

Set a monthly reminder to:

  1. Review auth logs
  2. Run system updates
  3. Check Fail2Ban stats
  4. Scan your ports
  5. Test a backup restore

With these foundations in place, your home server will be significantly more secure than 90% of self-hosted setups.


Next Steps:

Got questions? Join our Discord community or drop a comment below.