Zero-Trust VPS Security Guide (2026): How to Protect Low-Spec Servers from Daily Scans

๐Ÿš€ Managed Cloud Hosting โ€” Try Cloudways for Free Trial! Get Started โ†’

๐Ÿ’ก Summary

  • A newly deployed VPS connected to the public internet can rack up thousands of SSH brute-force attempt logs within 24 hours.
  • This is no exaggeration; it happens daily to every server with a public IP.
  • Most users rely on Fail2Ban for defense, yet it is only a temporary fix.
  • Drawing on zero-trust principles, this article uses free and low-cost tools including Cloudflare Tunnel, Tailscale, CrowdSec and UFW to systematically reduce your VPS attack surface.
  • No enterprise budget is needed โ€” even a $5 server can implement this security setup.
๐Ÿ’ก
๐Ÿ’ก

Hostinger โ€” Editor's Pick

Get the best price through our exclusive link and support our reviews.

Explore Hostinger โ†’

Start by checking your SSH logs if the server has been running for a while:

grep "Failed password" /var/log/auth.log | wc -l

If that number is in the hundreds or thousands, your server is being continuously scanned and brute-forced. This is just background noise on the internet โ€” not targeted at you specifically. There are large automated botnets constantly scanning every public IP for common ports: 22 (SSH), 3306 (MySQL), 6379 (Redis), 2375 (Docker API). Find one open, try weak passwords and known exploits.

The question isn't whether you'll be scanned. It's whether you have anything in place when you are.


The Core Zero Trust Logic

Zero trust sounds complicated. The underlying idea isn't. Traditional security thinking is: build a perimeter, trust what's inside. Zero trust flips that: verify at every layer, never assume trust by default.

Applied to a VPS, this means reducing what's exposed to the public internet, replacing open ports with private network access, and replacing IP whitelists with identity-based verification. Here's how to do that step by step.


Step 1: Harden SSH, Reduce Brute-Force Noise

SSH is the first thing to address. Edit /etc/ssh/sshd_config:

# Disable direct root login
PermitRootLogin no

# Disable password authentication, allow keys only
PasswordAuthentication no
PubkeyAuthentication yes

# Disallow empty passwords
PermitEmptyPasswords no

# Restrict access to specific users
AllowUsers yourusername

# Change default port (reduces log noise, not a core security measure)
Port 2222

Restart SSH after making changes:

sudo systemctl restart sshd

Important: Before changing the port, confirm the new port is already allowed through your firewall โ€” otherwise you'll lock yourself out. Changing the port reduces log noise from automated scanners, but it won't stop a targeted attack. Don't treat it as a meaningful security measure on its own.

If you don't have an SSH key pair yet, generate one:

ssh-keygen -t ed25519 -C "your_comment"

Copy the public key to your server:

ssh-copy-id -i ~/.ssh/id_ed25519.pub \
  user@your_server_ip

Step 2: Move Management Traffic to a Private Network

This is the most important step in the zero trust approach: stop exposing management ports to the public internet, and use private tunnels to administer your server instead. Three main options:

Tailscale (Recommended for Getting Started)

Tailscale is built on WireGuard and creates a private mesh network across your devices โ€” direct communication between them, no public ports required. Free for personal use, and the setup is minimal.

# Install Tailscale
curl -fsSL https://tailscale.com/install.sh | sh

# Start and log in
sudo tailscale up

After logging in, your server gets a private IP address (typically in the 100.x.x.x range). You can reach the server through that address without ever opening port 22 to the public internet.

Lock down SSH in your firewall to Tailscale traffic only:

# Allow SSH only from the Tailscale interface
sudo ufw allow in on tailscale0 to any port 22
sudo ufw deny 22

Cloudflare Tunnel (Good for Web Services)

If you're running web services that need to be publicly accessible, Cloudflare Tunnel lets you do that without exposing your real server IP. All traffic routes through Cloudflare's network. Completely free.

