Meta description: I’ve spent years living in the terminal — here are the Linux commands I actually reach for every day as a backend developer, not just theory.
Last updated: July 8, 2026
My first week as a backend developer, I remember tailing a log file, watching for an error, and repeatedly running cat logfile.txt over and over like a caveman. A senior engineer glanced over, said “just use tail -f,” and walked away. That one command saved me hours that week alone. If you’re early in your backend journey, this is the list I wish someone had handed me on day one.
TL;DR
- A handful of core Linux commands —
grep,tail -f,ps aux,netstat/ss, andjournalctl— cover 80% of daily backend debugging. - Piping and redirection (
|,>,>>) turn simple commands into powerful one-line debugging tools. - Knowing process and network commands cold means you can diagnose a production issue without opening a monitoring dashboard.
Background: Why the Terminal Still Matters
GUI tools and dashboards are great, but when a production server is on fire at 2 a.m. and your monitoring stack is the thing that’s down, the terminal is what’s left. Backend development is fundamentally about processes, files, and network connections, and Linux commands map directly onto those three things.
I’ve worked on teams that leaned entirely on managed platforms, and even there, SSH access to a debug container or a bastion host comes up constantly. Terminal fluency isn’t nostalgia — it’s still the fastest path to an answer in a lot of real incidents.
[SOURCE: https://www.gnu.org/software/coreutils/manual/coreutils.html]
Prerequisites
- Basic familiarity with a Linux or Unix-like shell (bash or zsh)
- SSH access to a remote server, or a local Linux/WSL environment
- A running application or service to practice against (a Node, Python, or Go API works fine)
Step-by-Step: The Commands I Actually Use
1. grep — searching logs and code fast
grep -i "error" /var/log/app/production.log
The -i flag makes it case-insensitive, which matters because I’ve seen the same app log both Error and ERROR depending on which module wrote it. Adding -r searches recursively through a whole directory, which I use constantly when hunting for a config value across a codebase.
2. tail -f — watching logs in real time
tail -f /var/log/app/production.log
This is the command that ended my cat-in-a-loop era. Combine it with grep using a pipe to watch only the lines you care about:
tail -f /var/log/app/production.log | grep -i "timeout"
3. ps aux and top — checking what’s actually running
ps aux | grep node
This tells me the PID, CPU, and memory usage of every matching process. When a server feels sluggish, I reach for top (or htop if it’s installed) first, since it updates live and sorts by resource usage automatically.
4. ss (or netstat) — checking open ports and connections
ss -tulpn
This shows every listening TCP/UDP port and the process bound to it. I use this constantly to answer “is my API actually listening on port 3000, or did it silently crash?” netstat does the same job but is deprecated on most modern distros in favor of ss.
5. journalctl — reading systemd service logs
journalctl -u myapp.service -f --since "10 minutes ago"
If your app runs as a systemd service (most production backend services do), this is where its logs actually live, not necessarily in /var/log. The -f flag follows the log live, same as tail -f.
Pro Tip: Add
--since "1 hour ago"tojournalctlwhen debugging an incident — scrolling through a full day of logs to find the relevant five minutes wastes real time during an outage.
[INTERNAL LINK: related article]
Real-World Tips I Use in Production
I keep a personal cheat sheet of curl one-liners for hitting internal health-check endpoints directly from the server, since it bypasses any load balancer or DNS issues that might be masking the real problem:
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/health
I also lean heavily on chmod and chown far more than I expected coming from a Windows background — file permission mismatches between deploy users and app runtime users are a recurring source of “it works locally but not on the server” bugs.
Common Errors and How I Fixed Them
Error: “Address already in use” when starting a service I used ss -tulpn | grep :3000 to find the PID already bound to that port, then kill -9 <PID> to free it up. This happens constantly after a crashed process doesn’t release its port cleanly.
Error: Permission denied when writing to a log directory This was a chown mismatch — the app was running as user appuser but the log directory was owned by root. Running sudo chown -R appuser:appuser /var/log/app fixed it permanently.
Error: Disk full, but du doesn’t show why df -h told me the disk was full, but du -sh /* didn’t add up to the total. The fix was lsof +L1, which found large deleted-but-still-open log files a crashed process was holding onto.
Important: Running
kill -9should be a last resort. It doesn’t let the process clean up connections or flush writes, which I learned the hard way after corrupting a half-written file during a production kill.
[SOURCE: https://man7.org/linux/man-pages/man1/ss.8.html]
FAQ
Q: What is the difference between netstat and ss on Linux? A: ss is the modern replacement for netstat, is significantly faster on systems with many connections, and is included by default on most current Linux distributions.
Q: How do I find which process is using a specific port on Linux? A: Run ss -tulpn | grep :PORT_NUMBER, or alternatively lsof -i :PORT_NUMBER if lsof is installed.
Q: What’s the best command to monitor a log file in real time? A: tail -f filename is the standard choice; pipe it into grep to filter for specific keywords like errors or a request ID.
Q: How do I check systemd service logs instead of a log file? A: Use journalctl -u service-name -f to follow the live log output of any systemd-managed service.
Q: Why does my backend server say permission denied when writing files? A: This is almost always a file or directory ownership mismatch — check it with ls -la and correct it with chown for the user your app actually runs as.
Conclusion
You don’t need to memorize a hundred Linux commands — a small set used fluently covers almost every backend debugging scenario you’ll hit. Start with grep, tail -f, ps aux, ss, and journalctl, and the rest tends to come naturally as you need it. What command do you reach for that isn’t on this list? Let me know in the comments.
About the Author
I’m a backend developer with over 8 years of experience running production services on Linux, spanning bare-metal servers, Docker containers, and cloud VMs on AWS. I’ve spent countless late nights debugging live incidents purely from a terminal, which shaped the command set in this article. My day-to-day stack includes Node.js, Python, PostgreSQL, and systemd-managed services.
