Linux VPS Setup and Hardening Guide
Learn to securely set up and harden a Virtual Private Server (VPS)
Buy a VPS privately
If you value privacy, choose providers that minimize data collection and support privacy-preserving payments:
Prefer paying with Bitcoin after a Whirlpool coinjoin, Bitcoin via Lightning, or Monero. These methods reduce linkage between your identity and your server. When possible, avoid providing personally identifying information during signup.
Choosing a Linux distro for your VPS (quick guide)
- Ubuntu (Debian-based)
- Pros: beginner-friendly, broad package support, many tutorials, frequent updates
- Cons: more default services running, therefore more bloated
- Debian (independent)
- Pros: very stable, lightweight baseline, ideal for long-running or low-RAM servers
- Cons: older packages by default, more manual setup early on
- Alpine (independent)
- Pros: extremely lightweight, fast boot, good security posture
- Cons: not beginner-friendly, more manual configuration, no systemd, smaller community
- Fedora (Red Hat family)
- Pros: cutting-edge stack, SELinux by default, strong dev tooling
- Cons: faster-moving base can require more maintenance and frequent updates
Rule of thumb: Ubuntu LTS or Debian Stable are solid defaults. If RAM is tight, lighter distros help.
Setup and Hardening guide
1) Inspect local SSH keys
1
ls -la ~/.ssh/
Lists your local SSH key files and permissions. You’ll use public keys to log in to the VPS; keep private keys protected with a strong passphrase.
1
rm ~/.ssh/<name>
Removes an old or unused key file. Do this only if you’re sure you won’t need it. Rotate keys rather than leaving stale credentials around.
1
cat ~/.ssh/*.pub
Displays all public keys. These are safe to share with your VPS provider or add to the server’s authorized_keys file.
1
cat ~/.ssh/<name>.pub
Shows a specific public key. Use the key that matches the private key you plan to use for login.
2) Generate SSH key for your VPS provider (local)
1
ssh-keygen
Generates a new SSH keypair interactively. Choose ed25519 when prompted and set a long passphrase. Store the passphrase in a password manager.
1
~/.ssh/<SSH_KEY_NAME>
This is the typical location for SSH keys. Replace
<SSH_KEY_NAME>with a clear name (e.g., id_ed25519_vps) to keep your keys organized.
1
ls -la ~/.ssh/
Verifies that your new keys exist and have appropriate permissions.
1
cat ~/.ssh/<SSH_KEY_NAME>.pub
Displays your public key. Add this to your VPS provider before creating the server so you can log in without passwords.
3) First login and initial updates
1
ssh root@<VPS_IP>
Logs in to the new server as root using your provider-injected key. Use this only for the initial setup; you’ll create a non-root admin shortly.
1
ssh -i ~/.ssh/<SSH_KEY_NAME> root@<VPS_IP>
Explicitly selects your private key file if your agent has multiple keys loaded or the default isn’t correct.
1
apt update
Refreshes the package index so your system knows about the latest available updates.
1
apt upgrade -y
Upgrades installed packages to their newest versions. Security patches often arrive via these updates.
1
apt install unattended-upgrades
Installs the tool that automatically applies security updates.
1
dpkg-reconfigure -plow unattended-upgrades
Enables unattended security updates through a guided configuration. Choose to apply security fixes automatically.
1
nano /etc/apt/apt.conf.d/50unattended-upgrades
Open the config and ensure “-security” origin is allowed. Consider enabling automatic reboots during a maintenance window (e.g., 02:00) to apply kernel fixes safely.
1
unattended-upgrades --dry-run --debug
Performs a dry run to confirm that automatic updates are configured as intended, without making changes.
4) Create a non-root admin and verify sudo
1
adduser <USERNAME>
Creates your daily admin account. Use a strong unique password even if you primarily log in via SSH keys.
1
usermod -aG sudo <USERNAME>
Grants sudo privileges to your admin account for controlled elevation.
1
su - <USERNAME>
Switches to your new account so you can test its environment and permissions.
1
sudo whoami
Confirms sudo works (should print “root”). After this, avoid direct root logins and use your admin account with sudo.
5) Configure SSH key authentication and harden SSH
1
ssh-keygen -t ed25519 -C "<KEY_LABEL>"
Generates a modern local key (if you haven’t already). The label helps you track purpose or ownership of the key.
1
mkdir -p ~/.ssh
Ensures the SSH directory exists on the server for your admin user.
1
chmod 700 ~/.ssh
Sets strict permissions so OpenSSH will accept the directory.
1
touch ~/.ssh/authorized_keys
Creates the authorized_keys file for your admin user.
1
chmod 600 ~/.ssh/authorized_keys
Sets strict permissions on the authorized_keys file to avoid login failures.
1
cat ~/.ssh/id_ed25519.pub
Shows your local public key. You’ll paste this into the server’s authorized_keys.
1
echo "paste-your-public-key-here" >> ~/.ssh/authorized_keys
Appends your public key to the server’s authorized_keys. Only paste the “.pub” line, not the private key.
1
nano ~/.ssh/authorized_keys
Verify the key was added correctly and is on a single line. Remove duplicates or stale keys.
1
nano ~/.ssh/config
Optional: create a local SSH profile. Example:
Host vps-server
HostNameUser IdentityFile ~/.ssh/id_ed25519
1
sudo nano /etc/ssh/sshd_config
Open the SSH daemon config to harden access. Disallow root logins and disable password authentication to force key-based access.
1
PermitRootLogin no
Prevents logins as root over SSH. Always log in as your admin user and use sudo for privilege escalation.
1
PasswordAuthentication no
Disables password-based SSH logins. This removes a major brute-force attack vector and ensures keys are required.
1
UsePAM no
Disables PAM modules for SSH. If you later need PAM features (e.g., 2FA), re-enable thoughtfully.
1
ChallengeResponseAuthentication no
Disables legacy interactive auth mechanisms, further tightening the SSH surface.
1
sudo cat /etc/ssh/sshd_config.d/50-cloud-init.conf
Checks for cloud-init overrides that might conflict with your hardening.
1
sudo cat /etc/ssh/sshd_config.d/60-cloudimg-settings.conf
Reviews additional layered settings; align them with your sshd_config.
1
sudo nano /etc/ssh/sshd_config.d/50-cloud-init.conf
Edit cloud-init drop-in config if needed to ensure passwords and root logins remain disabled.
1
sudo nano /etc/ssh/sshd_config.d/60-cloudimg-settings.conf
Update any defaults that re-enable weak SSH settings. Keep your original session open to avoid lockouts.
1
sudo systemctl restart ssh
Applies the SSH changes. Test a new SSH session in another terminal before closing the original one, so you can revert safely if needed.
6) Configure firewall (UFW)
1
sudo apt install ufw
Installs Ubuntu’s uncomplicated firewall. It’s a simple interface for default- deny inbound policies and explicit allowed ports.
1
sudo ufw default deny incoming
Blocks unsolicited inbound traffic. You will explicitly allow only what you need.
1
sudo ufw default allow outgoing
Allows outbound traffic by default so your server can reach package mirrors and APIs.
1
sudo ufw allow ssh
Opens the SSH port so you don’t lock yourself out. If you later change your SSH port, adjust this rule accordingly.
1
sudo ufw allow 80/tcp
Opens HTTP. Add only if you run a web server or reverse proxy.
1
sudo ufw allow 443/tcp
Opens HTTPS. Add only if you need encrypted web access.
1
sudo ufw enable
Activates the firewall with the current rules. Confirm access from a second terminal before closing your session.
1
sudo ufw status verbose
Displays active rules and policies so you can confirm the firewall is in the intended state.
7) Install and configure Fail2ban
1
sudo apt install fail2ban
Installs Fail2ban, which monitors logs and temporarily bans abusive IPs.
1
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Creates a local override file you can safely edit without changing defaults.
1
sudo nano /etc/fail2ban/jail.local
Enable the sshd jail and configure thresholds (e.g., maxretry=3, bantime=3600, findtime=600). Add ignoreip for trusted admin IPs to avoid accidental bans.
1
sudo systemctl enable fail2ban
Ensures Fail2ban starts automatically on boot.
1
sudo systemctl start fail2ban
Starts the service immediately so protections take effect.
1
sudo fail2ban-client status
Shows Fail2ban’s global status and enabled jails.
1
sudo fail2ban-client status sshd
Displays details for the sshd jail, including currently banned IPs.
8) Memory checks and swap file
1
sudo journalctl | grep -i "out of memory"
Searches logs for OOM events. Frequent OOMs indicate you should add RAM, reduce workloads, or add swap to buffer spikes.
1
sudo fallocate -l 2G /swapfile
Allocates a 2G swapfile. Adjust size based on your instance; small VPS hosts benefit from modest swap.
1
sudo chmod 600 /swapfile
Locks down permissions so the swapfile cannot be read by other users.
1
sudo mkswap /swapfile
Initializes the swapfile for use by the kernel.
1
sudo swapon /swapfile
Activates swap immediately.
1
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Makes swap persistent across reboots by adding it to fstab.
1
free -h
Verifies available memory and swap in a human-readable format.
9) Verification checklist
1
sudo sshd -T
Prints the effective SSH configuration as interpreted by the daemon, so you can confirm hardening settings are active.
1
sudo netstat -tulpn
Lists listening ports and owning processes. Requires net-tools. Use this to confirm only intended services are exposed.
1
sudo ufw status verbose
Displays firewall policies and open ports. Cross-check with netstat to ensure consistency.
1
sudo fail2ban-client status
Confirms Fail2ban is running and shows enabled jails.
1
sudo journalctl -fu sshd
Tails SSH logs in real time. Test a login and watch entries to verify behavior and investigate unexpected errors.
10) Regular maintenance tasks
1
sudo apt update
Refreshes package indexes so you see the latest available updates.
1
sudo apt upgrade
Applies updates. Schedule this weekly at minimum; more frequent for exposed services.
1
sudo tail -f /var/log/auth.log
Watches authentication logs in real time. Detects login attempts and unusual activity quickly.
1
sudo tail -f /var/log/fail2ban.log
Monitors Fail2ban’s actions and alerts so you know when IPs are being banned or unbanned.
1
sudo tail -f /var/log/ufw.log
Streams firewall logs to surface unexpected inbound hits or misconfigurations.
Security best practices
- Store SSH private keys securely with strong passphrases; back them up safely.
- Keep an inventory of authorized users and keys; remove stale accounts.
- Default-deny inbound with UFW; only open required ports.
- Rotate SSH keys periodically, especially when team membership changes.
- Monitor system resources, disk usage, and logs; set alerts for anomalies.
- Apply security updates promptly; unattended security upgrades help.
- Document custom ports and changes for easy auditing and troubleshooting.
- Prefer privacy-preserving VPS providers (e.g., 1984.hosting, mynymbox.net).
- Pay with Bitcoin after a Whirlpool coinjoin, Bitcoin via Lightning, or Monero to reduce identity linkage to your server.
Useful command list for beginners
System and OS information:
1
uname -a
Shows kernel and basic system info; useful for confirming environment.
1
hostnamectl
Displays and can set the system’s hostname and OS metadata.
1
uptime
Tells how long the server has been running and current load averages.
1
lsb_release -a
Prints distro details (if lsb-release is installed) for quick identification.
1
cat /etc/os-release
Shows OS name and version from the standard release file.
1
lscpu
Describes CPU model, cores, architecture—handy for sizing workloads.
Hardware and usage:
1
lspci
Lists PCI devices. In VPS, often minimal; more relevant on bare metal.
1
lsusb
Lists USB devices. In VPS, commonly empty; useful on physical hosts.
1
free -h
Shows memory usage with human-readable units.
1
df -h
Displays disk usage by filesystem, highlighting space pressure.
1
du -sh <directory>
Summarizes the size of a directory. Helps find large folders quickly.
Users and groups:
1
whoami
Prints your current username; confirms which account you’re operating under.
1
id
Shows user and group IDs as well as group memberships.
1
adduser <user>
Creates a user interactively with home directory and default settings.
1
usermod -aG sudo <user>
Adds a user to the sudo group for privilege escalation.
1
passwd <user>
Changes a user’s password. Use for initial setup or urgent rotation.
1
deluser <user>
Removes a user. Clean up accounts that no longer need access.
1
groups
Lists groups the current user is a member of.
1
groupadd <group>
Creates a new group, useful for organizing privileges.
1
gpasswd -a <user> <group>
Adds a user to a group via gpasswd (group password management).
1
last
Shows login history, useful for detecting unusual access patterns.
1
w
Shows who is logged in and their current activity.
Files and directories:
1
ls -l
Lists files with permissions, ownership, and timestamps.
1
ls -a
Includes hidden files (dotfiles) in listings.
1
cd <directory>
Changes the current directory.
1
pwd
Prints the present working directory.
1
mkdir <directoryname>
Creates a new directory.
1
rmdir <directoryname>
Removes an empty directory; fails if it contains files.
1
rm -rf <directory>
Recursively deletes a directory and all contents. Use with caution.
1
cp <file1> <file2>
Copies a file. Use -r for directories.
1
mv <file1> <file2>
Moves or renames a file or directory.
1
touch <file.txt>
Creates an empty file or updates its timestamp.
1
nano <file.txt>
Opens a file in the nano editor for quick edits.
1
cat <file.txt>
Prints file contents to the terminal.
1
less <file.txt>
Views a file with paging; search with “/pattern”, quit with “q”.
1
head -n 20 <file.txt>
Shows the first 20 lines of a file; adjust the number as needed.
1
tail -f /var/log/syslog
Streams a log in real time; great for debugging and monitoring.
Search and size:
1
find / -name "<name>.<file-type>"
Searches by name and extension, starting at root. May be slow; narrow paths for performance.
Networking:
1
ip a
Shows network interfaces and IP addresses; confirms connectivity config.
1
ifconfig
Legacy interface listing (requires net-tools). Use “ip” in modern setups.
1
ping <website>
Checks basic connectivity and round-trip latency.
1
traceroute <website>
Reveals the path packets take; useful for routing issues.
1
nslookup <website>
Queries DNS for a domain; confirm resolution and records.
1
dig <website>
Detailed DNS query tool; shows record TTLs and authoritative servers.
1
netstat -tulnp
Lists listening ports and processes (requires net-tools). Alternative: “ss”.
1
ss -tulnp
Modern tool to list sockets/ports without needing net-tools.
1
curl <URL>
Fetches URL content; great for testing endpoints and APIs.
1
wget <URL>
Downloads files over HTTP/HTTPS/FTP.
1
scp file user@server:/directory
Copies files over SSH; secure alternative to FTP.
1
rsync -av file user@server:/directory
Synchronizes files/directories efficiently; preserves attributes with “-a”.
1
ftp <server>
Connects to FTP servers (not recommended for secure workflows).
1
telnet host <port>
Tests TCP connectivity to a specific port; useful for quick checks.
Packages (Debian/Ubuntu):
1
apt update
Refreshes package lists; run before installing/upgrading.
1
apt upgrade
Upgrades packages; consider “-y” for automation with care.
1
apt full-upgrade
Upgrades including dependencies that may remove/install packages.
1
apt install <package>
Installs a package from the repositories.
1
apt remove <package>
Uninstalls a package but leaves config files.
1
apt purge <package>
Removes a package and its config files for a clean slate.
1
apt autoremove
Cleans up unused dependencies after removals.
1
apt dpkg -i <file.deb>
Installs a local .deb file; use with caution and verify signatures.
1
dpkg -l
Lists installed packages; useful for audits and troubleshooting.
Permissions:
1
chmod 755 <file>
Sets file permissions (rwx for owner, rx for group/others). Choose carefully.
1
chown <user>:<group> <file>
Changes file ownership to the specified user and group.
1
chgrp <group> <file>
Changes a file’s group ownership.
1
umask 022
Sets default permission mask for new files. Adjust to tighten defaults.
1
stat <file>
Shows detailed metadata and permissions for a file.
Extras:
1
alias ll='ls -la'
Sets a handy alias for detailed listings.
1
history
Displays your shell command history.
1
!<number>
Re-runs a specific command from history by its number.
1
clear
Clears the terminal screen for readability.
1
echo "Hello"
Prints a string to the terminal; useful for quick tests.
1
date
Shows the current date and time.
1
cal
Displays a calendar.
1
shutdown -h now
Shuts down the system immediately and halts power.
1
reboot
Restarts the system.
1
timedatectl
Shows or sets time and timezone; ensure correct time for TLS and logs.
1
crontab -e
Edits scheduled cron jobs for the current user.
Closing thoughts
This baseline focuses on strong, simple controls: SSH keys only, no root logins, default-deny firewall, abuse detection with Fail2ban, and routine updates.
This should help you get up and running with your first VPS securely.
Always remember to do your own research!
