Linux interview questions and answers for DevOps and SRE
26 Linux questions from real DevOps and SRE interviews, sorted by seniority: permissions, processes and signals, systemd, networking, and the live debugging you get asked to narrate.
All 26 questions
1
Explain what
Juniorchmod 644andchmod 755actually mean.Each digit is a three-bit field for one class of user: owner, group, other. Read is 4, write is 2, execute is 1.
644is owner read and write, group read, other read. That is the normal mode for a file.755is owner read, write and execute, group read and execute, other read and execute. That is the normal mode for a directory or a script.The part that shows understanding: on a directory, the bits mean something different. Read lets you list names, write lets you create and delete entries, and execute lets you traverse into it. A directory with read but not execute gives you the file names and nothing else, which is why
755rather than644on directories is not arbitrary.2
What is the difference between a hard link and a symbolic link in Linux?
JuniorA hard link is another name for the same inode, so it keeps working when the original name is removed. A symlink stores a path, so removing the original leaves it dangling. Hard link Symbolic link Points at The same inode A path, stored as text Crosses filesystems No Yes Can target a directory No Yes If the original is deleted Still works Dangles Costs an inode No, shares one Yes, it is a small file ln file.txt hard.txt # same inode ln -s file.txt soft.txt # contains the path "file.txt" ls -li # first column is the inode numberThe practical consequence is that deleting the original leaves a hard link fully working and leaves a symlink dangling.
3
How do you find which process is using a port in Linux?
Juniorsudo ss -tlnp | grep :8080ssis the current tool;netstatis deprecated and often not installed. The flags are worth knowing:tfor TCP,lfor listening,nfor numeric so it does not do DNS lookups,pfor the owning process, which needs root to see processes you do not own.sudo lsof -i :8080gives the same answer with more detail about the open files.A good follow-up answer notes that a port held by a process in
TIME_WAIThas no owner to show, and that inside a containersssees only that container's network namespace, so a conflict on the host will not appear there.4
On Linux the disk is full but deleting files does not free space. Why?
JuniorTwo usual causes.
A deleted file still held open by a process. Unlinking removes the name, but the kernel keeps the data until the last file descriptor closes. A log file rotated out from under a running service is the classic case.
sudo lsof +L1That lists open files with a link count of zero. Restarting the holding process, or truncating through its descriptor, releases the space.
Exhausted inodes rather than bytes. Millions of tiny files fill the inode table while
df -hstill shows free space.df -h /var df -i /varIf
df -ishows 100% use, you need to delete files rather than free bytes, and no amount of removing large files will help.5
What is the difference between
Junior>and>>in bash, and how do you redirect stderr?>truncates the target and writes;>>appends.Streams are numbered: 0 is stdin, 1 is stdout, 2 is stderr. So:
cmd > out.log # stdout only, truncating cmd 2> err.log # stderr only cmd > all.log 2>&1 # both into one file cmd &> all.log # same thing, bash shorthand cmd 2>&1 | grep error # send stderr through the pipe tooOrder matters in
> all.log 2>&1: stdout is pointed at the file first, then stderr is pointed at wherever stdout currently goes. Writing2>&1 > all.logsends stderr to the terminal and only stdout to the file, which is a real and common mistake.6
What is the difference between SIGTERM, SIGKILL and SIGHUP?
MidSignal Number Catchable Means SIGTERM15 Yes Stop when you are ready. What killsends by defaultSIGKILL9 No The kernel removes the process now, with no chance to flush or close SIGHUP1 Yes Originally "the terminal hung up". Daemons repurpose it as "reload your config" The interview point: reaching for
kill -9first is a habit worth arguing against. It risks corrupting state, and a process that ignoresSIGTERMis a bug to investigate. Note also that a process stuck in uninterruptible sleep, stateD, will not die even fromSIGKILL, because it is blocked in the kernel waiting on IO.7
A Linux server is slow. Walk me through diagnosing it.
MidWork outward from load, and name what each step rules out.
uptime # load average over 1, 5, 15 minutesLoad higher than the core count means processes are waiting. Compare the three numbers to see whether it is rising or recovering.
top -b -n1 | head -20Read the CPU line rather than just the process list:
Field High means Look at %usApplication work The process list, and the application itself %syKernel work Syscall or context-switch churn, vmstat%waIO wait Disk, with iostat -xzfor await and utilisation%stSteal time A noisy neighbour on shared hardware. Nothing local will fix it free -h # is it actually memory iostat -xz 1 3 # await and %util per device ss -s # socket totals, are we out of connections dmesg -T | tail -30 # OOM kills and hardware errorsThe strongest answers say what they expect to find before running each command, and check
dmesgfor OOM kills early, since "slow" is often a service being repeatedly killed and restarted.8
What do setuid, setgid and the sticky bit do in Linux?
MidBit On a file On a directory Shows as setuid Runs as its owner, which is how passwdwrites to/etc/shadowNo effect rws------setgid Runs as its group New files inherit the directory's group rwxrws---sticky No effect Only a file's owner may delete it, which is why /tmpis safedrwxrwxrwtchmod u+s binary # setuid, shows as rws------ chmod g+s shared/ # setgid chmod +t /tmp # sticky, shows as drwxrwxrwtAdd the security note: setuid root binaries are a standard privilege escalation route, and auditing for unexpected ones with
find / -perm -4000is a real hardening step.9
How do you investigate a systemd service that will not start?
Midsystemctl status myapp journalctl -u myapp -n 100 --no-pagerstatusgives the current state, the exit code and the last few log lines;journalctlgives the history, which is what you need when it is crash-looping and status only shows the newest attempt. Add-bto limit to this boot, or-fto follow.Then narrow by cause. A non-zero exit code with nothing in the journal usually means the unit file is wrong rather than the application: a bad
ExecStartpath, aWorkingDirectorythat does not exist, or aUserthat cannot read its own files.systemd-analyze verify /etc/systemd/system/myapp.service systemctl cat myapp # the effective unit, including drop-inssystemctl catis the one people miss. A drop-in under/etc/systemd/system/myapp.service.d/overrides the unit you are reading, and this shows what is actually in effect. And after editing any unit,systemctl daemon-reloadis required or systemd keeps using the old one.10
A Linux service cannot reach another host. How do you narrow it down?
MidGo up the stack, one layer at a time, so each step eliminates something.
ip addr; ip route # do we have an address and a route ping -c3 10.0.1.20 # layer 3, if ICMP is allowed getent hosts api.internal # is it name resolution nc -zv api.internal 8080 # is the specific port reachable curl -sv http://api.internal:8080/healthzgetent hostsis better thannslookuphere because it uses the same resolution path the application does, including/etc/hostsand nsswitch, rather than querying DNS directly.If the port is refused rather than timing out, something is there and actively saying no, which usually means the service is not listening or is bound to
127.0.0.1. A timeout points at a firewall or security group silently dropping packets.sudo ss -tlnp | grep 8080 # on the far end, is it 0.0.0.0 or 127.0.0.111
Using a shell pipeline, how would you find the ten IPs making the most requests in an access log?
Midawk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10Be able to explain each stage:
awktakes the first field,sortgroups identical lines together becauseuniqonly collapses adjacent duplicates,uniq -ccounts each group,sort -rnorders by that count numerically and descending, andheadtakes the top ten.The mistake interviewers watch for is omitting the first
sort, which makesuniqsilently undercount.A stronger answer scales it. On a very large file,
sortspills to disk, and doing the counting inawkavoids that entirely:awk '{c[$1]++} END {for (i in c) print c[i], i}' access.log | sort -rn | head -1012
What is a zombie process in Linux, and is it a problem?
MidA zombie is a process that has exited but whose parent has not yet read its exit status, so the kernel keeps the process table entry. It shows as state
Zand uses no memory or CPU.A few transient zombies are normal. A growing pile is a bug in the parent, which is not calling
wait(). The real risk is exhausting the process table, since each zombie holds a PID.You cannot kill a zombie, because it is already dead. Killing or restarting the parent clears them, and if the parent dies they are reparented to PID 1, which reaps them.
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /^Z/'The container connection is worth raising: an application running as PID 1 in a container inherits the duty of reaping orphans, and most application runtimes do not do it. That is exactly what
docker run --initandtiniare for.13
What does an inode hold, and what does it not?
MidAn inode holds a file's metadata: type, permissions, owner and group, size, timestamps, link count, and pointers to the data blocks.
It does not hold the filename. Names live in directory entries, which map a name to an inode number. That single fact explains several behaviours: hard links are two names for one inode, renaming a file does not touch the inode, and you can delete a file you cannot read as long as you have write permission on the directory.
ls -li file.txt # inode number stat file.txt # everything the inode holds df -i # inode usage per filesystemIt also explains running out of inodes with free disk space, since the table is sized at filesystem creation on ext4.
14
What does systemd give you over an init script, and what are the trade-offs?
SeniorConcretely: dependency-ordered parallel startup rather than sequential runlevels, supervision with configurable restart policies, cgroup-based resource limits per unit, socket and timer activation, a structured and indexed journal, and a consistent declarative unit format instead of a few hundred lines of bespoke shell per service.
[Service] ExecStart=/usr/local/bin/myapp Restart=on-failure RestartSec=5 MemoryMax=512M User=myappThe cgroup point matters for a senior answer: systemd puts each unit in its own cgroup, so a restart reliably kills every child process, which an init script's PID file approach frequently failed to do.
The honest trade-offs: it is large and does a lot beyond init, which is the substance of the long-running criticism; binary journals need
journalctlrather thangrep; and the behaviour is genuinely complex, so debugging ordering problems means understandingWants,Requires,AfterandBindsTorather than reading a script top to bottom.15
What is Linux load average actually measuring, and how do you interpret it?
SeniorOn Linux it is the exponentially-damped average number of processes in runnable or uninterruptible state over one, five and fifteen minutes. The second half is the part people miss: Linux counts processes blocked on IO, which other Unixes do not.
So a load of 8 on an 8-core box can mean fully utilised CPU, or it can mean eight processes all blocked on a failing disk while the CPU sits idle. Load alone does not distinguish them, which is why it is a starting signal and not a diagnosis.
uptime vmstat 1 5 # r is runnable, b is blockedCompare load to core count from
nproc, and read the three intervals as a trend: 1-minute well above 15-minute means something is starting now.The senior addition is pressure stall information, which answers the question load average cannot:
cat /proc/pressure/cpu /proc/pressure/io /proc/pressure/memory16
How does the Linux OOM killer decide what to kill, and how do you investigate afterwards?
SeniorWhen the kernel cannot reclaim enough memory it scores every process, roughly by memory footprint adjusted by
oom_score_adj, and kills the highest scorer to free the most memory for the least number of kills. It is not the process that requested the allocation, and it is not the oldest, which is why the victim is often a database rather than the leaking process.dmesg -T | grep -i "killed process" journalctl -k | grep -i oom cat /proc/<pid>/oom_scoreProtect the processes that matter by biasing the score, from -1000 to 1000:
echo -500 > /proc/<pid>/oom_score_adjTwo points that mark experience. In a container, hitting the cgroup memory limit produces an OOM kill of that container's process even though the host has memory free, which is the exit code 137 you see in Kubernetes. And overcommit settings matter: with the default heuristic the kernel allows more allocation than it can back, so the reckoning arrives at first touch rather than at allocation.
17
What happens, step by step, when you
Seniorcurl https://example.comfrom a Linux host?The point of the question is breadth, so move steadily and do not skip layers.
- 1Resolution. The stub resolver consults nsswitch, so
/etc/hoststhen DNS. A recursive resolver walks root, TLD and authoritative nameservers unless it is cached. - 2Routing. The kernel picks a route and a source address, then resolves the next hop's MAC with ARP.
- 3TCP. SYN, SYN-ACK, ACK.
- 4TLS. ClientHello with SNI so a shared host knows which certificate to send, then ServerHello, certificate, chain validation against the local trust store including expiry and hostname, key agreement, Finished. TLS 1.3 needs one round trip, not two.
- 5HTTP. The request is sent, the server responds, and the connection may be reused for keep-alive.
Strong answers note that failures are diagnosable by layer, and that
curl -vshows you exactly where it stopped. They also mention that the certificate is validated against the hostname, which is why an IP address in the URL fails even when the host is reachable.- 1Resolution. The stub resolver consults nsswitch, so
18
Why does
Seniorset -euo pipefailmatter in a bash script, and where does it still not protect you?By default a shell script continues after a failing command and exits 0, which means a broken deploy script reports success.
set -eexits on an unhandled non-zero status.set -uerrors on an unset variable, which catches therm -rf "$PREFIX/"typo wherePREFIXwas never set.set -o pipefailmakes a pipeline fail if any stage fails, not just the last, socurl bad-url | jq .stops being a success.Where it still does not protect you:
set -eis ignored in a condition, soif cmd; thenis fine, which is intended, but it also does not fire inside&&chains the way people expect.- A failure in a command substitution used in an assignment can be swallowed.
- It does nothing for a command that succeeds while doing the wrong thing.
So the fuller habit is
set -euo pipefail, quote every expansion, use"${VAR:?message}"where a value is mandatory, add atrapfor cleanup, and runshellcheckin CI.19
How would you find what is consuming disk space on a full Linux server?
SeniorEstablish whether it is bytes or inodes first, because the remedy differs:
df -h; df -iThen descend by size rather than guessing:
sudo du -xh --max-depth=1 / 2>/dev/null | sort -rh | head-xkeeps it on one filesystem, which stops you walking into network mounts and container overlays and wasting minutes.Then check the three usual culprits:
/var/logfor logs that are not rotating,/var/lib/dockeron a container host, and deleted-but-open files, whichducannot see at all:sudo lsof +L1The operational point worth making: on a full production disk, truncating a live log with
: > /var/log/app.logis safer than deleting it, because deleting leaves the space held by the writing process and rotation will not recover it until restart.20
What is the difference between a hard and soft ulimit, and when does it bite?
MidSoft limit Hard limit What it is The value currently enforced The ceiling Who can raise it The process itself, up to the hard limit Only root Read with ulimit -Snulimit -Hnulimit -Sn # soft open file descriptors ulimit -Hn # hardThe one that bites in production is
nofile. Every socket is a file descriptor, so a busy server hits the default 1024 and starts failing with "too many open files" while looking otherwise healthy. It presents as intermittent connection failures under load, not as a clear resource error.Raising it in your shell does nothing for a service started by systemd, which is the trap:
[Service] LimitNOFILE=65535Check what a running process actually has, rather than what you think you set:
cat /proc/<pid>/limits21
What is the difference between
Junior$?,$$and$!in bash?Variable Holds Typically used for $?Exit status of the last foreground command Branching on success or failure $$PID of the current shell Building a unique temporary filename $!PID of the last background command waiting for it, or killing it latergrep -q pattern file echo "exit status: $?" long_task & pid=$! wait "$pid"Worth adding:
$?is overwritten by every command, includingecho, so capture it into a variable immediately if you need it twice.22
How do you read journalctl logs for a service that has already restarted several times?
Midjournalctlkeeps history, which is the advantage over tailing a file that may have been rotated.journalctl -u myapp --since "1 hour ago" --no-pager journalctl -u myapp -p err # priority error and above journalctl -u myapp -b -1 # the previous boot journalctl -u myapp -o json-pretty # structured fields-p erris the one that saves time on a noisy service.-o json-prettyshows the fields you can then filter on directly, which is how you find all messages from one PID across restarts.The gotcha to mention: the journal is only persistent if it is configured to be. With
Storage=volatileor no/var/log/journaldirectory, everything is in memory and disappears on reboot, which is a genuinely unpleasant discovery during an incident.journalctl --disk-usage23
How do you give a Linux user one privileged capability without giving them root?
SeniorIn order of preference.
A targeted sudo rule. Specific commands, no wildcards that allow shell escapes:
deploy ALL=(root) NOPASSWD: /bin/systemctl restart myappBe alert that many commands allow escaping to a shell, so granting
sudo vimorsudo findis effectively granting root.Linux capabilities, when the need is a specific kernel privilege rather than a command. Binding a low port is the standard example:
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/myappThat replaces the old pattern of starting as root and dropping privileges.
Group membership, where a group already governs the resource. With the caveat worth stating in any interview: adding someone to the
dockergroup is equivalent to giving them root, because they can mount the host filesystem into a privileged container.systemd unit properties such as
AmbientCapabilities, so the service gets the privilege without any human having it.24
What is the difference between
Mid/etc/hosts, DNS and nsswitch on Linux?/etc/hostsis a local static file mapping names to addresses. DNS is the distributed lookup system./etc/nsswitch.confis what decides the order in which they are consulted.hosts: files dns myhostnamefilesmeans/etc/hostsis checked first, which is why an entry there overrides DNS entirely and is a common cause of "it resolves differently on that one box".This is why
getent hosts nameis the right diagnostic rather thandig name.digqueries DNS directly and bypasses nsswitch, so it can return the correct record while the application still resolves something else from/etc/hostsor a local caching resolver such as systemd-resolved on127.0.0.53.25
On a Linux server, requests are intermittently slow but CPU, memory and disk all look fine. Where do you look?
SeniorThis is usually a queue or a limit rather than a resource, and the interesting answers go to the network stack and to contention.
Connection and socket limits first. Accept queue overflows and conntrack table exhaustion both produce exactly this symptom:
ss -s netstat -s | grep -i -E "listen|retrans" # overflows and retransmits sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_maxRetransmits point at packet loss somewhere in the path. A non-zero and growing "times the listen queue of a socket overflowed" means the application is not accepting fast enough.
Then contention that does not show as utilisation: file descriptor limits near the ceiling, a database connection pool fully checked out, garbage collection pauses inside the runtime, DNS resolution timing out on a stale resolver, and steal time on a shared host.
cat /proc/pressure/io vmstat 1 10 # cs for context switchesThe framing worth offering: "fine on averages" often means bad at the tail, so look at p99 rather than means, and check whether slowness correlates with a specific instance, upstream or time pattern before tuning anything.
26
How do you grep for a string across a directory tree in Linux, excluding some files?
Juniorgrep -rn --include='*.py' --exclude-dir='.git' "TODO" .-rrecurses,-ngives line numbers,--includeand--exclude-dirnarrow the search, which matters both for speed and for not matching your ownnode_modules.Useful variations:
-ifor case-insensitive,-lto list only filenames,-cto count matches,-wfor whole words to stopcatmatchingconcatenate, and-A3 -B3for context lines around each hit.Worth mentioning
ripgrepif it is available, since it respects.gitignoreby default and is substantially faster on a large tree:rg -t py TODO
Live exercise: the server is slow
The most frequently asked Linux scenario. Each step should eliminate a class of cause, and saying what you expect to see before you run a command is what separates a strong answer.
Is load average above the core count?
uptime; nproc- yes
- Processes are queuing. Compare the 1, 5 and 15 minute figures to see whether it is building or recovering, then find out what they are waiting on.
- no
- It is not a capacity problem. Move straight to the application, its dependencies, and the network rather than tuning the host.
Where is the CPU time going?
top -b -n1 | head -5- yes
- High
%wais IO wait, so checkiostat -xz 1 3for per-device await and utilisation. High%syis kernel work, usually syscall or context-switch churn. - no
- High
%stis steal time, meaning a noisy neighbour on shared hardware. Nothing you tune locally will fix it, and that is the answer.
Is anything being killed for memory?
dmesg -T | grep -i 'killed process'- yes
- The slowness is a service being killed and restarted. Memory is the cause and the rest is a symptom, so stop here.
- no
- Memory is not the cause. Confirm with
free -hthat available memory is genuinely healthy rather than just cached.
Are sockets or file descriptors near a limit?
ss -s; cat /proc/$(pgrep -f myapp | head -1)/limits- yes
- This is a queue or a limit rather than a resource, which is exactly the case where everything looks fine on averages. Check the listen queue overflow counter and the conntrack table too.
- no
- Look at the tail rather than the mean: p99 latency, one bad instance, or a slow dependency. Correlate with deploys and with time of day before changing anything.
What each level is testing
- 1
Junior7 questions
Whether you are comfortable in a shell. Permission bits, links, redirection, finding what holds a port, and why deleting files can fail to free space. Be able to explain the digits in
chmod 755, not just type it. - 2
Mid11 questions
Whether you have run something in production. Signals and the difference between
SIGTERMandSIGKILL, systemd units and the journal, narrowing a network problem layer by layer, and text processing with a pipeline you can explain stage by stage. - 3
Senior8 questions
Whether you can debug a system you did not build. What load average actually counts, how the OOM killer chooses, descriptor and conntrack limits, and the intermittent-slowness case where every obvious resource looks fine. Expect open questions with no single right answer.
What the round is like
Linux rounds for DevOps and SRE roles are less about commands than about whether you can reason about a running system. Expect permissions and filesystem questions early, then processes and signals, then a scenario you have to narrate: a full disk, a slow server, a service that will not start. The commands matter less than saying what each one rules out.
How to prepare with this
- 1Practise narrating the slow-server flow below until it is automatic. It is the most common live Linux exercise and the sequence matters more than the commands.
- 2For every command you would run, be ready to say what result would rule something out. "I would run
iostat" is weak; "if await is high and %util is near 100 the disk is the constraint" is the answer. - 3Learn the two counter-intuitive ones properly: load average counts IO-blocked processes on Linux, and a deleted file still held open keeps its space. Both come up as gotchas.
- 4Know why
getent hostsis a better diagnostic thandig. It uses the same resolution path the application does, and it is a detail that reads as real experience. - 5Be honest when you do not know, then say how you would find out. On senior Linux questions, method is what is being scored.