Quick Answer: 1) SSH in as root. 2) Create a non-root user with sudo. 3) Set up SSH keys and disable password login. 4) Configure UFW firewall. 5) Update everything. 6) Install what you need. Takes about 15 minutes.
Need a VPS? Vultr (free credit), DigitalOcean ($200 free credit), or RackNerd (cheap annual deals).
Choose a Provider
| Provider | Starting Price | Best For |
|---|---|---|
| DigitalOcean | $4/month | Beginners, clean UI |
| Vultr , or RackNerd | $3.50/month | Budget, many locations |
| Hetzner | $3.29/month | Europe, best value |
| Linode | $5/month | Reliability |
| AWS Lightsail | $3.50/month | AWS ecosystem |
Recommended specs for starters:
- 1 vCPU, 1 GB RAM, 25 GB SSD — enough for a web server, proxy, or VPN
- Ubuntu 22.04 LTS or Debian 12 — most tutorials target these
- Location closest to your users
Step 1: First Login
Your provider gives you an IP and root password. SSH in:
ssh root@YOUR_SERVER_IP
First time connecting, you will see:
The authenticity of host 'x.x.x.x' can't be established.
ED25519 key fingerprint is SHA256:xxxxx
Are you sure you want to continue connecting (yes/no)?
Type yes.
Step 2: Update Everything
apt update && apt upgrade -y
This updates all packages to the latest versions. Do this first, every time.
Step 3: Create a Non-Root User
Never use root for daily operations. Create a user with sudo access:
# Create user
adduser sam
# Add to sudo group
usermod -aG sudo sam
# Verify
groups sam
# Should show: sam sudo
Step 4: Set Up SSH Keys
On your local machine:
# Generate key (if you don't have one)
ssh-keygen -t ed25519
# Copy key to server
ssh-copy-id sam@YOUR_SERVER_IP
Test it:
ssh sam@YOUR_SERVER_IP
# Should log in without password
Now disable password authentication:
sudo nano /etc/ssh/sshd_config
Change:
PasswordAuthentication no
PermitRootLogin no
sudo systemctl restart sshd
See our SSH Keys Guide and SSH Hardening Guide for more.
Step 5: Configure Firewall
# Allow SSH (before enabling!)
sudo ufw allow 22/tcp
# Enable firewall
sudo ufw enable
# Allow other services as needed
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
# Check status
sudo ufw status
See our UFW Cheat Sheet for more.
Step 6: Set Timezone and Hostname
# Set timezone
sudo timedatectl set-timezone America/Chicago
# Or: sudo dpkg-reconfigure tzdata
# Set hostname
sudo hostnamectl set-hostname myserver
# Verify
timedatectl
hostname
Step 7: Install Essential Software
# Essential tools
sudo apt install -y \
curl wget git htop \
unzip vim nano \
ufw fail2ban \
build-essential
# Install Fail2ban for brute-force protection
sudo systemctl enable --now fail2ban
Step 8: Enable Automatic Security Updates
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure unattended-upgrades
# Select "Yes"
This automatically installs security patches.
What to Install Next
Depends on what you are building:
Web Server
sudo apt install nginx -y
sudo systemctl enable --now nginx
sudo ufw allow "Nginx Full"
# Get SSL: sudo apt install certbot python3-certbot-nginx -y
See our Nginx Cheat Sheet and Reverse Proxy Guide.
Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker sam
# Log out and back in for group to take effect
See our Docker Cheat Sheet.
VPN (WireGuard)
sudo apt install wireguard -y
# Or use SamNet-WG for easy management:
curl -sSL https://raw.githubusercontent.com/SamNet-dev/wg-orchestrator/main/install.sh | sudo bash
See our WireGuard Setup Guide.
Proxy Server (3X-UI)
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
See our 3X-UI Setup Guide.
Database
# PostgreSQL
sudo apt install postgresql -y
# MySQL
sudo apt install mysql-server -y
# Redis
sudo apt install redis-server -y
Post-Setup Checklist
echo "=== VPS Setup Checklist ==="
echo "OS updated: $(apt list --upgradable 2>/dev/null | wc -l) packages pending"
echo "Non-root user: $(who | awk '{print $1}' | head -1)"
echo "SSH key auth: $(grep PasswordAuthentication /etc/ssh/sshd_config | head -1)"
echo "Root login: $(grep PermitRootLogin /etc/ssh/sshd_config | head -1)"
echo "Firewall: $(sudo ufw status | head -1)"
echo "Fail2ban: $(systemctl is-active fail2ban)"
echo "Auto-updates: $(systemctl is-active unattended-upgrades 2>/dev/null || echo 'check manually')"
echo "Timezone: $(timedatectl | grep 'Time zone')"
echo "Hostname: $(hostname)"