Linux Tips & Tricks
A place for small but useful Linux command-line statements that have helped me lately. This blog isn’t really for you — it’s for me. A learning repository. But if any of it helps you, great.
Packages & ISOs
Extracting an RPM without installing it
Useful for peeking inside a package, grabbing one file out of it, or unpacking it onto a system that doesn’t use RPM.
rpm2cpio ./package.rpm | cpio -idmv
Debian equivalent:
dpkg-deb -x ./package.deb ./extracted/
Rebuilding a custom CentOS installation ISO
When building a custom CentOS installation disk, I use a kickstart file to automate the installation responses — you can define virtually every installation parameter, enabling fully automated deployment without manual intervention.
After dropping in the kickstart and any other tweaks, rebuild the ISO with:
genisoimage -u -r -v -T -J -joliet-long \
-b isolinux/isolinux.bin -c isolinux/boot.cat \
-no-emul-boot -boot-load-size 4 -boot-info-table \
-eltorito-alt-boot -e images/efiboot.img \
-o ../new.iso .
Networking
Who’s listening on that port?
netstat is deprecated on modern distros. ss is faster and comes with iproute2.
# TCP listeners with process names
sudo ss -ltnp
# Everything on a specific port
sudo ss -tulnp '( sport = :443 or dport = :443 )'
If you only have lsof handy:
sudo lsof -i :443 -sTCP:LISTEN
A quick packet capture to a file
Grab everything on the wire for a host and a port, save to pcap, and open it later in Wireshark:
sudo tcpdump -i any -nn -s0 -w /tmp/cap.pcap 'host 10.0.0.5 and port 443'
Human-readable one-liner, no save:
sudo tcpdump -i any -nn -vv -A 'port 53'
Which process owns this socket, this file, this mount?
sudo fuser -v /var/lib/mysql # who has files open under this path
sudo lsof /var/log/messages # who has this file open
sudo lsof -p 1234 # everything this PID has open
A live top-like view of network sockets
watch -n 1 'ss -s; echo; ss -tn state established | head -20'
SSH superpowers
One hop to anywhere via a bastion
Put this in ~/.ssh/config:
Host bastion
HostName jump.example.com
User jbrown
Host internal-*
User jbrown
ProxyJump bastion
Now ssh internal-db01 tunnels through the bastion automatically. No more ssh -J on the command line every time.
Session multiplexing — make second connections instant
Also in ~/.ssh/config:
Host *
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 10m
First connection to a host sets up a master socket. Every connection after that for the next 10 minutes reuses it — scp, rsync, a second ssh, an Ansible run — they all open in under a second.
Local and remote port forwarding, mentally sorted
# "I want to reach THEIR port 5432 at my localhost:5432"
ssh -L 5432:db.internal:5432 bastion
# "I want THEM to reach MY localhost:3000 at their localhost:3000"
ssh -R 3000:localhost:3000 bastion
# "Make my browser's SOCKS proxy tunnel through this host"
ssh -D 1080 bastion
Generate and copy an SSH key in one go
ssh-keygen -t ed25519 -C "jbrown@$(hostname)" -f ~/.ssh/id_ed25519
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
Disk & files
What’s eating the disk?
# Top-level usage, sorted, human-readable
du -sh -- */ 2>/dev/null | sort -hr | head -20
# Interactive explorer — install this everywhere
ncdu /var
ncdu is worth installing on every server you touch.
Find files by size
# Files over 100M under the current filesystem only
find . -xdev -type f -size +100M -printf '%s\t%p\n' | sort -nr | head
A one-shot HTTP server over any directory
Share a file with someone on the same network without standing up nginx:
python3 -m http.server 8000
Needs an auth check? Use caddy file-server --listen :8000 instead.
Rsync that survives a dropped connection
Archive, preserve attrs, compress, show progress, and resume on interrupt:
rsync -aHAXz --info=progress2 --partial --append-verify \
/src/ user@host:/dst/
Dry-run first when --delete is involved:
rsync -aHAX --delete --dry-run /src/ /dst/
systemd & logs
Logs for one service, since last boot, follow mode
journalctl -u nginx.service -b -f
Why did this service fail?
systemctl status nginx # quick view with last 10 log lines
journalctl -xeu nginx.service # full story, jumps to errors
Override a unit without editing the vendor file
sudo systemctl edit nginx.service
Drops you into an editor pointed at /etc/systemd/system/nginx.service.d/override.conf. Anything you put there overlays the shipped unit and survives package upgrades.
Is this boot’s clock sane? Is NTP actually working?
timedatectl
Small quality-of-life wins
Follow a log that gets rotated
tail -f loses its grip when logrotate moves the file. -F re-opens on rotation:
tail -F /var/log/messages
Run any command whenever a file changes
# Debian/Ubuntu: apt install inotify-tools
while inotifywait -e modify ./config.yml; do
./reload.sh
done
Extract just about anything
# One command that handles tar, tar.gz, tar.bz2, tar.xz, zip, 7z, rar
atool -x archive.whatever
Or the old-school version that lives in my memory:
tar xaf archive.tar.anything # auto-detects compression
Decode a JSON blob without installing anything
If jq isn’t available:
curl -s https://example.com/api | python3 -m json.tool
With jq (do install it):
curl -s https://api.example.com/things | jq '.items[] | {id, name}'
Keep a command running when you disconnect
When tmux or screen isn’t installed:
nohup ./long-job.sh > job.log 2>&1 &
disown
But really — install tmux. Ctrl-b d to detach, tmux attach to come back. Sessions survive reboots if you use tmux-resurrect.