The majority of web servers run Linux. Even if you develop on macOS or Windows (with WSL), deploying means working with a Linux terminal. Knowing your way around the command line isn't just a nice-to-have — it's the difference between resolving a production issue in 30 seconds and fumbling for 30 minutes.

The good news is that a surprisingly small set of commands covers 95% of day-to-day server work. This guide walks through them in the order you tend to need them: moving around the filesystem, inspecting files, searching logs, fixing permissions, connecting to remote machines, and managing processes. Two habits will accelerate everything you learn here: press Tab constantly to autocomplete paths and commands, and when in doubt run man commandname — the manual pages are terse but authoritative.

Navigating the Filesystem

Everything starts with knowing where you are and what is around you. pwd prints your current location, and ls -lah is the listing you will actually use day to day: -l shows permissions, owner, and modification time, -a includes hidden dotfiles like .env, and -h prints sizes as "4.2M" instead of raw bytes. The cd - shortcut, which jumps back to wherever you just were, is one of those tricks that saves minutes every day once it enters your muscle memory.

find is the heavyweight of the group. The example below locates every .log file under /var/log modified in the last seven days — exactly the kind of query you need when disk space suddenly vanishes or you are hunting for which log captured last night's incident.

Essential Navigation Commands
# Print current directory
pwd

# List files (long format, human-readable sizes, hidden files)
ls -lah

# Change directory
cd /var/www/html
cd ~        # Go to home directory
cd -        # Go back to previous directory

# Create directories (including nested)
mkdir -p projects/my-app/src

# Find files
find /var/log -name "*.log" -mtime -7  # Logs modified in last 7 days

Working with Files

Choose your file viewer based on file size. cat dumps everything at once, which is fine for a config file; for a multi-gigabyte log it will flood your terminal, so use less, which streams the file and lets you scroll and search with /pattern. tail -f deserves special mention: it follows a file as new lines are appended, making it the standard way to watch application logs live while you reproduce a bug.

Treat rm with respect. There is no recycle bin on a server — rm -rf deletes immediately and permanently, and a mistyped path can destroy a system. Get in the habit of Tab-completing the path so you see exactly what you are targeting before pressing Enter. Finally, keep du and df straight: du -sh tells you how big a specific directory is, while df -h reports free space per filesystem. When a disk fills up, you use df to confirm it and du to find the culprit.

File Operations
# View file contents
cat config.json              # Entire file
head -n 20 access.log        # First 20 lines
tail -n 50 error.log         # Last 50 lines
tail -f error.log            # Live-follow (great for debugging)
less large-file.log          # Scrollable viewer

# Copy, move, remove
cp file.txt backup/file.txt
cp -r src/ src-backup/       # Copy directory recursively
mv old-name.txt new-name.txt
rm file.txt
rm -rf node_modules/         # Remove directory recursively (CAREFUL!)

# File sizes
du -sh node_modules/         # Total directory size
df -h                        # Disk usage summary

Text Processing: grep, sed, awk

These three tools are the Swiss Army knife of log analysis and text manipulation.

grep searches file contents for a pattern and prints matching lines. On a production server it is usually the fastest route from "something is wrong" to the actual error message: grep the log for "ERROR" or an exception name, then widen the view with -B and -A to see the lines before and after each hit. The pattern is a regular expression, so grep "50[23]" access.log finds both 502 and 503 responses in a single pass.

grep — Search for Patterns
# Search for a string in files
grep "ERROR" /var/log/app.log

# Recursive search in a directory
grep -r "TODO" src/

# Case-insensitive with line numbers
grep -in "database" config.php

# Show 3 lines before and after each match
grep -B3 -A3 "Exception" error.log

# Count matches
grep -c "404" access.log

sed edits text as it streams through, which makes it perfect for bulk substitutions. The syntax to memorize is s/old/new/g — substitute, globally. Without the trailing g, only the first match on each line is replaced, a detail that has quietly corrupted many a config migration. The -i flag edits the file in place; on anything important, use -i.bak instead so sed keeps a backup copy you can diff against or restore.

sed — Stream Editor
# Replace first occurrence per line
sed 's/http:/https:/' urls.txt

# Replace ALL occurrences (global flag)
sed 's/http:/https:/g' urls.txt

# In-place edit (modify the file directly)
sed -i 's/localhost/production.example.com/g' .env

awk thinks in columns. It splits every line into fields — $1, $2, and so on, whitespace-separated by default — which maps perfectly onto server logs and tabular data. The second example shows its other superpower: it can accumulate values across lines and print a result in an END block, giving you quick sums and averages without opening a spreadsheet. For comma-separated files, add -F',' to change the field separator.

