Linux Is Not Optional in DevOps

Let's get something out of the way immediately.

If you want to work in DevOps, Cloud, or SRE — you need to know Linux. Not "kind of know it." Not "I can Google my way through it." Actually know it.

Nearly every server running production workloads runs Linux. Every Docker container starts from a Linux base. Every Kubernetes node runs Linux. Your CI/CD pipelines run on Linux. Your cloud instances are Linux.

The terminal is your primary interface with all of it.

The good news is you don't need to memorize thousands of commands. You need to deeply understand the ones you'll actually use — and that's exactly what this guide covers.

These are the commands that come up every single day in real DevOps work. Not textbook theory. Real, practical, production-grade Linux knowledge.

Before We Start — Set Up Your Practice Environment

You can't learn Linux by reading about it. You need a terminal in front of you.

Option 1 — WSL2 on Windows: If you're on Windows, install WSL2 (Windows Subsystem for Linux) and run Ubuntu. It's free and takes about 10 minutes to set up. Open PowerShell as administrator and run:



wsl --install

Option 2 — VirtualBox: Download VirtualBox and create an Ubuntu 22.04 virtual machine. Free, isolated, and you can break things without consequences.

Option 3 — Cloud instance: Spin up a free tier EC2 instance on AWS or a free Droplet on DigitalOcean. This gets you a real cloud server to practice on.

Option 4 — Already on Mac or Linux: Open your terminal. You're ready.

Now let's get into the commands.

Navigation and File System

These are the first commands you learn and the ones you use most.

pwd — Print Working Directory



pwd

Shows you exactly where you are in the file system. When you're lost in a deep directory structure, this is your anchor.



/home/ubuntu/projects/myapp

ls — List Directory Contents



ls
ls -la
ls -lh /var/log

ls alone shows files in the current directory. But you'll almost always use flags:

-l gives you the long format — permissions, owner, size, date -a shows hidden files (files starting with a dot) -h makes file sizes human-readable (KB, MB, GB instead of bytes) -la combines long format with hidden files — your everyday go-to

The output tells you everything: who owns a file, when it was last modified, whether it's a file or directory, and what permissions apply.

cd — Change Directory



cd /var/log
cd ~
cd ..
cd -

cd ~ takes you home. cd .. goes up one level. cd - takes you back to the previous directory — incredibly useful when you're jumping between two locations.

find — Search for Files



find /etc -name "*.conf"
find /var/log -name "*.log" -mtime -1
find /home -type f -size +100M

find is one of the most powerful commands in Linux. Use it to locate files by name, type, size, modification time, or permissions.

The second example finds all log files modified in the last day. The third finds files larger than 100MB. These are the kinds of searches you run when debugging production issues.

tree — Visual Directory Structure



tree
tree -L 2
tree -a

tree prints a visual representation of your directory structure. -L 2 limits it to two levels deep. Not installed by default on all systems — apt install tree to get it.

File Operations

cp — Copy Files and Directories



cp file.txt /backup/file.txt
cp -r /etc/nginx /backup/nginx
cp -p config.yml config.yml.bak

-r copies directories recursively. -p preserves timestamps and permissions — important when backing up configuration files.

mv — Move or Rename



mv old-name.txt new-name.txt
mv /tmp/config.yml /etc/app/config.yml

mv both moves and renames. If source and destination are in the same directory, it renames. If they're different directories, it moves.

rm — Remove Files



rm file.txt
rm -rf /tmp/old-deployment

rm -rf removes directories recursively and forcefully. This command deserves respect — there is no recycle bin. Once it's gone, it's gone. Always double-check the path before running rm -rf.

mkdir — Create Directories



mkdir logs
mkdir -p /opt/myapp/config/environments

-p creates parent directories as needed. Without it, mkdir fails if the parent directory doesn't exist.

touch — Create Empty Files



touch deploy.log
touch .gitkeep

touch creates empty files or updates the timestamp on existing ones. Often used to create placeholder files or trigger file watchers.

Viewing and Editing Files

cat — Print File Contents



cat /etc/hosts
cat config.yml

For small files, cat is the quickest way to see the contents. For large files, use less instead.

less — Paginated File Viewing



less /var/log/syslog
less +F /var/log/app.log

less lets you scroll through large files without loading everything into memory. Use arrow keys to navigate, q to quit, / to search within the file.

less +F follows the file like tail -f — useful for watching logs in real time while still being able to scroll back.

tail — View End of File



