Focus: Terminal-first, step-by-step command explanations for practical exam prep
Table of Contents
- Linux Basics & File System
- Linux Commands & Navigation
- File Permissions & Ownership
- Users & Groups Management
- SSH (Secure Shell)
- Apache Web Server
- Nginx Web Server
- Port Debugging & Troubleshooting
- Bash Scripting
- Docker Containers
- Lab Exercises Summary
- Quick Reference Cheat Sheet
1. Linux Basics & File System
What is Linux?
Linux is an open-source operating system kernel. A Linux Distribution (distro) is a collection of software built around the Linux kernel, all licensed under open-source or GPL. 90% of all cloud infrastructure is powered by Linux, making it the foundation of DevOps.
Linux Distributions
-
Debian-based: Ubuntu, Debian — use
.debpackages andaptpackage manager -
Red Hat-based: CentOS, Fedora, RHEL — use
.rpmpackages andyum/dnfpackage manager - Technical differences are mainly about package management, software versions, and file locations
- Once you grasp those differences, switching between distros becomes painless
Choosing a Distribution — Key Questions
- What is the main function? (Server or Desktop?)
- What packages are important? (web server, database, etc.)
- How much disk space is available?
- How often are packages updated?
- How long is the support cycle? (LTS = Long Term Support)
- Do you need long-term stability or cutting-edge software?
Package Management (apt — Debian/Ubuntu)
apt update # Update the package index (local DB of available repos)
apt upgrade # Upgrade installed packages to latest versions
apt install <pkg_name> # Install a package
apt remove <pkg_name> # Remove a package
apt search <pkg_name> # Search for a package
apt show <pkg_name> # Show package details
apt list --installed # List all installed packages
🔥 EXAM TIP: Always run
apt updateBEFOREapt install. Update refreshes the package list, upgrade actually updates the software.
Linux File System Hierarchy
Linux organizes everything in a tree structure starting from / (root):
| Directory | Purpose |
|---|---|
/ |
Root — top of the entire filesystem tree |
/home |
User home directories (e.g., /home/daniyal) |
/etc |
System configuration files (ssh config, apache config, etc.) |
/var |
Variable data — logs (/var/log), web files (/var/www) |
/usr |
User programs and utilities (/usr/bin, /usr/lib) |
/bin |
Essential command binaries (ls, cp, mv, cat) |
/sbin |
System binaries (systemctl, fdisk) — need root |
/tmp |
Temporary files — cleared on reboot |
/opt |
Optional/third-party software |
/root |
Home directory of the root user |
/dev |
Device files (hardware represented as files) |
/proc |
Virtual filesystem — running process info |
🔥 EXAM TIP: Know these paths by heart:
/etc/ssh/sshd_config,/var/www/html,/var/log/apache2/,/etc/apache2/sites-available/
OS and Kernel Information
uname -a # Full system info (kernel name, version, architecture)
lsb_release -a # Distribution-specific info
cat /etc/os-release # OS release details
2. Linux Commands & Navigation
Command Structure
A Linux command has three parts: command [options] [arguments]
wc -l devops_course_outline.txt
# ^ ^ ^
# | | +-- argument (what to operate on)
# | +------- option (modifies behavior, starts with - or --)
# +------------ command (program to execute)
The sudo Command
sudo (superuser do) lets you run commands with root (administrator) privileges:
sudo ls -la /root # List root's home directory with elevated privileges
sudo apt install nginx # Install software (needs root)
Directory Navigation
| Command | What It Does | Example |
|---|---|---|
pwd |
Print current working directory |
pwd → /home/daniyal
|
cd |
Change directory | cd /var/www/html |
cd ~ or cd
|
Go to home directory | cd ~ |
cd .. |
Go up one level (parent dir) | cd .. |
cd - |
Go to previous directory | cd - |
ls |
List directory contents | ls /etc |
ls -la |
List ALL files (hidden + details) | ls -la |
tree |
Show directory tree structure | tree /var/www |
mkdir |
Create a directory | mkdir myproject |
mkdir -p |
Create nested directories | mkdir -p a/b/c |
rmdir |
Remove empty directory | rmdir myproject |
rm -r |
Remove directory and contents | rm -r myproject |
Absolute vs Relative Paths
-
Absolute path: Starts from root
/. Example:/usr/bin/python3 -
Relative path: Starts from current directory. Example:
../usr/bin
cd /usr/bin # Absolute path
cd ../usr/bin # Relative path
Viewing Files
| Command | Purpose |
|---|---|
cat file.txt |
Display entire file at once (not ideal for large files) |
cat -n file.txt |
Display with line numbers |
tac file.txt |
Display file in reverse (last line first) |
less file.txt |
Page through large files (scroll up/down, search with /) |
head file.txt |
Show first 10 lines (use -n 20 for first 20) |
tail file.txt |
Show last 10 lines (use -n 20 for last 20) |
tail -f file.txt |
Follow file in real-time (great for logs!) |
wc file.txt |
Count lines, words, characters |
wc -l file.txt |
Count only lines |
Creating & Manipulating Files
touch newfile.txt # Create empty file (or update timestamp)
touch -t 12091600 file.txt # Set specific timestamp (Dec 9, 4PM)
echo "hello" > file.txt # Write to file (OVERWRITES!)
echo "world" >> file.txt # Append to file
cp source.txt dest.txt # Copy file
mv old.txt new.txt # Rename/move file
rm file.txt # Delete file
rm -rf directory/ # Force delete directory and contents
Searching for Files
The find Command
The find command searches the filesystem in real-time. Extremely useful in DevOps for automation, cleanup, backups, and CI/CD scripts.
find /var/log -name "*.log" # Find all .log files in /var/log
find /usr -name gcc # Find files/dirs named gcc
find /usr -type d -name gcc # Find only DIRECTORIES named gcc
find /usr -type f -name gcc # Find only regular FILES named gcc
find / -size +10M # Find files larger than 10MB
find / -size 0 # Find empty files
find / -mtime 3 # Files modified 3 days ago
find / -user root # Files owned by root
find -name "*.jpg" -exec rm {} ';' # Find and DELETE all .jpg files
find / -size +10M -exec command {} ';' # Find large files and run command
Key find Options:
| Option | Purpose |
|---|---|
-name |
Match filename (case-sensitive) |
-iname |
Match filename (case-insensitive) |
-type f |
Regular files only |
-type d |
Directories only |
-size |
File size (+100M = over 100MB, -10k = under 10KB) |
-mtime |
Modified time in days |
-exec |
Execute a command on each result |
-user |
Files owned by specific user |
📝 NOTE: The
{}is a placeholder filled with each file found. The';'or\;terminates the-execcommand.
The locate Command
locate zip # Fast search using pre-built database
# Database is updated by 'updatedb' (runs daily automatically)
which & whereis
which python3 # Shows path of executable: /usr/bin/python3
whereis python3 # Shows binary, source, and man page locations
I/O Redirection & Pipes
echo "hello" > file.txt # Redirect stdout to file (overwrite)
echo "world" >> file.txt # Redirect stdout to file (append)
command < input.txt # Feed file as stdin to command
command 2> errors.txt # Redirect stderr to file
command > out.txt 2>&1 # Redirect BOTH stdout AND stderr to file
cat /etc/passwd | wc -l # Pipe: send output of cat as input to wc
cat /etc/passwd | cut -d: -f1 | sort | uniq # Chain multiple pipes
🔥 EXAM TIP:
>overwrites,>>appends.2>&1redirects errors to same place as stdout. The pipe|chains commands together.
Process Management
kill -SIGKILL <PID> # Force kill a process (same as kill -9)
kill -9 <PID> # Force kill by PID
node server.js & # Run process in background (& suffix)
lsof -i :80 # Find what process is using port 80
📝 NOTE: You can only kill your own processes (unless you are root).
Getting Help
man apache2 # Full manual page for a command
man -k compress # Search man pages by keyword
info make # GNU Info documentation (alternative to man)
command --help # Quick help/usage summary (fastest option)
3. File Permissions & Ownership
Three Types of Owners
- User (u): The owner of the file. When you create a file, you become the owner.
- Group (g): A collection of users. Useful in multi-user environments.
- Other (o): Everyone else on the system.
Three Types of Permissions
| Permission | Symbol | Number | On Files | On Directories |
|---|---|---|---|---|
| Read | r |
4 | View/copy file contents | List directory contents (ls) |
| Write | w |
2 | Modify file contents | Create/delete files inside |
| Execute | x |
1 | Run the file as program | Enter the directory (cd) |
Octal Permission Table (MEMORIZE THIS!)
| Number | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| Permission | --- |
--x |
-w- |
-wx |
r-- |
r-x |
rw- |
rwx |
| Meaning | None | Exec only | Write only | Write+Exec | Read only | Read+Exec | Read+Write | ALL |
Reading Permission Strings
-rw-r--r-- 1 sajid devops_students 13 2022-05-11 08:29 lecture.txt
^^^^^^^^^ ^ ^
| | +-- group owner
| +-------- file owner (user)
+-------------------- permission string
First char: - = file, d = directory, l = symlink
Next 9 chars: rwx for user | rwx for group | rwx for others
Example: -rw-r--r-- means:
User: rw- (read + write) = 4+2+0 = 6
Group: r-- (read only) = 4+0+0 = 4
Other: r-- (read only) = 4+0+0 = 4
Octal: 644
chmod — Change Permissions
chmod 644 file.txt # rw-r--r-- (standard file permission)
chmod 755 directory/ # rwxr-xr-x (standard directory permission)
chmod 700 secret.txt # rwx------ (owner only, full access)
chmod 666 file.txt # rw-rw-rw- (everyone can read/write)
chmod +x script.sh # Add execute permission for everyone
chmod u+x script.sh # Add execute for user only
chmod g-w file.txt # Remove write from group
chmod o-rwx file.txt # Remove all permissions from others
chown — Change Ownership
sudo chown root:root file.txt # Change owner AND group to root
sudo chown daniyal file.txt # Change owner only
sudo chown daniyal:www-data file.txt # Change owner to daniyal, group to www-data
sudo chown -R www-data:www-data /var/www/html/ # Recursive (all files inside)
⭐ DevOps Golden Rules for Permissions
| Rule | Permission | Why |
|---|---|---|
| Directories |
755 (rwxr-xr-x) |
Owner full access, others can read/enter |
| Regular files |
644 (rw-r--r--) |
Owner read/write, others read only |
| Scripts (.sh) |
755 (rwxr-xr-x) |
Must be executable |
| SSH private key |
600 (rw-------) |
ONLY owner can read (SSH refuses otherwise) |
| ~/.ssh/ directory |
700 (rwx------) |
ONLY owner can access |
| authorized_keys |
600 (rw-------) |
ONLY owner can read/write |
| Web files owner | www-data:www-data |
Web server user must be able to read |
| NEVER use | 777 |
SECURITY RISK — everyone has full access! |
🔥 EXAM TIP: If a web page shows '403 Forbidden', first check permissions and ownership! Owner should be
www-data, dirs755, files644.
4. Users & Groups Management
User Management Commands
cat /etc/passwd # List ALL users on the system
sudo adduser newuser # Create new user (interactive - sets password)
sudo useradd newuser # Create user (non-interactive - no password set)
sudo usermod -aG sudo newuser # Add user to sudo group (give admin rights)
sudo userdel newuser # Delete a user
sudo userdel -r newuser # Delete user AND their home directory
su - newuser # Switch to another user
whoami # Show current username
id # Show user ID, group ID, and groups
Group Management Commands
cat /etc/group # List all groups
sudo groupadd devopsgroup # Create a new group
sudo usermod -aG devopsgroup user1 # Add user1 to devopsgroup
sudo groupdel devopsgroup # Delete a group
groups username # Show which groups a user belongs to
📝 NOTE: The
-aGflag is critical! Without-a, the user gets REMOVED from all other groups. Always use-aGtogether.
Important Files
-
/etc/passwd— Contains user account info (username:x:UID:GID:info:home:shell) -
/etc/shadow— Contains encrypted passwords (only root can read) -
/etc/group— Contains group definitions
5. SSH (Secure Shell)
What is SSH?
SSH (Secure Shell) allows you to connect and log into remote systems securely. It encrypts ALL communication between client and server. SSH runs on port 22 by default. The server must have sshd (SSH daemon) installed and running.
Basic SSH Connection
ssh username@remote_server_ip # Connect to remote machine
ssh daniyal@192.168.1.100 # Example with IP
whoami # Verify you are logged in
hostname # Verify which machine you are on
exit # Disconnect from remote
SSH Service Control
sudo systemctl status ssh # Check if SSH is running
sudo systemctl start ssh # Start SSH service
sudo systemctl stop ssh # Stop SSH service
sudo systemctl restart ssh # Restart (apply config changes)
sudo systemctl enable ssh # Start automatically on boot
sudo systemctl disable ssh # Don't start on boot
🔥 EXAM TIP:
systemctl enablemakes service start on boot.systemctl startstarts it NOW. They are different! You often need BOTH.
SSH Configuration File
The main SSH server config file is: /etc/ssh/sshd_config
sudo nano /etc/ssh/sshd_config # Edit SSH server configuration
# Key settings to know:
Port 22 # Default SSH port
PermitRootLogin yes/no # Allow/block root login via SSH
PasswordAuthentication yes/no # Allow/block password-based login
PubkeyAuthentication yes # Allow key-based authentication
# IMPORTANT: After ANY change, restart SSH!
sudo systemctl restart ssh
SSH Key-Based Authentication
Key-based auth is more secure than passwords. It uses a pair of keys:
-
Private key (
~/.ssh/id_rsa): Stays on YOUR machine. NEVER share this! -
Public key (
~/.ssh/id_rsa.pub): Goes to the REMOTE server.
Step-by-step setup:
# STEP 1: Generate key pair on YOUR machine (client)
ssh-keygen -t rsa
# Press Enter for default location (~/.ssh/id_rsa)
# Press Enter for no passphrase (or set one for extra security)
# Creates: ~/.ssh/id_rsa (private) and ~/.ssh/id_rsa.pub (public)
# STEP 2: Copy public key to the REMOTE server
ssh-copy-id username@remote_server
# OR manually:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys # On the remote server
# STEP 3: Set correct permissions (CRITICAL!)
chmod 700 ~/.ssh # Directory: owner only
chmod 600 ~/.ssh/id_rsa # Private key: owner only
chmod 600 ~/.ssh/authorized_keys # Auth keys: owner only
# STEP 4: Now you can login without password!
ssh username@remote_server
📝 NOTE: The remote server stores public keys in
~/.ssh/authorized_keys(one key per line). If permissions on this file are wrong, SSH will REFUSE the key and fall back to password auth.
SSH Config File (Client Side)
Create ~/.ssh/config to avoid typing username and IP every time:
# File: ~/.ssh/config
Host myserver
HostName 192.168.1.100
User daniyal
IdentityFile ~/.ssh/id_rsa
# Now you can just type:
ssh myserver
# Instead of: ssh daniyal@192.168.1.100
Non-Interactive SSH Commands
Run commands on a remote server without opening a full session:
ssh user@server "whoami" # Run whoami on remote
ssh user@server "mkdir ~/test_dir" # Create dir on remote
ssh user@server "cat /etc/hostname" # Read remote file
ssh user@server "systemctl restart apache2" # Restart service remotely
🔥 EXAM TIP: Non-interactive SSH is key for scripting — you can loop over servers:
for server in list; do ssh server "command"; done
Disabling Root Login & Password Auth
# Edit /etc/ssh/sshd_config:
PermitRootLogin no # Block root from logging in via SSH
PasswordAuthentication no # Force key-based auth only
# Restart to apply:
sudo systemctl restart ssh
# Test: trying ssh root@server should now be DENIED
6. Apache Web Server
Installation & Service Management
sudo apt update
sudo apt install apache2 # Install Apache
sudo systemctl start apache2 # Start the service
sudo systemctl stop apache2 # Stop the service
sudo systemctl restart apache2 # Restart (apply changes)
sudo systemctl reload apache2 # Reload config without downtime
sudo systemctl status apache2 # Check if running
sudo systemctl enable apache2 # Start on boot
curl localhost # Test: should show Apache default page
Apache runs on Port 80 (HTTP) or Port 443 (HTTPS)
Apache Default Paths
| Path | Purpose |
|---|---|
/var/www/html/ |
Default web root (put your website files here) |
/etc/apache2/ |
Main configuration directory |
/etc/apache2/sites-available/ |
Virtual host config files (available) |
/etc/apache2/sites-enabled/ |
Symlinks to active virtual hosts |
/etc/apache2/apache2.conf |
Main Apache configuration file |
/etc/apache2/ports.conf |
Which ports Apache listens on |
/var/log/apache2/error.log |
Error log file |
/var/log/apache2/access.log |
Access log file |
Deploying a Static Website
# Step 1: Clone or copy your website files
sudo git clone https://github.com/user/repo.git /var/www/html/mysite
# Step 2: Set correct ownership
sudo chown -R www-data:www-data /var/www/html/mysite
# Step 3: Set correct permissions
sudo chmod -R 755 /var/www/html/mysite/ # Directories
sudo find /var/www/html/mysite -type f -exec chmod 644 {} \; # Files
# Step 4: Verify
curl localhost
Virtual Hosts (Multiple Websites)
Virtual hosts let you run MULTIPLE websites on one server, each on a different port or domain.
# Step 1: Create config file in sites-available
sudo nano /etc/apache2/sites-available/mysite.conf
Content of mysite.conf:
<VirtualHost *:8080>
ServerName mysite.local
DocumentRoot /var/www/mysite
ErrorLog /var/log/apache2/mysite-error.log
CustomLog /var/log/apache2/mysite-access.log combined
</VirtualHost>
# Step 2: Add Listen directive for new port
# Edit /etc/apache2/ports.conf and add: Listen 8080
# Step 3: Enable the site
sudo a2ensite mysite.conf
# Step 4: Test config and reload
sudo apache2ctl configtest # Check for syntax errors
sudo systemctl reload apache2
# Step 5: Verify
curl localhost:8080
🔥 EXAM TIP:
sites-available= config files stored here.sites-enabled= symlinks to active configs. Usea2ensite/a2dissiteto enable/disable.
7. Nginx Web Server
Installation & Service Management
sudo apt update
sudo apt install nginx
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl status nginx
sudo systemctl enable nginx
curl localhost # Test
Nginx Key Paths
- Default web root:
/var/www/html/(same as Apache) - Config files:
/etc/nginx/sites-available/and/etc/nginx/sites-enabled/ - Main config:
/etc/nginx/nginx.conf - Default site config:
/etc/nginx/sites-available/default
Nginx Virtual Host (Server Block)
# File: /etc/nginx/sites-available/mysite
server {
listen 80;
server_name mysite.local;
root /var/www/mysite;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
# Enable the site by creating a symlink:
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
# Test config:
sudo nginx -t
# Reload:
sudo systemctl reload nginx
📝 NOTE: Both Apache and Nginx use port 80 by default. They CANNOT run on the same port at the same time!
8. Port Debugging & Troubleshooting
Common Scenario: Port Conflict
If Apache fails to start with "Address already in use" error, another process (like Nginx) is already using port 80.
Debugging Commands
# Check what's using a specific port
sudo lsof -i :80 # Show process using port 80
# Production-friendly command (all open network connections)
sudo lsof -i -P -n
# -i = open network connections
# -P = show port numbers (not service names)
# -n = don't resolve hostnames
# Check service logs for errors
sudo journalctl -xe # Show recent system logs with details
sudo journalctl -u apache2 # Show only Apache logs
# Monitor log files in real-time
sudo tail -f /var/log/apache2/error.log
sudo tail -f /var/log/nginx/error.log
Fixing Port Conflicts Step by Step
# Step 1: Check which service is using port 80
sudo lsof -i :80
# Output shows: nginx (PID 1234)
# Step 2: Stop the conflicting service
sudo systemctl stop nginx
# Step 3: Start the service you want
sudo systemctl start apache2
# Step 4: Verify
sudo systemctl status apache2
curl localhost
Common Web Server Errors & Fixes
| Error | Likely Cause | Fix |
|---|---|---|
| 403 Forbidden | Wrong permissions/ownership |
chown www-data:www-data, chmod 755/644
|
| 404 Not Found | Wrong DocumentRoot path | Check config file, verify path exists |
| Address in use | Port conflict |
lsof -i :80, stop conflicting service |
| Service won't start | Config syntax error |
apache2ctl configtest or nginx -t
|
| Connection refused | Service not running | systemctl start apache2/nginx |
9. Bash Scripting
Script Basics
#!/bin/bash
# The first line is the SHEBANG — tells the system to use bash
# Every script MUST start with #!/bin/bash
# Make script executable:
chmod +x script.sh
# Run script:
./script.sh
# OR
bash script.sh
Variables
#!/bin/bash
NAME="Daniyal" # Assign (NO spaces around =)
echo "Hello $NAME" # Use variable with $
echo "Hello ${NAME}" # Curly braces version (safer)
# Read user input
echo "Enter your name:"
read USERNAME # Stores input in USERNAME
echo "Welcome $USERNAME"
# Command substitution — store command output in variable
TODAY=$(date) # Run date command, store result
echo "Today is: $TODAY"
HOSTNAME=$(hostname)
echo "Machine: $HOSTNAME"
🔥 EXAM TIP: NO SPACES around
=when assigning variables!NAME='value'is correct.NAME = 'value'is WRONG and will cause an error.
Command Line Arguments
| Variable | Meaning |
|---|---|
$0 |
Script name itself |
$1, $2, $3... |
First, second, third argument... |
$# |
Total number of arguments passed |
$@ |
All arguments as separate words |
$? |
Exit code of the LAST command (0=success, non-0=failure) |
#!/bin/bash
# Example: ./myscript.sh hello world
echo "Script name: $0" # ./myscript.sh
echo "First arg: $1" # hello
echo "Second arg: $2" # world
echo "Total args: $#" # 2
echo "All args: $@" # hello world
Exit Codes
#!/bin/bash
# Every command returns an exit code
# 0 = SUCCESS, anything else = FAILURE
ls /tmp
echo $? # 0 (success — /tmp exists)
ls /nonexistent
echo $? # 2 (failure — directory doesn't exist)
# Set your own exit code
exit 0 # Exit script with success
exit 1 # Exit script with failure
Conditionals (if/else)
#!/bin/bash
# Basic if/else
if [ -d "/var/www/html" ]; then
echo "Directory exists"
else
echo "Directory does NOT exist"
fi
# Check if file exists
if [ -f "/etc/ssh/sshd_config" ]; then
echo "SSH config found"
fi
# Compare strings
if [ "$1" == "install" ]; then
echo "Installing..."
elif [ "$1" == "remove" ]; then
echo "Removing..."
else
echo "Usage: $0 install|remove"
exit 1
fi
# Check if command succeeded
apt install nginx -y
if [ $? -eq 0 ]; then
echo "Installation successful"
else
echo "Installation FAILED"
exit 1
fi
Common test operators:
| Operator | Meaning |
|---|---|
-f file |
File exists and is a regular file |
-d dir |
Directory exists |
-e path |
Path exists (file or directory) |
-z string |
String is empty (zero length) |
-n string |
String is NOT empty |
str1 == str2 |
Strings are equal |
str1 != str2 |
Strings are NOT equal |
num1 -eq num2 |
Numbers are equal |
num1 -ne num2 |
Numbers are NOT equal |
num1 -gt num2 |
Greater than |
num1 -lt num2 |
Less than |
Case Statement (for Flags)
#!/bin/bash
# Great for handling command-line flags like -i, -r, -h
case "$1" in
-i|--install)
echo "Installing..."
;;
-r|--remove)
echo "Removing..."
;;
-h|--help)
echo "Usage: $0 [-i install] [-r remove] [-h help]"
;;
*)
echo "Invalid option: $1"
echo "Use -h for help"
exit 1
;;
esac
For Loops
#!/bin/bash
# Loop through a list
for server in server1 server2 server3; do
echo "Restarting $server..."
ssh $server "systemctl restart apache2"
done
# Loop through files
for file in *.sh; do
echo "Found script: $file"
done
# Loop with numbers
for i in 1 2 3 4 5; do
echo "Number: $i"
done
# C-style loop
for ((i=1; i<=5; i++)); do
echo "Count: $i"
done
The tar Command (Archives/Backups)
# Create a compressed archive
tar -czf backup.tar.gz /path/to/directory
# -c = create
# -z = compress with gzip
# -f = filename follows
# Create with timestamp in name
tar -czf backup_$(date +%Y%m%d_%H%M%S).tar.gz /var/www/html/
# Extract an archive
tar -xzf backup.tar.gz
# -x = extract
# List contents without extracting
tar -tzf backup.tar.gz
The awk Command
# awk processes text line by line, splitting into fields
# Default field separator is whitespace
# Print second column of output
df -h | awk '{print $2}'
# Print specific fields with custom format
free -m | awk '/Mem:/ {print "Total: "$2" MB, Used: "$3" MB"}'
# Use custom field separator
cat /etc/passwd | awk -F: '{print $1}' # Print usernames (field 1, : separator)
# Filter lines matching a pattern
df -h | awk '!/tmpfs/ {print $0}' # Exclude lines containing tmpfs
Heredoc (Writing Multi-line Content)
#!/bin/bash
# Heredoc writes multi-line content to a file
cat << EOF > /var/www/html/index.html
<!DOCTYPE html>
<html>
<head><title>System Report</title></head>
<body>
<h1>Server: $(hostname)</h1>
<p>Date: $(date)</p>
</body>
</html>
EOF
# Variables inside heredoc get expanded!
# Use << 'EOF' (with quotes) to PREVENT variable expansion
Redirection in Scripts
#!/bin/bash
# Redirect command output to log file
apt install nginx -y > nginx.log 2>&1
# > nginx.log = redirect stdout to file
# 2>&1 = redirect stderr (2) to same place as stdout (1)
# Combined: ALL output (normal + errors) goes to nginx.log
# Append to log
echo "$(date) - Installation complete" >> nginx.log
Lab Script Examples
Script 1: backup.sh — Automated Directory Backup
#!/bin/bash
echo "Enter directory path to backup:"
read DIR_PATH
if [ ! -d "$DIR_PATH" ]; then
echo "ERROR: Directory $DIR_PATH does not exist!"
exit 1
fi
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="backup_${TIMESTAMP}.tar.gz"
tar -czf "$BACKUP_FILE" "$DIR_PATH"
if [ $? -eq 0 ]; then
echo "SUCCESS: Backup created: $BACKUP_FILE"
echo "$(date) - SUCCESS - $BACKUP_FILE" >> backup.log
else
echo "FAILED: Backup failed!"
echo "$(date) - FAILED" >> backup.log
exit 1
fi
Script 2: Virtual Host Automator
#!/bin/bash
echo "Enter domain/directory name:"
read DOMAIN
sudo mkdir -p /var/www/$DOMAIN
sudo cat << EOF > /var/www/$DOMAIN/index.html
<html><body><h1>Welcome to $DOMAIN</h1></body></html>
EOF
sudo cat << EOF > /etc/apache2/sites-available/$DOMAIN.conf
<VirtualHost *:80>
ServerName $DOMAIN
DocumentRoot /var/www/$DOMAIN
ErrorLog /var/log/apache2/${DOMAIN}-error.log
CustomLog /var/log/apache2/${DOMAIN}-access.log combined
</VirtualHost>
EOF
sudo chown -R www-data:www-data /var/www/$DOMAIN
sudo chmod -R 755 /var/www/$DOMAIN
sudo a2ensite $DOMAIN.conf
sudo systemctl reload apache2
echo "Website $DOMAIN deployed successfully!"
Script 3: wserver.sh — Nginx Install/Remove with Flags
#!/bin/bash
case "$1" in
-i)
if dpkg -l | grep -q nginx; then
echo "Nginx is already installed."
exit 0
fi
sudo apt install nginx -y > nginx.log 2>&1
if [ $? -eq 0 ]; then
echo "Nginx installed successfully."
else
echo "ERROR: Installation failed. Check nginx.log"
exit 1
fi
;;
-r)
if ! dpkg -l | grep -q nginx; then
echo "Nginx is not installed."
exit 0
fi
sudo apt remove nginx -y > nginx.log 2>&1
if [ $? -eq 0 ]; then
echo "Nginx removed successfully."
else
echo "ERROR: Removal failed. Check nginx.log"
exit 1
fi
;;
*)
echo "Usage: $0 [-i install] [-r remove]"
exit 1
;;
esac
Script 4: system_health.sh — HTML Report
#!/bin/bash
TOTAL_MEM=$(free -m | awk '/Mem:/ {print $2}')
USED_MEM=$(free -m | awk '/Mem:/ {print $3}')
AVAIL_MEM=$(free -m | awk '/Mem:/ {print $7}')
TOTAL_SWAP=$(free -m | awk '/Swap:/ {print $2}')
USED_SWAP=$(free -m | awk '/Swap:/ {print $3}')
DISK_TOTAL=$(df -h --total --exclude-type=tmpfs | awk '/total/ {print $2}')
DISK_USED=$(df -h --total --exclude-type=tmpfs | awk '/total/ {print $3}')
DISK_AVAIL=$(df -h --total --exclude-type=tmpfs | awk '/total/ {print $4}')
cat << EOF > system_health.html
<!DOCTYPE html>
<html>
<head><title>System Health Report</title></head>
<body>
<h1>System Health Report</h1>
<p>Date: $(date)</p>
<h2>Memory Usage</h2>
<p>Total: ${TOTAL_MEM}MB | Used: ${USED_MEM}MB | Available: ${AVAIL_MEM}MB</p>
<h2>Disk Usage</h2>
<p>Total: $DISK_TOTAL | Used: $DISK_USED | Available: $DISK_AVAIL</p>
</body>
</html>
EOF
sudo cp system_health.html /var/www/html/index.html
if [ $? -eq 0 ]; then
echo "SUCCESS: Report hosted at http://localhost"
else
echo "ERROR: Failed to deploy report"
exit 1
fi
Script 5: systeminfo.sh
#!/bin/bash
echo "Kernel Name: $(uname -s)"
echo "Kernel Release: $(uname -r)"
echo "Processor: $(uname -p)"
echo "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)"
EDITOR="nano"
echo "Favorite Editor: $EDITOR"
echo "Editor Location: $(which $EDITOR)"
echo "Documentation: $(whereis $EDITOR)"
10. Docker Containers
What is Docker?
Docker is a platform that lets you package, ship, and run applications in isolated environments called containers. A container is like a lightweight virtual machine that shares the host OS kernel. Think of it as: your app + all its dependencies, packaged together so it runs the same everywhere.
Key Concepts
- Image: A blueprint/template for a container (like a class in OOP). Downloaded from Docker Hub.
- Container: A running instance of an image (like an object). You can run multiple from one image.
- Docker Hub: Online registry of Docker images (like GitHub for images).
-
Tag: Version of an image. Example:
ubuntu:22.04vsubuntu:latest
Verify Docker Installation
docker --version # Check Docker version
docker version # Detailed client + server version
docker run hello-world # Test Docker works
Docker Container Lifecycle
# PULL an image from Docker Hub
docker pull ubuntu # Download ubuntu image (latest)
docker pull ubuntu:22.04 # Download specific version
docker pull nginx # Download nginx image
# RUN a container from an image
docker run ubuntu # Runs and exits immediately (no process)
docker run ubuntu sleep 5 # Runs, sleeps 5 seconds, then exits
# RUN in interactive mode (get a shell inside container)
docker run -it ubuntu bash # -i=interactive, -t=terminal
# You are now INSIDE the container!
echo "Hello Docker"
ls
exit # Exit container (container stops)
# RUN with a custom name
docker run --name myubuntu ubuntu sleep 30
# RUN in detached mode (background)
docker run -d ubuntu sleep 300 # -d = detached (runs in background)
docker run -dit --name test ubuntu bash # Detached + interactive
Managing Containers
# LIST containers
docker ps # Show RUNNING containers only
docker ps -a # Show ALL containers (running + stopped)
# STOP a container
docker stop <container_id> # Graceful stop
docker stop myubuntu # Stop by name
# REMOVE a container
docker rm <container_id> # Remove stopped container
docker rm myubuntu # Remove by name
# STOP ALL containers at once
docker stop $(docker ps -q) # -q = quiet (only IDs)
# REMOVE ALL containers
docker rm $(docker ps -aq) # Remove all (running + stopped)
🔥 EXAM TIP:
docker run ubuntuexits immediately because there is no long-running process. Usesleep,-it bash, or-dto keep it alive.
Managing Images
# LIST downloaded images
docker images
# REMOVE an image
docker rmi ubuntu # Remove ubuntu image
docker rmi <image_id> # Remove by ID
# Note: Must remove all containers using that image first!
Attach vs Exec (IMPORTANT DIFFERENCE!)
# ATTACH to a running container (connects to main process)
docker attach test
# CTRL+P then CTRL+Q = detach WITHOUT stopping container
# If you type 'exit', container STOPS
# EXEC runs a NEW process inside a running container
docker exec -it test bash
# If you type 'exit', only the exec process ends
# The container keeps running!
📝 NOTE: Use
execwhen you want to inspect a running container without affecting it. Useattachto reconnect to the main process.
Container Logs & Inspect
docker logs <container_id> # View container logs
docker logs myubuntu
docker inspect test # Full container details (JSON)
docker inspect --format='{{.State.Status}}' test # Get specific info
Port Mapping (-p)
Port mapping connects a port on your HOST machine to a port inside the container.
# Map host port 8081 to container port 80
docker run -d -p 8081:80 nginx
# ^ ^
# | +-- container port (nginx listens on 80)
# +-------- host port (access via localhost:8081)
# Run multiple web servers on different ports
docker run -d --name web1 -p 8081:80 ubuntu/apache2
docker run -d --name web2 -p 8082:80 ubuntu/apache2
# Access in browser:
# http://localhost:8081 --> web1
# http://localhost:8082 --> web2
🔥 EXAM TIP: Format is
-p HOST_PORT:CONTAINER_PORT. The HOST port is what you type in the browser. The CONTAINER port is what the app listens on inside.
Volume Mounts (-v) / Bind Mounts
Volumes let you share files between your host machine and the container.
# Mount current directory into container
docker run -it -v $(pwd):/scripts ubuntu bash
# $(pwd) = your current directory on host
# /scripts = path inside the container
# Mount a specific file into nginx
echo '<h1>Hello Docker!</h1>' > index.html
docker run -d -p 8081:80 -v $(pwd)/index.html:/usr/share/nginx/html/index.html nginx
# You have just hosted a simple web app!
# Mount a Python script
echo 'print("Hello, world!")' > hello.py
docker run -it --rm -v $(pwd)/hello.py:/hello.py python:3.10-slim bash
# Then inside: python hello.py
📝 NOTE: The
--rmflag automatically removes the container when it exits. Great for temporary containers.
Complete Docker Command Reference
| Command | Purpose |
|---|---|
docker version |
Check Docker client and server version |
docker run <image> |
Start a container from an image |
docker run --name <n> <img> |
Run with a custom name |
docker run <img>:<tag> |
Run a specific version |
docker run -it <img> bash |
Run interactively with terminal |
docker run -d <img> |
Run in detached (background) mode |
docker run -p H:C <img> |
Map host port H to container port C |
docker run -v H:C <img> |
Mount host path H to container path C |
docker run --rm <img> |
Auto-remove container on exit |
docker ps |
List running containers |
docker ps -a |
List ALL containers |
docker stop <id/name> |
Stop a running container |
docker rm <id/name> |
Remove a stopped container |
docker images |
List downloaded images |
docker rmi <image> |
Remove an image |
docker pull <image> |
Download image from Docker Hub |
docker exec -it <id> bash |
Open shell in running container |
docker attach <id> |
Attach to main process of container |
docker logs <id> |
View container output logs |
docker inspect <id> |
Detailed container info (JSON) |
docker stop $(docker ps -q) |
Stop ALL running containers |
docker rm $(docker ps -aq) |
Remove ALL containers |
— list, create, add to sudo, switch user, create group
12. Quick Reference Cheat Sheet
systemctl Commands
systemctl start <service> # Start a service NOW
systemctl stop <service> # Stop a service NOW
systemctl restart <service> # Restart a service
systemctl reload <service> # Reload config without stopping
systemctl status <service> # Check if service is running
systemctl enable <service> # Start on boot
systemctl disable <service> # Don't start on boot
Key File Paths
| Path | What |
|---|---|
/etc/ssh/sshd_config |
SSH server configuration |
~/.ssh/id_rsa |
Your SSH private key |
~/.ssh/id_rsa.pub |
Your SSH public key |
~/.ssh/authorized_keys |
Public keys allowed to login |
~/.ssh/config |
Client SSH shortcuts |
/var/www/html/ |
Default web root (Apache + Nginx) |
/etc/apache2/sites-available/ |
Apache virtual host configs |
/etc/apache2/sites-enabled/ |
Active Apache sites (symlinks) |
/etc/nginx/sites-available/ |
Nginx server block configs |
/etc/nginx/sites-enabled/ |
Active Nginx sites (symlinks) |
/var/log/apache2/error.log |
Apache error log |
/var/log/nginx/error.log |
Nginx error log |
/etc/passwd |
User account information |
/etc/group |
Group definitions |
/etc/shadow |
Encrypted passwords (root only) |
Permission Quick Reference
644 = rw-r--r-- # Standard file permission
755 = rwxr-xr-x # Standard directory / script permission
700 = rwx------ # Private (owner only)
600 = rw------- # SSH keys
777 = rwxrwxrwx # NEVER USE (security risk)
Docker Quick Reference
docker run -it ubuntu bash # Interactive shell
docker run -d -p 8080:80 nginx # Background + port map
docker run -v $(pwd):/app ubuntu # Volume mount
docker ps -a # List all containers
docker stop $(docker ps -q) # Stop all running
docker rm $(docker ps -aq) # Remove all containers
docker exec -it <id> bash # Shell into running container
CTRL+P then CTRL+Q # Detach without stopping
Bash Scripting Quick Reference
#!/bin/bash # Shebang (always first line)
$1 $2 $# $@ $? # Args, count, all, exit code
read VAR # Read user input
if [ condition ]; then ... fi # Conditional
case "$1" in pattern) ... ;; esac # Flag handling
for item in list; do ... done # Loop
tar -czf name.tar.gz dir/ # Create archive
awk '{print $1}' file # Text processing
cat << EOF > file ... EOF # Heredoc
command > file 2>&1 # Redirect all output
Good luck on your exam! Practice these commands in the terminal — reading is not enough, you need muscle memory! 🚀
Top comments (0)