Linux

🐧 Linux System Administration

Linux is the backbone of virtually every server, container, and cloud environment. This reference covers essential commands and patterns for day-to-day system administration on Ubuntu/Debian and RHEL/Rocky distributions.

Filesystem & Permissions

Linux permissions are expressed as three groups (owner, group, others) each with read (r=4), write (w=2), and execute (x=1) bits.

bash
# Permissions
chmod 755 /var/www/html          # rwxr-xr-x (owner: rwx, group: rx, other: rx)
chmod 600 ~/.ssh/id_rsa          # rw------- (private key β€” owner read/write only)
chmod -R 644 /var/www/html/*.html  # Recursive set for files
chown -R www-data:www-data /var/www/html  # Change owner and group
chown deploy:deploy /opt/app

# File listing with details
ls -lah /etc/nginx/              # Long format, human sizes, hidden files
ls -lt /var/log/ | head -20      # Sort by modification time

# Finding files
find /var/log -name "*.log" -mtime +30 -delete   # Delete logs older than 30 days
find /opt/app -type f -name "*.conf" -exec grep -l "debug" {} \;
locate nginx.conf                # Fast file lookup (requires updatedb)

# Disk usage
df -hT                           # Disk space by filesystem type
du -sh /var/log/*                # Size of each log directory
ncdu /                           # Interactive disk usage explorer

Process Management

bash
# View processes
ps aux                           # All processes (full detail)
ps aux | grep nginx              # Filter by name
pgrep -a nginx                   # Process IDs matching name
htop                             # Interactive process manager (preferred)

# Signals
kill -15 1234                    # SIGTERM β€” graceful shutdown
kill -9 1234                     # SIGKILL β€” immediate kill (last resort)
killall nginx                    # Kill all processes named nginx
pkill -f "python worker.py"      # Kill by pattern match

# Background jobs
nohup ./long-script.sh > /var/log/script.log 2>&1 &  # Run detached
jobs -l                          # List background jobs
disown %1                        # Detach job from terminal

# Priority
nice -n 10 ./batch-job.sh        # Start with lower CPU priority
renice +5 -p 1234               # Change priority of running process

Networking

bash
# Network interfaces & IP
ip addr show                     # Show all interfaces
ip route show                    # Show routing table
ip link set eth0 up              # Enable interface

# Connectivity
ping -c 4 8.8.8.8                # Test ICMP reachability
traceroute api.maxiscomputers.com  # Trace network path
mtr --report api.maxiscomputers.com  # Combined ping + traceroute

# DNS
dig api.maxiscomputers.com       # DNS resolution (full detail)
dig +short api.maxiscomputers.com  # Just the IPs
nslookup api.maxiscomputers.com  # Legacy DNS tool
resolvectl status                # systemd-resolved status

# Ports & Connections
ss -tulpn                        # All listening sockets with PID
ss -tnp state established        # Active TCP connections
netstat -tulpn                   # Legacy equivalent

# Firewall (UFW β€” Ubuntu)
ufw status verbose
ufw allow 443/tcp
ufw allow from 10.0.0.0/8 to any port 22
ufw deny 23/tcp

# Firewall (firewalld β€” RHEL/Rocky)
firewall-cmd --list-all
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

# Traffic capture
tcpdump -i eth0 port 80 -w /tmp/capture.pcap
tcpdump -r /tmp/capture.pcap -nn "tcp"

systemd Services

bash
# Service management
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
systemctl reload nginx           # Reload config without downtime
systemctl status nginx           # View status + recent logs
systemctl enable nginx           # Auto-start on boot
systemctl disable nginx
systemctl is-active nginx

# Logs (journald)
journalctl -u nginx -f           # Follow service logs
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx -p err       # Errors only
journalctl --disk-usage
journalctl --vacuum-size=500M    # Trim journal to 500MB
ini
# /etc/systemd/system/api-server.service
[Unit]
Description=Maxi's Computers API Server
After=network-online.target postgresql.service
Wants=network-online.target
Requires=postgresql.service

[Service]
Type=simple
User=deploy
Group=deploy
WorkingDirectory=/opt/api-server
ExecStart=/usr/bin/node /opt/api-server/dist/index.js
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=api-server
LimitNOFILE=65536
NoNewPrivileges=yes
ProtectSystem=strict
PrivateTmp=true

[Install]
WantedBy=multi-user.target

SSH Hardening

⚠️

Disable password auth Only allow SSH key-based authentication on production servers. Password authentication is vulnerable to brute-force attacks.

bash
# Generate a secure Ed25519 key pair
ssh-keygen -t ed25519 -C "deploy@maxiscomputers.com" -f ~/.ssh/mc_ed25519

# Copy public key to server
ssh-copy-id -i ~/.ssh/mc_ed25519.pub deploy@server-ip

# SSH config (~/.ssh/config)
Host mc-prod
  HostName 203.0.113.45
  User deploy
  IdentityFile ~/.ssh/mc_ed25519
  ServerAliveInterval 60
  ServerAliveCountMax 3

# /etc/ssh/sshd_config hardening
Port 2222                        # Non-standard port
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
AllowUsers deploy jenkins
LoginGraceTime 30

Shell Scripting Patterns

bash
#!/usr/bin/env bash
# Deployment script template
set -euo pipefail  # Exit on error, unset variables, pipe failures
IFS=$'\n\t'        # Safe Internal Field Separator

readonly APP_DIR="/opt/api-server"
readonly BACKUP_DIR="/opt/backups/api-$(date +%Y%m%d-%H%M%S)"
readonly LOG_FILE="/var/log/deploy.log"

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }
error() { log "ERROR: $*" >&2; exit 1; }

check_dependencies() {
  local deps=(node npm systemctl curl)
  for dep in "${deps[@]}"; do
    command -v "$dep" &>/dev/null || error "Required: $dep not found"
  done
}

deploy() {
  log "Starting deployment of version ${VERSION:?VERSION required}"
  check_dependencies

  # Backup current version
  cp -r "$APP_DIR" "$BACKUP_DIR"
  log "Backup created: $BACKUP_DIR"

  # Download and install
  curl -fsSL "https://releases.maxiscomputers.com/api/${VERSION}.tar.gz" \
    | tar -xz -C "$APP_DIR" --strip-components=1

  # Restart service with validation
  systemctl restart api-server
  sleep 5
  if ! systemctl is-active --quiet api-server; then
    log "Deploy failed β€” rolling back"
    cp -r "$BACKUP_DIR/." "$APP_DIR/"
    systemctl restart api-server
    error "Deployment failed. Rolled back to previous version."
  fi

  log "Deployment successful: ${VERSION}"
}

deploy "$@"

Performance Tuning

bash
# CPU & Memory
vmstat 1 5                       # Virtual memory statistics every 1s, 5 times
mpstat -P ALL 1 3                # Per-CPU utilization
free -h                          # Memory usage
cat /proc/meminfo | grep -E "MemTotal|MemAvailable|SwapTotal"

# I/O
iostat -xz 1 5                   # Disk I/O stats
iotop -aod 1                     # Top processes by I/O
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE  # Block device layout

# Kernel tuning (sysctl)
sysctl -a | grep net.core        # View all network core params
sysctl net.core.somaxconn        # Max connection queue depth

# /etc/sysctl.d/99-mc-tuning.conf
net.core.somaxconn = 65536
net.ipv4.tcp_max_syn_backlog = 65536
net.ipv4.ip_local_port_range = 1024 65535
fs.file-max = 2097152
vm.swappiness = 10

Text Processing (grep, awk, sed)

bash
# grep
grep -r "ERROR" /var/log/app/ --include="*.log" -l   # Files with errors
grep -E "5[0-9]{2}" /var/log/nginx/access.log         # 5xx HTTP codes
grep -v "health" /var/log/nginx/access.log            # Exclude health checks
grep -c "POST /api" /var/log/nginx/access.log         # Count POST requests

# awk β€” field-based processing
awk '{print $1, $7, $9}' /var/log/nginx/access.log   # IP, path, status code
awk '$9 >= 500 {print}' /var/log/nginx/access.log    # 5xx responses
awk '{sum += $NF} END {print "Total:", sum}' sizes.txt  # Sum last column
awk -F: '{print $1}' /etc/passwd                     # Extract usernames

# sed β€” stream editor
sed -i 's/DEBUG/INFO/g' /etc/app/config.env          # In-place replace
sed -n '100,200p' /var/log/app.log                   # Print lines 100-200
sed '/^#/d; /^$/d' /etc/app/config.conf              # Remove comments & blanks

# sort, uniq, wc β€” pipeline power
sort -t '"' -k3 /var/log/nginx/access.log | uniq -c | sort -rn | head -20
# β†’ Top 20 most frequent request paths
πŸ“± Install MC Wiki
Add to home screen for offline access.