tail /var/log/nginx/error.log
tail -n 100 /var/log/app.log
tail -f /var/log/nginx/access.log

tail shows the last lines of a file. -n 100 shows the last 100 lines. -f follows the file in real time — this is what you use when watching live logs during a deployment.

tail -f on an application log during a deployment is something you'll do hundreds of times in your career.

head — View Beginning of File



head /etc/passwd
head -n 20 config.yml

The opposite of tail — shows the first lines. Useful for checking file headers or configuration file structure.

nano / vim — Text Editors



nano /etc/hosts
vim /etc/nginx/nginx.conf

You need to be able to edit files in the terminal. nano is beginner-friendly — it shows you the keyboard shortcuts at the bottom of the screen. vim is more powerful but has a learning curve.

At minimum, know how to open a file in vim, make a change, and save and exit (:wq). You will inevitably end up in vim at some point and need to get out.

Text Processing — The Power Trio

These three commands are where Linux really starts to shine. Master them and you can slice, filter, and transform text in ways that would take a full script in other environments.

grep — Search Text



grep "error" /var/log/app.log
grep -i "warning" /var/log/syslog
grep -r "database_url" /etc/
grep -n "timeout" config.yml
grep -v "DEBUG" app.log

grep filters lines containing a pattern. It's how you find errors in logs, search configuration files, and filter command output.

-i makes it case-insensitive -r searches recursively through directories -n shows line numbers -v inverts the match — shows lines that do NOT contain the pattern

Combine with pipes to filter the output of other commands:



cat /var/log/nginx/access.log | grep "404"
ps aux | grep nginx

awk — Field Processing



awk '{print $1}' access.log
awk -F: '{print $1}' /etc/passwd
awk '{sum += $NF} END {print sum}' numbers.txt

awk processes text field by field. $1 is the first field, $2 is the second, $NF is the last field. -F: sets the field separator to a colon.

A practical example — getting all usernames from /etc/passwd:



awk -F: '{print $1}' /etc/passwd

Or summing the request sizes in an nginx access log:



awk '{sum += $10} END {print "Total bytes:", sum}' /var/log/nginx/access.log

sed — Stream Editor



sed 's/old/new/g' config.yml
sed -i 's/localhost/production-db/g' config.yml
sed -n '10,20p' large-file.txt

sed finds and replaces text in files or streams. The s/old/new/g syntax replaces all occurrences of "old" with "new".

-i edits the file in place — be careful with this in production.

A real use case: updating a configuration file during a deployment:



sed -i "s/APP_VERSION=.*/APP_VERSION=${NEW_VERSION}/g" .env

Process Management

ps — List Running Processes



ps aux
ps aux | grep nginx
ps -ef | grep python

ps aux shows all running processes with their CPU and memory usage, the user they're running as, and the full command. This is how you see what's actually running on a server.

top / htop — Real-Time Process Monitor



top
htop

top gives you a live view of CPU, memory, and running processes. htop is an improved version with color coding and easier navigation — install it with apt install htop.

When a server is running slow, htop is often the first place you look.

kill — Terminate Processes



kill 1234
kill -9 1234
killall nginx

kill sends a signal to a process by its PID. By default it sends SIGTERM (graceful shutdown). -9 sends SIGKILL which forces immediate termination — use this when a process is completely unresponsive.

Get the PID from ps aux or pgrep:



pgrep nginx
kill $(pgrep nginx)

systemctl — Manage System Services



systemctl status nginx
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
systemctl enable nginx
systemctl disable nginx

systemctl manages services on modern Linux systems. enable makes a service start automatically on boot. disable prevents it from starting automatically.

When something isn't working, always check the status first:



systemctl status myapp

This shows you whether the service is running, recent log output, and any error messages.

journalctl — View System Logs



journalctl -u nginx
journalctl -u nginx -f
journalctl -u nginx --since "1 hour ago"
journalctl -xe

journalctl is the log viewer for systemd services. -u filters by unit (service name). -f follows in real time. -xe shows the most recent entries with extra detail — great for debugging a service that failed to start.

Networking Commands

curl — Make HTTP Requests



curl https://api.example.com/health
curl -I https://example.com
curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' https://api.example.com/endpoint
curl -o output.txt https://example.com/file

curl is essential for testing APIs, checking endpoints, downloading files, and debugging HTTP issues. -I fetches only the headers — useful for checking response codes and headers without downloading the full body.

wget — Download Files



wget https://example.com/file.tar.gz
wget -O custom-name.tar.gz https://example.com/file.tar.gz

