Index
This is my practical knowledge base. The intended audience is mostly me, but some notes are written in a tutorial-like format.
I can make no guarantees that any of the content here will work for others. If you break things after following something here, you’re the one responsible.
Anyway, you may find something useful here after all. But still, reader beware 🤨.
Apache
Install mod-evasive
sudo apt install libapache2-mod-evasive
Add mod_evasive to VirtualHost
<IfModule mod_evasive20.c>
DOSHashTableSize 3097
DOSPageCount 2
DOSSiteCount 60
DOSPageInterval 1
DOSSiteInterval 1
DOSBlockingPeriod 60
DOSEmailNotify <hyperreal@moonshadow.dev
</IfModule>
Restart apache2.
sudo systemctl restart apache2.service
AppArmor
Setup AppArmor on CachyOS
Install apparmor.
sudo pacman -S apparmor apparmor.d
Add the following line to /etc/limine-entry-tool.conf. This should enable AppArmor and auditd at boot time.
KERNEL_CMDLINE[default]+=lsm=landlock,lockdown,yama,integrity,apparmor,bpf audit=1
Update the limine config.
sudo limine-update
Enable apparmor.service and auditd.service on boot.
sudo systemctl enable apparmor.service
sudo systemctl enable auditd.service
Reboot.
Check to see if AppArmor is enabled.
aa-enabled
Arch Linux
Pacman cheatsheet
| Action | Command |
|---|---|
| Clean pacman cache | sudo pacman -Sc |
| Upgrade specific package(s) | sudo pacman -U <pkg0> <pkg1> ... <pkgN> |
| Remove all files from pacman cache | sudo pacman -Scc |
| Remove specific packages | sudo pacman -R <pkg0> <pkg1> ... <pkgN> |
| Display info on a given sync db package | sudo pacman -Si <pkg> |
| Search sync db for names or desc matching regexp | sudo pacman -Ss <regexp> |
| List all locally installed native packages | sudo pacman -Qn |
| List all locally installed foreign packages | sudo pacman -Qm |
| Display info on a given package | sudo pacman -Qi <pkg> |
| Search locally installed packages for name/desc | sudo pacman -Qs <regexp> |
| Refresh all package databases | sudo pacman -Syy |
| List orphan packages | sudo pacman -Qdt |
| Remove orphan packages | sudo pacman -Rs $(pacman -Qtdq) |
| Refresh the package file databases | sudo pacman -Fy |
| Query the files database for given package | sudo pacman -F <pkg> |
| List all files owned by given package | sudo pacman -Ql <pkg> |
| Search for packages that own given file | sudo pacman -Qo <file> |
Armbian
Disable armbian-ramlog
Edit /etc/default/armbian-ramlog:
ENABLED=false
Comment out the entry in /etc/cron.d/armbian-truncate-logs:
# 0,15,30,45 * * * * root /usr/lib/armbian/armbian-truncate-logs
Comment out the entry in /etc/cron.daily/armbian-ram-logging:
#/usr/lib/armbian/armbian-ramlog write >/dev/null 2>&1
Restart the server:
sudo systemctl reboot
Atop
Get lowest memfree for given analysis date
atopsar \
-r /var/log/atop/atop_20240703 \
-m \
-R 1 \
| awk 'NR<7{print $0;next}{print $0| "sort -k 3,4"}' \
| head -11
Get top 3 mem procs for given analysis date
atopsar \
-G \
-r /var/log/atop/atop_20240710
Identify top 5 most frequently executed procs during logging period
atop \
-r /var/log/atop/atop_20241123 \
-P PRG \
| grep -oP "(?<=\()[[:alnum:]]{1,}(?=\))" \
| sort \
| uniq -c \
| sort -k1rn \
| head -5
Count num of times a proc has been detected during logging period
atop \
-r /var/log/atop/atop_20241123 \
-P PRG \
| egrep "docker" \
| awk '{print $5}' \
| uniq -c -w5
Generate a chart of the num of instances of proc during logging period
atop \
-r /var/log/atop/atop_20241123 \
-P PRG \
| egrep "docker" \
| awk '{print $5}' \
| uniq -c -w8 \
| \
gnuplot -e \
"set terminal dumb 80 20; \
unset key; \
set style data labels; \
set xdata time; \
set xlabel 'Time'; \
set ylabel 'docker'; \
set timefmt '%H:%M:%S'; \
plot '-' using 2:1:ytic(1) with histeps"
Generate PNG chart of num of instances of proc during logging period
atop \
-r /var/log/atop/atop_20241123 \
-P PRG \
| egrep "docker" \
| awk '{print $5}' \
| uniq -c -w8 \
| \
gnuplot -e \
"set title 'Process Count'; \
set offset 1,1,1,1; \
set autoscale xy; \
set mxtics; \
set mytics; \
set style line 12 lc rgb '#ddccdd' lt 1 lw 1.5; \
set style line 13 lc rgb '#ddccdd' lt 1 lw 0.5; \
set grid xtics mxtics ytics mytics \
back ls 12, ls 13; \
set terminal png size 1920,1080 enhanced font \
'/usr/share/fonts/liberation/LiberationSans-Regular.ttf,10'; \
set output 'plot_$(date '+%Y-%m-%d_%H:%M:%S')_${RANDOM}.png'; \
set style data labels; \
set xdata time;
set xlabel 'Time' font \
'/usr/share/fonts/liberation/LiberationSans-Regular.ttf,8'; \
set ylabel 'Count' font \
'/usr/share/fonts/liberation/LiberationSans-Regular.ttf,8'; \
set timefmt '%H:%M:%S'; \
plot '-' using 2:1 with histeps"
Identify top 10 most frequently executed binaries from /sbin or /usr/sbin during logging period
for i in $(atop \
-r /var/log/atop/atop_20241123 \
-P PRG \
| grep -oP "(?<=\()[[:alnum:]]{1,}(?=\))" \
| sort \
| uniq -c \
| sort -k1rn \
| head -10); do
which "${i}" 2>/dev/null | grep sbin;
done
Identify disks with over 90% activity during logging period
atopsar \
-r /var/log/atop/atop_20241123 \
-d \
| egrep '^[0-9].*|(9[0-9]|[0-9]{3,})%'
Identify procs responsible for most disk I/O during logging period
atopsar \
-r /var/log/atop/atop_20241123 \
-D \
| sed 's/\%//g' \
| awk -v k=50 '$4 > k || $8 > k || $12 > k' \
| sed -r 's/([0-9]{1,})/%/5;s/([0-9]{1,})/%/7;s/([0-9]{1,})/%/9'
Identify periods of heavy swap activity during logging period
atopsar \
-r /var/log/atop/atop_20241123 \
-s \
| awk -v k=1000 '$2 > k || $3 > k || $4 > k'
Identify procs consuming > half of all CPUs
(( k = $(grep -c proc /proc/cpuinfo) / 2 * 100 ))
atopsar \
-r /var/log/atop/atop_20241123 \
-P \
| sed 's/\%//g' \
| awk -v k=$k '$4 > k || $8 > k || $12 > k' \
| sed -r 's/([0-9]{1,})/%/5;s/([0-9]{1,})/%/7;s/([0-9]{1,})/%/9'
Identify time of peak mem utilization
atopsar \
-r /var/log/atop/atop_20241123 \
-m \
-R 1 \
| awk 'NR<7{print $0;next}{print $0| "sort -k 3,3"}' \
| head -15
Bash
Print nth line from file
sed 'Nq;d' file.txt
Prepend text to beginning of file
echo "new content" | cat - file.txt > temp
mv temp file.txt
sed -i '1s/^/new content\n/' file.txt
Remove lines containing only whitespace
sed -i '/^\s*$/d' file.txt
Delete nth line from file
# N is the target line
sed -i 'Nd' file.txt
Replace an entire line in file by line number
# N is the target line
sed -i 'Ns/.*/replacement-line/' file.txt
Heredoc
cat << EOF > file.txt
The current working directory is $PWD.
Your are logged in as $(whoami).
EOF
Plain-print the difference between two files
Suppose we have two files: packages.fedora and packages.
packages.fedora
autossh
bash-completion
bat
bc
borgmatic
bzip2
cmake
curl
diff-so-fancy
diffutils
dnf-plugins-core
packages
bash-completion
bc
bzip2
curl
diffutils
dnf-plugins-core
To plain-print the lines that exist in packages.fedora but not in packages:
comm -23 <(sort packages.fedora) <(sort packages)
Output:
autossh
bat
borgmatic
cmake
diff-so-fancy
- The
commcommand compares two sorted files line by line. - The
-23flag is shorthand for-2and-3. -2suppresses column 2 (lines unique topackages).-3suppresses column 3 (lines that appear in both files).
Split large text file into smaller files with equal number of lines
split -l 60 bigfile.txt prefix-
Loop through lines of file
while read line; do
echo "$line";
done </path/to/file.txt
Use grep to find URLs from HTML file
cat urls.html | grep -Eo "(http|https)://[a-zA-Z0-9./?=_%:-]*"
Use Awk to print the first line of ps aux output followed by each grepped line
To find all cron processes with ps aux:
ps aux | awk 'NR<2{print $0;next}{print $0 | grep "cron"}' | grep -v "awk"
Btrfs
Create systemd.mount unit for Btrfs on external HDD
Get the UUID of the Btrfs partition:
sudo blkid -s UUID -o value /dev/sda1
d3b5b724-a57a-49a5-ad1d-13ccf3acc52f
Edit /etc/systemd/system/mnt-internet_archive.mount:
[Unit]
Description=internet_archive Btrfs subvolume
DefaultDependencies=yes
[Mount]
What=/dev/disk/by-uuid/d3b5b724-a57a-49a5-ad1d-13ccf3acc52f
Where=/mnt/internet_archive
Type=btrfs
Options=subvol=@internet_archive,compress=zstd:1
[Install]
WantedBy=multi-user.target
Note that the name of the unit file, e.g.,
mnt-internet_archive.mount, must correspond to theWhere=/mnt/internet_archivedirective, such that the filesystem path separator/in theWheredirective is replaced by an en dash in the unit file name.
Reload the daemons and enable the mount unit:
sudo systemctl daemon-reload
sudo systemctl enable --now mnt-internet_archive.mount
Setup encrypted external drive for backups
Prepare the external drive
sudo cryptsetup --type luks2 -y -v luksFormat /dev/sda1
sudo cryptsetup -v luksOpen /dev/sda1 cryptbackup
sudo mkfs.btrfs /dev/mapper/cryptbackup
sudo mkdir /srv/backup
sudo mount -o noatime,compress=zstd:1 /dev/mapper/cryptbackup /srv/backup
sudo restorecon -Rv /srv/backup
Setup /etc/crypttab
sudo blkid -s UUID -o value /dev/sda1 | sudo tee -a /etc/crypttab
Add the following line to /etc/crypttab:
cryptbackup UUID=<UUID of /dev/sda1> none discard
Setup /etc/fstab
sudo blkid -s UUID -o value /dev/mapper/cryptbackup | sudo tee -a /etc/fstab
Add the following line to /etc/fstab:
UUID=<UUID of /dev/mapper/cryptbackup> /srv/backup btrfs compress=zstd:1,nofail 0 0
Reload the daemons:
sudo systemctl daemon-reload
Mount the filesystems:
sudo mount -av
Btrfs backup script
#!/usr/bin/env bash
LOGFILE="/var/log/btrfs-backup.log"
SNAP_DATE=$(date '+%Y-%m-%d_%H%M%S')
# Check if device is mounted
if ! grep "/srv/backup" /etc/mtab >/dev/null; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup device is not mounted." | tee -a "$LOGFILE"
notify-send -i computer-fail "Backup device is not mounted"
exit 1
fi
create_snapshot() {
if ! btrfs subvolume snapshot -r "$1" "${1}/.snapshots/$2-$SNAP_DATE" >/dev/null; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Error creating snapshot of $1" | tee -a "$LOGFILE"
notify-send -i computer-fail "Error creating snapshot of $1"
exit 1
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Create snapshot of $1: OK" | tee -a "$LOGFILE"
fi
}
send_snapshot() {
mkdir -p "/srv/backup/$SNAP_DATE"
if ! btrfs send -q "${1}/.snapshots/$2-$SNAP_DATE" | btrfs receive -q "/srv/backup/$SNAP_DATE"; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Error sending snapshot of $1 to /srv/backup" | tee -a "$LOGFILE"
notify-send -i computer-fail "Error sending snapshot of $1 to /srv/backup"
exit 1
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Send snapshot of $1 to /srv/backup: OK" | tee -a "$LOGFILE"
fi
}
# Create root and home snapshots
create_snapshot "/" "root"
create_snapshot "/home" "home"
# Send root and home snapshots
send_snapshot "/" "root"
send_snapshot "/home" "home"
Move/copy the script to /etc/cron.daily/btrfs-backup.
CachyOS
Gaming
Resources:
DLSS
Edit /etc/environment.
PROTON_DLSS_UPGRADE=1
PROTON_DLSS_INDICATOR=1
Fix possible RTX 4000+ performance issues
Edit /etc/environment.
PROTON_NVIDIA_LIBS_NO_32BIT=1
Increase maximum shader cache size (NVIDIA)
Edit /etc/environment.
__GL_SHADER_DISK_CACHE_SIZE=12000000000
Reboot the system.
scx_bpfland
Source: https://wiki.cachyos.org/configuration/sched-ext
Edit /etc/scx_loader.toml.
default_sched = "scx_bpfland" # Edit this line to the scheduler you want scx_loader to start at boot
default_mode = "Auto" # Possible values: "Auto", "Gaming", "LowLatency", "PowerSave".
Enable or restart the scx_loader.service.
sudo systemctl enable --now scx_loader.service
sudo systemctl restart scx_loader.service
Caddy
IP whitelist
irc.hyperreal.coffee {
@me {
client_ip 1.2.3.4
}
handle @me {
reverse_proxy localhost:9000
}
respond "You are attempting to access protected resources!" 403
}
Reverse proxy for qBittorrent over Tailscale
hostname.tailnet.ts.net:8888 {
reverse_proxy localhost:8080 {
header_up Host localhost:8080
header_up X-Forwarded-Host {host}:{hostport}
header_up -Origin
header_up -Referer
}
}
Cgit
Dependencies
- xcaddy package from releases page.
Install caddy-cgi.
xcaddy build --with github.com/aksdb/caddy-cgi/v2
Install remaining dependencies:
sudo apt install gitolite3 cgit python-is-python3 python3-pygments python3-markdown docutils-common groff
Configuration
Make a git user.
sudo adduser --system --shell /bin/bash --group --disabled-password --home /home/git git
Configure gitolite for the git user in ~/.gitolite.rc.
UMASK => 0027,
GIT_CONFIG_KEYS => 'gitweb.description gitweb.owner gitweb.homepage gitweb.category',
Add caddy user to the git group.
sudo usermod -aG git caddy
Configure cgit in /etc/cgitrc.
#
# cgit config
# see cgitrc(5) for details
css=/cgit/cgit.css
logo=/cgit/cgit.png
favicon=/cgit/favicon.ico
enable-index-links=1
enable-commit-graph=1
enable-log-filecount=1
enable-log-linecount=1
enable-git-config=1
branch-sort=age
repository-sort=name
clone-url=https://git.hyperreal.coffee/$CGIT_REPO_URL git://git.hyperreal.coffee/$CGIT_REPO_URL ssh://git@git.hyperreal.coffee:$CGIT_REPO_URL
root-title=hyperreal.coffee Git repositories
root-desc=Source code and configs for my projects
##
## List of common mimetypes
##
mimetype.gif=image/gif
mimetype.html=text/html
mimetype.jpg=image/jpeg
mimetype.jpeg=image/jpeg
mimetype.pdf=application/pdf
mimetype.png=image/png
mimetype.svg=image/svg+xml
# Enable syntax highlighting
source-filter=/usr/lib/cgit/filters/syntax-highlighting.py
# Format markdown, rst, manpages, text files, html files, and org files.
about-filter=/usr/lib/cgit/filters/about-formatting.sh
##
### Search for these files in the root of the default branch of repositories
### for coming up with the about page:
##
readme=:README.md
readme=:README.org
robots=noindex, nofollow
section=personal-config
repo.url=doom-emacs-config
repo.path=/home/git/repositories/doom-emacs-config.git
repo.desc=My Doom Emacs config
DietPi
systemd-logind
Install libpam-systemd:
sudo apt install -y libpam-systemd
Unmask and enable systemd-logind:
sudo systemctl unmask systemd-logind
sudo systemctl enable systemd-logind
sudo systemctl reboot
DRM
nix-shell
Install libgourou in nix-shell.
nix-shell -p libgourou
Docker
docker run \
-v "${PATH_TO_ADOBE_CREDS}:/home/libgourou/.adept" \
-v "$(pwd):/home/libgourou/files" \
--rm \
bcliang/docker-libgourou \
<name_of_adept_metafile.acsm>
Extract PDF or EPUB from ACSM file
Register the device with Adobe username and password.
adept_activate -u user -p password
Download the ACSM file. Make sure the ACSM file is in the current working directory.
acsmdownloader -f Dragon_Age_The_Missing_1.acsm
The downloaded file requires a password to open. Remove the DRM from the files.
find . -type f -name "Dragon_Age_The_Missing*.pdf" -exec adept_remove {} \;
Fail2Ban
Configure fail2ban on Linux with firewalld
sudo cp -v /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nvim /etc/fail2ban/jail.local
bantime = 1h
findtime = 1h
maxretry = 5
sudo cp -v /etc/fail2ban/jail.d/00-firewalld.conf /etc/fail2ban/jail.d/00-firewalld.local
sudo nvim /etc/fail2ban/jail.d/sshd.local
[sshd]
enabled = true
bantime = 1d
maxretry = 3
sudo systemctl restart fail2ban.service
sudo fail2ban-client status
Configure fail2ban on FreeBSD with PF
sudo pkg install -y py311-fail2ban
Edit /usr/local/etc/fail2ban/jail.local.
[DEFAULT]
bantime = 86400
findtime = 3600
maxretry = 3
banaction = pf
[sshd]
enabled = true
Enable and start fail2ban.
sudo sysrc fail2ban_enable="YES"
sudo service fail2ban start
# If not enabled already:
sudo sysrc pf_enable="YES"
sudo service pf start
Configure /etc/pf.conf.
table <fail2ban> persist
set skip on lo0
block in all
block in quick from <fail2ban>
...
Check and reload PF rules.
sudo pfctl -nf /etc/pf.conf
sudo pfctl -f /etc/pf.conf
Fedora Atomic
Access USB serial device in container
Create a udev rule on the host for all usb serial devices. Set OWNER to your main user.
cat << EOF | sudo tee /etc/udev/rules.d/50-usb-serial.rules
SUBSYSTEM=="tty", SUBSYSTEMS=="usb-serial", OWNER="jas"
EOF
Reload udev.
sudo udevadm control --reload-rules
sudo udevadm trigger
The serial device should now be owned by your user.
ls -l /dev/ttyUSB0
crw-rw----. 1 jas dialout 188, 0 Mar 15 11:09 /dev/ttyUSB0
You can now run minicom inside the toolbox container.
distrobox enter default
minicom -D /dev/ttyUSB0
Fedora
Repo priorities and exclusions
Terra repositories (Fyra Labs)
Prioritize the fdk-aac-free package from upstream by excluding the fdk-aac from Terra:
sudo dnf config-manager setopt "*terra*".exclude="fdk-aac"
Set Terra repositories to priority 3:
sudo dnf config-manager setopt "*terra*".priority=3
RPMFusion repositories
Set all RPMFusion repositories priorities to 5:
sudo dnf config-manager setopt "*rpmfusion*".priority=5
Exclude mesa-* packages from RPMFusion:
sudo dnf config-manager setopt "*rpmfusion*".exclude="mesa-*"
Fedora repositories
Exclude mesa-* packages from upstream Fedora repositories:
sudo dnf config-manager setopt "*fedora*".exclude="mesa-*"
All overrides can be viewed in /etc/dnf/repos.override.d/99-config_manager.repo.
Firewalld
Allow connections only from tailnet
Create a new zone for the tailscale0 interface.
sudo firewall-cmd --permanent --new-zone=tailnet
sudo firewall-cmd --permanent --zone=tailnet --add-interface=tailscale0
sudo firewall-cmd --reload
Add services and ports to the tailnet zone.
sudo firewall-cmd --permanent --zone=tailnet --add-service={http,https,ssh}
sudo firewall-cmd --permanent --zone=tailnet --add-port=9100/tcp
sudo firewall-cmd --reload
Ensure the public zone does not have any interfaces or sources.
sudo firewall-cmd --permanent --zone=public --remove-interface=eth0
sudo firewall-cmd --reload
The firewall should now only allow traffic coming from the tailnet interface.
FreeBSD
USB 3.1 Type-C to RJ45 Gigabit Ethernet adapter
The Amazon Basics Aluminum USB 3.1 Type-C to RJ45 Gigabit Ethernet Adapter works well with FreeBSD 14.1-RELEASE. It uses the AX88179 chipset from ASIX Electronics Corp.
Install the ports tree
Checkout the FreeBSD source code.
sudo git clone -o freebsd -b releng/14.1 https://git.FreeBSD.org/src.git /usr/src
Checkout the ports tree.
sudo git clone --depth 1 https://git.FreeBSD.org/ports.git -b 2024Q3 /usr/ports
To switch to a different quarterly branch:
sudo git -C /usr/ports switch 2024Q4
drm-61-kmod
Install from the ports tree.
cd /usr/ports/graphics/drm-61-kmod
sudo make install clean
Alternatively, for Alderlake GPUs:
sudo pkg install drm-kmod
Edit /etc/rc.conf.
kld_list="i915kms"
Add user to video group:
sudo pw groupmod video -m jas
Mount filesystem in single-user mode
When booted into single-user mode:
fsck
mount -u /
mount -a -t zfs
zfs mount -a
You should now be able to edit files, add/remove packages, etc.
Mount encrypted zroot in LiveCD
Boot into the LiveCD environment.
mkdir /tmp/mnt
geli attach /dev/nda0p4
zpool import -f -R /tmp/mnt zroot
zfs mount zroot/ROOT/default
The root directory ofthe zroot, zroot/ROOT/default, is labeled to not be automounted when imported, hence the need for the last command.
Setup Podman (FreeBSD >= 14)
The following is a condensed version of the guide found at CloudSpinx: Install Podman and run Containers in FreeBSD 14.
sudo pkg install podman-suite
sudo mount -t fdescfs fdesc /dev/fd
Add the following line to /etc/fstab:
fdesc /dev/fd fdescfs rw 0 0
Enable the Podman service.
sudo sysrc podman_enable="YES"
Container networking requires a NAT to allow the container network’s packets to reach the host’s network. Copy the sample pf.conf for Podman.
sudo cp -v /usr/local/etc/containers/pf.conf.sample /etc/pf.conf
Change v4egress_if and v6egress_if to the host’s main network interface in /etc/pf.conf.
v4egress_if="igc0"
v6egree_if="igc0"
Enable and start PF.
sudo sysrc pf_enable="YES"
sudo service pf start
FreeBSD >= 13.3 has support for rerouting connections from the host to services inside the container. To enable this, load the PF kernel module, then use sysctl to activate PF support for this rerouting.
echo 'pf_load="YES"' | sudo tee -a /boot/loader.conf
sudo kldload pf
sudo sysctl net.pf.filter_local=1
echo 'net.pf.filter_local=1' | sudo tee -a /etc/sysctl.conf.local
sudo service pf restart
The rerouting rules will only work if the destination address is localhost. Ensure the following exists in /etc/pf.conf.
nat-anchor "cni-rdr/*"
Container images and related state is stored in /var/db/containers. Create a ZFS dataset for this with the mountpoint set to that directory.
sudo zfs create -o mountpoint=/var/db/containers zroot/containers
If the system is not using ZFS, change storage.conf to use the vfs storage driver.
sudo sed -I .bak -e 's/driver = "zfs"/driver = "vfs"/' /usr/local/etc/containers/storage.conf
If there are any errors caused by the /var/db/containers/storage database, remove it.
sudo rm -rfv /var/db/containers/storage
Note: Podman can only be run with root privileges on FreeBSD at this time.
Enable the Linux service.
sudo sysrc linux_enable="YES"
sudo service linux start
To run Linux containers, add the --os=linux argument to Podman commands.
sudo podman run --os=linux ubuntu /usr/bin/cat "/etc/os-release"
Everything should work as expected.
Install Linux VM in Bhyve
Based on How to install Linux VM on FreeBSD using bhyve and ZFS, but condensed and collated for my use-case.
Setting up the network interfaces
Make the tap device UP by default in /etc/sysctl.conf.
echo "net.link.tap.up_on_open=1" >> /etc/sysctl.conf
sysctl net.link.tap.up_on_open=1
Load the kernel modules needed for bhyve.
kldload vmm
kldload nmdm
Make sure the modules are loaded at boot time.
echo 'vmm_load="YES"' >> /boot/loader.conf
echo 'nmdm_load="YES"' >> /boot/loader.conf
echo 'if_tap_load="YES"' >> /boot/loader.conf
echo 'if_bridge_load="YES"' >> /boot/loader.conf
Create the bridge and tap device. If you already have a bridge created, use that instead. We’ll assume this is the case, and the bridge is called igb0bridge.
ifconfig bridge create
If a bridge is already created and the main network interface igc0 is attached to it, the following command is not necessary.
ifconfig igb0bridge addm igc0
Create tap interface and attach it to the igb0bridge.
ifconfig tap0 create
ifconfig igb0bridge addm tap0
If there wasn’t a bridge already being used for jails, then /etc/rc.conf should contain the following:
cloned_interfaces="igb0bridge tap0"
ifconfig_igb0bridge="addm igc0 addm tap0 up"
If there was already a bridge used for jails, then /etc/rc.conf should contain the following:
cloned_interfaces="igb0bridge tap0"
ifconfig_igb0bridge="inet 10.0.0.8/24 addm igc0 addm tap0 up"
Setting up ZFS volumes for Linux Bhyve VM
zfs create -V128G -o volmode=dev zroot/debianvm
Downloading the Debian installer ISO
cd /tmp/
DEBIAN_VERSION=12.10.0
wget "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-${DEBIAN_VERSION}-amd64-netinst.iso"
Installing Debian in VM
Install the grub-bhyve binary to allow booting of non-FreeBSD guest OSes.
pkg install grub2-bhyve bhyve-firmware
Install Debian by running bhyve with the netinstall iso image and the zvol attached.
bhyve -c 4 -m 8G -w -H \
-s 0,hostbridge \
-s 3,ahci-cd,/tmp/debian-12.10.0-amd64-netinst.iso \
-s 4,virtio-blk,/dev/zvol/zroot/debianvm \
-s 5,virtio-net,tap0 \
-s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,wait \
-s 30,xhci,tablet \
-s 31,lpc \
-l com1,stdio \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
debianvm
When the command runs, use a remote VNC view to connect to and start the netinstall iso.
The following step is required to boot from UEFI.
Run the Debian installer with desired configuration. When you reach the “Finish the installation” stage, select “Go Back”, then select “Execute a shell”. Once in the shell, run the following commands:
mkdir /target/boot/efi/EFI/BOOT/
cp -v /target/boot/efi/EFI/debian/grubx64.efi /target/boot/efi/EFI/BOOT/bootx64.efi
exit
Now continue with “Finish the installation”.
Booting Debian bhyve VM
The instance of the virtual machine needs to be destroyed before it can be started again.
bhyvectl --destroy --vm=debianvm
Boot the Debian VM.
bhyve -c 4 -m 8G -w -H \
-s 0,hostbridge \
-s 4,virtio-blk,/dev/zvol/zroot/debianvm \
-s 5,virtio-net,tap0 \
-s 29,fbuf,tcp=0.0.0.0:5900,w=1024,h=768 \
-s 30,xhci,tablet \
-s 31,lpc \
-l com1,stdio \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
debianvm
Starting the Debian VM on boot with a shell script
#!/bin/sh
# Name: startdebianvm
# Purpose: Simple script to start my Debian 10 VM using bhyve on FreeBSD
# Author: Vivek Gite {https://www.cyberciti.biz} under GPL v2.x+
-------------------------------------------------------------------------
# Lazy failsafe (not needed but I will leave them here)
ifconfig tap0 create
ifconfig em0bridge addm tap0
if ! kldstat | grep -w vmm.ko
then
kldload -v vmm
fi
if ! kldstat | grep -w nmdm.ko
then
kldload -v nmdm
fi
bhyve -c 1 -m 1G -w -H \
-s 0,hostbridge \
-s 4,virtio-blk,/dev/zvol/zroot/debianvm \
-s 5,virtio-net,tap0 \
-s 29,fbuf,tcp=0.0.0.0:5900,w=1024,h=768 \
-s 30,xhci,tablet \
-s 31,lpc -l com1,stdio \
-l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
debianvm
Create a crontab entry:
@reboot /path/to/startdebianvm
Installing a Linux jail
Create the ZFS datasets for the base jail and Linux jail.
sudo zfs create naspool/jails/debian
sudo zfs create naspool/jails/14.2-RELEASE
Download the base userland system for FreeBSD.
fetch https://download.freebsd.org/ftp/releases/amd64/amd64/14.2-RELEASE/base.txz
Extract the base userland into the base jail’s directory.
sudo tar -xf base.txz -C /jails/14.2-RELEASE --unlink
Copy DNS and timezone files.
sudo cp -v /etc/resolv.conf /jails/14.2-RELEASE/etc/resolv.conf
sudo cp -v /etc/localtime /jails/14.2-RELEASE/etc/localtime
Update the base jail to the latest patch level.
sudo freebsd-update -b /jails/14.2-RELEASE/ fetch intall
Create a ZFS snapshot from the base jail.
sudo zfs snapshot naspool/jails/14.2-RELEASE@base
Clone the base jail to create a thin jail for the Linux distribution.
sudo zfs clone naspool/jails/14.2-RELEASE@base naspool/jails/debian
Enable the Linux ABI.
sudo sysrc linux_enable="YES"
sudo service linux start
Run the jail command with a quick configuration.
sudo jail -cm \
name=debian \
host.hostname="debian" \
path="/jails/debian" \
interface="igc0" \
ip4.addr="10.0.0.21" \
exec.start="/bin/sh /etc/rc" \
exec.stop="/bin/sh /etc/rc.shutdown" \
mount.devfs \
devfs_ruleset=11 \
allow.mount \
allow.mount.devfs \
allow.mount.fdescfs \
allow.mount.procfs \
allow.mount.linprocfs \
allow.mount.linsysfs \
allow.mount.tmpfs \
enforce_statfs=1
Access the jail.
sudo jexec -u root debian
Install the debootstrap program and prepare the Debian environment.
pkg install debootstrap
debootstrap bookworm /compat/debian
When the process finishes, stop the jail from the host system.
sudo service jail onestop debian
Add an entry in /etc/jail.conf for the Debian jail.
debian {
# STARTUP/LOGGING
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.consolelog = "/var/log/jail_console_${name}.log";
# PERMISSIONS
allow.raw_sockets;
exec.clean;
mount.devfs;
devfs_ruleset = 11;
# HOSTNAME/PATH
host.hostname = "${name}";
path = "/jails/${name}";
# NETWORK
ip4.addr = 10.0.0.21;
interface = igc0;
# MOUNT
mount += "devfs $path/compat/debian/dev devfs rw 0 0";
mount += "tmpfs $path/compat/debian/dev/shm tmpfs rw,size=1g,mode=1777 0 0";
mount += "fdescfs $path/compat/debian/dev/fd fdescfs rw,linrdlnk 0 0";
mount += "linprocfs $path/compat/debian/proc linprocfs rw 0 0";
mount += "linsysfs $path/compat/debian/sys linsysfs rw 0 0";
mount += "/tmp $path/compat/debian/tmp nullfs rw 0 0";
mount += "/home $path/compat/debian/home nullfs rw 0 0";
}
Start the jail.
sudo service jail start debian
The Debian environment can be accessed with the following command:
sudo jexec debian chroot /compat/debian /bin/bash
Internet Archive
Install Python CLI client
pipx install internetarchive
Use Python client to download torrent files from given collection
In qBittorrent, ensure “Automatically add torrents from” > Monitored Folder is set the /mnt/torrent_files and the Override save path is Default save path.
Get itemlist from collection.
ia search --itemlist "collection:bbsmagazine" | tee bbsmagazine.txt
Download torrent files from each item using parallel.
cat bbsmagazine.txt | parallel 'ia download --format "Archive BitTorrent" --destdir=/mnt/torrent_files {}'
Move .torrent files from their directories to /mnt/torrent_files.
find /mnt/torrent_files -type f -name "*.torrent" -exec mv {} /mnt/torrent_files \;
Note: .torrent files will be removed from
/mnt/torrent_filesby qBittorrent once they are added to the instance.
Remove empty directories.
find /mnt/torrent_files -maxdepth 1 -mindepth 1 -type d -delete
Kernel
Basic hardening
Disable coredumps
Edit /etc/security/limits.conf and append the following lines:
* hard core 0
* soft core 0
Edit /etc/sysctl.d/9999-disable-core-dump.conf:
fs.suid_dumpable=0
kernel.core_pattern=|/bin/false
Create and edit /etc/systemd/coredump.conf.d/custom.conf:
sudo mkdir /etc/systemd/coredump.conf.d/
sudo nvim /etc/systemd/coredump.conf.d/custom.conf
[Coredump]
Storage=none
ProcessSizeMax=0
Reload the daemons.
sudo systemctl daemon-reload
Edit /etc/systemd/system.conf. Make sure DefaultLimitCORE is commented out.
#DefaultLimitCORE=infinity
sudo systemctl daemon-reexec
Libvirt
Setup bridged networking with systemd-networkd
Edit /etc/systemd/network/br0.netdev.
[NetDev]
Name=br0
Kind=bridge
Edit /etc/systemd/network/br0.network.
[Match]
Name=br0
[Network]
Address=10.0.0.96/24
Gateway=10.0.0.1
Broadcast=10.0.0.255
Edit /etc/systemd/network/eth0.network.
[Match]
Name=eth0
[Network]
Bridge=br0
Restart systemd-networkd and verify.
sudo systemctl restart systemd-networkd.service
sudo networkctl status br0
sudo brctl show br0 # requires bridge-utils package
Edit bridge.xml.
<!-- bridge.xml -->
<network
<name>br0</name>
<forward mode="bridge"/>
<bridge name="br0"/>
</network>
Define, start, and verify the network.
sudo virsh net-define bridge.xml
sudo virsh net-start br0
sudo virsh net-autostart br0
sudo virsh net-list --all
Lutris
Add game-performance
- Go to Preferences -> Global options.
- Enable Advanced mode.
- Scroll down to Command prefix.
- Add
game-performanceto command prefix.
LVM
Add disk to LVM volume
Create a new physical volume on the new disk.
sudo pvcreate /dev/vdb
sudo lvmdiskscan -l
Add the newly created physical volume to an existing logical volume.
sudo vgextend almalinux /dev/vdb
Extend the /dev/almalinux/root to create a total 1000 GB.
sudo lvm lvextend -l +100%FREE /dev/almalinux/root
Grow the filesystem of the root volume.
# ext4
sudo resize2fs -p /dev/mapper/almalinux-root
# xfs
sudo xfs_growfs /
Neovim Cheatsheet
NERD Commenter
| Mode | Keybind | Action |
|---|---|---|
| normal | SPACE + cc | NERDCommenterComment |
| normal | SPACE + c + SPACE | NERDCommenterToggle |
| normal | SPACE + cm | NERDCommenterMinimal |
| normal | SPACE + cn | NERDCommenterNested |
| normal | SPACE + c$ | NERDCommenterToEOL |
| normal | SPACE + ci | NERDCommenterInvert |
| normal | SPACE + cs | NERDCommenterSexy |
| normal | SPACE + cy | NERDCommenterYank |
| normal | SPACE + cA | NERDCommenterAppend |
| normal | SPACE + cl | NERDCommenterAlignLeft |
| normal | SPACE + cb | NERDCommenterAlignBoth |
| normal | SPACE + cu | NERDCommenterUncomment |
| normal | SPACE + ca | NERDCommenterAltDelims |
Search
| Mode | Keybind | Action |
|---|---|---|
| normal | SPACE + sh | [S]earch [H]elp |
| normal | SPACE + sk | [S]earch [K]eymaps |
| normal | SPACE + sf | [S]earch [F]iles |
| normal | SPACE + ss | [S]earch [S]elect Telescope |
| normal | SPACE + sw | [S]earch current [W]ord |
| normal | SPACE + sg | [S]earch by [G]rep |
| normal | SPACE + sd | [S]earch [D]iagnostics |
| normal | SPACE + sr | [S]earch [R]esume |
| normal | SPACE + s. | [S]earch Recent Files (“.” for repeat) |
| normal | SPACE + SPACE | [ ] Find existing buffers |
| normal | SPACE + / | [/] Fuzzily search in current buffer |
| normal | SPACE + s/ | [S]earch [/] in Open Files |
| normal | SPACE + sn | [S]earch [N]eovim files |
| normal | ESC | nohlsearch |
Editing
| Mode | Keybind | Action |
|---|---|---|
| normal | sa | Add surrounding |
| normal | sd | Delete surrounding |
| normal | sr | Replace surrounding |
| normal | sf | Find right surrounding |
| normal | sF | Find left surrounding |
| normal | sh | Highlight surrounding |
| normal | Shift-o | Add empty line below cursor |
| normal | Shift-O | Add empty line above curosr |
| normal | SPACE + f | Format buffer |
| insert | Arrows | Traverse completion menu |
| insert | CTRL-y | Select completion |
Diagnostics
| Mode | Keybind | Action |
|---|---|---|
| normal | ]d | Jump to next diagnostic in current buffer |
| normal | ]D | Jump to last diagnostic in current buffer |
| normal | [d | Jump to previous diagnostic in current buffer |
| normal | [D | Jump to first diagnostic in current buffer |
| normal | SPACE + q | Open diagnostic [Q]uickfix list |
| normal | CTRL-w + d | Show diagnostics under cursor |
Splits and tabs
| Mode | Keybind | Action |
|---|---|---|
| command | :sp | Split window horizontally |
| command | :vsp | Split window vertically |
| command | :tabe | Create new tab |
| command | :tabc | Close the current tab |
| command | :tabn | Go to next tab |
| command | :tabp | Go to previous tab |
Networking
Disable IPv6 on Debian
Edit /etc/sysctl.conf.
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
Apply the changes.
sudo sysctl -p
Disable IPv6 on Fedora
sudo grubby --args=ipv6.disable=1 --update-kernel=ALL
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
Rename network interface when using systemd-networkd
Create a udev rule at /etc/udev/rules.d/70-my-net-names.rules.
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="your-mac-address", NAME="wlan0"
Using 70-my-net-name.rules as the filename ensures the rule is ordered before /usr/lib/udev/rules.d/80-net-setup-link.rules.
Connecting to WiFi network using systemd-networkd and wpa_supplicant
Create a file at /etc/wpa_supplicant/wpa_supplicant-wlan0.conf. Use wpa_passphrase to hash the passphrase.
wpa_passphrase your-ssid your-ssid-passphrase | sudo tee -a /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
Edit /etc/wpa_supplicant/wpa_supplicant-wlan0.conf.
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=0
update_config=1
network={
ssid="your-ssid"
psk="your-hashed-ssid-passphrase"
key_mgmt=WPA-PSK
proto=WPA2
scan_ssid=1
}
Create a file at /etc/systemd/network/25-wlan.network.
[Match]
Name=wlan0
[Network]
DHCP=ipv4
Enable and start the network services.
sudo systemctl enable --now wpa_supplicant@wlan0.service
sudo systemctl restart systemd-networkd.service
sudo systemctl restart wpa_supplicant@wlan0.service
Check the interface status with ip a.
Use tailnet DNS and prevent DNS leaks
After the above WiFi interface is setup, disable IPv6 as per the above sections, and enable the Tailscale service.
sudo systemctl enable --now tailscaled.service
sudo tailscale up
Edit /etc/systemd/network/25-wlan-network again, and add the following contents.
[Match]
Name=wlan0
[Network]
DHCP=ipv4
DNS=100.100.100.100
DNSSEC=allow-downgrade
[DHCPv4]
UseDNS=no
This will tell the wlan0 interface to use Tailscale’s MagicDNS, along with DNSSEC if it is available, and not to get the nameservers from the DHCPv4 connection.
NFS
Setup NFS server on Debian
sudo apt install -y nfs-kernel-server nfs-common
Configure NFSv4 in /etc/default/nfs-common.
NEED_STATD="no"
NEED_IDMAPD="yes"
Configure NFSv4 in /etc/default/nfs-kernel-server. Disable NFSv2 and NFSv3.
RPCNFSDOPTS="-N 2 -N 3"
RPCMOUNTDOPTS="--manage-gids -N 2 -N 3"
sudo systemctl restart nfs-server.service
Configure Firewalld.
sudo firewall-cmd --zone=public --permanent --add-service=nfs
sudo firewall-cmd --reload
Setup pseudo filesystem and exports.
sudo mkdir /shared
sudo chown -R nobody:nogroup /shared
Add exported directory to /etc/exports.
/shared <IP address of client>(rw,no_root_squash,no_subtree_check,crossmnt,fsid=0)
Create the NFS table.
sudo exportfs -a
Setup NFS client on Debian
sudo apt install -y nfs-common
Create shared directory.
sudo mkdir -p /mnt/shared
Mount NFS exports. We’ll assume the IP address of the NFS server is 10.0.0.64.
sudo mount.nfs4 10.0.0.64:/ /mnt/shared
Note that the
10.0.0.64:/is relative to the exported directory. So/mnt/sharedon the client is/sharedon the server. If you try to mount withmount -t nfs 10.0.0.64:/shared /mnt/sharedyou will get a no such file or directory error.
Edit /etc/fstab.
10.0.0.64:/ /mnt/shared nfs4 soft,intr,rsize=8192,wsize=8192
sudo systemctl daemon-reload
sudo mount -av
Setup NFS server on FreeBSD
Edit /etc/rc.conf.
nfs_server_enable="YES"
nfs_server_flags="-u -t -n 4"
rpcbind_enable="YES"
mountd_flags="-r"
mountd_enable="YES"
Edit /etc/exports.
/data1 -alldirs -mapall=user1 host1 host2 host3
/data2 -alldirs -maproot=user2 host2
Start the services.
sudo service rpcbind start
sudo service nfsd start
sudo service mountd start
After making changes to the exports file, you need to restart NFS for the changes to take effect.
kill -HUP `cat /var/run/mountd.pid`
Setup NFS client on FreeBSD
Edit /etc/rc.conf.
nfs_client_enable="YES"
nfs_client_flags="-n 4"
rpc_lockd_enable="YES"
rpc_statd_enable="YES"
Mount NFS share on client with systemd
Create a file at /etc/systemd/system/mnt-backup.mount.
[Unit]
Description=borgbackup NFS share from FreeBSD
DefaultDependencies=no
Conflicts=umount.target
After=network-online.target remote-fs.target
Before=umount.target
[Mount]
What=10.0.0.119:/coffeeNAS/borgbackup/repositories
Where=/mnt/backup
Type=nfs
Options=defaults,vers=3
[Install]
WantedBy=multi-user.target
Nmap
Target specification
| Example | Description |
|---|---|
nmap 192.168.1.1 | Scan a single IP |
nmap 192.168.1.1 192.168.2.1 | Scan specific IPs |
nmap 192.168.1.1-254 | Scan a range |
nmap scanme.nmap.org | Scan a domain |
nmap 192.168.1.0/24 | Scan using CIDR notation |
nmap -iL targets.txt | Scan targets from a file |
nmap -iR 100 | Scan 100 random hosts |
nmap -exclude 192.168.1.1 | Exclude listed hosts |
Nmap scan techniques
| Example | Description |
|---|---|
nmap 192.168.1.1 -sS | TCP SYN port scan (default) |
nmap 192.168.1.1 -sT | TCP connect port scan |
nmap 192.168.1.1 -sU | UDP port scan |
nmap 192.168.1.1 -sA | TCP ACK port scan |
nmap 192.168.1.1 -sW | TCP Window port scan |
nmap 192.168.1.1 -sM | TCP Maimon port scan |
Host discovery
| Example | Description |
|---|---|
nmap 192.168.1.1-3 -sL | No scan. List targets only |
nmap 192.168.1.1/24 -sn | Disable port scanning. Host discovery only. |
nmap 192.168.1.1-5 -Pn | Disable host discovery. Port scan only. |
nmap 192.168.1.1-5 -PS22-25,80 | TCP SYN discovery on ports 22-25, 80 (Port 80 by default) |
nmap 192.168.1.1-5 -PA22-25,80 | TCP ACK discovery on ports 22-25, 80 (Port 80 by default) |
nmap 192.168.1.1-5 -PU53 | UDP discovery on port 53. (Port 40125 by default) |
nmap 192.168.1.1-1/24 -PR | ARP discovery on local network |
nmap 192.168.1.1 -n | Never do DNS resolution |
Port specification
| Example | Description |
|---|---|
nmap 192.168.1.1 -p 21 | Port scan for port 21 |
nmap 192.168.1.1 -p 21-100 | Port scan for range 21-100 |
nmap 192.168.1.1 -p U:53,T:21-25,80 | Port scan multiple TCP and UDP ports |
nmap 192.168.1.1 -p- | Port scan all ports |
nmap 192.168.1.1 -p http,https | Port scan from service name |
nmap 192.168.1.1 -F | Fast port scan (100 ports) |
nmap 192.168.1.1 -top-ports 2000 | Port scan the top 2000 ports |
nmap 192.168.1.1 -p-65535 | Leaving off the initial port in range makes the scan start at port 1 |
nmap 192.168.1.1 -p0- | Leaving off the end port in range makes the scan go through to port 65535 |
Service and version detection
| Example | Description |
|---|---|
nmap 192.168.1.1 -sV | Attempts to determine version of the service running on port. |
nmap 192.168.1.1 -sV -version-intensity 8 | Intensity level 0-9. Higher number increases possibility of correctness. |
nmap 192.168.1.1 -sV -version-light | Enable light mode. Lower possibility of correctness. Faster. |
nmap 192.168.1.1 -sV -version-all | Enable intensity level 9. Higher possibility of correctness. Slower. |
nmap 192.168.1.1 -A | Enable OS detection, version detection, script scanning, and traceroute. |
OS detection
| Example | Description |
|---|---|
nmap 192.168.1.1 -O | Remote OS detection using TCP/IP stack fingerprinting |
nmap 192.168.1.1 -O -osscan-limit | If at least one open and one closed TCP port are not found it will not try OS detection against host. |
nmap 192.168.1.1 -P -osscan-guess | Makes nmap guess more aggressively. |
nmap 192.168.1.1 -O -max-os-tries 1 | Set the maximum number of OS detection tries |
nmap 192.168.1.1 -A | Enables OS detection, version detection, script scanning, and traceroute. |
Timing and performance
| Example | Description |
|---|---|
nmap 192.168.1.1 -T0 | Paranoid (0) IDS evasion |
nmap 192.168.1.1 -T1 | Sneaky (1) IDS evasion |
nmap 192.168.1.1 -T2 | Polite (2) slows down the scan to use less bandwidth and use less target machine resources. |
nmap 192.168.1.1 -T3 | Normal (3) which is default speed. |
nmap 192.168.1.1 -T4 | Aggressive (4) speed scans. Assumes you are on a reasonably fast and reliable network. |
nmap 192.168.1.1 -T5 | Insane (5) speed scan. Assumes you are on an extraordinarily fast network. |
Timing and performance switches
| Example | Description |
|---|---|
-host-timeout 1s; -host-timeout 4m; | Give up on target after this long. |
-min-rtt-timeout/max-rtt-timeout/initial-rtt-timeout 4m; | Specifies probe round trip time. |
-min-hostgroup/max-hostgroup 50 | Parallel host scan group sizes |
-min-parallelism/max-parallelism 10 | Probe parallelization |
-max-retries 3 | Specify the max number of port scan probe retransmissions. |
-min-rate 100 | Send packets to no slower than 100 per second |
-max-rate 100 | Send packets no faster than 100 per second |
NSE scripts
| Example | Description |
|---|---|
nmap 192.168.1.1 -sC | Scan with default NSE scripts. Useful and safe. |
nmap 192.168.1.1 -script default | Scan with default NSE scripts. |
nmap 192.168.1.1 -script=banner | Scan with single script. Example banner. |
nmap 192.168.1.1 -script=http* | Scan with a wildcard. Example http. |
nmap 192.168.1.1 -script=http,banner | Scan with two scripts. http and banner. |
nmap 192.168.1.1 -script "not intrusive" | Scan default, but remove intrusive scripts. |
nmap -script snmp-sysdescr -script-args snmpcommunity=admin 192.168.1.1 | NSE script with arguments |
Useful NSE script examples
| Example | Description |
|---|---|
nmap -Pn -script=http-sitemap-generator scanme.nmap.org | http site map generator |
nmap -n -Pn -p 80 -open -sV -vvv -script banner,http-title -iR 1000 | Fast search for random web servers |
nmap -Pn -script=dns-brute domain.com | Brute forces DNS hostnames guessing subdomains |
nmap -n -Pn -vv -O -sV -script smb-enum*,smb-ls,smb-mbenum,smb-os-discovery,smb-s*,smb-vuln*,smbv2* -vv 192.168.1.1 | Safe SMB scripts to run |
nmap -script whois* domain.com | Whois query |
nmap -p80 -script http-unsafe-output-escaping scanme.nmap.org | Detect cross site scripting vulnerabilities |
nmap -p80 -script http-sql-injection scanme.nmap.org | Check for SQL injections |
Firewall/IDS evasion and spoofing
| Example | Description |
|---|---|
nmap 192.168.1.1 -f | Requested scan (including ping scans) use tiny fragmented IP packets. Harder for packet filters. |
nmap 192.168.1.1 -mtu 32 | Set your own offset size |
nmap -D 192.168.1.101,192.168.1.102,192.168.1.103 | Send scans from spoofed IPs |
nmap -D decoy-ip1,decoy-ip2,your-own-ip | Same as above |
nmap -S www.microsoft.com www.facebook.com | Scan Facebook from Microsoft (-e eth0 -Pn may be required |
nmap -g 53 192.168.1.1 | Use given source port number |
nmap -proxies http://192.168.1.1:8080,http://192.168.1.2:8080,http://192.168.1.2:8080 | Relay connections through HTTP/SOCKS4 proxies |
nmap -data-length 200 192.168.1.1 | Appends random data to sent packets |
Output
| Example | Description |
|---|---|
nmap 192.168.1.1 -oN normal.file | Normal output to the file normal.file |
nmap 192.168.1.1 -oX xml.file | XML output to the file xml.file |
nmap 192.168.1.1 -oG grep.file | Grepable output to the file grep.file |
nmap 192.168.1.1 -oA results | Output in the three major formats at once |
nmap 192.168.1.1 -oG - | Grepable output to screen. -oN, -oX also usable. |
nmap 192.168.1.1 -oN file.txt -append-output | Append a scan to a previous scan file |
nmap 192.168.1.1 -v | Increase verbosity level (use -vv or more) |
nmap 192.168.1.1 -d | Increase debugging level (use -dd or more) |
nmap 192.168.1.1 -reason | Display the reason a port is in a particular state, same output as -vv |
nmap 192.168.1.1 -open | Only show open (or possibly open) ports |
nmap 192.168.1.1 -T4 -packet-trace | Show all packets sent and received |
nmap -iflist | Shows the host interfaces and routes |
nmap -resume results.file | Resume a scan from results.file |
Helpful nmap output examples
Scan for web servers and grep to show IPs running web servers
nmap -p80 -sV -oG - -open 192.168.1.1/24 | grep open
Generate a list of IPs of live hosts
nmap -iR 10 -n -oX out.xml | grep "Nmap" | cut -d " " -f5 > live-hosts.txt
Append IP to the list of live hosts
nmap -iR 10 -n -oX out2.xml | grep "Nmap" | cut -d "" -f5 >> live-hosts.txt
Compare output of two scan results
ndiff scan.xml scan2.xml
Convert nmap xml files to html files
xsltproc nmap.xml -o nmap.html
Other useful nmap commands
| Example | Description |
|---|---|
nmap -iR 10 -PS22-25,80,113,1050,35000 -v -sn | Discovery only on ports X, no port scan |
nmap 192.168.1.1-1/24 -PR -sn -vv | ARP discovery only on local network, no port scan |
nmap -iR 10 -sn -traceroute | Traceroute to random targets, no port scan |
nmap 192.168.1.1-50 -sL -dns-server 192.168.1.1 | Query the internal DNS for hosts, list targets only |
nmap 192.168.1.1 --packet-trace | Show the details of the packets that are sent and received during a scan and capture the traffic |
Orange Pi 5+
Disable blinky LEDs
Edit /etc/udev/rules.d/led_control.rules.
SUBSYSTEM=="leds", KERNEL=="blue_led", ACTION=="add", ATTR{trigger}="none"
SUBSYSTEM=="leds", KERNEL=="green_led", ACTION=="add", ATTR{trigger}="none"
SUBSYSTEM=="leds", KERNEL=="mmc0::", ACTION=="add", ATTR{trigger}="none"
Reboot the system.
Packet Tracer
Fix GUI issues with KDE Plasma dark theme
mkdir ~/.config-pt
cd ~/.config
cp -rf dconf gtk-3.0 gtk-4.0 xsettingsd ~/.config-pt
- Right-click on Menu button.
- Click Edit Applications.
- Select Packet Tracer.
- Add
XDG_CONFIG_HOME=/home/jas/.config-ptto Environment variables. - Save.
Parallel
Pulling files from remote server with rsync
To transfer just the files:
ssh user@remote -- find /path/to/parent/directory -type f | parallel -v -j16 rsync -Havessh -aAXP user@remote:{} /local/path
To transfer the entire directory:
echo "/path/to/parent/directory" | parallel -v -j16 rsync -Havessh -aAXP user@remote:{} /local/path
Pushing files to remote server with rsync
To transfer just the files:
find /path/to/local/directory -type f | parallel -v -j16 -X rsync -aAXP /path/to/local/directory/{} user@remote:/path/to/dest/directory
Running the same command on multiple remote hosts
parallel --tag --nonall -S remote0,remote1,remote2 uptime
PostgreSQL
Change password for user
sudo -u user_name psql db_name
ALTER USER user_name WITH PASSWORD 'new_password';
Update password auth method to SCRAM
Edit /etc/postgresql/16/main/postgresql.conf.
password_encryption = scram-sha-256
Restart postgresql.service.
At this point, any services using the old MD5 auth method will fail to connect to their PostgreSQL databases.
Update the settings in /etc/postgresql/16/main/pg_hba.conf.
TYPE DATABASE USER ADDRESS METHOD
local all mastodon scram-sha-256
local all synapse_user scram-sha-256
Enter a psql shell and determine who needs to upgrade their auth method.
SELECT rolname, rolpassword ~ '^SCRAM-SHA-256\$' AS has_upgraded FROM pg_authid WHERE rolcanlogin;
\password username
Restart postgresql.service and all services using a PostgreSQL database.
Qcow2
Mount qcow2 image
Enable NBD on the host.
sudo modprobe nbd max_part=8
Connect qcow2 image as a network block device.
sudo qemu-nbd --connect=/dev/nbd0 /path/to/image.qcow2
Find the VM’s partitions.
sudo fdisk /dev/nbd0 -l
Mount the root partition from the VM.
sudo mount /dev/nbd0p3 /mnt/point
To unmount:
sudo umount /mnt/point
sudo qemu-nbd --disconnect /dev/nbd0
sudo rmmod nbd
Resize qcow2 image
Install guestfs-tools (required for virt-resize command).
sudo dnf install -y guestfs-tools
sudo apt install -y guestfs-tools libguestfs-tools
To resize qcow2 images, you’ll have to create a new qcow2 image with the size you want, then use virt-resize on the old qcow2 image to the new one.
You’ll need to know the root partition within the old qcow2 image.
Create a new qcow2 image with desired size.
qemu-img create -f qcow2 -o preallocation=metadata newdisk.qcow2 100G
Now resize the old one to the new one.
virt-resize --expand /dev/vda3 olddisk.qcow2 newdisk.qcow2
Once you boot into the new qcow2 image, you’ll probably have to adjust the size of the logical volume if it has LVM.
sudo lvresize -l +100%FREE /dev/mapper/sysvg-root
Then resize the XFS root partition within the logical volume.
sudo xfs_growfs /dev/mapper/sysvg-root
Qemu
Take snapshot of VM
sudo virsh domblklist vm1
sudo virsh snapshot-create-as \
--domain vm1 \
--name guest-state1 \
--diskspec vda,file=/var/lib/libvirt/images/overlay1.qcow2 \
--disk-only \
--atomic \
--quiesce
Ensure qemu-guest-agent is installed inside the VM. Otherwise omit the --quiesce flag, but when you restore the VM it will be as if the system had crashed. Not that big of a deal since the VM’s OS should flush required data and maintain consistency of its filesystem.
sudo rsync -avhW --progress /var/lib/libvirt/images/vm1.img /var/lib/libvirt/images/vm1-copy.img
sudo virsh blockcommit vm1 vda --active --verbose --pivot
Full disk backup of VM
Start the guest VM.
sudo virsh start vm1
Enumerate the disk(s) in use.
sudo virsh domblklist vm1
Begin the backup.
sudo virsh backup-begin vm1
Check the job status. “None” means the job has likely completed.
sudo virsh domjobinfo vm1
Check the completed job status.
sudo virsh domjobinfo vm1 --completed
Now we see the copy of the backup.
sudo ls -lash /var/lib/libvirt/images/vm1.qcow2*
Resident Evil HD
Installation
- Download Resident Evil Classic Triple Pack PC from archive.org. This contains the Sourcenext versions of all three games.
- Install all three games using their installers.
- Download the following files:
- Biohazard PC CD-ROM Mediakite patch version 1.01
- Resident Evil Classic REbirth
- Resident Evil 2 Classic REbirth
- Resident Evil 3 Classic REbirth
- Biohazard Mediakite
- Resident Evil HD mod by TeamX
- Resident Evil 2 HD mod by TeamX
- Resident Evil 3 HD mod by TeamX
- Resident Evil Seamless HD Project v1.1
- Resident Evil 2 Seamless HD Project v2.0
- Resident Evil 3: Nemesis Seamless HD Project v2.0
- Open the Biohazard Mediakite disc image with 7zip and drag the JPN folder from the disc into
C:\Program Files (x86)\Games Retro\Resident Evil Classic
Resident Evil Director’s Cut
Extract the following files to %ProgramFiles(x86)%\Games Retro\Resident Evil Classic:
Biohazard.exefrom Mediakite v1.01ddraw.dllfrom Resident Evil Classic REbirth- All from Resident Evil HD mod by TeamX
- All from Resident Evil Seamless HD Project v1.1
Resident Evil 2
Extract the following files to %ProgramFiles(x86)%\Games Retro\BIOHAZARD 2 PC:
ddraw.dllfrom Resident Evil 2 Classic REbirth- All from Resident Evil 2 HD mod by TeamX
- All from Resident Evil 2 Seamless HD Project v2.0
Resident Evil 3: Nemesis
Extract the following files to %ProgramFiles(x86)%\Games Retro\BIOHAZARD 3 PC:
ddraw.dllfrom Resident Evil 3 Classic REbirth- All from Resident Evil 3 HD mod by TeamX
- All from Resident Evil 3: Nemesis Seamless HD Project v2.0
Testing
Test each game by launching them with the following config changes:
- Resolution 1280x960
- RGB88 colors
- Disable texture filtering
RetroPie
Bluetooth: protocol not available
sudo apt install pulseaudio-module-bluetooth
Add to /lib/systemd/system/bthelper@.service.
ExecStartPre=/bin/sleep 4
sudo systemctl start sys-subsystem-bluetooth-devices-hci0.device
sudo hciconfig hci0 down
sudo killall pulseaudio
systemctl --user enable --now pulseaudio.service
sudo systemctl restart bluetooth.service
Router
- Ubuntu 24.04
- Orange Pi 5 Plus
- ISP router in bridge mode
- Ethernet from ISP router -> Orange Pi 5 Plus WAN port
- Ethernet from Orange Pi 5 Plus LAN port to switch
Install packages
sudo apt install -y neovim firewalld fail2ban atop htop python3-dev nmap tcpdump rsync rsyslog iptraf-ng iftop sysstat conntrack logwatch unattended-upgrades byobu
Register router as Tailnet node.
sudo systemctl enable --now tailscaled.service
sudo tailscale up
Netplan with DHCP WAN
Edit /etc/netplan/01-netcfg.yaml.
network:
version: 2
renderer: networkd
ethernets:
eth0: # WAN interface (connected to internet)
dhcp4: true
dhcp6: false
nameservers:
addresses:
- 9.9.9.9
- 149.112.112.112
eth1: # LAN interface (connected to local network)
dhcp4: false
dhcp6: false
addresses:
- 10.0.2.1/24
nameservers:
addresses:
- 9.9.9.9
- 149.112.112.112
Bridged LAN+WiFi AP
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: true
dhcp6: false
nameservers:
addresses:
- 9.9.9.9
- 149.112.112.112
eth1:
dhcp4: false
dhcp6: false
addresses:
- 10.0.2.1/24
nameservers:
addresses:
- 9.9.9.9
- 149.112.112.112
wifis:
wlan0:
access-points:
coffeenet:
auth:
key-management: psk
password: "password"
bridges:
br0:
interfaces:
- eth1
- wlan0
addresses:
- 10.0.2.1/24
nameservers:
addresses:
- 9.9.9.9
- 149.112.112.112
Netplan with static IP
network:
version: 2
renderer: networkd
ethernets:
eth0: # WAN interface (connected to internet)
addresses:
- WAN public IP/prefix
nameservers:
addresses:
- 9.9.9.9
- 149.112.112.112
routes:
- to: default
via: WAN default gateway
metric: 100
eth1:
dhcp4: false
dhcp6: false
addresses:
- 10.0.2.1/24
nameservers:
addresses:
- 9.9.9.9
- 149.112.112.112
Bridged LAN+WiFi AP
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: false
dhcp6: false
addresses:
- WAN public IP
nameservers:
addresses:
- 9.9.9.9
- 149.112.112.112
routes:
- to: default
via: WAN default gateway
metric: 100
eth1:
dhcp4: false
dhcp6: false
addresses:
- 10.0.2.1/24
nameservers:
addresses:
- 9.9.9.9
- 149.112.112.112
wifis:
wlan0:
access-points:
coffeenet:
auth:
key-management: psk
password: "password"
bridges:
br0:
interfaces:
- eth1
- wlan0
addresses:
- 10.0.2.1/24
nameservers:
addresses:
- 9.9.9.9
- 149.112.112.112
Apply the netplan settings.
sudo netplan apply
IP forwarding
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Firewalld
sudo firewall-cmd --permanent --zone=home --add-interface=br0
sudo firewall-cmd --permanent --zone=home --add-service={ssh,dns,http,https,dhcp}
sudo firewall-cmd --permanent --zone=home --add-forward
sudo firewall-cmd --permanent --zone=external --add-interface=eth0
sudo firewall-cmd --permanent --zone=external --add-service=dhcpv6-client
sudo firewall-cmd --permanent --zone=external --add-forward
Create /etc/firewalld/policies/masquerade.xml to allow traffic to flow from LAN to WAN.
<?xml version="1.0" encoding="utf-8"?>
<policy target="ACCEPT">
<masquerade/>
<ingress-zone name="home"/>
<egress-zone name="external"/>
</policy>
Reload the firewalld configuration.
sudo firewall-cmd --reload
RSS
Source: Simple RSS, Atom, and JSON feed for your blog
RSS
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Example website title</title>
<link>https://example.com</link>
<description>Example website description.</description>
<atom:link href="https://example.com/rss.xml" rel="self" type="application/rss+xml" />
<item>
<title>Post one</title>
<link>https://example.com/posts-one</link>
<description>Post one content.</description>
<guid isPermaLink="true">https://example.com/posts-one</guid>
<pubDate>Mon, 22 May 2023 13:00:00 -0600</pubDate>
</item>
<item>
<title>Post two</title>
<link>https://example.com/posts-two</link>
<description>Post two content.</description>
<guid isPermaLink="true">https://example.com/posts-two</guid>
<pubDate>Mon, 15 May 2023 13:00:00 -0600</pubDate>
</item>
</channel>
</rss>
Atom
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>http://example.com/</id>
<title>Example website title</title>
<updated>2023-05-22T13:00:00.000Z</updated>
<author>
<name>John Doe</name>
</author>
<link href="https://example.com/atom.xml" rel="self" type="application/rss+xml" />
<subtitle>Example website description.</subtitle>
<entry>
<id>https://example.com/posts-one</id>
<title>Post one</title>
<link href="https://example.com/posts-one"/>
<updated>2023-05-22T13:00:00.000Z</updated>
<summary type="html">https://example.com/posts-one</summary>
<content type="html">Post one content.</content>
</entry>
<entry>
<id>https://example.com/posts-two</id>
<title>Post two</title>
<link href="https://example.com/posts-two"/>
<updated>2023-05-15T13:00:00.000Z</updated>
<summary type="html">https://example.com/posts-two</summary>
<content type="html">Post two content.</content>
</entry>
</feed>
JSON
{
"version": "https://jsonfeed.org/version/1.1",
"title": "Example website title",
"home_page_url": "https://example.com",
"feed_url": "https://example.com/feed.json",
"description": "Example website description.",
"items": [
{
"id": "https://example.com/posts-one",
"url": "https://example.com/posts-one",
"title": "Post one content.",
"content_text": "Post one content.",
"date_published": "2023-05-22T13:00:00.000Z"
},
{
"id": "https://example.com/posts-two",
"url": "https://example.com/posts-two",
"title": "Post two content.",
"content_text": "Post two content.",
"date_published": "2023-05-15T13:00:00.000Z"
}
]
}
Resources
- The RSS 2.0 Specification
- The Atom Syndication Format Specification
- The JSON Feed Version 1.1 Specification
- RSS and Atom Feed validator
- JSON Feed validator
Steam
Capturing and sharing Proton logs
- Right-click on the game in Steam and select Properties.
- Under Launch Options, add the following.
PROTON_LOG=1 PROTON_LOG_DIR=/home/jas/steam-proton-logs %command%
game-performance
To use CachyOS’s game-performance script to switch power profiles while a game is running, add the following to each Steam game’s Launch Options:
game-performance %command%
Combined with the Proton logging options:
PROTON_LOG=1 PROTON_LOG_DIR=/home/jas/steam-proton-logs game-performance %command%
Pre-caching shaders with Proton-CachyOS, -GE, -EM
Pre-caching of shaders is not needed on CachyOS, as Proton-CachyOS already contains all the necessary codecs.
- Go to Steam Setttings -> Downloads
- Go to the SHADER PRE-CACHING section
- Disable Shader Pre-caching
- Disable Allow background processing of Vulkan shaders
Systemd
Install systemd-boot on Debian
sudo mkdir /boot/efi/loader
printf "default systemd\ntimeout 5\neditor 1\n" | sudo tee /boot/efi/loader/loader.conf
sudo mkdir -p /boot/efi/loader/entries
sudo apt install -y systemd-boot
sudo bootctl install --path=/boot/efi
Check efibootmgr.
sudo efibootmgr
Output:
BootOrder: 0000,0001
Boot0000* Linux Boot Manager
Mount NFS share
See NFS
UFW
Allow ports only on specific interface
sudo ufw allow in on tailscale0 to any port 22 proto tcp
Weechat
Smart filter for JOIN, PART, QUIT
/set irc.look.smart_filter on
/filter add irc_smart * irc_smart_filter *