# Install cloudflared
wget -q https://github.com/cloudflare/cloudflared/releases/latest/\
download/cloudflared-linux-amd64.deb

sudo dpkg -i cloudflared-linux-amd64.deb

# Log in to your Cloudflare account
cloudflared tunnel login

# Create a tunnel
cloudflared tunnel create my-tunnel

# Configure routing (edit ~/.cloudflared/config.yml)
# tunnel: <your-tunnel-id>
# credentials-file: /root/.cloudflared/<id>.json
# ingress:
#   - hostname: app.yourdomain.com
#     service: http://localhost:8080
#   - service: http_status:404

# Start the tunnel
cloudflared tunnel run my-tunnel

With a tunnel in place, ports 80 and 443 don't need to be open directly โ€” traffic enters through Cloudflare.

WireGuard (For Self-Hosted VPN)

WireGuard is the self-managed VPN option โ€” more flexible than Tailscale, more involved to configure. Appropriate when you want full control over the infrastructure.

# Install WireGuard
sudo apt install wireguard -y

# Generate key pair
wg genkey | tee /etc/wireguard/privatekey \
  | wg pubkey > /etc/wireguard/publickey

# View public key
cat /etc/wireguard/publickey

Full WireGuard configuration involves both server and client sides โ€” refer to the official documentation or a dedicated WireGuard guide for the complete setup.


Step 3: Default-Deny Firewall Policy

The basic principle: deny all inbound by default, explicitly allow only what's necessary.

# Install UFW
sudo apt install ufw -y

# Default policy: deny inbound, allow outbound
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH (if public access is still needed)
sudo ufw allow 2222/tcp

# Allow HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable firewall
sudo ufw enable

# Review rules
sudo ufw status verbose

If you're already managing SSH through Tailscale, there's no need to open port 22 or 2222 publicly โ€” just 80 and 443.

A few ports that are easy to overlook. Check what's actually listening:

# Check which ports are listening
ss -tlnp

If you see 3306 (MySQL), 6379 (Redis), 5432 (PostgreSQL), or 2375 (Docker API) bound to 0.0.0.0, they're open to the entire internet. Fix that immediately โ€” restrict them to 127.0.0.1 or your private network range.


Step 4: Use CrowdSec Instead of Fail2Ban

Fail2Ban is a well-known tool that bans IPs after repeated failed attempts. CrowdSec goes further: it maintains a shared threat intelligence network, so when an IP gets flagged across the global CrowdSec user base, your server automatically blocks it before it ever tries to attack you.

# Install CrowdSec
curl -s https://install.crowdsec.net | sudo bash
sudo apt install crowdsec -y

# Install UFW bouncer
sudo apt install crowdsec-firewall-bouncer-iptables -y

# View live alerts
sudo cscli alerts list

# View banned IPs
sudo cscli decisions list

Once installed, CrowdSec parses SSH, Nginx, and system logs automatically. Anomalous behavior triggers the bouncer, which pushes block rules directly to the firewall. If you're comfortable with Fail2Ban, the two aren't mutually exclusive โ€” but the community intelligence sharing is what makes CrowdSec worth the switch.


Step 5: Don't Expose Service Management Ports

A few high-risk configurations worth checking explicitly:

Redis

Redis ships with no password and commonly binds to 0.0.0.0 by default. Edit /etc/redis/redis.conf:

# Listen on localhost only
bind 127.0.0.1

# Set a strong password
requirepass your_strong_password

# Disable dangerous commands
rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command KEYS ""

MySQL / PostgreSQL

Same principle โ€” confirm both are listening only on 127.0.0.1. If your application and database are on the same server, there is no reason to expose these ports publicly at all.

Docker API

This one is the most dangerous. A Docker API exposed on port 2375 gives an attacker complete control over your container environment and a path to escape to the host. Check:

# Confirm Docker is not listening on a public interface
ss -tlnp | grep 2375

