Zum Inhalt springen

Securing a VPS: Essential Hardening Steps for Web Developers (Part 1)

After working with various PaaS solutions for years, I decided to set up a VPS with Contabo for hosting a few personal projects. While nothing particularly sensitive will be hosted there, I still wanted to implement proper security practices from the start.

Even simple hobby projects can become targets for automated attacks or get compromised for cryptocurrency mining. Here’s my systematic approach to hardening a fresh Ubuntu VPS, covering the essential security fundamentals.

The Starting Point

Fresh VPS with Ubuntu, an admin user with sudo privileges, and SSH key authentication already configured during setup. Time to implement proper security measures.

Step 1: SSH Hardening

The default SSH configuration needed immediate attention. Running SSH on the default port 22 makes your server a target for automated scanning tools that constantly probe this port.

sudo nano /etc/ssh/sshd_config

Key changes made:

Port 2222                   # Move away from the default port
PermitRootLogin no          # Disable direct root access
PasswordAuthentication no   # Enforce key-based authentication
PubkeyAuthentication yes    # Enable SSH keys
MaxAuthTries 3              # Limit failed attempts
AllowUsers admin            # Restrict user access

Important: Always test your SSH configuration in a separate terminal session before closing your current connection. This prevents accidental lockouts.

Step 2: Firewall Configuration

Ubuntu’s UFW provides straightforward firewall management. The approach is to deny all incoming connections by default, then explicitly allow only necessary services.

# Set restrictive defaults
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow essential services
sudo ufw allow 2222/tcp   # SSH on custom port
sudo ufw allow 80/tcp     # HTTP
sudo ufw allow 443/tcp    # HTTPS

# Enable firewall
sudo ufw enable

Critical note: Always configure firewall rules for your new SSH port before changing the SSH configuration. Otherwise, you’ll lose access to your server.

Step 3: Automated Intrusion Prevention with Fail2Ban

Fail2Ban monitors log files and automatically bans IP addresses showing suspicious behavior, such as repeated failed login attempts.

sudo apt install fail2ban

Modern Ubuntu systems use systemd journaling instead of traditional log files, which requires specific configuration:

sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600      # Ban duration in seconds
findtime = 600      # Time window for counting failures
maxretry = 3        # Maximum attempts before ban

[sshd]
enabled = true
port = ssh
filter = sshd
backend = systemd   # Use systemd journal
journalmatch = _SYSTEMD_UNIT=ssh.service

Step 4: Docker Security Configuration

Since applications run in Docker containers, the Docker daemon requires security hardening. Create /etc/docker/daemon.json:

{
  "live-restore": true,
  "userland-proxy": false,
  "no-new-privileges": true,
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

The no-new-privileges setting is particularly important as it prevents containers from escalating their privileges during runtime, blocking a common attack vector.

Current Security Status

The VPS now has:

  • SSH access secured with custom port and key-only authentication
  • Firewall blocking unauthorized connections
  • Automated intrusion detection and response
  • Hardened Docker daemon configuration

This setup effectively blocks automated attacks and provides a solid security foundation for hosting web applications.

Coming Up in Part 2

The next article will cover:

  • Setting up a reverse proxy with Nginx in Docker
  • SSL certificate management with Let’s Encrypt
  • Container security best practices
  • System monitoring and maintenance

These foundational security measures provide essential protection while maintaining accessibility for legitimate use.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert