Linux System Administration Guide
System Administration Arsenal
This collection contains practical sysadmin commands I've gathered over years of Linux system administration.
Network Analysis¶
Connection Monitoring¶
- Shows unique IP addresses of connected machines using modern
sscommand
SSH Operations¶
ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" -o "GlobalKnownHostsFile=/dev/null" user@host #(1)!
- Useful for rescue mode servers where host keys change frequently
Ghostty Terminfo on Remote Servers¶
When using Ghostty as your terminal, SSH sessions may fail with Error opening terminal: xterm-ghostty if the terminfo entry is missing on the remote server.
Run this once from your local machine to compile and install the terminfo for all users on the remote server:
- Replace
YOUR-SERVERwith your server hostname or IP. The-o /usr/share/terminfoflag writes system-wide instead of to~/.terminfo.
On systems where ncurses 6.5+ is installed, the entry exists as ghostty (without the xterm- prefix). Tools like htop may still look for xterm-ghostty specifically. Create a symlink to fix it:
Why not in Ubuntu yet?
Ubuntu 24.04 ships ncurses 6.4, which predates the ghostty terminfo entry (added in ncurses 6.5, December 2024). The manual install above is the correct workaround until Ubuntu 26.04.
System Updates & Configuration¶
Arch Linux Package Management¶
for i in $(find /etc -iname '*.pacnew'); do sudo meld $i ${i%%.pacnew} && sudo rm -i $i; done #(1)!
for i in $(find /etc -iname '*.pacsave'); do sudo meld $i ${i%%.pacsave} && sudo rm -i $i; done #(2)!
- Compare and merge .pacnew files with current configs
- Handle .pacsave backup files from package updates
Debian/Ubuntu Configuration Merging¶
for file in $(find /etc -iname '*.dpkg-dist'); do vimdiff ${file%%.dpkg-dist} $file; rm $file; done #(1)!
for file in $(find /etc -iname '*.dpkg-old'); do vimdiff ${file%%.dpkg-old} $file; rm $file; done #(2)!
for file in $(find /etc -iname '*.dpkg-new'); do vimdiff ${file%%.dpkg-new} $file; rm $file; done #(3)!
- Merge distribution config files with local versions
- Handle old configuration backups
- Process new configuration files from packages
SSL/TLS Management¶
Let's Encrypt Certificates¶
certbot certonly --non-interactive --webroot --webroot-path /var/www/html/ -d foo.bar -d www.foo.bar #(1)!
- Non-interactive certificate generation using webroot validation
Certificate Analysis¶
find /etc/ssl/certs/ -type f -print -exec openssl x509 -text -in {} \; | grep --color=auto -e etc -e CN= -e DNS: -e After #(1)!
- Display custom certificates with Common Names, SANs, and expiration dates
User Management¶
User Migration¶
for i in user1 user2 user3; do echo -n 'useradd -m -s /bin/bash -u '$(grep -E "^$i" /etc/passwd | cut -d':' -f3) && echo -en ' -p'\''$(grep -E "^$i" /etc/shadow | cut -d ':' -f2)'\'' $i ''\n'; done #(1)!
- Generates useradd commands with existing UIDs and password hashes for account migration
Group Management¶
for group in $(grep user1 /etc/group | cut -d':' -f1 | sed '/user1/d'); do adduser user2 $group; done #(1)!
- Adds user2 to all groups that user1 belongs to
Storage & File Systems¶
Loop Device Management¶
- Creates loop device with partition support for disk image files
File System Creation¶
- Creates ext4 without modern features for compatibility with older systems
File Operations¶
- Finds files modified before specific date and copies them
find ./ -type f ! -perm /g=r -exec ls -l {} \; #(1)!
find ./ -type d \( ! -perm /g=r -o ! -perm /g=x \) -exec ls -ld {} \; #(2)!
find ./ -perm /g=w #(3)!
find ./ -perm -007 -o -type f -perm -006 #(4)!
- Find files not readable by group (Apache)
- Find directories not accessible by group (Apache)
- Find files/directories writable by group
- Find files/directories with world write permissions
Database Operations¶
MySQL Management¶
mysql -e "set global innodb_max_dirty_pages_pct = 0;" #(1)!
mysqladmin ext -i10 | grep dirty #(2)!
- Forces InnoDB to flush dirty pages for faster shutdown
- Monitors dirty page count during flush process
#!/bin/bash
SEC=$1
IFS='|'
if [[ $SEC -lt 1 ]]; then
echo "Usage: $0 SECONDS"
exit 1
fi
mysqladmin proc -v|grep Query|grep -Evi "delete|update|insert|alter table" |while read dummy qid qusr qhost qdb qstat qsec qstat2 query; do
if [ $qsec -gt $SEC ]; then
echo "Killing query $qid..."
mysqladmin kill $qid
fi
done
# Source Server
mysql mysql -e "select * from user WHERE USER='user1' OR USER='user2' INTO OUTFILE '/tmp/mysql_user';" #(1)!
mysql mysql -e "select * from db WHERE USER='user1' OR USER='user2' INTO OUTFILE '/tmp/mysql_db';" #(2)!
# Destination Server
scp server:/tmp/mysql_{db,user} /tmp #(3)!
chmod 664 /tmp/mysql_{db,user} #(4)!
mysql mysql -e "LOAD DATA INFILE '/tmp/mysql_user' INTO TABLE user;" #(5)!
mysql mysql -e "LOAD DATA INFILE '/tmp/mysql_db' INTO TABLE db;" #(6)!
- :material-account-export: Export user account information
- Export database permissions
- Copy files to destination server
- Set appropriate permissions
- :material-account-import: Import user accounts
- Import database permissions
#!/bin/bash
tables=$(grep crashed /var/log/syslog | grep -Eo '\./.*' --color=auto | sed s#\'./## | sed s#\'## | uniq | tr -s '\n' ' ') #(1)!
for tableC in $tables; do
db=${tableC%/*} #(2)!
table=${tableC#*/} #(3)!
mysqlcheck --auto-repair --check $db $table #(4)!
done
- Extract crashed table names from syslog
- Extract database name from path
- Extract table name from path
- Repair crashed table automatically
Mail System Management¶
Postfix Operations¶
- Extract mail from queue by ID
- Resend mail with specified sender and recipient
System Monitoring & Troubleshooting¶
Process Analysis¶
- Detailed process information with extended user field
System Debugging¶
strace -p $(ps auwwwx | grep apache | tr -s '\t' ' ' | cut -d' ' -f2 | tr '\n' ' ' | sed 's/ / -p /g') 9999 #(1)!
- Attach strace to all Apache processes for debugging
PHP Debugging¶
HTTP_HOST=www.site.com SCRIPT_FILENAME=index.php REDIRECT_STATUS=CGI SERVER_NAME=www.site.com strace -s 65535 -o /tmp/strace php-cgi -f index.php #(1)!
- Debug PHP execution with full environment and system call tracing
Package Management¶
Debian Package Analysis¶
dpkg-query -W -f='${Section}\\t${Package}\\n' | grep ^non-free #(1)!
- List all packages installed from non-free repository section
DNS Management¶
sed -ri 's/^\\s*[0-9]+\\s*; serial/\\t\\t\\t 2017041010\\t ; serial/' db.* #(1)!
- Update DNS zone serial numbers (requires customization for your format)
Service Management¶
Namespace Operations¶
- Enter LXD namespace to access internal filesystem structures
GPG Agent Management¶
gpg-connect-agent
KEYINFO --ssh-list --ssh-fpr #(1)!
DELETE_KEY $HASH #(2)!
- List SSH keys managed by GPG agent
- Remove specific key by hash
Web Services¶
Python HTTP Server¶
- Start simple HTTP server for testing (useful for Munin, etc.)
Squid Proxy Analysis¶
tail -n100 /var/log/squid3/access.log | grep -oE 'http.*' | cut -d ' ' -f1 | sort | uniq #(1)!
- Extract and list unique URLs from recent Squid access logs
System Recovery¶
Password Recovery¶
Boot-time password recovery procedure:
Boot Recovery
At GRUB stage, press e to edit the kernel line and add init=/bin/bash. This drops you into a shell before the init system.
- Remount root filesystem as read-write
- Change root password
Log Management¶
- Manually rotate log file without using logrotate
Contact Information¶
Technical Contact Templates¶
When contacting domains without published technical contacts:
abuse@<domain>
admin@<domain>
administrator@<domain>
contact@<domain>
info@<domain>
postmaster@<domain>
support@<domain>
webmaster@<domain>
Additional Resources¶
Useful Monitoring Tools
Auditing Modified Config Files¶
After a major Ubuntu upgrade, some config files may have changed upstream but kept your old version. Use debsums to find which conffiles differ from their package originals, then diff them to see exactly what changed.
for f in $(debsums -ce 2>/dev/null); do
pkg=$(dpkg -S "$f" 2>/dev/null | head -1 | cut -d: -f1)
tmp=$(mktemp -d)
cd "$tmp"
apt download "$pkg" 2>/dev/null
dpkg-deb -x *.deb extract
echo "=== $f ==="
diff -u "extract$f" "$f" || true
echo
cd /
rm -rf "$tmp"
done
This is especially useful after jumping multiple Ubuntu releases (e.g. 24.04 → 25.10), where dpkg may have kept old config files that no longer match what the new package ships. Look for syntax changes, new defaults, or deprecated options that could cause silent failures.