wget downloads files from the internet. Simpler than curl for downloads but less flexible for API testing.

ssh — Secure Shell



ssh ubuntu@192.168.1.100
ssh -i ~/.ssh/mykey.pem ec2-user@54.123.45.67
ssh -L 8080:localhost:3000 user@remote-server

ssh connects you to remote servers. -i specifies a private key file. -L creates a local port forward — incredibly useful for accessing services on remote servers that aren't exposed publicly.

scp — Secure Copy



scp file.txt ubuntu@192.168.1.100:/home/ubuntu/
scp -r /local/directory ubuntu@server:/remote/path/
scp ubuntu@server:/var/log/app.log ./local-copy.log

scp copies files between local and remote machines over SSH. -r copies directories recursively.

netstat / ss — Network Connections



ss -tulnp
netstat -tulnp
ss -s

ss (and the older netstat) show open network connections and listening ports. -tulnp shows TCP, UDP, listening ports, numeric addresses, and the process using each port.

Use this to check which process is listening on a port:



ss -tulnp | grep :80

ping — Test Connectivity



ping google.com
ping -c 4 192.168.1.1

Basic connectivity test. -c 4 sends exactly 4 packets then stops.

dig / nslookup — DNS Lookups



dig example.com
dig example.com A
dig @8.8.8.8 example.com
nslookup example.com

dig queries DNS records. Invaluable when debugging DNS issues — checking if records have propagated, verifying A records, or testing from different DNS servers.

Permissions and Ownership

Understanding Linux permissions is non-negotiable for DevOps work. Misconfigured permissions cause security vulnerabilities and application failures.

chmod — Change File Permissions



chmod 755 script.sh
chmod +x deploy.sh
chmod 600 ~/.ssh/id_rsa
chmod -R 755 /var/www/html

Permissions are represented as three groups of three bits: owner, group, world.

7 = read + write + execute (rwx) 5 = read + execute (r-x) 4 = read only (r--) 6 = read + write (rw-)

Common patterns:

  • 755 — scripts and directories (owner can do everything, others can read and execute)
  • 644 — regular files (owner can read/write, others can read)
  • 600 — sensitive files like SSH keys (owner only, no one else)
  • +x — add execute permission without changing other permissions

chown — Change Ownership



chown ubuntu:ubuntu /var/www/html
chown -R www-data:www-data /var/www/
chown root:root /etc/sudoers

chown user:group file changes both owner and group. -R changes recursively. Getting ownership right is critical — applications often fail because they don't have the right permissions to read their configuration files or write to their log directories.

sudo — Run as Superuser



sudo apt update
sudo systemctl restart nginx
sudo -i
sudo -u www-data command

sudo runs a command as root or another user. sudo -i gives you a root shell — use with caution. sudo -u runs as a specific user.

Disk and Storage

df — Disk Space Usage



df -h
df -h /var

Shows disk space usage for all mounted filesystems. -h makes it human-readable. Run this when you suspect disk space issues — a full disk is one of the most common causes of production incidents.

du — Directory Size



