VPS vs. Dedicated Server: When to Use Each
Understanding the difference is critical for choosing the right hosting for your project:
| Feature | VPS (Virtual Private Server) | Dedicated Server |
|---|---|---|
| Hardware | Shared physical host, isolated via hypervisor | Entire physical machine is yours |
| Resources | Allocated vCPUs, RAM, storage | Full CPU, RAM, all disks |
| Scalability | Resize on the fly (most providers) | Hardware upgrade = migration or swap |
| Cost | $5–$100/mo typical | $80–$500+/mo typical |
| Best For | Web apps, dev environments, small-to-mid traffic sites | High-traffic sites, databases, compliance, game servers |
| Root Access | Full root/admin access | Full root/admin access |
Popular VPS providers include DigitalOcean, Linode (Akamai), Vultr, and AWS Lightsail. For dedicated servers, OVH, Hetzner, and Liquid Web are well-regarded. Many hosting companies like InMotion and A2 Hosting offer both with managed support options.
Linux VPS: Initial Setup
After provisioning a new Linux VPS (Ubuntu/Debian or CentOS/AlmaLinux), these are the first steps to secure and configure it:
Step 1: Connect & Update
# Connect via SSH (see our SSH Essentials guide)
ssh root@your_server_ip
# Update all packages immediately
# Ubuntu/Debian
apt update && apt upgrade -y
# CentOS/AlmaLinux/Rocky
dnf update -y
Step 2: Create a Non-Root User
# Never run services as root in production
adduser deploy
usermod -aG sudo deploy # Ubuntu/Debian
# usermod -aG wheel deploy # CentOS/AlmaLinux
# Copy SSH keys to new user
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy
# Test login in a NEW terminal before closing root session
ssh deploy@your_server_ip
Step 3: Secure SSH
# Edit /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
Port 2222 # Change from default 22
AllowUsers deploy
# Restart SSH
systemctl restart sshd
See our SSH Essentials guide for full key auth setup and hardening.
Step 4: Configure the Firewall
# UFW (Ubuntu/Debian)
ufw default deny incoming
ufw default allow outgoing
ufw allow 2222/tcp # SSH (your custom port)
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw enable
# firewalld (CentOS/AlmaLinux/Rocky)
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
Step 5: Install fail2ban
# Ubuntu/Debian
apt install fail2ban -y
# CentOS/AlmaLinux
dnf install epel-release -y && dnf install fail2ban -y
# Enable and start
systemctl enable fail2ban
systemctl start fail2ban
# Check status
fail2ban-client status sshd
Linux: Web Server Configuration
Nginx Setup
# Install Nginx
apt install nginx -y # Ubuntu/Debian
dnf install nginx -y # CentOS/AlmaLinux
# Start and enable
systemctl enable nginx
systemctl start nginx
# Test configuration
nginx -t
# Basic server block (/etc/nginx/sites-available/mysite)
server {
listen 80;
server_name example.com www.example.com;
root /var/www/mysite;
index index.html index.php;
location / {
try_files $uri $uri/ =404;
}
# PHP-FPM
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Deny hidden files
location ~ /\. {
deny all;
}
}
# Enable the site
ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Apache Setup
# Install Apache + PHP
apt install apache2 libapache2-mod-php php php-mysql -y
# Enable modules
a2enmod rewrite ssl headers
# Virtual host (/etc/apache2/sites-available/mysite.conf)
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/mysite
<Directory /var/www/mysite>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/mysite_error.log
CustomLog ${APACHE_LOG_DIR}/mysite_access.log combined
</VirtualHost>
# Enable site and restart
a2ensite mysite.conf
systemctl reload apache2
PHP-FPM Configuration
# Install PHP-FPM with common extensions
apt install php8.2-fpm php8.2-mysql php8.2-curl php8.2-gd \
php8.2-mbstring php8.2-xml php8.2-zip php8.2-intl -y
# Key settings (/etc/php/8.2/fpm/php.ini)
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
max_input_vars = 5000
# Pool config (/etc/php/8.2/fpm/pool.d/www.conf)
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
systemctl restart php8.2-fpm
Linux: Control Panels
Plesk on Linux
Plesk is a commercial server management panel that supports both Linux and Windows. It provides a web-based GUI for managing websites, databases, email, DNS, and SSL certificates.
# One-click Plesk installation (official installer)
sh <(curl https://autoinstall.plesk.com/one-click-installer \
|| wget -O - https://autoinstall.plesk.com/one-click-installer)
# After installation, access at:
# https://your_server_ip:8443
# CLI management via plesk bin
plesk bin domain --create example.com -hosting true \
-ip your_server_ip -login admin -passwd "secure_pass"
# List all domains
plesk bin domain --list
# Manage PHP version per domain
plesk bin domain -u example.com -php_handler_id plesk-php82-fpm
# Restart Plesk services
plesk repair web -y
Plesk works on both Linux and Windows, has a cleaner UI, and includes WordPress Toolkit. It's ideal when you manage both Linux and Windows servers.
cPanel/WHM is Linux-only, the industry standard for shared hosting resellers. WHM is the server-level admin panel, cPanel is the per-account panel.
Both handle domains, email, databases, SSL, DNS, and backups through a GUI.
cPanel/WHM on Linux
# Install WHM/cPanel (CentOS/AlmaLinux only)
cd /home && curl -o latest -L https://secup.cpanel.net/latest
sh latest
# Access WHM at: https://your_server_ip:2087 (root login)
# Access cPanel at: https://your_server_ip:2083 (account login)
# CLI: create an account
/scripts/createacct --domain example.com --user exampleusr
# CLI: list accounts
whmapi1 listaccts
# Restart services
/scripts/restartsrv_httpd
/scripts/restartsrv_mysql
Windows Server: Setup & Configuration
Windows Server is used when your stack requires IIS, ASP.NET, MSSQL, or Active Directory. Common editions include Windows Server 2019 and 2022.
Initial Configuration
# PowerShell: Set hostname
Rename-Computer -NewName "WEBSERVER01" -Restart
# Configure static IP
New-NetIPAddress -InterfaceAlias "Ethernet" -IPAddress 10.0.0.5 `
-PrefixLength 24 -DefaultGateway 10.0.0.1
Set-DnsClientServerAddress -InterfaceAlias "Ethernet" `
-ServerAddresses 8.8.8.8,8.8.4.4
# Enable Windows Firewall rules
New-NetFirewallRule -DisplayName "HTTP" -Direction Inbound `
-Protocol TCP -LocalPort 80 -Action Allow
New-NetFirewallRule -DisplayName "HTTPS" -Direction Inbound `
-Protocol TCP -LocalPort 443 -Action Allow
New-NetFirewallRule -DisplayName "RDP" -Direction Inbound `
-Protocol TCP -LocalPort 3389 -Action Allow
# Enable Windows Updates
Install-Module PSWindowsUpdate -Force
Get-WindowsUpdate -Install -AcceptAll -AutoReboot
IIS Web Server
# Install IIS with common features
Install-WindowsFeature Web-Server, Web-Asp-Net45, `
Web-Mgmt-Console, Web-Scripting-Tools, `
Web-Http-Redirect, Web-Url-Auth, Web-IP-Security
# Install ASP.NET Core hosting bundle (download from Microsoft)
# Then configure a site in IIS Manager or via PowerShell:
Import-Module WebAdministration
# Create a new site
New-Website -Name "MySite" -PhysicalPath "C:\inetpub\mysite" `
-Port 80 -HostHeader "example.com"
# Create an application pool
New-WebAppPool -Name "MySitePool"
Set-ItemProperty "IIS:\AppPools\MySitePool" `
-Name processModel.identityType -Value "ApplicationPoolIdentity"
Set-ItemProperty "IIS:\Sites\MySite" `
-Name applicationPool -Value "MySitePool"
# Enable HTTPS binding (after installing certificate)
New-WebBinding -Name "MySite" -Protocol "https" `
-Port 443 -HostHeader "example.com" -SslFlags 1
Plesk on Windows Server
# Download Plesk installer from plesk.com
# Run the installer — it will configure IIS, mail, DNS, etc.
# After installation, access at:
# https://your_server_ip:8443
# Plesk on Windows manages:
# - IIS websites and application pools
# - ASP.NET and PHP configurations
# - SQL Server and MySQL databases
# - SSL certificates
# - DNS zones and mail
# - Windows Firewall rules
# CLI examples (run in Plesk command prompt)
plesk bin domain --create example.com -hosting true
plesk bin database --create mydb -domain example.com -type mssql
plesk bin domain -u example.com -asp_dot_net true
Windows Server Security
# Change default RDP port (registry + firewall)
Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" `
-Name PortNumber -Value 33389
New-NetFirewallRule -DisplayName "RDP Custom" -Direction Inbound `
-Protocol TCP -LocalPort 33389 -Action Allow
# Disable SMBv1 (security risk)
Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -NoRestart
# Enable Windows Defender
Set-MpPreference -DisableRealtimeMonitoring $false
# Configure account lockout policy
net accounts /lockoutthreshold:5 /lockoutduration:30 /lockoutwindow:30
# Enable audit logging
auditpol /set /category:"Logon/Logoff" /success:enable /failure:enable
auditpol /set /category:"Account Logon" /success:enable /failure:enable
Performance Tuning
Linux VPS Optimization
# Check current resource usage
free -h # Memory
df -h # Disk
nproc # CPU cores
uptime # Load average
# Swap file (if VPS has limited RAM)
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
# Kernel tuning (/etc/sysctl.conf)
# Increase max connections
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
# TCP optimization
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
# Apply changes
sysctl -p
Windows Server Optimization
# Check resource usage
Get-Process | Sort-Object CPU -Descending | Select -First 10
Get-Counter '\Processor(_Total)\% Processor Time'
Get-Counter '\Memory\Available MBytes'
# IIS Application Pool recycling (prevent memory leaks)
Set-ItemProperty "IIS:\AppPools\MySitePool" `
-Name recycling.periodicRestart.time -Value "1.00:00:00"
Set-ItemProperty "IIS:\AppPools\MySitePool" `
-Name recycling.periodicRestart.privateMemory -Value 1048576
# Disable unnecessary services
Set-Service -Name "Spooler" -StartupType Disabled # Print spooler
Set-Service -Name "XblGameSave" -StartupType Disabled
SSL Certificates on VPS/Dedicated
# Let's Encrypt with Certbot (Linux)
apt install certbot python3-certbot-nginx -y # For Nginx
apt install certbot python3-certbot-apache -y # For Apache
# Obtain and auto-configure SSL
certbot --nginx -d example.com -d www.example.com
# Auto-renewal (certbot adds a timer automatically)
certbot renew --dry-run
# Windows: Use win-acme for Let's Encrypt
# Download from https://www.win-acme.com/
# Run wacs.exe and follow the prompts for IIS binding
For more details, see our SSL Certificate Installation guide.
Backup Strategies
# Linux: Full server backup with rsync
rsync -avz --delete /var/www/ backup@backup-server:/backups/www/
rsync -avz /etc/nginx/ backup@backup-server:/backups/nginx-config/
# Automated daily backup script
#!/bin/bash
DATE=$(date +%Y-%m-%d)
BACKUP_DIR="/backups/$DATE"
mkdir -p $BACKUP_DIR
tar -czf $BACKUP_DIR/www.tar.gz /var/www/
mysqldump --all-databases | gzip > $BACKUP_DIR/all-databases.sql.gz
# Windows: Windows Server Backup
Install-WindowsFeature Windows-Server-Backup
wbadmin start backup -backuptarget:E: -include:C: -allCritical -quiet
# Plesk backup (works on both Linux and Windows)
plesk bin pleskbackup domains-only --output-file=/backups/domains.tar
Keep 3 copies of your data, on 2 different types of media, with 1 copy offsite. For servers, this means: local backup + remote server/NAS + cloud storage (S3, Backblaze B2, etc.).
Monitoring & Maintenance
# Linux: Install monitoring tools
apt install htop iotop nethogs -y
# Check for listening ports
ss -tulnp
# Linux: Unattended security updates
apt install unattended-upgrades -y
dpkg-reconfigure -plow unattended-upgrades
# Windows: Check event logs via PowerShell
Get-EventLog -LogName System -Newest 50 | Where-Object {$_.EntryType -eq "Error"}
Get-EventLog -LogName Application -Newest 50 | Where-Object {$_.EntryType -eq "Error"}
Set up uptime monitoring with a free service like UptimeRobot or Hetrixtools. These will alert you via email, SMS, or Slack when your server goes down — often before your users even notice. For resource monitoring, Netdata (Linux) provides real-time dashboards with zero configuration.