How to Lock Down a New Hosting Account in the First Hour
To secure a new hosting account, assume the machine is hostile until you have proved otherwise. The first hour is about closing the doors that ship open by default: root login over SSH, weak or shared credentials, an unconfigured firewall, and a web root that anyone can browse. Work through the items below in order, because each one depends on the last.
Get in, then change how you get in
Most provisioning systems hand you a root password or drop an SSH key into /root/.ssh/authorized_keys. Either way, your first job is to stop logging in as root over a password. Create a normal user, give it sudo rights, and install your own public key.
adduser deploy
usermod -aG sudo deploy
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
Open a second terminal and confirm you can log in as that user before you touch the SSH daemon. Locking yourself out of a fresh box is the most common way to ruin the first hour. Once the new session works, edit /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers deploy
Validate the file with sshd -t, then reload with systemctl reload sshd. Keep the original session open until you have logged in again on a new connection. If the host runs a control panel, check whether it manages SSH for you; a panel that rewrites sshd_config on update will silently undo this.
Firewall first, services second
A firewall rule set is only useful if you know what is listening. Run ss -tulpn and read the output before you write any rules. You will typically see SSH, and whatever the host preinstalled: a mail transfer agent, a database bound to 0.0.0.0, a panel on a high port, sometimes a status page.
With that list in hand, allow only what you need. On a system using ufw:
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
If you moved SSH to a nonstandard port, allow that port before enabling, not after. On hosts using firewalld or raw nftables, the principle is identical: default deny inbound, explicit allows, and no rule that exposes a database port to the internet. Bind MySQL or PostgreSQL to 127.0.0.1 in its config if the application runs on the same machine. A database reachable from outside is the single most exploited misconfiguration on small hosting accounts.
Do not forget the provider's own firewall if one exists above the guest. Two layers that disagree are worse than one you understand, so pick the layer you will actually maintain.
Secure the new hosting account at the application layer
Hardening the operating system does nothing for a web app with default credentials. If the host preinstalled a CMS, a panel, or a sample application, log in and change the admin username, the admin password, and the admin email address before the site resolves publicly. Delete any demo content, sample users, and unused plugins or themes. An unused plugin is still code that executes.
Check the web server configuration for directory listing. In nginx, autoindex on; inside a location block lets anyone browse a folder that has no index file. Turn it off, and confirm the web root has no backup archives, no .sql dumps, and no .env files sitting in it. Deny access to dotfiles explicitly:
location ~ /\. {
deny all;
return 404;
}
On Apache, the equivalent is Options -Indexes and a <FilesMatch> block for sensitive extensions. Either way, test it: request a path you know exists and confirm you get a 404 rather than a listing or a download.
File permissions deserve a pass too. Directories at 755, files at 644, and nothing writable by the web server user except the directories the application genuinely needs to write to, such as an uploads folder or a cache directory. If the application's own documentation tells you to set 777 on something, find out what it actually needs instead.
TLS, headers, and the boring defaults
Before the domain resolves, issue a certificate and set the redirect from HTTP to HTTPS. Then add the response headers that cost nothing and close real classes of attack. A minimal set:
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Add a Content Security Policy once you know which origins the site loads from. A strict policy applied blind will break the site, so start in report-only mode if your server supports it. Verify the headers with curl -I https://yourdomain.example rather than trusting the config file.
Finally, deal with the unglamorous items. Set the system timezone and confirm timedatectl reports it as synchronized, because log timestamps and certificate validation both depend on a correct clock. Configure unattended security updates if the host supports them, or at minimum know how you will apply kernel patches. Turn off any service you cannot name a use for. Set up a non root backup that leaves the machine, and test a restore before you need one. Check whether the provider sends mail from the host; a fresh account with a mail transfer agent listening on port 25 is a spam relay waiting to be found.
What to do next
Write down what you changed and why, in a file on the server or in your own notes, because the next person to touch this box may be you in six months. Then verify from outside: scan your own host from a different network, confirm only the ports you intended are reachable, and confirm the site serves over HTTPS with the headers you set. Repeat the whole pass on your next provisioning, and it will take twenty minutes instead of an hour.