du -sh /var/log
du -sh /*
du -h --max-depth=1 /var

du shows how much space directories are using. -s summarizes, -h is human-readable. Use this to find what's eating your disk space.

A classic troubleshooting workflow:



df -h                    # see which filesystem is full
du -h --max-depth=1 /    # find the biggest directories
du -h --max-depth=1 /var # drill down

lsblk — List Block Devices



lsblk
lsblk -f

Shows all block devices (disks and partitions) and how they're mounted. Useful when adding new storage volumes to a server.

Compression and Archives

tar — Archive Files



tar -czf backup.tar.gz /etc/nginx
tar -xzf backup.tar.gz
tar -tzf backup.tar.gz
tar -xzf archive.tar.gz -C /opt/

tar creates and extracts archives. The flags you'll use constantly:

-c create, -x extract, -z gzip compression, -f filename, -t list contents, -C extract to specific directory

The mnemonic: "Create: czf, eXtract: xzf"

zip / unzip



zip -r archive.zip directory/
unzip archive.zip
unzip archive.zip -d /destination/

For working with zip files — common when dealing with Lambda deployment packages or downloaded software.

Environment Variables and Shell

export — Set Environment Variables



export DATABASE_URL="postgresql://localhost/mydb"
export PATH=$PATH:/usr/local/bin
echo $DATABASE_URL

Environment variables pass configuration to applications without hardcoding values. echo $VARIABLE_NAME prints the current value.

env — View All Environment Variables



env
env | grep DATABASE
printenv PATH

env lists all current environment variables. Pipe through grep to find specific ones.

which / whereis — Find Command Location



which python3
which docker
whereis nginx

which tells you exactly where a command lives. Useful when you have multiple versions of something installed and need to know which one is being used.

history — Command History



history
history | grep docker
!150
!!

history shows your command history. !150 runs command number 150. !! repeats the last command — often used as sudo !! when you forget to add sudo.

Pipes and Redirection

These aren't individual commands but they're how you combine commands into powerful one-liners.

Pipe — |



ps aux | grep nginx
cat /var/log/app.log | grep "ERROR" | tail -n 50
ls -la | sort -k5 -n

The pipe sends the output of one command as input to the next. This is the foundation of the Linux philosophy — small tools that do one thing well, chained together.

Redirect Output — > and >>



echo "hello" > file.txt
ls -la > directory-listing.txt
command >> logfile.txt

> writes output to a file, overwriting existing content. >> appends to a file. This is how you save command output to files.

Redirect Errors — 2> and 2>&1



command 2> errors.log
command > output.log 2>&1
command > /dev/null 2>&1

2> redirects stderr (error output). 2>&1 redirects stderr to the same place as stdout. > /dev/null 2>&1 silences all output — used in cron jobs.

One-Liners DevOps Engineers Actually Use

Here are real commands from real DevOps work:

Find the 10 largest files on the system:



find / -type f -printf '%s %p\n' | sort -rn | head -10

Check which process is using port 8080:



ss -tulnp | grep :8080

Watch a log file for errors in real time:



tail -f /var/log/app.log | grep --line-buffered "ERROR"

Count how many times each IP appears in nginx access logs:



awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Find all files modified in the last 24 hours:



find /var/www -type f -mtime -1

Check memory usage sorted by process:



ps aux --sort=-%mem | head -20

Recursively search for a string in all config files:



grep -r "database_host" /etc/ 2>/dev/null

Create a timestamped backup of a config file:



cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%Y%m%d_%H%M%S).bak

Kill all processes matching a name:



pkill -f "python manage.py"

Check disk I/O in real time:



iostat -x 2

Building Good Linux Habits

Knowing commands is one thing. Using them effectively in production is another. Here are the habits that separate good DevOps engineers from great ones.

Always check before you delete. Before rm -rf, run ls on the path first. Verify you're deleting what you think you're deleting.

Use tab completion. Press Tab to autocomplete commands, file paths, and flags. It's faster and reduces typos.

Read man pages. man command shows the full documentation for any command. man grep, man awk, man find — these are worth reading once in full.

Use aliases for commands you type constantly. Add these to your ~/.bashrc:



alias ll='ls -la'
alias ..='cd ..'
alias grep='grep --color=auto'
alias k='kubectl'

Keep a personal runbook. When you figure out a useful command or one-liner, write it down. A personal commands.md file in your home directory or a private Git repo is invaluable.

Don't run things as root unnecessarily. Use sudo only when you need it. Running everything as root is a security risk and a bad habit.

Test destructive commands on non-production first. rm, sed -i, chmod -R — test these in a safe environment before running on production.

What to Learn Next

Once you're comfortable with these commands, the natural next steps are:

Shell scripting — combine these commands into scripts that automate repetitive tasks. Start with simple Bash scripts and work up to more complex automation.

Regular expressionsgrep, sed, and awk all support regex. Learning regex deeply unlocks a whole new level of text processing power.

Cron jobs — scheduling commands to run automatically at specific times. Essential for maintenance tasks, backups, and log rotation.

vim properly — invest a few hours learning vim beyond the basics. The efficiency gains are real once it becomes muscle memory.

Linux networking deeperiptables, nftables, network namespaces, and routing tables. Important for understanding how containers and Kubernetes networking actually works.

The Real Secret to Learning Linux

You already know it: use it every day.

Set your development environment to run on Linux or WSL. SSH into servers instead of using web consoles. Write scripts instead of clicking through UIs.

Every hour you spend in a Linux terminal makes the next hour easier. The commands that felt foreign at first become muscle memory. You stop thinking about syntax and start thinking about solutions.

That's when Linux stops feeling like a barrier and starts feeling like a superpower.

Looking for DevOps roles where Linux expertise is valued? Browse remote DevOps, SRE and Cloud Engineer jobs on StackHire — new positions added daily.