10 Things to Do First on a New VPS
2026-09-28 · 9 min read
Don't install the site on a fresh VPS right away. A brand-new box uses default configs — the door wide open waiting for someone to try it. Minutes after a new machine goes online, the first brute-force records appear in /var/log/auth.log — bots across the internet scan port 22 and try passwords 24/7; that's an open secret. Do these 10 things in order and an afternoon gets them done; afterward your server is safer than 80% of personal small sites. Each item says how to verify; don't move on if verification fails — an unverified setup might as well not exist. Don't reorder: the first 6 are life-saving (SSH and firewall), the middle ones save hassle (updates, timezone, naming), the last two are the safety net (backups, snapshots).
How to use this checklist: read this before starting
Every item below is three-part: what (why), how (copy the commands), how to verify (must run after finishing). Don't skip verification — the most common init failure is configuring without verifying, discovering the misconfiguration three months later when something breaks, having long forgotten how it was configured. Also keep two terminal windows ready: one stays logged in untouched (the lifeline), the other makes changes — so a mistake still leaves you a way back.
Item 1: Change SSH's default port 22
Bots across the internet scan port 22 and try passwords 24/7 — your machine gets scanned minutes after going online. Changing the port doesn't stop targeted attacks, but it blocks 90%+ of noise scans, and the logs go quiet. Pick a port above 1024, like 2222 — easy on the eyes and memorable.
sudo nano /etc/ssh/sshd_config # change Port 22 to Port 2222
sudo systemctl restart sshdHow to verify: open a new terminal — ssh -p 2222 user@YOUR_SERVER_IP should connect; try the default port — failing is correct. Don't pick overly common ports like 8080 or 8443 — that's rearranging deck chairs. Also update the firewall and the provider's security group in sync: if ufw opened 22, change it to 2222, or you'll lock yourself out the moment you change the port.
Item 2: Switch to key login, disable password login
Passwords, however complex, fall to dictionary brute-forcing eventually; keys plus disabled passwords settle it in one move. Watch the order: confirm key login works BEFORE disabling passwords — reverse it and you lock yourself out.
ssh-keygen -t ed25519 # generate the key locally, just press Enter through the prompts
ssh-copy-id -p 2222 user@IP # copy the public key up
# after confirming key login works, change the server side:
sudo nano /etc/ssh/sshd_config # PasswordAuthentication no
sudo systemctl restart sshdHow to verify: ssh -o PreferredAuthentications=password user@YOUR_SERVER_IP -p 2222 — being rejected means success. ssh-copy-id really does one thing: it appends your public key to the server's ~/.ssh/authorized_keys. If ssh-copy-id isn't available on that machine, do it manually: cat ~/.ssh/id_ed25519.pub locally and paste the content at the end of the server's authorized_keys file — same effect. The -C flag adds a comment to the key (like -C my-laptop) so you can tell which key belongs to which computer when you have several.
Item 3: Create a normal user — don't live as root
root's power is too big; one slip of rm can wipe the database. Do daily work as a normal user and prepend sudo when you need elevation — basic hygiene in the Linux world.
sudo adduser deploy # set the password as prompted
sudo usermod -aG sudo deploy # give it sudo privilegesHow to verify: ssh deploy@IP -p 2222 in, run sudo whoami — showing root means sudo works. The deploy user needs key login too, same steps as item 2 (ssh-copy-id targeting deploy@IP) — don't let the new user still log in with a password, or item 2 was wasted. root's password login stays disabled; daily work as deploy, sudo when you need root privileges — that's the standard operating posture.
Item 4: Firewall — open only the doors you must
Servers ship with all ports open — the front door wide open. Open only SSH (your changed port), 80, 443; database ports (5432, 3306, etc.) never to the public internet — the app and database talk over the internal network.
sudo ufw allow 2222
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enableHow to verify: ss -tlnp shows the listening ports — only the ones you opened should remain; then run sudo ufw status verbose to confirm the rules took effect. If the provider also has a security group, configure both sides — not just one. Remember ufw's default policy: anything not explicitly allowed is denied, so when you open a new service later (like an app on port 3000), come back and add a rule, or it won't connect from outside no matter what — check the firewall first.
Item 5: Turn on automatic security updates
Unpatched vulnerabilities are a broken lock left unrepaired. On Ubuntu, unattended-upgrades installs security updates automatically; don't auto-update business software (incompatibility fears) — auto-update security patches only.
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgradesHow to verify: systemctl status unattended-upgrades shows active, with logs in /var/log/unattended-upgrades/. To see what it actually installed, run apt list --upgradable and see how many updates remain — the list is usually long right after a fresh install; the first time, manually run sudo apt update && sudo apt upgrade -y to clear the backlog, then let automatic updates stand guard.
Item 6: Install fail2ban against SSH brute-forcing
After changing the port and disabling passwords, brute-forcing basically can't get in — but install fail2ban anyway: when it sees too many failures from one IP in a short time, it bans the IP outright, and the logs go quiet. The default SSH rule works out of the box — no config fiddling needed.
sudo apt install -y fail2ban
sudo systemctl enable --now fail2banHow to verify: sudo fail2ban-client status sshd shows the jail status and current ban count (0 is fine — means nobody's bothering you). The default policy bans for 10 minutes after 5 failures in 10 minutes — enough for scan bots. If you ban yourself (e.g. a misconfigured key tried a few times), unban with sudo fail2ban-client set sshd unbanip YOUR_SERVER_IP — don't reboot the server.
Item 7: Set the timezone to Shanghai
The default timezone is usually UTC; log timestamps won't match yours, and converting while troubleshooting drives you mad. One command sets it to Asia/Shanghai — done forever.
sudo timedatectl set-timezone Asia/Shanghai
dateHow to verify: date shows CST, matching Beijing time. No more converting when reading logs. Accurate time matters too — server time usually syncs automatically via NTP; run timedatectl status and check that “System clock synchronized” is yes. If no, install chrony (sudo apt install -y chrony) and time aligns itself — cron jobs and certificate validation both depend on accurate time.
Item 8: Set the hostname
The default hostname is a random string; after ssh login you can't tell which box you're on. Give it a name, like blog-prod — with three to five machines later you won't connect to the wrong one.
sudo hostnamectl set-hostname blog-prodHow to verify: hostname shows blog-prod; re-ssh and the prompt starts with the name you gave. A side benefit: machines without a set hostname warn “unable to resolve host” on sudo — setting it makes that warning disappear.
Item 9: Set up automatic backups
This is the most important of the 10. Lost configs can be reconfigured; lost data is truly lost. The database auto-dumps daily, the site directory gets packed, cron runs in the early morning daily, kept 7 days. Don't keep backup files on the same machine — put them on another machine or object storage; if this machine's disk dies, the backups survive.
# back up the database daily at 3 AM, keep 7 days (example — adapt to your database)
0 3 * * * pg_dump mydb | gzip > /backup/db-$(date +\%F).sql.gz
0 3 * * * find /backup -name "db-*.sql.gz" -mtime +7 -deleteHow to verify: the backup files actually exist and aren't size 0. Advanced verification: actually restore one backup once — a backup never rehearsed equals no backup. There's a 3-2-1 backup rule worth remembering: at least 3 copies, on 2 kinds of media, 1 offsite. Personal small sites can't go that heavy, but the baseline is: don't keep backups only on the local machine — if the disk dies or the box gets hacked, local backups die with it. Object storage, another machine, even a home NAS all work.
Item 10: Install common tools, take a snapshot
Install curl, git, htop, tmux — you'll use them daily for deploying and troubleshooting. A word on tmux: it opens a session on the server that survives SSH disconnects — run long commands (big file transfers, migrations) inside it; if the network drops you can come back and keep watching. Run backups inside it before snapshotting for maximum peace of mind. Then take a system snapshot in the provider's console — that's this machine's undo medicine; if you break things you can roll the whole box back. Note the snapshot and item 9's backups are different things: snapshots are whole-machine undo, fast to restore but big and usually only one or two kept; backups are the steady drip of data, automatic daily. You need both.
sudo apt install -y curl git htop tmuxHow to verify: which curl git htop all show paths; the provider console's snapshot list holds one snapshot from today. Snapshots bill by disk size — check the price; some providers' snapshots cost more than the disk itself. Delete expired ones after snapshotting; don't let them quietly eat your balance.
With the 10 done, this server is truly yours. To install the site, follow “Caddy Reverse Proxy: HTTPS for Your Site in 5 Minutes”; to make services restart themselves when they crash, see “systemd Services: Restarting Automatically When They Crash.” If shell commands are unfamiliar, this site has a shell command cheat sheet (the /shell page on this site) — 40 common commands, one-click copy. One last habit: every month spend 10 minutes on 4 things — apt update to check for security updates, df -h for disk, fail2ban-client status for abnormal brute-forcing, and a look at the backup directory to confirm files exist. Servers are raised, not configured once and abandoned — bookmark this checklist, walk it for every new machine, and once practiced it takes half an hour.