Welcome to the Café

Explore the world of Linux with clear, approachable guides. Whether you’re just starting out or looking to sharpen your skills, you’ll find something to brew your interest here.

How I Use Find and Xargs to Delete Temp Files Older Than 7 Days Without Risking rm ‑rf

Cleaning up old temp files is a daily chore that can quickly become dangerous if you use the wrong tool.
A single misplaced rm -rf can wipe out a whole directory tree, and that risk grows when you’re running scripts as root.
The combination of find and xargs (or -delete) gives you a precise, race‑condition‑aware way to target only the files you really want gone.

Why find + xargs beats a blind rm -rf

  • Scope control – find lets you restrict the search to a specific path, depth, file type, age, size, or owner.
  • Safety – -delete removes only the matched files; it never walks into a directory you didn’t ask for.
  • Speed – xargs batches deletions, reducing the number of rm invocations.
  • Robustness – -print0 + xargs -0 handles filenames with spaces, newlines, or other odd characters.

A minimal, production‑ready command

# Delete regular files in /tmp older than 7 days
find /tmp -type f -mtime +7 -print0 | xargs -0 rm -v
  • -type f skips directories and symlinks.
  • -mtime +7 matches files whose modification time is more than seven days ago.
  • -print0 outputs a null‑terminated list; xargs -0 consumes it safely.
  • -v gives you a quick audit trail.

If you prefer a single‑step solution and your find supports it, replace the pipe with -delete:

[Read More]

Fixing ACME DNS‑01 on a Home Lab Using Pi‑hole and Cloudflare

Running a single DNS server on a Raspberry Pi or a tiny VM is a common pattern in home labs.
When Let’s Encrypt asks you to prove domain ownership via a DNS‑01 challenge, the classic “edit a TXT record” dance becomes a chore if you’re juggling Cloudflare’s web UI.
Below is a quick, repeatable recipe that plugs a Pi‑hole into Cloudflare’s API, lets Cert‑bot finish the challenge automatically, and keeps the whole thing lean and secure.

[Read More]

How I stopped a 16‑GB microSD Raspberry Pi from dying mid‑boot because /var/log grew to 10 GB after a year of unattended cron jobs

Raspberry Pi’s are perfect for low‑power tinkering, but a 16‑GB microSD can start biting back if something writes too much data. After a year of unattended cron jobs, my Pi’s /var/log ballooned to 10 GB and the boot process stalled. Below is the exact walk‑through I used to bring the system back online and prevent a repeat.

Why the logs ate the SD card

The default Raspberry Pi OS ships with systemd‑journald for kernel and service logs and rsyslog for the classic syslog files. Both dump their output into /var/log. If you run cron jobs that spit out text and you don’t redirect or limit that output, each run just appends. Over a year, even a few megabytes per job can turn into gigabytes. The SD card’s limited write endurance means a bloated log file can accelerate wear‑out.

[Read More]

How a Forgotten SSH Key Stopped My Nightly Off‑Site Borg Backup and the Quick Fix I Implemented

The night I lost an off‑site Borg backup

I run a 24/7 home‑lab server that backs up my home directories to a remote NAS with Borg. The backup is triggered by a systemd timer that fires every night at 02:00 UTC. For months it worked flawlessly, but one morning the timer ran, the job logged “ssh: connect to host …: Permission denied”, and the backup vanished into the night. The culprit? A forgotten SSH key.

[Read More]

Why my 4GB Raspberry Pi 4 keeps swapping during a Python script – and how I fixed it by moving swap to USB

Why the Pi keeps swapping

I was running a memory‑hungry Python data‑pipeline on a 4 GB Raspberry Pi 4 when the system started thrashing every few minutes. top was showing swap usage climbing to 90 % while my script was still busy. The Pi’s 4 GB RAM was the hard limit, and the default swap file on the SD card was the culprit.

The culprit

The SD card is the only storage medium on the Pi, but it’s also the slowest. When the kernel starts paging, it writes to the swap file on the card, creating I/O bottlenecks that stall the Python interpreter. The swap file is defined in /etc/fstab:

[Read More]

Rescuing a system that boots to emergency mode because /boot ran out of space

When /boot runs out of space and the machine drops into emergency mode

A few minutes after a kernel update, you power on the server and the console shows:

System boot failed.
Emergency mode - type "journalctl -xb" to view logs.

The root filesystem is mounted read‑only, the initramfs cannot be loaded, and the machine refuses to start. The culprit is almost always a full /boot partition. In this post I walk through the exact steps to diagnose, free space, and reboot safely. I’ll cover the most common distributions, show how to keep the system lean, and touch on security best‑practices that come with kernel housekeeping.

[Read More]

When systemd‑journald ate my 2 GB SSD: how I capped it to 200 MB in a single config line

I was running a little home‑lab server on a 2 GB SSD. The board was an Orange Pi Zero‑like single‑board computer, and it was juggling a personal web server, a GitLab instance, and a handful of containerised apps. After a month of steady traffic, the SSD hit 100 % on /var. The culprit? systemd‑journald had quietly gobbled up the whole drive.

journald is the default logger on most modern distros. It keeps logs in binary form under /var/log/journal. By default it will keep everything until the filesystem is full, then start deleting the oldest entries. On a tiny SSD that can happen faster than you can say “disk full”.

[Read More]

Why My Home Server Keeps Crashing After Reboot: Fixing the Broken systemd Service for My Docker Compose Deployment

The mystery of the reboot crash

I had a single‑board server running Debian 12 in my living‑room. Every time I rebooted it, the Docker Compose stack that powers my home‑lab services would fail to start, and the machine would hang in a boot loop. The logs were a jumble of “failed to start” messages, but the root cause turned out to be a mis‑configured systemd unit. Below is the exact process I followed to diagnose and fix the issue, with a few trade‑offs and security notes that apply to any Docker‑based deployment on a small server.

[Read More]

Freeing a Full `/var/log` on a Home Lab Server with `journalctl --vacuum-time` and a One‑Line Bash Cleanup

When /var/log fills up

I’ve run a handful of services on my homelab box—Docker containers, an Nginx reverse proxy, a Samba share, and a few cron jobs that ping my home router. It’s a quiet machine most of the time, but every so often the disk starts choking on logs. When /var/log hits the filesystem limit, new log entries stop, services can silently die, and journalctl starts spitting out “no space left on device”. The fix is usually a quick vacuum of the journal and a tidy‑up of the plain‑text logs. Below is a step‑by‑step recipe that works on Debian, Ubuntu, Arch, and other systemd‑based distros.

[Read More]

Why ssh keeps spawning new processes on every connect and how ControlPersist solves it

Why SSH keeps spawning new processes on every connect

Every time I run ssh host, the client forks a new process that talks to the remote sshd.
On the server side, sshd spawns a child for each accepted connection.
The model is simple and works fine for a handful of sessions, but it starts to feel like a drain when you:

  • run a script that opens dozens of SSH connections in a row,
  • use CI/CD pipelines that hit a remote host repeatedly, or
  • have a home‑lab with many small services that need quick SSH access.

Each fork eats a few kilobytes of RAM and a handful of file descriptors.
If you hit the per‑user process limit (ulimit -u) or the system’s max_user_processes, you’ll see “Too many users” or “Connection refused” errors.
Even on a modest machine, the cumulative CPU cost of negotiating the SSH handshake over and over can add up.

[Read More]