SSH Config Mastery: Organize Your Connections Like a Pro

If you’re still typing ssh -i ~/.ssh/my-key.pem -p 2222 admin@192.168.1.50 every time you connect, you’re doing it wrong. The SSH config file is one of the most underutilized productivity tools in a developer’s arsenal. The Basics: ~/.ssh/config Create or edit ~/.ssh/config: 1 2 3 4 5 Host dev HostName dev.example.com User deploy IdentityFile ~/.ssh/deploy_key Port 22 Now you just type ssh dev. That’s it. Host Patterns Wildcards let you apply settings to multiple hosts: ...

February 25, 2026 Â· 5 min Â· 955 words Â· Rob Washington

chmod: Understanding Unix File Permissions

Unix permissions determine who can do what with files and directories. Understanding them is fundamental to system security and avoiding “Permission denied” errors. The Permission Model Every file has three permission types for three user classes: Permission Types: r (read) = 4 w (write) = 2 x (execute) = 1 User Classes: u (user/owner) g (group) o (others) Reading Permissions 1 2 ls -l file.txt # -rw-r--r-- 1 user group 1234 Feb 25 12:00 file.txt Breaking down -rw-r--r--: ...

February 25, 2026 Â· 6 min Â· 1087 words Â· Rob Washington

Environment Variables: Configuration Done Right

The twelve-factor app methodology made environment variables the standard for configuration. They’re simple, universal, and keep secrets out of code. But there are right and wrong ways to use them. The Basics 1 2 3 4 5 6 7 8 9 10 11 # Set in current shell export DATABASE_URL="postgres://localhost/mydb" # Set for single command DATABASE_URL="postgres://localhost/mydb" ./myapp # Check if set echo $DATABASE_URL # Unset unset DATABASE_URL .env Files Don’t commit secrets. Use .env files for local development: ...

February 24, 2026 Â· 5 min Â· 1050 words Â· Rob Washington

Systemd Service Hardening: Running Services Securely

Most systemd services run with full system access by default. That’s fine until one gets compromised. Systemd provides powerful sandboxing options that most people never use. The Basics: User and Group Never run services as root if they don’t need it: 1 2 3 [Service] User=myapp Group=myapp Create a dedicated user: 1 sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp Filesystem Restrictions Read-Only Root Make the entire filesystem read-only: ...

February 24, 2026 Â· 5 min Â· 961 words Â· Rob Washington

Secrets Management in the Modern Stack

We’ve all done it. Committed an API key to git. Hardcoded a database password “just for testing.” Posted a screenshot with credentials visible in the corner. The security community has a name for this: Tuesday. But secrets management doesn’t have to be painful. Let’s walk through the progression from “please no” to “actually reasonable” in handling sensitive credentials. The Hierarchy of Secrets (From Worst to Best) Level 0: Hardcoded in Source 1 2 3 # Don't do this. Ever. db_password = "hunter2" api_key = "sk-live-definitely-real-key" This is how breaches happen. Credentials in source code get committed to git, pushed to GitHub, indexed by bots within minutes, and suddenly someone’s mining crypto on your AWS account. ...

February 24, 2026 Â· 5 min Â· 969 words Â· Rob Washington

JWT Authentication Done Right: Tokens Without the Footguns

JSON Web Tokens are everywhere in modern authentication. They’re stateless, portable, and self-contained. They’re also easy to implement insecurely. These practices help you use JWTs without shooting yourself in the foot. JWT Structure A JWT has three parts, base64-encoded and dot-separated: h e e y a J d h e b r G . c p i a O y i l J o I a U d z . I s 1 i N g i n J a 9 t . u e r y e J z d W I i O i I x M j M i f Q . s I G 5 n 8 l 7 . . . Header: ...

February 24, 2026 Â· 6 min Â· 1177 words Â· Rob Washington

Container Security Basics: Don't Ship Vulnerabilities

Containers provide isolation, not security. A misconfigured container is as vulnerable as a misconfigured server — sometimes more so, because containers make it easy to ship the same vulnerability everywhere. These basics prevent the most common container security issues. Don’t Run as Root The most common mistake: 1 2 3 4 5 6 7 8 9 10 11 12 # ❌ Bad: Runs as root by default FROM node:20 COPY . /app CMD ["node", "server.js"] # ✅ Good: Create and use non-root user FROM node:20 RUN useradd -r -u 1001 appuser WORKDIR /app COPY --chown=appuser:appuser . . USER appuser CMD ["node", "server.js"] Many base images include non-root users: ...

February 23, 2026 Â· 5 min Â· 1046 words Â· Rob Washington

Secrets Management Patterns for Modern Infrastructure

Every infrastructure team eventually faces the same uncomfortable question: where do the secrets go? API keys, database passwords, TLS certificates, OAuth tokens — they all need to live somewhere. The wrong answer (“in the repo, it’s fine, it’s private”) creates technical debt that compounds silently until someone accidentally pushes to public or an ex-employee still has access to production credentials. The Anti-Patterns First Environment variables everywhere. Yes, the twelve-factor app says config comes from the environment. But “the environment” doesn’t mean a .env file committed to git. Environment variables are runtime config, not secret storage. ...

February 23, 2026 Â· 4 min Â· 709 words Â· Rob Washington

SSH Security Hardening: Protecting Your Most Critical Access Point

SSH is the front door to your infrastructure. Every server, every cloud instance, every piece of automation relies on it. A compromised SSH setup means game over. These hardening steps dramatically reduce your attack surface. Disable Password Authentication Passwords can be brute-forced. Keys can’t (practically): 1 2 3 4 # /etc/ssh/sshd_config PasswordAuthentication no ChallengeResponseAuthentication no UsePAM no 1 2 # Restart SSH (keep your current session open!) sudo systemctl restart sshd Before doing this, ensure your key is in ~/.ssh/authorized_keys. ...

February 23, 2026 Â· 5 min Â· 904 words Â· Rob Washington

CORS Demystified: Why Your API Calls Get Blocked

You’ve built an API. It works perfectly in Postman. Then you call it from your frontend and get: A h i c a s c s e p s b r s e e e s t n e o n b t f l e o o t c n c k h e t d h a e t b y r ' e h C q t O u t R e p S s s t : p e / d l a i r p c e i y s . : o e u x N r a o c m e p ' . l A e c . c c e o s m s ' - C f o r n o t m r o o l r - i A g l i l n o w ' - h O t r t i p g s i : n / ' m h y e a a p d p e . r c o m ' CORS isn’t your API being broken. It’s your browser protecting users. Understanding why it exists makes fixing it straightforward. ...

February 23, 2026 Â· 7 min Â· 1478 words Â· Rob Washington