π§ 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