If there's output, handle it immediately. Docker's default Unix socket (/var/run/docker.sock) allows local access only โ€” do not enable TCP listening unless you have a specific, well-understood reason to do so.


Step 6: Secure Docker Deployments

If you're running containers, a few baseline practices:

Don't run containers as root. In your Dockerfile:

RUN useradd -m appuser
USER appuser

Network isolation โ€” put different services on separate Docker networks. Containers that don't need to communicate with each other shouldn't share a network:

# Create an isolated network
docker network create --internal backend-net

# Attach containers only to the networks they need
docker run --network backend-net your-image

Don't mount the Docker socket into containers unless the container genuinely needs to manage other containers. Mounting the socket effectively grants the container root access to the host.

Manage sensitive values through Docker Secrets or environment variable files โ€” don't hardcode them into images or docker-compose.yml.


Step 7: Monitoring and Alerts

Security configuration is only part of it โ€” you also need visibility into what's happening. A few low-cost options:

Uptime Kuma is a self-hosted monitoring tool that tracks websites, ports, and SSL certificates, with alerts via Telegram, email, Slack, and others:

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

Netdata provides real-time system resource monitoring with minimal resource overhead:

bash <(curl -Ss https://my-netdata.io/kickstart.sh)

Check CrowdSec's alert logs periodically. Understanding what types of attacks are hitting your server helps you tune the protection strategy over time.


Common Mistakes Worth Avoiding

A few patterns that keep showing up:

Everything bound to 0.0.0.0. This is the most frequent issue โ€” Redis, MySQL, admin interfaces all open to the internet. Massive attack surface, easy to fix.

Ignoring system updates. Exploitation of known vulnerabilities is automated. Not patching is essentially leaving the door open. Enable automatic security updates:

sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure unattended-upgrades

Thinking a non-standard SSH port equals security. Port scanners cover full ranges. Changing the port reduces log noise โ€” it isn't a security control. Not having backups. When a security incident happens, fast recovery matters more than having prevented every possible intrusion. Backups are the last line of defense, and the most overlooked one.


Security Configuration Checklist

Go through these after completing setup:

[ ] SSH password authentication disabled, key-only login enforced
[ ] Root SSH login disabled
[ ] UFW default-deny inbound, only necessary ports open
[ ] Tailscale or WireGuard in place for management access
[ ] Cloudflare Tunnel configured for web services (if applicable)
[ ] CrowdSec installed and running
[ ] Redis bound to 127.0.0.1 with password set
[ ] MySQL/PostgreSQL not exposed publicly
[ ] Docker API TCP listener not enabled
[ ] Containers running as non-root users
[ ] Automatic security updates enabled
[ ] Monitoring and alerting configured
[ ] Regular backups scheduled


On Cost

Every tool covered here โ€” Tailscale personal tier, Cloudflare Tunnel, CrowdSec, UFW, Uptime Kuma โ€” is free or has a fully functional free tier. This entire setup costs nothing beyond time. A $5 VPS with this configuration in place has a smaller attack surface than a lot of unhardened enterprise servers. Security isn't a function of budget. It's a function of configuration.

๐Ÿš€

Ready for Hostinger? Now is the perfect time

Use our exclusive link for the best price โ€” and help support our content.

โ† Previous
DigitalOcean Kimi K3 Launch & GPU Droplet Price Changes (Effective Aug 1): Developer Guide

๐Ÿท๏ธ Related Keywords

๐Ÿ’ฌ Comments

150 characters left

No comments yet. Be the first!

โ† Back to Articles

VPS Rankings specializes in VPS selection, featuring provider reviews, rankings, practical tutorials, performance benchmarks and exclusive deals. Everything you need for research, comparison and purchase is available in one place.We cover budget web hosting and overseas cloud servers, enabling straightforward comparisons of specs, routing and pricing across providers. We also track CN2 GIA, low-latency Asian routes and other optimized solutions for China-facing networks and cross-border businesses. Our regularly updated VPS recommendations and practical guides help you make quick, well-informed decisions.