I used to think security was someone else's job. The "security team" would handle it, right? Then I deployed a side project to a VPS and watched the authentication logs fill up with brute force attempts within the first hour. That was my wake-up call.

Here are the security basics I wish someone had hammered into me on day one.

SSH Keys, Not Passwords

If you're still logging into servers with a password, stop. Right now. SSH key authentication is more secure and more convenient. Generate a key pair with ssh-keygen -t ed25519, copy the public key to your server, then disable password authentication entirely in /etc/ssh/sshd_config.

Set PasswordAuthentication no and PermitRootLogin no. Restart the SSH service. That single change eliminates an entire class of brute force attacks. I also change the default SSH port from 22 to something else. It's not real security (security through obscurity never is), but it cuts down on automated scanning noise dramatically.

While you're at it, use ssh-agent so you don't have to type your key passphrase every time. And yes, put a passphrase on your key. An unencrypted private key on your laptop is a disaster waiting to happen if that machine gets compromised.

Firewall Basics

Every server you deploy should have a firewall configured before anything else. On Ubuntu, ufw makes this dead simple:

ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

That's it. Five commands. You've just blocked every port except SSH, HTTP, and HTTPS. I'm amazed how many tutorials skip this step entirely. I've seen production servers with every port wide open because nobody bothered to set up a firewall.

If you're running a database, it should never be exposed to the public internet. Bind it to localhost or a private network interface. If you need remote access to your database, tunnel through SSH. There is no good reason to have PostgreSQL listening on 0.0.0.0 on a public server.

Secrets Management

Hardcoded secrets in source code are probably the most common security mistake I see, and the OWASP Foundation consistently ranks it among the top risks for web applications. API keys, database passwords, JWT secrets, all just sitting in config files that get committed to Git. I've done it myself early in my career. It's embarrassing but it's incredibly common.

The bare minimum: use environment variables. Your app reads DATABASE_URL from the environment, not from a config file. Use a .env file locally and add it to .gitignore immediately. I mean immediately. Before you write any code. Before you do anything else.

For production, use your platform's secret management. AWS has Secrets Manager and Parameter Store. Vercel and Railway have built-in env var management. If you're on a VPS, at minimum put secrets in a file outside the repo directory that gets sourced by your process manager.

One thing that caught me off guard: Git remembers everything. If you accidentally commit a secret and then remove it in the next commit, it's still in the Git history. You need to use git filter-branch or BFG Repo Cleaner to actually purge it. And if you pushed to a public repo, assume the secret is compromised and rotate it immediately.

Keep Things Updated

I know this sounds obvious, but I regularly see servers running packages that are months or years out of date. Set up unattended security updates on Ubuntu with unattended-upgrades. It takes two minutes to configure and it automatically applies security patches.

For your application dependencies, use tools like npm audit, pip audit, or Dependabot. GitHub's built-in security alerts are actually quite good. Don't ignore them. I used to dismiss those yellow warning banners as noise. Then I actually looked at what vulnerabilities they were flagging and realized some were genuinely critical.

HTTPS Everywhere

There's no excuse for serving anything over plain HTTP in 2022. Let's Encrypt is free and Certbot makes setup automatic. If you're behind Cloudflare or a similar CDN, they handle TLS termination for you. Either way, your users should never see a browser security warning.

Force HTTPS redirects. Set HSTS headers. Use secure cookie flags. These are small configuration changes that meaningfully improve security.

The Mindset Shift

The biggest change for me wasn't any specific tool or technique. It was starting to think adversarially about my own code. Every input is potentially malicious. Every endpoint is a potential attack surface. Every dependency is a potential supply chain risk. I went deeper on web application vulnerabilities in my practical guide to the OWASP Top 10.

You don't need to become a security expert. But you need to know the basics well enough that you're not the easy target. Attackers go for the low-hanging fruit. Don't be the low-hanging fruit.