The same six steps every server gets before it runs a single app: access, firewall, users, baseline, backups and monitoring.
Before a new server runs a single app, it gets the same six steps, in the same order. I look after 29 client sites on Linux servers, and this checklist matters more than any single tool. A server set up from memory is how gaps sneak in.
The commands below are simplified examples. Swap in your own names and paths.
1. Access: keys only, no root
In /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
Test the config, then reload. Keep your current session open until a new login works:
sudo sshd -t && sudo systemctl reload ssh
2. Firewall: start from closed
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable
Allow SSH before enabling the firewall, or you'll lock yourself out.
3. Users: nothing runs as root
Each service gets its own system user and owns only what it needs to write to:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin my-app
sudo chown -R my-app:my-app /var/www/my-app/storage
If that service is ever compromised, the damage stops at that user.
4. Baseline: write down what normal looks like
Right after setup, record what should be there:
# who can log in
cat /root/.ssh/authorized_keys /home/*/.ssh/authorized_keys
# what runs on a schedule
for u in $(cut -d: -f1 /etc/passwd); do crontab -l -u "$u" 2>/dev/null; done
# what is listening
ss -tulpn
Save the output somewhere off the server. Later, anything that isn't on this list is worth a closer look.
5. Backups: off site from day one
A backup on the same server dies with the server. Send it somewhere else:
mysqldump --single-transaction my_app_db | gzip > /var/backups/my-app-$(date +%F).sql.gz
rclone copy /var/backups remote:backups/my-app
Keep database credentials in ~/.my.cnf, not in the script. And restore one into a scratch database now and then. A backup you have never restored is a hope, not a plan.
6. Watching: let problems find you
A watchdog every 5 minutes, uptime and SSL checks, and alerts that land somewhere a human actually looks. Mine go to Discord and email.
*/5 * * * * /opt/monitor/check-sites.sh
Then, and only then, deploy
None of these steps are advanced. That's exactly why they get skipped when someone is in a hurry, and why they belong on a checklist instead of in your memory.
Lock the doors before you move the furniture in.
Top comments (0)