A fresh VDS is a machine with root access, a public address, and no opinions. Within minutes of it coming up, automated scanners will be trying passwords against port 22, and everything else you do to it assumes a base that is patched, has a user who is not root, and answers only on the ports you chose. That base takes about twenty minutes. The hour in the title is because you should read what you are typing, and because rushing this part is how people end up rebuilding the machine in a fortnight.
The order below matters. Updates come before configuration, because the packages you are about to configure are the ones being replaced. The user comes before the SSH lockdown, because locking root out before you have another way in is the classic way to lose a server on day one. The firewall comes after SSH, because a default-deny rule with no exception for port 22 ends the session and the conversation.
Commands are for Debian and Ubuntu, which is what most VDS images are. On RHEL-family systems substitute dnf for apt, wheel for sudo, and firewalld for ufw; the shape does not change.
The first login, and what to check#
You will have been sent an address and either a root password or a key. Log in and read the fingerprint prompt rather than typing yes reflexively - it is the one chance you get to confirm you are talking to your machine. Compare it with the fingerprint shown in your provider's console if they publish one.
$ ssh root@203.0.113.10The authenticity of host '203.0.113.10' can't be established.ED25519 key fingerprint is SHA256:5xM8n...Are you sure you want to continue connecting (yes/no/[fingerprint])?Then spend two minutes finding out what you actually have. This is worth doing before you install anything, because it is the only time the machine is in a known state:
$ cat /etc/os-release # distribution and version$ uname -r # kernel$ lscpu | head -20 # cores, model, virtualisation flags$ free -h # memory, and whether swap exists$ df -h / # disk, and how much the image used$ ip -brief address # addresses, v4 and v6$ ss -ltnp # what is already listening$ systemd-detect-virt # kvm, lxc, noness -ltnp is the interesting one. A clean image usually shows only sshd, and sometimes a DHCP client or a mail transfer agent listening on localhost. Anything else listening on 0.0.0.0 is something you did not ask for and should look into. systemd-detect-virt tells you whether you are on full virtualisation or sharing a kernel, which decides whether some later steps are even possible - VPS, VDS or dedicated server explains why that distinction matters more than the marketing does.
If the root password arrived by email, treat it as already public and plan to disable password login entirely within the next twenty minutes. That is step four.
Update everything, then reboot#
An image is a snapshot from whenever it was built, which can be months ago. Before anything else:
$ apt update$ apt full-upgrade -y$ apt autoremove --purge -yfull-upgrade rather than upgrade, because upgrade refuses to remove packages and therefore quietly skips updates that need a dependency change. On a fresh image that difference is usually the kernel.
Then check whether a reboot is needed, and do it now rather than at an inconvenient moment later:
$ [ -f /var/run/reboot-required ] && cat /var/run/reboot-required$ rebootA kernel update does nothing until the machine restarts on the new one. A brand new VDS with nothing running is the cheapest reboot you will ever take, so take it. Log back in and confirm with uname -r that the version changed.
A user that is not root#
Working as root all day means every typo is executed with full authority and every process you start inherits it. Make an ordinary account with the ability to escalate deliberately:
$ adduser deploy$ usermod -aG sudo deployadduser is the interactive Debian wrapper: it creates the home directory, sets the shell and prompts for a password. Give it a real password even if you intend to log in with keys, because sudo will ask for it.
Now give that user your SSH key. The simplest reliable way, if root already has your key installed, is to copy the whole directory with the ownership fixed in one step:
$ rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy/$ chmod 700 /home/deploy/.ssh$ chmod 600 /home/deploy/.ssh/authorized_keysThose permissions are not decoration. sshd refuses to use an authorized_keys file that is writable by anyone but its owner, and it does so silently from the client's point of view, which produces the "it keeps asking for a password" mystery.
Open a second terminal and test before you change anything else:
$ ssh deploy@203.0.113.10$ sudo -vKeep that second session open for the rest of this post. If a configuration change breaks logins, the session you already have is what saves you.
SSH keys, and closing the front door#
If you do not have a key pair yet, make one on your own machine, not on the server:
$ ssh-keygen -t ed25519 -C "deploy@laptop"$ ssh-copy-id deploy@203.0.113.10Use ed25519. It is smaller and faster than RSA, and every SSH implementation from the last decade supports it. Give the private key a passphrase and let your agent hold it unlocked for the working day.
Then turn off the two things that make a server guessable. On modern Debian and Ubuntu, /etc/ssh/sshd_config begins with an Include /etc/ssh/sshd_config.d/*.conf line, and this detail catches almost everyone: sshd uses the first value it obtains for a keyword, so anything in that directory wins over the main file below it. Cloud images frequently ship a file there that turns password authentication back on.
$ ls -la /etc/ssh/sshd_config.d/$ grep -r PasswordAuthentication /etc/ssh/sshd_config /etc/ssh/sshd_config.d/Write your own file, named so that it sorts before anything already there:
PermitRootLogin noPasswordAuthentication noKbdInteractiveAuthentication noPubkeyAuthentication yesAuthenticationMethods publickeyMaxAuthTries 3LoginGraceTime 20AllowUsers deployCheck the syntax before you restart, because a bad config file means sshd does not come back:
$ sshd -t && systemctl restart sshNow, from a third terminal, prove that a new login still works and that a password login is refused. Only then close the root session.
SSH keys and hardening covers the rest of this properly: agents, jump hosts, per-key restrictions and what to do when you do lock yourself out.
The firewall: default deny#
Default deny inbound, allow outbound, then open exactly what you need. On Ubuntu that is ufw, and the order of the commands matters enormously:
$ ufw default deny incoming$ ufw default allow outgoing$ ufw allow OpenSSH$ ufw enable$ ufw status numberedufw allow OpenSSH before ufw enable, every time. Enabling a default-deny policy without an SSH rule disconnects you immediately and the only way back is your provider's console. ufw does warn you, and the warning is easy to click past.
Then the services you are actually going to run:
$ ufw allow 80/tcp$ ufw allow 443/tcp$ ufw allow 27015:27020/udp # a range for game servers$ ufw allow from 10.0.0.0/24 to any port 5432 proto tcpThat last form is the one worth learning. A database, a metrics endpoint or an admin panel should be reachable from named addresses, not from everywhere. Firewall rules that matter has the reasoning, and the ufw guide has the syntax in full.
One trap: Docker publishes ports by writing its own iptables rules, and those bypass ufw's rules entirely. A container started with -p 5432:5432 is open to the internet even with a tidy-looking ufw status. Either bind the publish to localhost with -p 127.0.0.1:5432:5432, or add your rules to the DOCKER-USER chain. Docker on a VDS covers it in context.
Time, hostname and the small settings#
Wrong clocks produce wrong logs, failed TLS handshakes and expired tokens, and they are invisible until they are not.
$ timedatectl set-timezone Etc/UTC$ timedatectl set-ntp true$ timedatectlUse UTC on servers. You will eventually correlate a log on this machine with a log on another one, and the version of that job where everything is already in UTC is the pleasant version.
Give the machine a name that means something, especially if there will be a second one:
$ hostnamectl set-hostname web-01Add that name to /etc/hosts beside 127.0.1.1, or sudo will pause for a second on every command while it tries to resolve the host name and fails.
Two more small things worth doing while you are here. Set the locale (update-locale LANG=en_GB.UTF-8) so scripted tools stop printing locale warnings, and cap the journal so logs cannot fill the disk:
[Journal]SystemMaxUse=500MSystemMaxFileSize=50MA full root filesystem takes a server down as effectively as anything an attacker could do, and an uncapped journal on a chatty service is the most common cause. Logs worth keeping covers what to retain.
Automatic security updates#
A server nobody patches is a server that will be broken into eventually. Automatic security updates are the highest-value twenty seconds in this list.
$ apt install unattended-upgrades$ dpkg-reconfigure --priority=low unattended-upgradesThat writes /etc/apt/apt.conf.d/20auto-upgrades. Then open /etc/apt/apt.conf.d/50unattended-upgrades and decide two things: whether the machine may reboot itself, and when.
Unattended-Upgrade::Automatic-Reboot "true";Unattended-Upgrade::Automatic-Reboot-WithUsers "false";Unattended-Upgrade::Automatic-Reboot-Time "04:00";Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";Automatic reboots are right for a web server and wrong for a game server with people on it at four in the morning. If you turn them off, you have taken on the job of rebooting after kernel updates yourself, and /var/run/reboot-required is what to check. Verify the whole thing works rather than assuming:
$ unattended-upgrade --dry-run --debug$ cat /var/log/unattended-upgrades/unattended-upgrades.logBy default this applies security updates only, which is the right scope. Widening it to all updates on a production machine trades a small risk of being exploited for a larger risk of a package changing behaviour while you sleep.
Swap, and the memory ceiling#
Most small VDS images ship with no swap at all. Without it, a memory spike does not slow down, it kills something: the kernel's out-of-memory killer picks the largest process, which is usually the exact thing you are running the server for.
A modest swap file is insurance, not extra memory. Two gigabytes is plenty on an 8 GB machine.
$ fallocate -l 2G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=2048$ chmod 600 /swapfile$ mkswap /swapfile$ swapon /swapfile$ swapon --showMake it survive a reboot by adding one line to /etc/fstab:
/swapfile none swap sw 0 0Then lower the kernel's willingness to use it, so it stays a safety net rather than becoming the normal state:
$ echo 'vm.swappiness=10' > /etc/sysctl.d/99-swap.conf$ sysctl --systemfallocate fails on some filesystems, which is why the dd fallback is there. And if a server is genuinely swapping during normal operation, swap is not the fix - the machine is too small, or something is leaking. Linux swap and the OOM killer covers reading the evidence, and CPU vs RAM for game servers covers which one you are actually short of.
What can wait until hour two#
You are done with the part that has to happen before the machine does any work. The next layer, in the order most people need it:
| Next | Why |
|---|---|
| A backup or snapshot, taken now | A clean baseline costs nothing and is worth a lot later |
fail2ban | Repeated failures start costing the attacker something |
| A reverse proxy and TLS | Anything serving HTTP wants nginx and a certificate |
systemd units for your services | Restart on failure, start on boot, logs in one place |
| Monitoring | Disk, memory and whether the thing is still answering |
| Docker or Compose | Only if the workload is genuinely several services |
fail2ban, systemd services for your apps and nginx as a reverse proxy each take one of those properly. If the plan is several game servers on one box, multiple game servers on one VDS covers ports, users and process supervision before you get into a mess with them.
What not to do in the first hour: install a control panel you have not decided on, open ports for services that do not exist yet, or follow a hardening guide that changes forty sysctl values you cannot explain. Every change you cannot explain is a change you will not think to undo when something breaks.
A VDS is a machine you own the whole of, including the maintenance. If that list reads like work you would rather not do monthly, the honest comparison is in VDS or a game panel, and the answer is genuinely different for different people.
FAQ#
Which distribution should I pick?
Whichever long-term-support release you already know. Ubuntu LTS and Debian stable both get security updates for years, have the largest amount of accurate documentation written about them, and are what most install instructions assume. A newer, shorter-lived release buys you package versions you probably do not need in exchange for an upgrade every nine months.
Do I really need a non-root user if I am the only person using the machine?
Yes, and the reason is not other people. It is that running as root makes every mistake maximal, every compromised process a root process, and every copied-and-pasted command from the internet a root command. Typing sudo deliberately is a half-second pause in front of the destructive ones.
Is changing the SSH port worth it?
It removes most of the noise from your authentication logs, which makes real events easier to see. It does not add security against anyone aiming at you specifically, because a port scan finds the new port in seconds. Do it for the quiet logs if you like, but never instead of keys and a firewall.
Should I install fail2ban straight away?
It is useful, and it is second-order. With password authentication disabled, brute force against SSH cannot succeed regardless of how many attempts are made, so fail2ban is mostly saving you log volume there. It earns its place in front of web logins, mail and anything else that still accepts a password.
How much swap should I add?
Enough to absorb a spike, not enough to hide a problem. One to two gigabytes on a machine with 8 GB or more, and vm.swappiness set low. Servers that need swap proportional to their memory are a rule from an era of much smaller machines and hibernation.
What is the one step people skip and regret?
Testing the second login before closing the first session. Every lockout story starts with someone restarting sshd after a config change, closing the terminal, and discovering that AllowUsers had a typo in it. Keep the working session open until a fresh one has succeeded.




Комментарии
Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.