awk — Column Extraction
# Print the 1st and 4th columns of a space-separated file
awk '{print $1, $4}' access.log

# Sum up a column of numbers
awk '{sum += $5} END {print sum}' data.csv

Permissions & Ownership

Every file has three permission sets — owner, group, and everyone else — each combining read (4), write (2), and execute (1). That is all the octal notation is: 754 means the owner can read, write, and execute (7), the group can read and execute (5), and others can only read (4). When a web app cannot write to its uploads directory, or Nginx returns 403 for files that clearly exist, permissions or ownership are the first thing to check.

The pragmatic fix is usually ownership, not wider permissions: web server processes typically run as www-data, so a recursive chown of the web root to that user solves most access errors cleanly. Resist the temptation of chmod 777 — it makes files writable by every account on the machine and turns a minor misconfiguration into a genuine security hole.

chmod & chown
# Make a script executable
chmod +x deploy.sh

# Set specific permissions (owner: rwx, group: r-x, others: r--)
chmod 754 app.js

# Change file ownership
chown www-data:www-data /var/www/html -R

SSH & Remote Servers

SSH is how you will do everything on a remote server, so it pays to set it up properly. Key-based authentication is both more secure and more convenient than passwords: generate a key pair with ssh-keygen, put the public key on the server, and disable password login entirely. If you juggle several servers, define them in ~/.ssh/config with a host alias, key path, and username — then ssh myserver replaces a long incantation you would otherwise retype daily.

The last example in the block below is underrated: passing a command string to ssh runs it remotely and returns, which is the seed of every deployment script you will ever write. For copying files, scp works fine, but look into rsync once transfers get large — it only sends the parts of files that actually changed.

SSH Commands
# Connect to a remote server
ssh [email protected]

# Use a specific SSH key
ssh -i ~/.ssh/my-key.pem [email protected]

# Copy files to a remote server (SCP)
scp -r ./dist [email protected]:/var/www/html/

# Run a command remotely without logging in
ssh [email protected] "sudo systemctl restart nginx"

Process Management

Two questions come up constantly on servers: "is my app actually running?" and "what is hogging this port?". ps aux piped through grep answers the first, and lsof -i :3000 or ss -tulnp answers the second — indispensable when a deployment fails with "address already in use".

When you need to stop a process, prefer plain kill, which sends SIGTERM and lets the program shut down gracefully — closing files, finishing requests, releasing locks. kill -9 sends SIGKILL, which the process cannot catch or clean up after; treat it as a last resort for a truly hung process, not the default. For a live overview of CPU and memory, htop gives you a sortable, scrollable dashboard right in the terminal.

Managing Processes
# List running processes
ps aux | grep node

# Check what's using a port
lsof -i :3000
# or
ss -tulnp | grep 3000

# Kill a process by PID
kill 12345
kill -9 12345  # Force kill

# Monitor system resources (interactive)
htop

Piping & Redirection

The pipe (|) sends the output of one command as input to the next. This is what makes the command line so powerful.

Instead of one monolithic tool, you compose small ones: in the examples below, du measures, sort orders, and head trims — together they answer "what is eating my disk?" in one line. Redirection is the other half of the story: > writes command output to a file (overwriting it), >> appends, and 2> captures the error stream separately, which is handy for keeping build warnings out of your regular output.

Practical Pipe Examples
# Find the 10 largest files in a directory
du -ah /var/log | sort -rh | head -10

# Count unique IP addresses in access log
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20

# Save command output to a file
echo "Deployment at $(date)" >> deploy.log

# Redirect errors to a file
npm run build 2> errors.log

Common Pitfalls

Most command-line disasters follow the same few scripts. Watch out for these:

  • Unquoted variables in destructive commands. If $DIR happens to be empty, rm -rf $DIR/ becomes rm -rf /. Always quote variables and double-check paths before recursive deletes.
  • Spaces in filenames. my file.txt is two separate arguments to most commands unless you quote it. Quote paths by default and this entire class of bug disappears.
  • Working as root out of habit. Use a normal account and sudo for the specific commands that need it — the extra keystrokes are cheap insurance against catastrophic typos.
  • Editing production files without a backup. Before changing any config, copying it to filename.bak takes two seconds and makes rollback trivial.

Where to Go from Here

Fluency comes from repetition, not memorization. Pick two or three tasks from this guide that you currently do through a GUI — following logs with tail -f, searching with grep, checking disk usage — and force yourself to do them in the terminal for a week. Once these feel natural, the logical next step is shell scripting: take a sequence you type repeatedly, put it in a .sh file, make it executable with chmod +x, and you have written your first deployment tool. The commands in this article are the vocabulary; scripts are the sentences.

Try Our Free Developer Tools

Encode, decode, and format your code instantly.