OTOMY
SERVER CONFIGJune 6, 20266 min

Set Up a Secure VPS for Your Web App in 2025

A misconfigured VPS is an open door for attackers. Here's the step-by-step guide to deploy a hardened, production-ready server in under one hour.

M

By

Melissa Slimani

Set Up a Secure VPS for Your Web App in 2025

Why Your VPS Security Configuration Matters in 2025

Every day, thousands of VPS instances get compromised because of untouched default configurations. Active root passwords, open ports, no firewall — automated bots exploit these weaknesses within minutes of provisioning.

At Otomy, we deploy VPS servers for SMBs across France and Algeria hosting Next.js apps on Vercel, Supabase backends, n8n automation workflows, and e-commerce platforms. This guide is our exact production checklist.


Step 1 — Choose the Right Provider and OS

Pick a provider with European data centers for GDPR compliance: Hetzner, OVH, Scaleway, or Contabo. For the OS, go with Ubuntu 24.04 LTS or Debian 12 — both offer long-term support and a massive community.

Otomy tip: Avoid pre-configured images with control panels (cPanel, Plesk). They add unnecessary attack surface.


Step 2 — First Login and SSH Hardening

As soon as you receive your VPS, log in as root and apply these changes:

# Update the system
apt update && apt upgrade -y

# Create a non-root user
adduser deploy
usermod -aG sudo deploy

# Set up SSH key authentication
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys

Then harden the SSH configuration in /etc/ssh/sshd_config:

Port 2222                    # Change default port
PermitRootLogin no           # Disable root login
PasswordAuthentication no    # SSH keys only
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
systemctl restart sshd

Critical: Test the connection with your new user before closing your root session.


Step 3 — Firewall with UFW and Fail2Ban Protection

A VPS without a firewall is a sitting duck. Configure UFW (Uncomplicated Firewall):

ufw default deny incoming
ufw default allow outgoing
ufw allow 2222/tcp    # SSH on new port
ufw allow 80/tcp      # HTTP
ufw allow 443/tcp     # HTTPS
ufw enable

Then install Fail2Ban to block brute-force attempts:

apt install fail2ban -y
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Edit /etc/fail2ban/jail.local:

[sshd]
enabled = true
port = 2222
maxretry = 3
bantime = 3600
findtime = 600
systemctl enable fail2ban && systemctl start fail2ban

Step 4 — Automatic Security Updates

Zero-day vulnerabilities don't wait. Enable automatic security patches:

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

Verify in /etc/apt/apt.conf.d/50unattended-upgrades that this line is uncommented:

"${distro_id}:${distro_codename}-security";

Step 5 — Nginx Reverse Proxy with Let's Encrypt SSL

To expose your application (Next.js, n8n, Node.js API), use Nginx as a reverse proxy:

apt install nginx certbot python3-certbot-nginx -y

Create a config file at /etc/nginx/sites-available/myapp:

server {
    server_name myapp.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
certbot --nginx -d myapp.example.com

Certbot will auto-renew your certificates through a built-in cron job.


Step 6 — Containerization with Docker (Optional but Recommended)

To isolate your services (n8n, self-hosted Supabase, databases), Docker is essential:

curl -fsSL https://get.docker.com | sh
usermod -aG docker deploy

Sample docker-compose.yml for n8n:

version: '3.8'
services:
  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD}
    volumes:
      - n8n_data:/home/node/.n8n
volumes:
  n8n_data:

Note the 127.0.0.1 binding: the service is only accessible through the Nginx reverse proxy, never directly from the internet.


Step 7 — Monitoring and Alerts

A secure server is a monitored server. Our recommendations:

  • Netdata: Real-time monitoring, one-command install
  • Uptime Kuma: Self-hosted alternative to UptimeRobot
  • Logwatch: Daily log summaries via email
# Install Netdata
curl https://get.netdata.cloud/kickstart.sh > /tmp/netdata-kickstart.sh && sh /tmp/netdata-kickstart.sh

Pair this with alerts sent to Slack, Telegram, or a Make workflow for real-time notifications.


VPS Security Configuration Checklist

  • ✅ Non-root user with SSH key
  • ✅ SSH port changed, root login disabled
  • ✅ UFW firewall active (ports 80, 443, SSH only)
  • ✅ Fail2Ban configured for SSH
  • ✅ Automatic security updates enabled
  • ✅ Nginx reverse proxy + Let's Encrypt SSL
  • ✅ Containerized services (Docker) bound to localhost
  • ✅ Active monitoring with alerts

Conclusion

A solid VPS security configuration doesn't take hours — it takes method. By following these 7 steps, you get a hardened server ready to host your web applications in production.

Need help deploying your infrastructure? Otomy configures, secures, and maintains VPS servers for SMBs in France and Algeria. Contact us for a free server audit.

OTOMY

Ready to automate your business?

Book a free call — 30 minutes to identify what we can automate for you.