Compare commits
No commits in common. "7e422ee332356633ee678f4553514373587b794b" and "f40f497b464197e65cbdb16dbcf1604f9abd18a9" have entirely different histories.
7e422ee332
...
f40f497b46
29 changed files with 197 additions and 851 deletions
|
|
@ -1,36 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
# pre-commit — fail if a newly-added article is not linked from SUMMARY.md.
|
|
||||||
# Bypass with `git commit --no-verify` if you genuinely need to.
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Articles being added or renamed in this commit (excludes meta/index/README/SUMMARY/MajorWiki-Deploy-Status, and any */index.md).
|
|
||||||
added=$(git diff --cached --name-only --diff-filter=AR -- '*.md' \
|
|
||||||
| grep -vE '^(README|index|SUMMARY|MajorWiki-Deploy-Status)\.md$|/index\.md$' \
|
|
||||||
|| true)
|
|
||||||
|
|
||||||
[ -z "$added" ] && exit 0
|
|
||||||
|
|
||||||
# Read the staged SUMMARY.md if it's part of the commit; otherwise the working-tree copy.
|
|
||||||
if git diff --cached --name-only | grep -q '^SUMMARY\.md$'; then
|
|
||||||
summary=$(git show :SUMMARY.md)
|
|
||||||
else
|
|
||||||
summary=$(cat SUMMARY.md)
|
|
||||||
fi
|
|
||||||
|
|
||||||
missing=()
|
|
||||||
while IFS= read -r article; do
|
|
||||||
[ -z "$article" ] && continue
|
|
||||||
if ! grep -qF -- "$article" <<<"$summary"; then
|
|
||||||
missing+=("$article")
|
|
||||||
fi
|
|
||||||
done <<<"$added"
|
|
||||||
|
|
||||||
if [ ${#missing[@]} -gt 0 ]; then
|
|
||||||
echo "✗ pre-commit: new article(s) not linked from SUMMARY.md:" >&2
|
|
||||||
printf ' %s\n' "${missing[@]}" >&2
|
|
||||||
echo "" >&2
|
|
||||||
echo "Add a SUMMARY.md entry for each, or use 'git commit --no-verify' to bypass." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
|
|
@ -10,7 +10,7 @@ tags:
|
||||||
- majorrig
|
- majorrig
|
||||||
status: published
|
status: published
|
||||||
created: 2026-03-16
|
created: 2026-03-16
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-29T22:45
|
||||||
---
|
---
|
||||||
|
|
||||||
# WSL2 Backup via PowerShell Scheduled Task
|
# WSL2 Backup via PowerShell Scheduled Task
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ tags:
|
||||||
- remote-access
|
- remote-access
|
||||||
status: published
|
status: published
|
||||||
created: 2026-03-08
|
created: 2026-03-08
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-22T09:20
|
||||||
---
|
---
|
||||||
|
|
||||||
# SSH Config and Key Management
|
# SSH Config and Key Management
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ tags:
|
||||||
- asus
|
- asus
|
||||||
- ssh
|
- ssh
|
||||||
created: 2026-04-19
|
created: 2026-04-19
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-29T22:45
|
||||||
---
|
---
|
||||||
|
|
||||||
# Wake-on-LAN via Router SSH
|
# Wake-on-LAN via Router SSH
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
created: 2026-04-13T10:15
|
created: 2026-04-13T10:15
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-29T22:45
|
||||||
---
|
---
|
||||||
# 🏠 Self-Hosting & Homelab
|
# 🏠 Self-Hosting & Homelab
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,11 @@
|
||||||
---
|
---
|
||||||
title: Tuning Netdata Docker Health Alarms to Prevent Update Flapping
|
title: "Tuning Netdata Docker Health Alarms to Prevent Update Flapping"
|
||||||
domain: selfhosting
|
domain: selfhosting
|
||||||
category: monitoring
|
category: monitoring
|
||||||
tags:
|
tags: [netdata, docker, nextcloud, alarms, health, monitoring]
|
||||||
- netdata
|
|
||||||
- docker
|
|
||||||
- nextcloud
|
|
||||||
- alarms
|
|
||||||
- health
|
|
||||||
- monitoring
|
|
||||||
status: published
|
status: published
|
||||||
created: 2026-03-18
|
created: 2026-03-18
|
||||||
updated: 2026-05-02T11:04
|
updated: 2026-03-28
|
||||||
---
|
---
|
||||||
|
|
||||||
# Tuning Netdata Docker Health Alarms to Prevent Update Flapping
|
# Tuning Netdata Docker Health Alarms to Prevent Update Flapping
|
||||||
|
|
@ -67,9 +61,9 @@ chart labels: container_name=!nextcloud-aio-nextcloud *
|
||||||
|
|
||||||
### Dedicated Nextcloud AIO Alarm
|
### Dedicated Nextcloud AIO Alarm
|
||||||
|
|
||||||
Added 2026-03-23, updated 2026-05-02. The `nextcloud-aio-nextcloud` container needs a more lenient window than other containers. Its healthcheck (`/healthcheck.sh`) verifies PostgreSQL connectivity (port 5432) and PHP-FPM (port 9000). PHP-FPM takes ~90 seconds to warm up after a normal restart — but during nightly AIO update cycles, the full startup (occ upgrade, app updates, migrations) can take 5+ minutes. On 2026-03-27, a startup hung and left the container unhealthy for 20 hours until the next nightly cycle replaced it.
|
Added 2026-03-23, updated 2026-03-28. The `nextcloud-aio-nextcloud` container needs a more lenient window than other containers. Its healthcheck (`/healthcheck.sh`) verifies PostgreSQL connectivity (port 5432) and PHP-FPM (port 9000). PHP-FPM takes ~90 seconds to warm up after a normal restart — but during nightly AIO update cycles, the full startup (occ upgrade, app updates, migrations) can take 5+ minutes. On 2026-03-27, a startup hung and left the container unhealthy for 20 hours until the next nightly cycle replaced it.
|
||||||
|
|
||||||
The dedicated alarm uses a 30-minute lookup window and 10-minute delay to absorb normal startup and update cycles (~40 minutes total grace), while still catching sustained failures:
|
The dedicated alarm uses a 10-minute lookup window and 10-minute delay to absorb normal startup, while still catching sustained failures:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# Dedicated alarm for nextcloud-aio-nextcloud — lenient window to absorb nightly update cycle
|
# Dedicated alarm for nextcloud-aio-nextcloud — lenient window to absorb nightly update cycle
|
||||||
|
|
@ -82,23 +76,15 @@ template: docker_nextcloud_unhealthy
|
||||||
component: Docker
|
component: Docker
|
||||||
units: status
|
units: status
|
||||||
every: 30s
|
every: 30s
|
||||||
lookup: average -30m of unhealthy
|
lookup: average -10m of unhealthy
|
||||||
chart labels: container_name=nextcloud-aio-nextcloud
|
chart labels: container_name=nextcloud-aio-nextcloud
|
||||||
warn: $this >= 1
|
warn: $this > 0
|
||||||
delay: up 10m down 5m multiplier 1.5 max 30m
|
delay: up 10m down 5m multiplier 1.5 max 30m
|
||||||
summary: Nextcloud container health sustained
|
summary: Nextcloud container health sustained
|
||||||
info: nextcloud-aio-nextcloud has been continuously unhealthy for 30+ minutes — not a transient update blip
|
info: nextcloud-aio-nextcloud has been unhealthy for a sustained period — not a transient update blip
|
||||||
to: sysadmin
|
to: sysadmin
|
||||||
```
|
```
|
||||||
|
|
||||||
**Tuning history:**
|
|
||||||
|
|
||||||
| Date | Lookup | Delay | Trigger | Notes |
|
|
||||||
|---|---|---|---|---|
|
|
||||||
| 2026-03-23 | 35m | 35m | Initial split from general alarm | Absorbed PHP-FPM warm-up |
|
|
||||||
| 2026-04-29 | 15m | 5m | Backup blip (~6m) never triggered | Tightened after stability |
|
|
||||||
| 2026-05-02 | 30m | 10m | 15m still too aggressive for update cycles | ~40m total grace; catches real outages |
|
|
||||||
|
|
||||||
## Watchdog Cron: Auto-Restart on Sustained Unhealthy
|
## Watchdog Cron: Auto-Restart on Sustained Unhealthy
|
||||||
|
|
||||||
If the Nextcloud container stays unhealthy for more than 1 hour (well past any normal startup window), a cron watchdog on majorlab auto-restarts it and logs the event. This was added 2026-03-28 after an incident where the container sat unhealthy for 20 hours until the next nightly backup cycle replaced it.
|
If the Nextcloud container stays unhealthy for more than 1 hour (well past any normal startup window), a cron watchdog on majorlab auto-restarts it and logs the event. This was added 2026-03-28 after an incident where the container sat unhealthy for 20 hours until the next nightly backup cycle replaced it.
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ tags:
|
||||||
- cron
|
- cron
|
||||||
status: published
|
status: published
|
||||||
created: 2026-04-18
|
created: 2026-04-18
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-18T11:13
|
||||||
---
|
---
|
||||||
# ClamAV Fleet Deployment with Ansible
|
# ClamAV Fleet Deployment with Ansible
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,11 @@
|
||||||
---
|
---
|
||||||
title: Fail2Ban Digest Mode — Fleet-Wide Quiet Alerts
|
title: "Fail2Ban Digest Mode — Fleet-Wide Quiet Alerts"
|
||||||
domain: selfhosting
|
domain: selfhosting
|
||||||
category: security
|
category: security
|
||||||
tags:
|
tags: [fail2ban, security, email, ansible, fleet, cron, digest]
|
||||||
- fail2ban
|
|
||||||
- security
|
|
||||||
- email
|
|
||||||
- ansible
|
|
||||||
- fleet
|
|
||||||
- cron
|
|
||||||
- digest
|
|
||||||
status: published
|
status: published
|
||||||
created: 2026-04-22
|
created: 2026-04-22
|
||||||
updated: 2026-05-02T14:56
|
updated: 2026-04-22
|
||||||
---
|
---
|
||||||
# Fail2Ban Digest Mode — Fleet-Wide Quiet Alerts
|
# Fail2Ban Digest Mode — Fleet-Wide Quiet Alerts
|
||||||
|
|
||||||
|
|
@ -28,11 +21,11 @@ Three tiers replace the firehose:
|
||||||
|
|
||||||
| Tier | Jails | Action | Why |
|
| Tier | Jails | Action | Why |
|
||||||
|------|-------|--------|-----|
|
|------|-------|--------|-----|
|
||||||
| **Immediate email** | `recidive` | `action_mwl` | Repeat offenders only — someone has been banned multiple times across jails |
|
| **Immediate email** | `sshd`, `recidive` | `action_mwl` | Security-critical — someone is actively targeting auth or is a repeat offender |
|
||||||
| **Silent ban** | Everything else | `action_` (default) | Ban happens, firewall rule applied, no email sent |
|
| **Silent ban** | Everything else | `action_` (default) | Ban happens, firewall rule applied, no email sent |
|
||||||
| **Daily digest** | All jails | Cron script at 08:00 UTC | One summary email per host with ban counts across all jails |
|
| **Daily digest** | All jails | Cron script at 08:00 UTC | One summary email per host with ban counts across all jails |
|
||||||
|
|
||||||
This reduces email volume from hundreds per day to ~10 (one digest per host + occasional recidive alerts).
|
This reduces email volume from hundreds per day to ~10 (one digest per host + occasional sshd/recidive alerts).
|
||||||
|
|
||||||
## jail.local Configuration
|
## jail.local Configuration
|
||||||
|
|
||||||
|
|
@ -47,20 +40,18 @@ action = %(action_)s
|
||||||
|
|
||||||
This overrides the stock `action_mwl` for all jails. Bans still happen — the firewall rule is applied — but no email is sent.
|
This overrides the stock `action_mwl` for all jails. Bans still happen — the firewall rule is applied — but no email is sent.
|
||||||
|
|
||||||
### Keep immediate alerts for recidive only
|
### Keep immediate alerts for critical jails
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[sshd]
|
[sshd]
|
||||||
enabled = true
|
enabled = true
|
||||||
action = %(action_)s
|
action = %(action_mwl)s
|
||||||
|
|
||||||
[recidive]
|
[recidive]
|
||||||
enabled = true
|
enabled = true
|
||||||
action = %(action_mwl)s
|
action = %(action_mwl)s
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Updated 2026-05-02:** sshd was moved to silent (`action_`). Only recidive (repeat offenders) now triggers immediate email. sshd bans are captured in the daily digest.
|
|
||||||
|
|
||||||
### Clean up email subjects with fq-hostname
|
### Clean up email subjects with fq-hostname
|
||||||
|
|
||||||
By default, fail2ban uses the system FQDN in email subjects. On Tailscale hosts, this produces ugly subjects like `[Fail2Ban] sshd: banned 1.2.3.4 on MajorToot.tail7f2d9.ts.net`. Override it in `[DEFAULT]`:
|
By default, fail2ban uses the system FQDN in email subjects. On Tailscale hosts, this produces ugly subjects like `[Fail2Ban] sshd: banned 1.2.3.4 on MajorToot.tail7f2d9.ts.net`. Override it in `[DEFAULT]`:
|
||||||
|
|
@ -100,9 +91,8 @@ The playbook `configure_fail2ban_digest.yml` deploys the full digest model fleet
|
||||||
### What it does
|
### What it does
|
||||||
|
|
||||||
1. Deploys a Python helper script that performs **section-aware editing** of `jail.local` (see gotchas below)
|
1. Deploys a Python helper script that performs **section-aware editing** of `jail.local` (see gotchas below)
|
||||||
2. Sets `action = %(action_)s` in `[DEFAULT]` and `[sshd]`
|
2. Sets `action = %(action_)s` in `[DEFAULT]`
|
||||||
3. Sets `action = %(action_mwl)s` in `[recidive]`
|
3. Sets `action = %(action_mwl)s` in `[sshd]` and `[recidive]`
|
||||||
4. Removes stale `action = %(action_mwl)s` from `defaults-debian.conf` if present
|
|
||||||
4. Sets `fq-hostname` per host using an override dict
|
4. Sets `fq-hostname` per host using an override dict
|
||||||
5. Deploys the digest script from a Jinja2 template
|
5. Deploys the digest script from a Jinja2 template
|
||||||
6. Creates the cron job via `ansible.builtin.cron`
|
6. Creates the cron job via `ansible.builtin.cron`
|
||||||
|
|
@ -153,14 +143,6 @@ option 'action' in section 'DEFAULT' already exists
|
||||||
|
|
||||||
The Python editor script handles this by replacing existing keys rather than appending.
|
The Python editor script handles this by replacing existing keys rather than appending.
|
||||||
|
|
||||||
### defaults-debian.conf overrides jail.local
|
|
||||||
|
|
||||||
On Debian/Ubuntu, `/etc/fail2ban/jail.d/defaults-debian.conf` is loaded **after** `jail.local`. If it contains `action = %(action_mwl)s`, it silently overrides your silent default — every jail sends email on every ban. The Ansible playbook now removes this line automatically. If you see per-ban emails after deploying digest mode, check this file first:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
grep action /etc/fail2ban/jail.d/defaults-debian.conf
|
|
||||||
```
|
|
||||||
|
|
||||||
### fq-hostname scope
|
### fq-hostname scope
|
||||||
|
|
||||||
Setting `fq-hostname` in `[DEFAULT]` affects all action templates that use the `<fq-hostname>` tag — including both immediate emails and the digest subject. This is the desired behavior, but be aware that it overrides the system hostname globally within fail2ban.
|
Setting `fq-hostname` in `[DEFAULT]` affects all action templates that use the `<fq-hostname>` tag — including both immediate emails and the digest subject. This is the desired behavior, but be aware that it overrides the system hostname globally within fail2ban.
|
||||||
|
|
|
||||||
|
|
@ -1,151 +0,0 @@
|
||||||
---
|
|
||||||
title: "wp-fail2ban Plugin Logpath on Debian/Ubuntu (auth.log, not syslog)"
|
|
||||||
domain: selfhosting
|
|
||||||
category: security
|
|
||||||
tags: [fail2ban, wordpress, wp-fail2ban, debugging, gotcha, debian, ubuntu]
|
|
||||||
status: published
|
|
||||||
created: 2026-04-30
|
|
||||||
updated: 2026-04-30
|
|
||||||
---
|
|
||||||
# wp-fail2ban Plugin Logpath on Debian/Ubuntu (auth.log, not syslog)
|
|
||||||
|
|
||||||
## The Problem
|
|
||||||
|
|
||||||
You install the [WP fail2ban](https://wordpress.org/plugins/wp-fail2ban/) WordPress plugin, configure the fleet-standard `wordpress-hard`, `wordpress-soft`, and `wordpress-extra` jails, and… nothing. Weeks pass. `fail2ban-client status wordpress-hard` reports `Total failed: 0, Total banned: 0`. Your site is being attacked, but the jails are dead.
|
|
||||||
|
|
||||||
Meanwhile the `wordpress-login` jail (which reads Apache access logs for `POST /wp-login.php` directly) is happily catching brute-forcers. So the problem isn't fail2ban itself — it's specifically the wp-fail2ban-plugin-derived jails.
|
|
||||||
|
|
||||||
## The Cause
|
|
||||||
|
|
||||||
The wp-fail2ban plugin emits events via PHP's `syslog()` call with facility `LOG_AUTH`. On Debian/Ubuntu, rsyslog routes the `auth` facility to **`/var/log/auth.log`**, NOT `/var/log/syslog`. On RHEL/Fedora it's `/var/log/secure`.
|
|
||||||
|
|
||||||
A lot of tutorials, ansible-galaxy roles, and copy-paste config snippets specify:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
logpath = /var/log/syslog
|
|
||||||
```
|
|
||||||
|
|
||||||
That's wrong on Debian/Ubuntu. The events never land there, so the filter regex has nothing to match, so the jail catches zero events forever. Silently.
|
|
||||||
|
|
||||||
## Diagnostic Steps
|
|
||||||
|
|
||||||
If a `wordpress-{hard,soft,extra}` jail shows `Total failed: 0` over a long window despite the plugin being active and the site getting attacked:
|
|
||||||
|
|
||||||
**1. Check what the jail thinks it's watching:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo fail2ban-client status wordpress-hard | grep "File list"
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Check where wp-fail2ban events actually land:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo grep -c "wordpress(" /var/log/auth.log /var/log/syslog /var/log/secure 2>/dev/null
|
|
||||||
```
|
|
||||||
|
|
||||||
You'll see something like:
|
|
||||||
|
|
||||||
```
|
|
||||||
/var/log/auth.log:314
|
|
||||||
/var/log/syslog:0
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. If the jail's `File list` ≠ the file with events, fix the `logpath`.**
|
|
||||||
|
|
||||||
A real event line on Debian/Ubuntu looks like:
|
|
||||||
|
|
||||||
```
|
|
||||||
2026-04-18T23:28:21.027004-04:00 hostname wordpress(example.com)[719989]: XML-RPC authentication failure for someone from 1.2.3.4
|
|
||||||
```
|
|
||||||
|
|
||||||
The `wordpress(domain)[pid]` syslog tag is the giveaway — those are wp-fail2ban events.
|
|
||||||
|
|
||||||
## The Fix
|
|
||||||
|
|
||||||
Edit the jail blocks in `/etc/fail2ban/jail.local` (or your Ansible source for the jail) and set:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[wordpress-hard]
|
|
||||||
enabled = true
|
|
||||||
port = http,https
|
|
||||||
filter = wordpress-hard
|
|
||||||
logpath = /var/log/auth.log
|
|
||||||
maxretry = 1
|
|
||||||
findtime = 60
|
|
||||||
bantime = 30d
|
|
||||||
backend = polling
|
|
||||||
|
|
||||||
[wordpress-soft]
|
|
||||||
enabled = true
|
|
||||||
port = http,https
|
|
||||||
filter = wordpress-soft
|
|
||||||
logpath = /var/log/auth.log
|
|
||||||
maxretry = 5
|
|
||||||
findtime = 60
|
|
||||||
bantime = 30d
|
|
||||||
backend = polling
|
|
||||||
|
|
||||||
[wordpress-extra]
|
|
||||||
enabled = true
|
|
||||||
port = http,https
|
|
||||||
filter = wordpress-extra
|
|
||||||
logpath = /var/log/auth.log
|
|
||||||
maxretry = 5
|
|
||||||
findtime = 60
|
|
||||||
bantime = 30d
|
|
||||||
backend = polling
|
|
||||||
```
|
|
||||||
|
|
||||||
Then:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo fail2ban-client -t # validate
|
|
||||||
sudo fail2ban-client reload
|
|
||||||
sudo fail2ban-client status wordpress-hard | grep "File list"
|
|
||||||
# should now show /var/log/auth.log
|
|
||||||
```
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
You can prove the filter regex actually matches your real events without waiting for an attack — run `fail2ban-regex` against the rotated log:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo fail2ban-regex /var/log/auth.log.1 /etc/fail2ban/filter.d/wordpress-hard.conf | grep -E "Failregex:|Lines:"
|
|
||||||
```
|
|
||||||
|
|
||||||
Healthy output looks like:
|
|
||||||
|
|
||||||
```
|
|
||||||
Failregex: 81 total
|
|
||||||
Lines: 13008 lines, 0 ignored, 81 matched, 12927 missed
|
|
||||||
```
|
|
||||||
|
|
||||||
If you see `Failregex: 0 total`, the filter regex doesn't match what the plugin actually emits — which is a different bug (filter version skew vs. plugin version), not the logpath gotcha. Investigate `/etc/fail2ban/filter.d/wordpress-{hard,soft}.conf` against actual event lines.
|
|
||||||
|
|
||||||
> **Note:** On a freshly-fixed jail, counters will sit at `Total failed: 0` for a while — the `polling` backend starts at the file's current EOF, so old events aren't retroactively counted. New events from the moment of `reload` onward will accumulate. Allow a few days of normal attack traffic before declaring the fix broken.
|
|
||||||
|
|
||||||
## Distribution Cheat Sheet
|
|
||||||
|
|
||||||
| Distro family | wp-fail2ban events land in |
|
|
||||||
|---|---|
|
|
||||||
| Debian / Ubuntu | `/var/log/auth.log` |
|
|
||||||
| RHEL / CentOS / Fedora | `/var/log/secure` |
|
|
||||||
| systemd-journal-only systems | `journalctl SYSLOG_FACILITY=4` (use `backend = systemd` + `journalmatch = SYSLOG_FACILITY=4`) |
|
|
||||||
|
|
||||||
If you have a mixed fleet, parameterize the path:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# Ansible vars
|
|
||||||
wp_fail2ban_log_path: "{{ '/var/log/auth.log' if ansible_os_family == 'Debian' else '/var/log/secure' }}"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Why wordpress-login Is Unaffected
|
|
||||||
|
|
||||||
The `wordpress-login` jail is a different beast — it reads `/var/log/apache2/access.log` directly and matches `^<HOST> -.*"POST /wp-login.php` via the `wordpress-login` filter. No plugin involved, no syslog facility involved. So a host can have `wordpress-login` working perfectly while `wordpress-{hard,soft,extra}` are silently dead. Don't let a healthy `wordpress-login` reassure you that the rest of the wp-fail2ban stack is also fine.
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- [[fail2ban-wordpress-login-jail]] — the access-log layer that catches WP brute force without any plugin dependency
|
|
||||||
- [[fail2ban-apache-bad-request-jail]]
|
|
||||||
- [[fail2ban-apache-php-probe-jail]]
|
|
||||||
- [[clamav-fleet-deployment]]
|
|
||||||
|
|
@ -10,7 +10,7 @@ tags:
|
||||||
- docker
|
- docker
|
||||||
status: published
|
status: published
|
||||||
created: 2026-04-02
|
created: 2026-04-02
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-29T22:45
|
||||||
---
|
---
|
||||||
|
|
||||||
# Mastodon Instance Tuning
|
# Mastodon Instance Tuning
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ tags:
|
||||||
- troubleshooting
|
- troubleshooting
|
||||||
status: published
|
status: published
|
||||||
created: 2026-04-18
|
created: 2026-04-18
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-29T22:45
|
||||||
---
|
---
|
||||||
# Ansible Check Mode False Positives in Verify/Assert Tasks
|
# Ansible Check Mode False Positives in Verify/Assert Tasks
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
---
|
|
||||||
title: "Ansible regex_search — capture-group argument doesn't work in set_fact"
|
|
||||||
domain: troubleshooting
|
|
||||||
category: general
|
|
||||||
tags: [ansible, jinja, regex, set_fact, gotcha]
|
|
||||||
status: published
|
|
||||||
created: 2026-05-06
|
|
||||||
updated: 2026-05-06
|
|
||||||
---
|
|
||||||
|
|
||||||
# Ansible `regex_search` — capture-group argument doesn't work in `set_fact`
|
|
||||||
|
|
||||||
## Problem
|
|
||||||
|
|
||||||
You want to extract a number from a registered command's stdout — e.g. the package count from a dnf or apt upgrade — and stash it in a fact. The natural-looking `regex_search('pattern', '\1')` form fails or produces an empty string when used inside `set_fact`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- name: Capture package count # ❌ does not behave as expected
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
pkg_count: "{{ apt_upgrade_result.stdout | regex_search('([0-9]+) upgraded', '\\1') }}"
|
|
||||||
```
|
|
||||||
|
|
||||||
You'll see one of:
|
|
||||||
|
|
||||||
- An empty `pkg_count` (the filter ran but the back-reference returned nothing in this context)
|
|
||||||
- A Jinja error about argument arity if the syntax is slightly off
|
|
||||||
- The whole matched substring instead of just the captured group
|
|
||||||
|
|
||||||
## Root cause
|
|
||||||
|
|
||||||
In `set_fact` templating, the second-positional-argument form of `regex_search` (the back-reference `'\1'` you've seen in tutorials) doesn't reliably select capture groups. The filter is happiest returning the full match. Capture-group selection works in some contexts (e.g. `vars:` blocks, certain Jinja invocations) but not consistently inside `set_fact`, which makes "copy this snippet from the docs" fail intermittently.
|
|
||||||
|
|
||||||
## Fix — match the broader pattern, then split
|
|
||||||
|
|
||||||
Stop fighting the back-reference. Use `regex_search` to grab a string that *contains* the value you want, then peel it apart with plain Python string ops:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- name: Capture package count # ✅ works in set_fact
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
pkg_count: "{{ (apt_upgrade_result.stdout | regex_search('[0-9]+ upgraded') | default('0')).split()[0] }}"
|
|
||||||
```
|
|
||||||
|
|
||||||
What this does:
|
|
||||||
|
|
||||||
1. `regex_search('[0-9]+ upgraded')` returns the matching substring (e.g. `"7 upgraded"`) or `None` on no match.
|
|
||||||
2. `default('0')` turns the `None` case into the string `"0"` so the next step always has something to operate on.
|
|
||||||
3. `.split()[0]` keeps just the number.
|
|
||||||
|
|
||||||
The result (`"7"`) is a string — cast with `| int` if you need arithmetic.
|
|
||||||
|
|
||||||
## Where this comes up in MajorAnsible
|
|
||||||
|
|
||||||
The `update.yml` executive-summary task uses this pattern to pull package counts out of `apt_upgrade_result.stdout` and `dnf_upgrade_result.stdout` so each host can print one tidy line:
|
|
||||||
|
|
||||||
```
|
|
||||||
majorhome: 7 pkg(s) upgraded | No reboot needed | 2 active screen(s)
|
|
||||||
majormail: 14 pkg(s) upgraded | REBOOT REQUIRED | Snapshot taken
|
|
||||||
majorlab: 0 pkg(s) upgraded | No reboot needed
|
|
||||||
```
|
|
||||||
|
|
||||||
The summary line is built with a Jinja `parts` array joined with `' | '` so segments that don't apply (no snapshot, no screens) drop out cleanly without leaving trailing separators.
|
|
||||||
|
|
||||||
## Quick checks if this still misbehaves
|
|
||||||
|
|
||||||
- **Confirm the source variable.** Ansible 2.x sometimes returns stdout as `result.stdout` and sometimes as `result.stdout_lines`; the `regex_search` filter wants a string, not a list. Use `.stdout` (or `.stdout | join('\n')` for a multi-line list).
|
|
||||||
- **Escape your backslashes.** In YAML strings, `\d` needs to be written `\\d` or wrapped in single quotes: `'(\d+) upgraded'`.
|
|
||||||
- **Always provide a default.** `regex_search` returns `None` on miss, which will explode `.split()[0]`. The `| default('0')` bridge is mandatory in production playbooks where some hosts will legitimately have zero upgrades.
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- [[ansible-vault-password-file-missing]] — another set_fact / vault interaction quirk
|
|
||||||
- [[ansible-ssh-timeout-dnf-upgrade]] — companion gotcha when running `update.yml`
|
|
||||||
|
|
@ -1,119 +0,0 @@
|
||||||
---
|
|
||||||
title: "LoRA adapter — GGUF conversion fails with 'config.json not found'"
|
|
||||||
domain: troubleshooting
|
|
||||||
category: gpu-display
|
|
||||||
tags: [lora, qlora, gguf, llama.cpp, unsloth, fine-tuning, qwen]
|
|
||||||
status: published
|
|
||||||
created: 2026-04-30
|
|
||||||
updated: 2026-04-30
|
|
||||||
---
|
|
||||||
|
|
||||||
# LoRA adapter — GGUF conversion fails with 'config.json not found'
|
|
||||||
|
|
||||||
## Problem
|
|
||||||
|
|
||||||
After a QLoRA fine-tune, you point `llama.cpp/convert_hf_to_gguf.py` at the training output directory and it crashes immediately:
|
|
||||||
|
|
||||||
```
|
|
||||||
FileNotFoundError: [Errno 2] No such file or directory:
|
|
||||||
'/path/to/training-runs/<run>/final/config.json'
|
|
||||||
```
|
|
||||||
|
|
||||||
The output directory looks fine — it contains:
|
|
||||||
|
|
||||||
```
|
|
||||||
adapter_config.json
|
|
||||||
adapter_model.safetensors (~150 MB for a 7B base)
|
|
||||||
chat_template.jinja
|
|
||||||
tokenizer_config.json
|
|
||||||
tokenizer.json
|
|
||||||
```
|
|
||||||
|
|
||||||
But no `config.json`, and `adapter_model.safetensors` is 150 MB — way smaller than the ~14 GB you'd expect for a full Qwen2.5-7B 16-bit checkpoint.
|
|
||||||
|
|
||||||
## Root cause
|
|
||||||
|
|
||||||
`model.save_pretrained()` after a LoRA/QLoRA train saves **only the adapter weights**, not a merged full-precision model. `convert_hf_to_gguf.py` expects a full HuggingFace model directory — it reads `config.json` to identify the architecture. Adapter-only directories don't have one.
|
|
||||||
|
|
||||||
You need to merge the LoRA adapter into the base model first, then point the GGUF converter at the merged dir.
|
|
||||||
|
|
||||||
## Solution
|
|
||||||
|
|
||||||
### Quick fix — inline merge step
|
|
||||||
|
|
||||||
Insert this block between training completion and `convert_hf_to_gguf.py`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from unsloth import FastLanguageModel
|
|
||||||
|
|
||||||
adapter = "/path/to/training-runs/<run>/final"
|
|
||||||
merged = "/path/to/training-runs/<run>/merged"
|
|
||||||
|
|
||||||
model, tok = FastLanguageModel.from_pretrained(
|
|
||||||
model_name=adapter,
|
|
||||||
max_seq_length=2048,
|
|
||||||
load_in_4bit=True,
|
|
||||||
)
|
|
||||||
model.save_pretrained_merged(merged, tok, save_method="merged_16bit")
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run the GGUF converter against the **merged** dir, not the adapter dir:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python3 llama.cpp/convert_hf_to_gguf.py /path/to/training-runs/<run>/merged \
|
|
||||||
--outfile model-f16.gguf --outtype f16
|
|
||||||
```
|
|
||||||
|
|
||||||
The merged dir will contain `config.json`, `model-00001-of-00004.safetensors` (multiple shards totaling the full base model size), `generation_config.json`, etc.
|
|
||||||
|
|
||||||
### Cleaner fix — use a wrapper
|
|
||||||
|
|
||||||
If you do this often, encapsulate it:
|
|
||||||
|
|
||||||
1. Wrapper Python script accepts `--adapter`, `--output`, `--skip-merge`, `--all-quants`
|
|
||||||
2. Step 1: load adapter via `FastLanguageModel.from_pretrained()`, call `save_pretrained_merged()`
|
|
||||||
3. Step 2: subprocess `convert_hf_to_gguf.py` on the merged dir
|
|
||||||
4. Step 3: subprocess `llama-quantize` for each requested quant
|
|
||||||
|
|
||||||
This is what `~/corpus/scripts/convert_gguf.py` does on MajorRig (rewritten 2026-04-09 for the MajorTwin v7b cycle).
|
|
||||||
|
|
||||||
## Why this trips people up
|
|
||||||
|
|
||||||
- Unsloth and PEFT both save adapter-only by default after `trainer.save_model()` or `model.save_pretrained()`. There's no warning that downstream tools expect a merged model.
|
|
||||||
- The training output **looks** complete — there's a `tokenizer.json`, a `chat_template.jinja`, and a non-trivial `.safetensors`. It feels like a checkpoint.
|
|
||||||
- A pipeline that uses `convert_gguf.py` (with merge) once and then someone reimplements Step 4 inline (skipping the wrapper) will silently lose the merge step. This is what happened in MajorTwin v8c (Apr 30, 2026) — see [[majortwin-v8b-plan#Pipeline Bug + Fix (2026-04-30)]].
|
|
||||||
|
|
||||||
## Verification checklist
|
|
||||||
|
|
||||||
After training, before running the GGUF converter, verify the directory you're pointing at:
|
|
||||||
|
|
||||||
| File | Adapter-only dir | Merged dir |
|
|
||||||
|---|---|---|
|
|
||||||
| `adapter_config.json` | ✅ | ❌ |
|
|
||||||
| `adapter_model.safetensors` | ✅ (~150 MB / 7B) | ❌ |
|
|
||||||
| `config.json` | ❌ | ✅ |
|
|
||||||
| `model-*.safetensors` (sharded) | ❌ | ✅ (~14 GB / 7B) |
|
|
||||||
| `generation_config.json` | ❌ | ✅ |
|
|
||||||
| `tokenizer.json` | ✅ | ✅ |
|
|
||||||
|
|
||||||
If you see only the left column, you need to merge before converting.
|
|
||||||
|
|
||||||
## Resuming a failed pipeline without re-training
|
|
||||||
|
|
||||||
The adapter is small and self-contained. If your pipeline crashes at the GGUF step, you do NOT need to retrain — the LoRA adapter at `<run>/final/` is intact. Write a resume wrapper that runs only:
|
|
||||||
|
|
||||||
1. Merge (`save_pretrained_merged`)
|
|
||||||
2. F16 conversion (`convert_hf_to_gguf.py`)
|
|
||||||
3. Quantization (`llama-quantize`)
|
|
||||||
4. Deploy
|
|
||||||
|
|
||||||
This saves the cost of however many GPU-hours the training took. See `~/corpus/scripts/resume_v8c_step4.sh` on MajorRig for an example.
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- [[qwen-14b-oom-3080ti]] — base model size choice on a 12GB GPU
|
|
||||||
- [[majortwin-v8b-plan]] — v8c pipeline architecture and resume
|
|
||||||
|
|
||||||
## Maintenance
|
|
||||||
|
|
||||||
- 2026-04-30 — Created after MajorTwin v8c pipeline failed Step 4. Root-caused, patched, resumed.
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
created: 2026-03-15T06:37
|
created: 2026-03-15T06:37
|
||||||
updated: 2026-05-02T17:50
|
updated: 2026-04-29T22:45
|
||||||
---
|
---
|
||||||
# 🔧 General Troubleshooting
|
# 🔧 General Troubleshooting
|
||||||
|
|
||||||
|
|
@ -8,14 +8,12 @@ Practical fixes for common Linux, networking, and application problems.
|
||||||
|
|
||||||
## 🖥️ GPU & AI
|
## 🖥️ GPU & AI
|
||||||
- [Qwen2.5-14B OOM on RTX 3080 Ti (12GB)](gpu-display/qwen-14b-oom-3080ti.md)
|
- [Qwen2.5-14B OOM on RTX 3080 Ti (12GB)](gpu-display/qwen-14b-oom-3080ti.md)
|
||||||
- [LoRA adapter — GGUF conversion fails with 'config.json not found'](gpu-display/lora-adapter-gguf-conversion-fails.md)
|
|
||||||
|
|
||||||
## 🌐 Networking & Web
|
## 🌐 Networking & Web
|
||||||
- [Apache Outage: Fail2ban Self-Ban + Missing iptables Rules](networking/fail2ban-self-ban-apache-outage.md)
|
- [Apache Outage: Fail2ban Self-Ban + Missing iptables Rules](networking/fail2ban-self-ban-apache-outage.md)
|
||||||
- [Mail Client Stops Receiving: Fail2ban IMAP Self-Ban](networking/fail2ban-imap-self-ban-mail-client.md)
|
- [Mail Client Stops Receiving: Fail2ban IMAP Self-Ban](networking/fail2ban-imap-self-ban-mail-client.md)
|
||||||
- [firewalld: Mail Ports Wiped After Reload](networking/firewalld-mail-ports-reset.md)
|
- [firewalld: Mail Ports Wiped After Reload](networking/firewalld-mail-ports-reset.md)
|
||||||
- [Tailscale SSH: Unexpected Re-Authentication Prompt](networking/tailscale-ssh-reauth-prompt.md)
|
- [Tailscale SSH: Unexpected Re-Authentication Prompt](networking/tailscale-ssh-reauth-prompt.md)
|
||||||
- [iOS Tailscale Clients Report HostName="localhost" — Breaks /etc/hosts Generators](networking/tailscale-status-json-hostname-localhost-ios.md)
|
|
||||||
- [rsync over Tailscale: Hung in TCP Teardown After Transfer Completes](networking/rsync-tailscale-teardown-stall.md)
|
- [rsync over Tailscale: Hung in TCP Teardown After Transfer Completes](networking/rsync-tailscale-teardown-stall.md)
|
||||||
- [Windows OpenSSH: WSL Default Shell Breaks Remote Commands](networking/windows-openssh-wsl-default-shell-breaks-remote-commands.md)
|
- [Windows OpenSSH: WSL Default Shell Breaks Remote Commands](networking/windows-openssh-wsl-default-shell-breaks-remote-commands.md)
|
||||||
- [Pi-hole AI Blocklist Blocks Claude Desktop (ERR_CONNECTION_REFUSED)](networking/pihole-blocks-claude-desktop.md)
|
- [Pi-hole AI Blocklist Blocks Claude Desktop (ERR_CONNECTION_REFUSED)](networking/pihole-blocks-claude-desktop.md)
|
||||||
|
|
@ -27,7 +25,6 @@ Practical fixes for common Linux, networking, and application problems.
|
||||||
- [SSH Timeout During dnf upgrade on Fedora Hosts](ansible-ssh-timeout-dnf-upgrade.md)
|
- [SSH Timeout During dnf upgrade on Fedora Hosts](ansible-ssh-timeout-dnf-upgrade.md)
|
||||||
- [Vault Password File Missing](ansible-vault-password-file-missing.md)
|
- [Vault Password File Missing](ansible-vault-password-file-missing.md)
|
||||||
- [ansible.cfg Ignored on WSL2 Windows Mounts](ansible-wsl2-world-writable-mount-ignores-cfg.md)
|
- [ansible.cfg Ignored on WSL2 Windows Mounts](ansible-wsl2-world-writable-mount-ignores-cfg.md)
|
||||||
- [regex_search — capture-group argument doesn't work in set_fact](ansible-regex-search-set-fact-capture-group.md)
|
|
||||||
|
|
||||||
## 📦 Docker & Systems
|
## 📦 Docker & Systems
|
||||||
- [Docker & Caddy Recovery After Reboot (Fedora + SELinux)](docker-caddy-selinux-post-reboot-recovery.md)
|
- [Docker & Caddy Recovery After Reboot (Fedora + SELinux)](docker-caddy-selinux-post-reboot-recovery.md)
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,11 @@
|
||||||
---
|
---
|
||||||
title: ISP SNI Filtering & Caddy Troubleshooting
|
title: "ISP SNI Filtering & Caddy Troubleshooting"
|
||||||
domain: troubleshooting
|
domain: troubleshooting
|
||||||
category: general
|
category: general
|
||||||
tags:
|
tags: [isp, sni, caddy, tls, dns, cloudflare]
|
||||||
- isp
|
|
||||||
- sni
|
|
||||||
- caddy
|
|
||||||
- tls
|
|
||||||
- dns
|
|
||||||
- cloudflare
|
|
||||||
status: published
|
status: published
|
||||||
created: 2026-04-02
|
created: 2026-04-02
|
||||||
updated: 2026-04-30T13:07
|
updated: 2026-04-02
|
||||||
---
|
---
|
||||||
# ISP SNI Filtering & Caddy Troubleshooting
|
# ISP SNI Filtering & Caddy Troubleshooting
|
||||||
|
|
||||||
|
|
@ -35,89 +29,3 @@ notes.majorshouse.com {
|
||||||
```
|
```
|
||||||
|
|
||||||
Once the hostname was changed to one without the "wiki" keyword, the TLS handshake completed successfully.
|
Once the hostname was changed to one without the "wiki" keyword, the TLS handshake completed successfully.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔁 2026-04-30 Update — Stale A Record + Cloudflare Proxy Fix
|
|
||||||
|
|
||||||
The hostname rename held for ~4 weeks. On 2026-04-30 the wiki went down with a TLS handshake failure on `notes.majorshouse.com`. The on-the-spot framing was "ISP filter expanded to include 'notes'" — but Cloudflare DNS audit showed a different (and arguably worse) root cause: **the `notes` A record was pointing at `136.54.3.248`, an IP that is not majorlab's current home IP.** Whichever host responds at that address either does not run Caddy or does not know about the `notes.majorshouse.com` SNI, so the TLS handshake was rejected with `internal_error 80`.
|
|
||||||
|
|
||||||
### Re-diagnosis
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Cert + Caddy + mkdocs all healthy on majorlab
|
|
||||||
$ ssh majorlab 'systemctl is-active caddy; ss -tlnp | grep :443'
|
|
||||||
active
|
|
||||||
LISTEN 0 4096 *:443 users:(("caddy",pid=1549,fd=7))
|
|
||||||
|
|
||||||
# Loopback-served TLS works fine — cert valid Mar 11 → Jun 9 2026
|
|
||||||
$ ssh majorlab 'curl -sS -o /dev/null -w "%{http_code}\n" --resolve notes.majorshouse.com:443:127.0.0.1 https://notes.majorshouse.com/'
|
|
||||||
200
|
|
||||||
|
|
||||||
# External TLS handshake gets rejected with internal_error
|
|
||||||
$ openssl s_client -servername notes.majorshouse.com -connect 136.54.3.248:443
|
|
||||||
… SSL alert number 80 (internal_error) …
|
|
||||||
```
|
|
||||||
|
|
||||||
### The smoking-gun comparison
|
|
||||||
|
|
||||||
Other `*.majorshouse.com` services worked because they were CNAMEs to the apex, which resolves to majorlab's actual home IP:
|
|
||||||
|
|
||||||
| Subdomain | DNS shape | Final IP | Status |
|
|
||||||
|---|---|---|---|
|
|
||||||
| `notes.majorshouse.com` | **A → `136.54.3.248`** (stale) | `136.54.3.248` (wrong host) | ❌ TLS rejected |
|
|
||||||
| `git.majorshouse.com` | CNAME → `majorshouse.com.` | `136.56.0.55` (majorlab) | ✅ |
|
|
||||||
| `n8n.majorshouse.com` | CNAME → `majorshouse.com.` | `136.56.0.55` (majorlab) | ✅ |
|
|
||||||
| `matrix.majorshouse.com` | CNAME → `majorshouse.com.` | `136.56.0.55` (majorlab) | ✅ |
|
|
||||||
|
|
||||||
None of the working subdomains were proxied through Cloudflare (`proxied=false` on all of them); they simply had the right IP. The `notes` A record was the only one pointing somewhere wrong — most likely a stale value from a prior ISP / IP change that never got cleaned up.
|
|
||||||
|
|
||||||
### ✅ Fix — switch `notes` to a Cloudflare-proxied CNAME
|
|
||||||
|
|
||||||
Rather than just correcting the A record (which would silently break again the next time the home IP changes), the fix is a CNAME to the apex with proxy on. That gives two protections in one move: it always tracks the apex (so home IP changes propagate automatically) and it puts the wiki behind Cloudflare's edge (so any future ISP-side weirdness like the original `wiki` SNI filter is also bypassed).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# via Cloudflare API (token from ansible-vault: vault_cloudflare_api_token)
|
|
||||||
PUT /zones/{ZONE_ID}/dns_records/{NOTES_RECORD_ID}
|
|
||||||
{
|
|
||||||
"type": "CNAME",
|
|
||||||
"name": "notes.majorshouse.com",
|
|
||||||
"content": "majorshouse.com",
|
|
||||||
"ttl": 1,
|
|
||||||
"proxied": true,
|
|
||||||
"comment": "switched A→CNAME proxied to bypass stale IP / ISP SNI filter"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Or via the dashboard:
|
|
||||||
|
|
||||||
1. Cloudflare → `majorshouse.com` zone → DNS → Records
|
|
||||||
2. Edit the `notes` record: Type `CNAME`, Target `majorshouse.com`, Proxy `Proxied` (orange cloud)
|
|
||||||
3. Save
|
|
||||||
|
|
||||||
External clients now hit Cloudflare edge IPs (`104.21.x.x` / `172.67.x.x`) which TLS-terminate at the edge and tunnel back to majorlab's apex IP. ACME on majorlab keeps working — Cloudflare passes the HTTP-01 challenge through on port 80. Caddy's `notes.majorshouse.com {}` block needs no change.
|
|
||||||
|
|
||||||
Verify (response should show `server: cloudflare` and `via: 1.0 Caddy`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -sSI https://notes.majorshouse.com/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Why a Cloudflare-proxied CNAME is the durable shape
|
|
||||||
|
|
||||||
- **Apex follows the home IP automatically.** Update the apex A record once when the ISP changes; every subdomain inherits it without per-record fixes.
|
|
||||||
- **TLS handshake is offloaded to CF.** Any ISP-level SNI weirdness (the original `wiki` ban; theoretical future bans) becomes irrelevant — external clients SNI=`notes.majorshouse.com` to Cloudflare, which the ISP doesn't filter.
|
|
||||||
- **Free.** Cloudflare's free tier covers proxy + TLS termination.
|
|
||||||
|
|
||||||
### Audit checklist for any home-hosted `*.majorshouse.com` subdomain
|
|
||||||
|
|
||||||
- [ ] DNS record is a **CNAME** to `majorshouse.com.`, not an A record to a literal home IP.
|
|
||||||
- [ ] Cloudflare proxy (orange cloud, `proxied=true`) enabled on the record — at minimum for any subdomain where TLS reachability matters.
|
|
||||||
- [ ] Caddy entry on majorlab references the public hostname; `reverse_proxy` stays on the localhost port.
|
|
||||||
- [ ] HTTPS verified from outside the LAN (phone on cellular is sufficient) within the first hour after the change.
|
|
||||||
- [ ] If an A record is genuinely required (e.g. it must NOT go through CF), document why in the deploy notes for that service.
|
|
||||||
|
|
||||||
### Related
|
|
||||||
|
|
||||||
- [[majwiki-setup-and-pipeline]] — full wiki deploy pipeline; the DNS step there should reference this fix
|
|
||||||
- [[Network-Overview]] — fleet IP table
|
|
||||||
|
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
---
|
|
||||||
title: iOS Tailscale Clients Report HostName="localhost" — Breaks /etc/hosts Generators
|
|
||||||
domain: troubleshooting
|
|
||||||
category: networking
|
|
||||||
tags:
|
|
||||||
- tailscale
|
|
||||||
- ios
|
|
||||||
- postfix
|
|
||||||
- etc-hosts
|
|
||||||
- jq
|
|
||||||
status: published
|
|
||||||
created: 2026-04-29
|
|
||||||
updated: 2026-04-29
|
|
||||||
---
|
|
||||||
|
|
||||||
# iOS Tailscale Clients Report HostName="localhost" — Breaks /etc/hosts Generators
|
|
||||||
|
|
||||||
## Problem
|
|
||||||
|
|
||||||
A homegrown script that builds an `/etc/hosts` block from `tailscale status --json` silently corrupted the file the moment any iOS device joined the tailnet. After the next run, services bound to `localhost` started failing.
|
|
||||||
|
|
||||||
On the affected host (`majordiscord`), Postfix refused to start with:
|
|
||||||
|
|
||||||
```
|
|
||||||
postfix: fatal: parameter inet_interfaces: no local interface found for 100.127.114.10
|
|
||||||
```
|
|
||||||
|
|
||||||
`/etc/hosts` looked fine at the top — `127.0.0.1 localhost` was still present — but inside the Tailscale-managed block:
|
|
||||||
|
|
||||||
```
|
|
||||||
# TAILSCALE_START
|
|
||||||
100.84.42.102 tttpod
|
|
||||||
100.110.197.17 majortoot
|
|
||||||
100.95.55.40 localhost <-- WRONG (this is an iPhone)
|
|
||||||
100.84.165.52 majormail
|
|
||||||
...
|
|
||||||
100.127.114.10 localhost <-- WRONG (this is an iPad)
|
|
||||||
# TAILSCALE_END
|
|
||||||
```
|
|
||||||
|
|
||||||
When Postfix resolved `localhost` (because `inet_interfaces = localhost` in `main.cf`), the **last matching entry** in `/etc/hosts` won — a Tailscale IP that doesn't exist on this host — and the daemon died on bind.
|
|
||||||
|
|
||||||
## Root Cause
|
|
||||||
|
|
||||||
The script used `.HostName` from the Tailscale JSON:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
tailscale status --json \
|
|
||||||
| jq -r '.Peer[] | "\(.TailscaleIPs[0]) \(.HostName)"' \
|
|
||||||
>> "$TEMP_HOSTS"
|
|
||||||
```
|
|
||||||
|
|
||||||
iOS Tailscale clients (iPhone, iPad) **always report `HostName: "localhost"`** in the JSON. iOS doesn't expose the real device name to apps the way macOS/Linux/Windows do, so the Tailscale client falls back to the literal string `localhost`.
|
|
||||||
|
|
||||||
Inspect it directly:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ tailscale status --json | jq '.Peer[] | select(.OS == "iOS") | {DNSName, HostName, OS}'
|
|
||||||
{
|
|
||||||
"DNSName": "iphone171.tail7f2d9.ts.net.",
|
|
||||||
"HostName": "localhost",
|
|
||||||
"OS": "iOS"
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"DNSName": "ipad166.tail7f2d9.ts.net.",
|
|
||||||
"HostName": "localhost",
|
|
||||||
"OS": "iOS"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Every iOS device contributes a line `<tailscale-ip> localhost` to `/etc/hosts`, hijacking the `localhost` lookup.
|
|
||||||
|
|
||||||
## Fix
|
|
||||||
|
|
||||||
Use `.DNSName` (the unique tailnet DNS name) and take the first dotted component instead of `.HostName`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
tailscale status --json \
|
|
||||||
| jq -r '.Peer[] | "\(.TailscaleIPs[0]) \(.DNSName | rtrimstr(".") | split(".")[0])"' \
|
|
||||||
>> "$TEMP_HOSTS"
|
|
||||||
```
|
|
||||||
|
|
||||||
`DNSName` is always set, always unique, and produces clean labels like `iphone171`, `ipad166`, `majorlab`, etc.
|
|
||||||
|
|
||||||
After patching the script and re-running it:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ bash /root/update_tailscale_hosts.sh
|
|
||||||
$ systemctl restart postfix
|
|
||||||
$ systemctl is-active postfix
|
|
||||||
active
|
|
||||||
```
|
|
||||||
|
|
||||||
## Why It's Hard to Spot
|
|
||||||
|
|
||||||
- The corruption only triggers when an iOS device is in the tailnet — so the script "worked" for months.
|
|
||||||
- `/etc/hosts` files are commonly skimmed top-down. The bogus `localhost` line is buried in the Tailscale block, well below the legitimate `127.0.0.1 localhost` line, and looks superficially like a normal Tailscale entry.
|
|
||||||
- Postfix's error message names the IP, not `localhost`, so the connection to `/etc/hosts` isn't obvious.
|
|
||||||
- `getent hosts localhost` shows the *first* match (`127.0.0.1`), not the one Postfix's resolver actually picks for `inet_interfaces` lookup.
|
|
||||||
|
|
||||||
## Verification Checklist
|
|
||||||
|
|
||||||
If you suspect this on any host using a similar generator script:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Any non-loopback "localhost" entries are bugs
|
|
||||||
grep -nE '^[0-9]+\..* localhost\s*$' /etc/hosts
|
|
||||||
|
|
||||||
# Look at iOS peers' HostName field
|
|
||||||
tailscale status --json | jq '.Peer[] | select(.OS == "iOS") | .HostName'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- [[majordiscord]] — affected host (incident logged 2026-04-29)
|
|
||||||
- [[Network Overview]] — Tailscale fleet topology
|
|
||||||
|
|
@ -11,7 +11,7 @@ tags:
|
||||||
- powershell
|
- powershell
|
||||||
status: published
|
status: published
|
||||||
created: 2026-04-03
|
created: 2026-04-03
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-22T09:20
|
||||||
---
|
---
|
||||||
|
|
||||||
# Windows OpenSSH: WSL as Default Shell Breaks Remote Commands
|
# Windows OpenSSH: WSL as Default Shell Breaks Remote Commands
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ tags:
|
||||||
- majorrig
|
- majorrig
|
||||||
status: published
|
status: published
|
||||||
created: 2026-04-02
|
created: 2026-04-02
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-22T09:20
|
||||||
---
|
---
|
||||||
# Windows OpenSSH Server (sshd) Stops After Reboot
|
# Windows OpenSSH Server (sshd) Stops After Reboot
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ tags:
|
||||||
- deno
|
- deno
|
||||||
status: published
|
status: published
|
||||||
created: 2026-04-02
|
created: 2026-04-02
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-22T11:33
|
||||||
---
|
---
|
||||||
# yt-dlp YouTube JS Challenge Fix (Fedora)
|
# yt-dlp YouTube JS Challenge Fix (Fedora)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
title: MajorWiki Deployment Status
|
title: MajorWiki Deployment Status
|
||||||
status: deployed
|
status: deployed
|
||||||
project: MajorTwin
|
project: MajorTwin
|
||||||
updated: 2026-04-30T05:30
|
updated: 2026-04-07T10:48
|
||||||
created: 2026-04-02T16:10
|
created: 2026-04-02T16:10
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -79,23 +79,6 @@ git push
|
||||||
|
|
||||||
Gitea receives the push → fires webhook → majorlab pulls → MkDocs rebuilds → `notes.majorshouse.com` updates automatically.
|
Gitea receives the push → fires webhook → majorlab pulls → MkDocs rebuilds → `notes.majorshouse.com` updates automatically.
|
||||||
|
|
||||||
> [!tip] One-liner wrapper
|
|
||||||
> On MajorRig, the `~/bin/wiki-commit "msg"` helper runs `git pull --rebase --autostash` → `git add -A` → `git commit` → `git push` in one shot. Sidesteps fast-forward rejections from cowork pushes (e.g. MajorAir pushing in parallel) and the empty-credentials issue with HTTPS.
|
|
||||||
|
|
||||||
## 🔒 Pre-Commit Hook (in repo)
|
|
||||||
|
|
||||||
`.githooks/pre-commit` (tracked) blocks any commit that adds or renames a `*.md` article without a corresponding entry in `SUMMARY.md`. Bypass with `git commit --no-verify` if you genuinely need to.
|
|
||||||
|
|
||||||
**Per-clone setup** (one-time, per workstation that uses the repo):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd <wiki-repo>
|
|
||||||
git config core.hooksPath .githooks
|
|
||||||
git config pull.rebase true
|
|
||||||
```
|
|
||||||
|
|
||||||
The hooksPath line is required — git doesn't run hooks from a tracked directory by default. The `pull.rebase true` makes plain `git pull` always rebase locally, matching the `wiki-commit` wrapper's behavior.
|
|
||||||
|
|
||||||
## 📋 Wiki Maintenance Protocol
|
## 📋 Wiki Maintenance Protocol
|
||||||
|
|
||||||
Every time a new article is added, the following **MUST** be updated to maintain index integrity:
|
Every time a new article is added, the following **MUST** be updated to maintain index integrity:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
created: 2026-04-06T09:52
|
created: 2026-04-06T09:52
|
||||||
updated: 2026-04-30T05:21
|
updated: 2026-04-29T22:46
|
||||||
---
|
---
|
||||||
# MajorLinux Tech Wiki — Index
|
# MajorLinux Tech Wiki — Index
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
created: 2026-04-02T16:03
|
created: 2026-04-02T16:03
|
||||||
updated: 2026-05-05T23:39
|
updated: 2026-04-29T22:45
|
||||||
---
|
---
|
||||||
* [Home](index.md)
|
* [Home](index.md)
|
||||||
* [Linux & Sysadmin](01-linux/index.md)
|
* [Linux & Sysadmin](01-linux/index.md)
|
||||||
|
|
@ -43,7 +43,6 @@ updated: 2026-05-05T23:39
|
||||||
* [Fail2ban Custom Jail: Apache 404 Scanner Detection](02-selfhosting/security/fail2ban-apache-404-scanner-jail.md)
|
* [Fail2ban Custom Jail: Apache 404 Scanner Detection](02-selfhosting/security/fail2ban-apache-404-scanner-jail.md)
|
||||||
* [Fail2ban Custom Jail: Apache PHP Webshell Probe Detection](02-selfhosting/security/fail2ban-apache-php-probe-jail.md)
|
* [Fail2ban Custom Jail: Apache PHP Webshell Probe Detection](02-selfhosting/security/fail2ban-apache-php-probe-jail.md)
|
||||||
* [Fail2ban Custom Jail: WordPress Login Brute Force](02-selfhosting/security/fail2ban-wordpress-login-jail.md)
|
* [Fail2ban Custom Jail: WordPress Login Brute Force](02-selfhosting/security/fail2ban-wordpress-login-jail.md)
|
||||||
* [wp-fail2ban Plugin Logpath on Debian/Ubuntu (auth.log not syslog)](02-selfhosting/security/wp-fail2ban-logpath-debian-ubuntu.md)
|
|
||||||
* [SELinux: Fixing Fail2ban grep execmem Denial](02-selfhosting/security/selinux-fail2ban-execmem-fix.md)
|
* [SELinux: Fixing Fail2ban grep execmem Denial](02-selfhosting/security/selinux-fail2ban-execmem-fix.md)
|
||||||
* [UFW Firewall Management](02-selfhosting/security/ufw-firewall-management.md)
|
* [UFW Firewall Management](02-selfhosting/security/ufw-firewall-management.md)
|
||||||
* [Firewall Hardening with firewalld on Fedora Fleet](02-selfhosting/security/firewalld-fleet-hardening.md)
|
* [Firewall Hardening with firewalld on Fedora Fleet](02-selfhosting/security/firewalld-fleet-hardening.md)
|
||||||
|
|
@ -51,8 +50,6 @@ updated: 2026-05-05T23:39
|
||||||
* [Fail2ban Custom Jail: Apache Bad Request Detection](02-selfhosting/security/fail2ban-apache-bad-request-jail.md)
|
* [Fail2ban Custom Jail: Apache Bad Request Detection](02-selfhosting/security/fail2ban-apache-bad-request-jail.md)
|
||||||
* [SSH Hardening Fleet-Wide with Ansible](02-selfhosting/security/ssh-hardening-ansible-fleet.md)
|
* [SSH Hardening Fleet-Wide with Ansible](02-selfhosting/security/ssh-hardening-ansible-fleet.md)
|
||||||
* [ClamAV Fleet Deployment with Ansible](02-selfhosting/security/clamav-fleet-deployment.md)
|
* [ClamAV Fleet Deployment with Ansible](02-selfhosting/security/clamav-fleet-deployment.md)
|
||||||
* [Fail2Ban Digest Mode — Fleet-Wide Quiet Alerts](02-selfhosting/security/fail2ban-digest-mode-fleet.md)
|
|
||||||
* [Apache CVE-2026-23918 — HTTP/2 Double Free Mitigation](02-selfhosting/security/apache-cve-2026-23918-http2-mitigation.md)
|
|
||||||
* [Open Source & Alternatives](03-opensource/index.md)
|
* [Open Source & Alternatives](03-opensource/index.md)
|
||||||
* [SearXNG: Private Self-Hosted Search](03-opensource/alternatives/searxng.md)
|
* [SearXNG: Private Self-Hosted Search](03-opensource/alternatives/searxng.md)
|
||||||
* [FreshRSS: Self-Hosted RSS Reader](03-opensource/alternatives/freshrss.md)
|
* [FreshRSS: Self-Hosted RSS Reader](03-opensource/alternatives/freshrss.md)
|
||||||
|
|
@ -80,7 +77,6 @@ updated: 2026-05-05T23:39
|
||||||
* [ISP SNI Filtering with Caddy](05-troubleshooting/isp-sni-filtering-caddy.md)
|
* [ISP SNI Filtering with Caddy](05-troubleshooting/isp-sni-filtering-caddy.md)
|
||||||
* [Obsidian Vault Recovery — Loading Cache Hang](05-troubleshooting/obsidian-cache-hang-recovery.md)
|
* [Obsidian Vault Recovery — Loading Cache Hang](05-troubleshooting/obsidian-cache-hang-recovery.md)
|
||||||
* [Qwen2.5-14B OOM on RTX 3080 Ti (12GB)](05-troubleshooting/gpu-display/qwen-14b-oom-3080ti.md)
|
* [Qwen2.5-14B OOM on RTX 3080 Ti (12GB)](05-troubleshooting/gpu-display/qwen-14b-oom-3080ti.md)
|
||||||
* [LoRA adapter — GGUF conversion fails with 'config.json not found'](05-troubleshooting/gpu-display/lora-adapter-gguf-conversion-fails.md)
|
|
||||||
* [yt-dlp YouTube JS Challenge Fix on Fedora](05-troubleshooting/yt-dlp-fedora-js-challenge.md)
|
* [yt-dlp YouTube JS Challenge Fix on Fedora](05-troubleshooting/yt-dlp-fedora-js-challenge.md)
|
||||||
* [Gemini CLI Manual Update](05-troubleshooting/gemini-cli-manual-update.md)
|
* [Gemini CLI Manual Update](05-troubleshooting/gemini-cli-manual-update.md)
|
||||||
* [MajorWiki Setup & Publishing Pipeline](05-troubleshooting/majwiki-setup-and-pipeline.md)
|
* [MajorWiki Setup & Publishing Pipeline](05-troubleshooting/majwiki-setup-and-pipeline.md)
|
||||||
|
|
@ -94,13 +90,11 @@ updated: 2026-05-05T23:39
|
||||||
* [Ollama Drops Off Tailscale When Mac Sleeps](05-troubleshooting/ollama-macos-sleep-tailscale-disconnect.md)
|
* [Ollama Drops Off Tailscale When Mac Sleeps](05-troubleshooting/ollama-macos-sleep-tailscale-disconnect.md)
|
||||||
* [Ollama: `ollama run` with Piped Stdin Bypasses Chat Template + SYSTEM Prompt](05-troubleshooting/ollama-chat-template-pipe-stdin-bypass.md)
|
* [Ollama: `ollama run` with Piped Stdin Bypasses Chat Template + SYSTEM Prompt](05-troubleshooting/ollama-chat-template-pipe-stdin-bypass.md)
|
||||||
* [rsync over Tailscale: Hung in TCP Teardown After Transfer Completes](05-troubleshooting/networking/rsync-tailscale-teardown-stall.md)
|
* [rsync over Tailscale: Hung in TCP Teardown After Transfer Completes](05-troubleshooting/networking/rsync-tailscale-teardown-stall.md)
|
||||||
* [iOS Tailscale Clients Report HostName="localhost" — Breaks /etc/hosts Generators](05-troubleshooting/networking/tailscale-status-json-hostname-localhost-ios.md)
|
|
||||||
* [macOS: Repeating Alert Tone from Mirrored iPhone Notification](05-troubleshooting/macos-mirrored-notification-alert-loop.md)
|
* [macOS: Repeating Alert Tone from Mirrored iPhone Notification](05-troubleshooting/macos-mirrored-notification-alert-loop.md)
|
||||||
* [ClamAV CPU Spike: Safe Scheduling with nice/ionice](05-troubleshooting/security/clamscan-cpu-spike-nice-ionice.md)
|
* [ClamAV CPU Spike: Safe Scheduling with nice/ionice](05-troubleshooting/security/clamscan-cpu-spike-nice-ionice.md)
|
||||||
* [Ansible: Vault Password File Not Found](05-troubleshooting/ansible-vault-password-file-missing.md)
|
* [Ansible: Vault Password File Not Found](05-troubleshooting/ansible-vault-password-file-missing.md)
|
||||||
* [Ansible: ansible.cfg Ignored on WSL2 Windows Mounts](05-troubleshooting/ansible-wsl2-world-writable-mount-ignores-cfg.md)
|
* [Ansible: ansible.cfg Ignored on WSL2 Windows Mounts](05-troubleshooting/ansible-wsl2-world-writable-mount-ignores-cfg.md)
|
||||||
* [Ansible: SSH Timeout During dnf upgrade on Fedora Hosts](05-troubleshooting/ansible-ssh-timeout-dnf-upgrade.md)
|
* [Ansible: SSH Timeout During dnf upgrade on Fedora Hosts](05-troubleshooting/ansible-ssh-timeout-dnf-upgrade.md)
|
||||||
* [Ansible: regex_search Capture-Group Argument Fails in set_fact](05-troubleshooting/ansible-regex-search-set-fact-capture-group.md)
|
|
||||||
* [Fedora Networking & Kernel Troubleshooting](05-troubleshooting/fedora-networking-kernel-recovery.md)
|
* [Fedora Networking & Kernel Troubleshooting](05-troubleshooting/fedora-networking-kernel-recovery.md)
|
||||||
* [Systemd Session Scope Fails at Login](05-troubleshooting/systemd/session-scope-failure-at-login.md)
|
* [Systemd Session Scope Fails at Login](05-troubleshooting/systemd/session-scope-failure-at-login.md)
|
||||||
* [wget/curl: URLs with Special Characters Fail in Bash](05-troubleshooting/wget-url-special-characters.md)
|
* [wget/curl: URLs with Special Characters Fail in Bash](05-troubleshooting/wget-url-special-characters.md)
|
||||||
|
|
|
||||||
336
index.md
336
index.md
|
|
@ -1,210 +1,179 @@
|
||||||
---
|
---
|
||||||
created: 2026-04-06T09:52
|
created: 2026-04-06T09:52
|
||||||
updated: 2026-05-02T16:45
|
updated: 2026-04-29T22:45
|
||||||
---
|
---
|
||||||
# MajorLinux Tech Wiki — Index
|
# MajorLinux Tech Wiki — Index
|
||||||
|
|
||||||
> A growing reference of Linux, self-hosting, open source, streaming, and troubleshooting guides. Written by MajorLinux. Used by MajorTwin.
|
> A growing reference of Linux, self-hosting, open source, streaming, and troubleshooting guides. Written by MajorLinux. Used by MajorTwin.
|
||||||
>
|
>
|
||||||
> **Last updated:** 2026-05-02
|
> **Last updated:** 2026-04-18
|
||||||
> **Article count:** 106
|
> **Article count:** 89
|
||||||
|
|
||||||
## Domains
|
## Domains
|
||||||
|
|
||||||
| Domain | Folder | Articles |
|
| Domain | Folder | Articles |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 🐧 Linux & Sysadmin | `01-linux/` | 12 |
|
| 🐧 Linux & Sysadmin | `01-linux/` | 12 |
|
||||||
| 🏠 Self-Hosting & Homelab | `02-selfhosting/` | 39 |
|
| 🏠 Self-Hosting & Homelab | `02-selfhosting/` | 32 |
|
||||||
| 🔓 Open Source Tools | `03-opensource/` | 10 |
|
| 🔓 Open Source Tools | `03-opensource/` | 10 |
|
||||||
| 🎙️ Streaming & Podcasting | `04-streaming/` | 2 |
|
| 🎙️ Streaming & Podcasting | `04-streaming/` | 2 |
|
||||||
| 🔧 General Troubleshooting | `05-troubleshooting/` | 43 |
|
| 🔧 General Troubleshooting | `05-troubleshooting/` | 34 |
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🐧 Linux & Sysadmin
|
## 🐧 Linux & Sysadmin
|
||||||
|
|
||||||
### Distro-Specific
|
|
||||||
- [Linux Distro Guide for Beginners](01-linux/distro-specific/linux-distro-guide-beginners.md)
|
|
||||||
- [WSL2 Backup via PowerShell Scheduled Task](01-linux/distro-specific/wsl2-backup-powershell.md)
|
|
||||||
- [WSL2 Instance Migration (Fedora 43)](01-linux/distro-specific/wsl2-instance-migration-fedora43.md)
|
|
||||||
- [Wsl2 Rebuild Fedora43 Training Env](01-linux/distro-specific/wsl2-rebuild-fedora43-training-env.md)
|
|
||||||
|
|
||||||
### Files & Permissions
|
### Files & Permissions
|
||||||
- [Linux File Permissions and Ownership](01-linux/files-permissions/linux-file-permissions.md)
|
- [Linux File Permissions](01-linux/files-permissions/linux-file-permissions.md) — chmod, chown, special bits, finding permission problems
|
||||||
|
|
||||||
### Networking
|
|
||||||
- [SSH Config and Key Management](01-linux/networking/ssh-config-key-management.md)
|
|
||||||
|
|
||||||
### Package Management
|
|
||||||
- [Linux Package Management Reference: apt, dnf, pacman](01-linux/packages/package-management-reference.md)
|
|
||||||
|
|
||||||
### Process Management
|
### Process Management
|
||||||
- [Managing Linux Services: systemd and Ansible](01-linux/process-management/managing-linux-services-systemd-ansible.md)
|
- [Managing Linux Services with systemd](01-linux/process-management/managing-linux-services-systemd-ansible.md) — systemctl, journalctl, writing service files, Ansible service management
|
||||||
|
|
||||||
|
### Networking
|
||||||
|
- [SSH Config & Key Management](01-linux/networking/ssh-config-key-management.md) — key generation, ssh-copy-id, ~/.ssh/config, managing multiple keys, Windows OpenSSH admin key auth
|
||||||
|
|
||||||
|
### Package Management
|
||||||
|
- [Package Management Reference](01-linux/packages/package-management-reference.md) — apt, dnf, pacman side-by-side reference, Flatpak/Snap
|
||||||
|
|
||||||
### Shell & Scripting
|
### Shell & Scripting
|
||||||
- [Ansible Getting Started: Inventory, Playbooks, and Ad-Hoc Commands](01-linux/shell-scripting/ansible-getting-started.md)
|
- [Ansible Getting Started](01-linux/shell-scripting/ansible-getting-started.md) — inventory, ad-hoc commands, playbooks, handlers, roles
|
||||||
- [Bash Scripting Patterns for Sysadmins](01-linux/shell-scripting/bash-scripting-patterns.md)
|
- [Bash Scripting Patterns](01-linux/shell-scripting/bash-scripting-patterns.md) — set -euo pipefail, logging, error handling, argument parsing, common patterns
|
||||||
|
|
||||||
### Storage
|
### Storage
|
||||||
- [SnapRAID & MergerFS Storage Setup](01-linux/storage/snapraid-mergerfs-setup.md)
|
- [SnapRAID & MergerFS Storage Setup](01-linux/storage/snapraid-mergerfs-setup.md) — Pooling mismatched drives and adding parity on Linux
|
||||||
- [mdadm — Rebuilding a RAID Array After Reinstall](01-linux/storage/mdadm-raid-rebuild.md)
|
- [mdadm — Rebuilding a RAID Array After Reinstall](01-linux/storage/mdadm-raid-rebuild.md) — reassembling and recovering mdadm arrays after OS reinstall
|
||||||
|
|
||||||
|
### Distro-Specific
|
||||||
|
- [Linux Distro Guide for Beginners](01-linux/distro-specific/linux-distro-guide-beginners.md) — Ubuntu recommendation, distro comparison, desktop environments
|
||||||
|
- [WSL2 Instance Migration to Fedora 43](01-linux/distro-specific/wsl2-instance-migration-fedora43.md) — moving WSL2 VHDX from C: to another drive
|
||||||
|
- [WSL2 Training Environment Rebuild (Fedora 43)](01-linux/distro-specific/wsl2-rebuild-fedora43-training-env.md) — rebuilding the MajorTwin training env in WSL2 from scratch
|
||||||
|
- [WSL2 Backup via PowerShell Scheduled Task](01-linux/distro-specific/wsl2-backup-powershell.md) — automating WSL2 exports on a schedule using PowerShell
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🏠 Self-Hosting & Homelab
|
## 🏠 Self-Hosting & Homelab
|
||||||
|
|
||||||
### Cloud
|
|
||||||
- [AWS S3 Cost Management](02-selfhosting/cloud/aws-s3-cost-management.md)
|
|
||||||
|
|
||||||
### DNS & Networking
|
|
||||||
- [Network Overview](02-selfhosting/dns-networking/network-overview.md)
|
|
||||||
- [Pi-hole DoH / DoT Bypass Defense](02-selfhosting/dns-networking/pihole-doh-dot-bypass-defense.md)
|
|
||||||
- [Pi-hole v6 Adlist Management via SQL](02-selfhosting/dns-networking/pihole-v6-adlist-management.md)
|
|
||||||
- [Pi-hole v6 Group Management: Per-Client DNS Rules](02-selfhosting/dns-networking/pihole-v6-group-management.md)
|
|
||||||
- [Tailscale for Homelab Remote Access](02-selfhosting/dns-networking/tailscale-homelab-remote-access.md)
|
|
||||||
- [Wake-on-LAN via Router SSH](02-selfhosting/dns-networking/wake-on-lan-router-ssh.md)
|
|
||||||
|
|
||||||
### Docker & Containers
|
### Docker & Containers
|
||||||
- [Debugging Broken Docker Containers](02-selfhosting/docker/debugging-broken-docker-containers.md)
|
- [Self-Hosting Starter Guide](02-selfhosting/docker/self-hosting-starter-guide.md) — hardware options, Docker install, first services, networking basics
|
||||||
- [Docker Healthchecks](02-selfhosting/docker/docker-healthchecks.md)
|
- [Docker vs VMs for the Homelab](02-selfhosting/docker/docker-vs-vms-homelab.md) — when to use containers vs VMs, KVM setup, how to run both
|
||||||
- [Docker vs VMs in the Homelab: Why Not Both?](02-selfhosting/docker/docker-vs-vms-homelab.md)
|
- [Debugging Broken Docker Containers](02-selfhosting/docker/debugging-broken-docker-containers.md) — logs, inspect, exec, port conflicts, permission errors
|
||||||
- [Self-Hosting Starter Guide](02-selfhosting/docker/self-hosting-starter-guide.md)
|
- [Docker Healthchecks](02-selfhosting/docker/docker-healthchecks.md) — writing and debugging HEALTHCHECK instructions in Docker containers
|
||||||
- [Watchtower SMTP via Localhost Postfix Relay](02-selfhosting/docker/watchtower-smtp-localhost-relay.md)
|
- [Watchtower SMTP via Localhost Postfix Relay](02-selfhosting/docker/watchtower-smtp-localhost-relay.md) — credential-free container update notifications by routing through a local Postfix relay
|
||||||
|
|
||||||
### Monitoring
|
|
||||||
- [Deploying Netdata to a New Server](02-selfhosting/monitoring/netdata-new-server-setup.md)
|
|
||||||
- [Netdata SELinux AVC Denial Monitoring](02-selfhosting/monitoring/netdata-selinux-avc-chart.md)
|
|
||||||
- [Netdata n8n Enriched Alert Emails](02-selfhosting/monitoring/netdata-n8n-enriched-alerts.md)
|
|
||||||
- [Tuning Netdata Docker Health Alarms to Prevent Update Flapping](02-selfhosting/monitoring/netdata-docker-health-alarm-tuning.md)
|
|
||||||
- [Tuning Netdata Web Log Alerts](02-selfhosting/monitoring/tuning-netdata-web-log-alerts.md)
|
|
||||||
|
|
||||||
### Reverse Proxies
|
### Reverse Proxies
|
||||||
- [Setting Up a Reverse Proxy with Caddy](02-selfhosting/reverse-proxy/setting-up-caddy-reverse-proxy.md)
|
- [Setting Up Caddy as a Reverse Proxy](02-selfhosting/reverse-proxy/setting-up-caddy-reverse-proxy.md) — Caddyfile basics, automatic HTTPS, local TLS, DNS challenge
|
||||||
|
|
||||||
### Security
|
### DNS & Networking
|
||||||
- [ClamAV Fleet Deployment with Ansible](02-selfhosting/security/clamav-fleet-deployment.md)
|
- [Tailscale for Homelab Remote Access](02-selfhosting/dns-networking/tailscale-homelab-remote-access.md) — installation, MagicDNS, making services accessible, subnet router, ACLs
|
||||||
- [Fail2Ban Digest Mode — Fleet-Wide Quiet Alerts](02-selfhosting/security/fail2ban-digest-mode-fleet.md)
|
- [Network Overview](02-selfhosting/dns-networking/network-overview.md) — MajorsHouse network topology, Tailscale IPs, and connectivity map
|
||||||
- [Fail2ban Custom Jail: Apache 404 Scanner Detection](02-selfhosting/security/fail2ban-apache-404-scanner-jail.md)
|
- [Wake-on-LAN via Router SSH](02-selfhosting/dns-networking/wake-on-lan-router-ssh.md) — send WOL magic packets through an Asus router over SSH, with Ansible vault integration
|
||||||
- [Fail2ban Custom Jail: Apache Bad Request Detection](02-selfhosting/security/fail2ban-apache-bad-request-jail.md)
|
|
||||||
- [Fail2ban Custom Jail: Apache PHP Webshell Probe Detection](02-selfhosting/security/fail2ban-apache-php-probe-jail.md)
|
|
||||||
- [Fail2ban Custom Jail: WordPress Login Brute Force](02-selfhosting/security/fail2ban-wordpress-login-jail.md)
|
|
||||||
- [Fail2ban: Enable the nginx-bad-request Jail](02-selfhosting/security/fail2ban-nginx-bad-request-jail.md)
|
|
||||||
- [Firewall Hardening with firewalld on Fedora Fleet](02-selfhosting/security/firewalld-fleet-hardening.md)
|
|
||||||
- [Linux Server Hardening Checklist](02-selfhosting/security/linux-server-hardening-checklist.md)
|
|
||||||
- [SELinux: Fixing Fail2ban grep execmem Denial on Fedora](02-selfhosting/security/selinux-fail2ban-execmem-fix.md)
|
|
||||||
- [SSH Hardening Fleet-Wide with Ansible](02-selfhosting/security/ssh-hardening-ansible-fleet.md)
|
|
||||||
- [Standardizing unattended-upgrades Across Ubuntu Fleet with Ansible](02-selfhosting/security/ansible-unattended-upgrades-fleet.md)
|
|
||||||
- [UFW Firewall Management](02-selfhosting/security/ufw-firewall-management.md)
|
|
||||||
- [wp-fail2ban Plugin Logpath on Debian/Ubuntu (auth.log, not syslog)](02-selfhosting/security/wp-fail2ban-logpath-debian-ubuntu.md)
|
|
||||||
|
|
||||||
### Services
|
### Cloud
|
||||||
- [Claude Code Remote Control — Mobile Access to a Persistent Host Session](02-selfhosting/services/claude-code-remote-control.md)
|
- [AWS S3 Cost Management](02-selfhosting/cloud/aws-s3-cost-management.md) — identify and control S3 costs: lifecycle rules, storage class selection, bucket inventory, unexpected-growth investigation
|
||||||
- [Ghost Email Configuration with Mailgun](02-selfhosting/services/ghost-smtp-mailgun-setup.md)
|
|
||||||
- [Mastodon DB Maintenance — Statuses, Accounts, and VACUUM](02-selfhosting/services/mastodon-db-maintenance.md)
|
|
||||||
- [Mastodon Federation — Domain Blocks, Silencing, and FediSeer](02-selfhosting/services/mastodon-federation.md)
|
|
||||||
- [Mastodon Instance Tuning](02-selfhosting/services/mastodon-instance-tuning.md)
|
|
||||||
- [Updating n8n Running in Docker](02-selfhosting/services/updating-n8n-docker.md)
|
|
||||||
|
|
||||||
### Storage & Backup
|
### Storage & Backup
|
||||||
- [rsync Backup Patterns](02-selfhosting/storage-backup/rsync-backup-patterns.md)
|
- [rsync Backup Patterns](02-selfhosting/storage-backup/rsync-backup-patterns.md) — flags reference, remote backup, incremental with hard links, cron/systemd
|
||||||
|
|
||||||
|
### Monitoring
|
||||||
|
- [Tuning Netdata Web Log Alerts](02-selfhosting/monitoring/tuning-netdata-web-log-alerts.md) — tuning web_log_1m_redirects threshold for HTTPS-forcing servers
|
||||||
|
- [Tuning Netdata Docker Health Alarms](02-selfhosting/monitoring/netdata-docker-health-alarm-tuning.md) — preventing false alerts during nightly Nextcloud AIO container update cycles
|
||||||
|
- [Deploying Netdata to a New Server](02-selfhosting/monitoring/netdata-new-server-setup.md) — install, email notifications, and Netdata Cloud claim for Ubuntu/Debian servers
|
||||||
|
- [Netdata + n8n Enriched Alert Emails](02-selfhosting/monitoring/netdata-n8n-enriched-alerts.md) — rich HTML alert emails with remediation steps and wiki links via n8n
|
||||||
|
- [Netdata SELinux AVC Denial Monitoring](02-selfhosting/monitoring/netdata-selinux-avc-chart.md) — custom Netdata chart for tracking SELinux AVC denials
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- [Linux Server Hardening Checklist](02-selfhosting/security/linux-server-hardening-checklist.md) — non-root user, SSH key auth, sshd_config, firewall, fail2ban, SpamAssassin
|
||||||
|
- [Standardizing unattended-upgrades with Ansible](02-selfhosting/security/ansible-unattended-upgrades-fleet.md) — fleet-wide automatic security updates across Ubuntu servers
|
||||||
|
- [Fail2ban Custom Jail: Apache 404 Scanner Detection](02-selfhosting/security/fail2ban-apache-404-scanner-jail.md) — custom filter and jail for blocking 404 scanners
|
||||||
|
- [Fail2ban Custom Jail: Apache PHP Webshell Probe Detection](02-selfhosting/security/fail2ban-apache-php-probe-jail.md) — catching PHP webshell/backdoor probes that return 301 on HTTPS-redirecting servers
|
||||||
|
- [Fail2ban Custom Jail: WordPress Login Brute Force](02-selfhosting/security/fail2ban-wordpress-login-jail.md) — access-log-based wp-login.php brute force detection without plugins
|
||||||
|
- [SELinux: Fixing Fail2ban grep execmem Denial](02-selfhosting/security/selinux-fail2ban-execmem-fix.md) — resolving execmem AVC denials from Fail2ban's grep on Fedora
|
||||||
|
- [UFW Firewall Management](02-selfhosting/security/ufw-firewall-management.md) — managing UFW rules, common patterns, troubleshooting
|
||||||
|
- [Firewall Hardening with firewalld on Fedora Fleet](02-selfhosting/security/firewalld-fleet-hardening.md) — audit-and-harden pattern for Fedora fleet hosts using Ansible; flush stale rules, rebuild minimal whitelists
|
||||||
|
- [Fail2ban Custom Jail: Nginx Bad Request Detection](02-selfhosting/security/fail2ban-nginx-bad-request-jail.md) — wiring the stock nginx-bad-request filter to a jail to catch malformed-request scanners
|
||||||
|
- [Fail2ban Custom Jail: Apache Bad Request Detection](02-selfhosting/security/fail2ban-apache-bad-request-jail.md) — custom filter for Apache 400 Bad Request responses (no stock equivalent exists)
|
||||||
|
- [SSH Hardening Fleet-Wide with Ansible](02-selfhosting/security/ssh-hardening-ansible-fleet.md) — drop-in sshd config hardening across mixed Ubuntu/Fedora fleets
|
||||||
|
- [ClamAV Fleet Deployment with Ansible](02-selfhosting/security/clamav-fleet-deployment.md) — deploy ClamAV with nice/ionice throttling, freshclam, and quarantine to internet-facing hosts
|
||||||
|
|
||||||
|
### Services
|
||||||
|
- [Updating n8n Running in Docker](02-selfhosting/services/updating-n8n-docker.md) — pinned version updates, password reset, Arcane timing gaps
|
||||||
|
- [Mastodon Instance Tuning](02-selfhosting/services/mastodon-instance-tuning.md) — character limit increase, media cache management for self-hosted Mastodon
|
||||||
|
- [Ghost Email Configuration with Mailgun](02-selfhosting/services/ghost-smtp-mailgun-setup.md) — configuring Ghost's two independent mail systems (newsletter API + transactional SMTP) with Mailgun
|
||||||
|
- [Claude Code Remote Control — Mobile Access to a Persistent Host Session](02-selfhosting/services/claude-code-remote-control.md) — running `claude remote-control` on a host so `claude.ai` and the Claude mobile app can drive the CLI, with vault + MCPs intact
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔓 Open Source Tools
|
## 🔓 Open Source Tools
|
||||||
|
|
||||||
### Alternatives
|
### Alternatives
|
||||||
- [FreshRSS — Self-Hosted RSS Reader](03-opensource/alternatives/freshrss.md)
|
- [SearXNG: Private Self-Hosted Search](03-opensource/alternatives/searxng.md) — metasearch engine that queries multiple engines without exposing your identity
|
||||||
- [Gitea — Self-Hosted Git](03-opensource/alternatives/gitea.md)
|
- [FreshRSS: Self-Hosted RSS Reader](03-opensource/alternatives/freshrss.md) — algorithm-free feed aggregator with mobile app sync
|
||||||
- [SearXNG — Private Self-Hosted Search](03-opensource/alternatives/searxng.md)
|
- [Gitea: Self-Hosted Git](03-opensource/alternatives/gitea.md) — lightweight GitHub alternative, webhooks, single Docker container
|
||||||
|
|
||||||
### Development Tools
|
|
||||||
- [Ventoy — Multi-Boot USB Tool](03-opensource/dev-tools/ventoy.md)
|
|
||||||
- [rsync — Fast, Resumable File Transfers](03-opensource/dev-tools/rsync.md)
|
|
||||||
- [screen — Simple Persistent Terminal Sessions](03-opensource/dev-tools/screen.md)
|
|
||||||
- [tmux — Persistent Terminal Sessions](03-opensource/dev-tools/tmux.md)
|
|
||||||
|
|
||||||
### Media & Creative
|
|
||||||
- [yt-dlp — Video Downloading](03-opensource/media-creative/yt-dlp.md)
|
|
||||||
|
|
||||||
### Privacy & Security
|
|
||||||
- [Vaultwarden — Self-Hosted Password Manager](03-opensource/privacy-security/vaultwarden.md)
|
|
||||||
|
|
||||||
### Productivity
|
### Productivity
|
||||||
- [rmlint — Extreme Duplicate File Scanning](03-opensource/productivity/rmlint-duplicate-scanning.md)
|
- [rmlint: Duplicate File Scanning](03-opensource/productivity/rmlint-duplicate-scanning.md) — extremely fast duplicate file finding and storage reclamation
|
||||||
|
|
||||||
|
### Development Tools
|
||||||
|
- [tmux: Persistent Terminal Sessions](03-opensource/dev-tools/tmux.md) — detachable sessions for long-running jobs over SSH
|
||||||
|
- [screen: Simple Persistent Sessions](03-opensource/dev-tools/screen.md) — lightweight terminal multiplexer, universally available
|
||||||
|
- [rsync: Fast, Resumable File Transfers](03-opensource/dev-tools/rsync.md) — incremental file sync locally and over SSH, survives interruptions
|
||||||
|
- [Ventoy: Multi-Boot USB Tool](03-opensource/dev-tools/ventoy.md) — drop ISOs on a USB drive and boot any of them, no reflashing
|
||||||
|
|
||||||
|
### Privacy & Security
|
||||||
|
- [Vaultwarden: Self-Hosted Password Manager](03-opensource/privacy-security/vaultwarden.md) — Bitwarden-compatible server in a single Docker container, passwords stay on your hardware
|
||||||
|
|
||||||
|
### Media & Creative
|
||||||
|
- [yt-dlp: Video Downloading](03-opensource/media-creative/yt-dlp.md) — download from YouTube and hundreds of other sites, Plex-optimized format selection
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎙️ Streaming & Podcasting
|
## 🎙️ Streaming & Podcasting
|
||||||
|
|
||||||
### OBS Studio
|
### OBS Studio
|
||||||
- [OBS Studio Setup and Encoding Settings](04-streaming/obs/obs-studio-setup-encoding.md)
|
- [OBS Studio Setup & Encoding](04-streaming/obs/obs-studio-setup-encoding.md) — installation, NVENC/x264 settings, scene setup, audio filters, Linux Wayland notes
|
||||||
|
|
||||||
### Plex
|
### Plex
|
||||||
- [Plex 4K Codec Compatibility (Apple TV)](04-streaming/plex/plex-4k-codec-compatibility.md)
|
- [Plex 4K Codec Compatibility (Apple TV)](04-streaming/plex/plex-4k-codec-compatibility.md) — AV1/VP9 vs HEVC, batch conversion script, yt-dlp auto-convert hook
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔧 General Troubleshooting
|
## 🔧 General Troubleshooting
|
||||||
|
|
||||||
- [Ansible Check Mode False Positives in Verify/Assert Tasks](05-troubleshooting/ansible-check-mode-false-positives.md)
|
- [Apache Outage: Fail2ban Self-Ban + Missing iptables Rules](05-troubleshooting/networking/fail2ban-self-ban-apache-outage.md) — diagnosing and fixing Apache outages caused by missing firewall rules and Fail2ban self-bans
|
||||||
- [Ansible Fails with Permission Denied While `ssh <alias>` Works (Host Alias Bypass)](05-troubleshooting/ansible-ssh-host-alias-bypass.md)
|
- [Mail Client Stops Receiving: Fail2ban IMAP Self-Ban](05-troubleshooting/networking/fail2ban-imap-self-ban-mail-client.md) — diagnosing why one device stops receiving email when the mail server is healthy
|
||||||
- [Ansible SSH Timeout During dnf upgrade on Fedora Hosts](05-troubleshooting/ansible-ssh-timeout-dnf-upgrade.md)
|
- [firewalld: Mail Ports Wiped After Reload](05-troubleshooting/networking/firewalld-mail-ports-reset.md) — recovering IMAP and webmail after firewalld reload drops all mail service rules
|
||||||
- [Ansible: Vault Password File Not Found](05-troubleshooting/ansible-vault-password-file-missing.md)
|
- [Fail2ban & UFW Rule Bloat: 30k Rules Slowing Down a VPS](05-troubleshooting/networking/fail2ban-ufw-rule-bloat-cleanup.md) — diagnosing and cleaning up massive nftables/UFW rule accumulation
|
||||||
- [Ansible Ignores ansible.cfg on WSL2 Windows Mounts](05-troubleshooting/ansible-wsl2-world-writable-mount-ignores-cfg.md)
|
- [Tailscale SSH: Unexpected Re-Authentication Prompt](05-troubleshooting/networking/tailscale-ssh-reauth-prompt.md) — resolving unexpected re-auth prompts on Tailscale SSH connections
|
||||||
- [claude-mem Silently Fails with Claude Code 2.1+ (Empty --setting-sources)](05-troubleshooting/claude-mem-setting-sources-empty-arg.md)
|
- [Docker & Caddy Recovery After Reboot (Fedora + SELinux)](05-troubleshooting/docker-caddy-selinux-post-reboot-recovery.md) — fixing docker.socket, SELinux port blocks, and httpd_can_network_connect after reboot
|
||||||
- [Cron Heartbeat False Alarm: /var/run Cleared by Reboot](05-troubleshooting/cron-heartbeat-tmpfs-reboot-false-alarm.md)
|
- [n8n Behind Reverse Proxy: X-Forwarded-For Trust Fix](05-troubleshooting/docker/n8n-proxy-trust-x-forwarded-for.md) — fixing webhook failures caused by missing proxy trust configuration
|
||||||
- [Docker & Caddy Recovery After Reboot (Fedora + SELinux)](05-troubleshooting/docker-caddy-selinux-post-reboot-recovery.md)
|
- [Nextcloud AIO Container Unhealthy for 20 Hours](05-troubleshooting/docker/nextcloud-aio-unhealthy-20h-stuck.md) — diagnosing stuck Nextcloud AIO containers after nightly update cycles
|
||||||
- [Fantastical Google Sync Error Flood — Phantom Calendars Fixed via syncselect](05-troubleshooting/fantastical-google-phantom-calendar-syncselect.md)
|
- [ISP SNI Filtering with Caddy](05-troubleshooting/isp-sni-filtering-caddy.md) — troubleshooting why wiki.majorshouse.com was blocked by Google Fiber
|
||||||
- [Fantastical MCP Server: Permission Denied on Launch (macOS Quarantine)](05-troubleshooting/fantastical-mcp-permission-denied.md)
|
- [Obsidian Cache Hang Recovery](05-troubleshooting/obsidian-cache-hang-recovery.md) — resolving "Loading cache" hang in Obsidian by cleaning Electron app data and ML artifacts
|
||||||
- [Fedora Networking & Kernel Troubleshooting](05-troubleshooting/fedora-networking-kernel-recovery.md)
|
- [macOS Repeating Alert Tone from Mirrored Notification](05-troubleshooting/macos-mirrored-notification-alert-loop.md) — stopping alert tone loops from mirrored iPhone notifications on Mac
|
||||||
- [Gemini CLI: Manual Update Guide](05-troubleshooting/gemini-cli-manual-update.md)
|
- [Qwen2.5-14B OOM on RTX 3080 Ti (12GB)](05-troubleshooting/gpu-display/qwen-14b-oom-3080ti.md) — fixes and alternatives when hitting VRAM limits during fine-tuning
|
||||||
- [Ghost EmailAnalytics Lag Warning — What It Means and When to Worry](05-troubleshooting/ghost-emailanalytics-lag-warning.md)
|
- [yt-dlp YouTube JS Challenge Fix on Fedora](05-troubleshooting/yt-dlp-fedora-js-challenge.md) — fixing YouTube JS challenge solver errors and missing formats on Fedora
|
||||||
- [Gitea Actions Runner: Boot Race Condition Fix](05-troubleshooting/gitea-runner-boot-race-network-target.md)
|
- [Gemini CLI Manual Update](05-troubleshooting/gemini-cli-manual-update.md) — how to manually update the Gemini CLI when automatic updates fail
|
||||||
- [ISP SNI Filtering & Caddy Troubleshooting](05-troubleshooting/isp-sni-filtering-caddy.md)
|
- [MajorWiki Setup & Pipeline](05-troubleshooting/majwiki-setup-and-pipeline.md) — setting up MajorWiki and the Obsidian → Gitea → MkDocs publishing pipeline
|
||||||
- [macOS Repeating Alert Tone from Mirrored iPhone Notification](05-troubleshooting/macos-mirrored-notification-alert-loop.md)
|
- [Gitea Actions Runner: Boot Race Condition Fix](05-troubleshooting/gitea-runner-boot-race-network-target.md) — fixing act_runner crash loop on boot caused by DNS not ready at startup
|
||||||
- [MajorWiki Setup & Publishing Pipeline](05-troubleshooting/majwiki-setup-and-pipeline.md)
|
- [Cron Heartbeat False Alarm: /var/run Cleared by Reboot](05-troubleshooting/cron-heartbeat-tmpfs-reboot-false-alarm.md) — why `/run` is tmpfs and how a reboot wipes cron heartbeat files, and where to put them instead
|
||||||
- [Obsidian Vault Recovery — Loading Cache Hang](05-troubleshooting/obsidian-cache-hang-recovery.md)
|
- [SELinux: Fixing Dovecot Mail Spool Context (/var/vmail)](05-troubleshooting/selinux-dovecot-vmail-context.md) — fixing thousands of AVC denials when /var/vmail has wrong SELinux context
|
||||||
- [Ollama: `ollama run` with Piped Stdin Bypasses Chat Template + SYSTEM Prompt](05-troubleshooting/ollama-chat-template-pipe-stdin-bypass.md)
|
- [mdadm RAID Recovery After USB Hub Disconnect](05-troubleshooting/storage/mdadm-usb-hub-disconnect-recovery.md) — diagnosing and recovering a failed mdadm array caused by a USB hub dropout
|
||||||
- [Ollama Drops Off Tailscale When Mac Sleeps](05-troubleshooting/ollama-macos-sleep-tailscale-disconnect.md)
|
- [Windows OpenSSH Server (sshd) Stops After Reboot](05-troubleshooting/networking/windows-sshd-stops-after-reboot.md) — fixing sshd not running after reboot due to Manual startup type
|
||||||
- [Python smtplib: Missing Date/Message-ID Headers Break Mail Clients](05-troubleshooting/python-smtplib-missing-rfc-headers.md)
|
- [Windows OpenSSH: WSL Default Shell Breaks Remote Commands](05-troubleshooting/networking/windows-openssh-wsl-default-shell-breaks-remote-commands.md) — fixing remote SSH command failures when wsl.exe is the default shell
|
||||||
- [SELinux: Fixing Dovecot Mail Spool Context (/var/vmail)](05-troubleshooting/selinux-dovecot-vmail-context.md)
|
- [Ollama Drops Off Tailscale When Mac Sleeps](05-troubleshooting/ollama-macos-sleep-tailscale-disconnect.md) — keeping Ollama reachable over Tailscale by disabling macOS sleep on AC power
|
||||||
- [Ubuntu dist-upgrade Quarantines Third-Party Repos](05-troubleshooting/ubuntu-dist-upgrade-repo-quarantine.md)
|
- [Ansible: Vault Password File Not Found](05-troubleshooting/ansible-vault-password-file-missing.md) — fixing the missing vault_pass file error when running ansible-playbook
|
||||||
- [wget/curl: URLs with Special Characters Fail in Bash](05-troubleshooting/wget-url-special-characters.md)
|
- [Ansible: ansible.cfg Ignored on WSL2 Windows Mounts](05-troubleshooting/ansible-wsl2-world-writable-mount-ignores-cfg.md) — fixing silent config ignore due to world-writable /mnt/d/ permissions
|
||||||
- [yt-dlp YouTube JS Challenge Fix (Fedora)](05-troubleshooting/yt-dlp-fedora-js-challenge.md)
|
- [Ansible SSH Timeout During dnf upgrade](05-troubleshooting/ansible-ssh-timeout-dnf-upgrade.md) — preventing SSH timeouts during long-running dnf upgrades on Fedora
|
||||||
### Docker & Containers
|
- [Fedora Networking & Kernel Troubleshooting](05-troubleshooting/fedora-networking-kernel-recovery.md) — nmcli quick fix, GRUB kernel rollback, and recovery for Fedora fleet
|
||||||
- [Nextcloud AIO Container Unhealthy for 20 Hours After Nightly Update](05-troubleshooting/docker/nextcloud-aio-unhealthy-20h-stuck.md)
|
- [Custom Fail2ban Jail: Apache Directory Scanning](05-troubleshooting/security/apache-dirscan-fail2ban-jail.md) — blocking directory scanners and junk HTTP methods
|
||||||
- [n8n Behind Reverse Proxy: X-Forwarded-For Trust Fix](05-troubleshooting/docker/n8n-proxy-trust-x-forwarded-for.md)
|
- [ClamAV Safe Scheduling on Live Servers](05-troubleshooting/security/clamscan-cpu-spike-nice-ionice.md) — preventing clamscan CPU spikes with nice and ionice
|
||||||
|
- [Systemd Session Scope Fails at Login](05-troubleshooting/systemd/session-scope-failure-at-login.md) — fixing session-cN.scope failures during login
|
||||||
### GPU & Display
|
- [wget/curl: URLs with Special Characters Fail in Bash](05-troubleshooting/wget-url-special-characters.md) — fixing broken downloads caused by unquoted URLs with &, ?, # characters
|
||||||
- [LoRA adapter — GGUF conversion fails with 'config.json not found](05-troubleshooting/gpu-display/lora-adapter-gguf-conversion-fails.md)
|
- [Ansible: Check Mode False Positives in Verify/Assert Tasks](05-troubleshooting/ansible-check-mode-false-positives.md) — guarding verify/assert tasks with `when: not ansible_check_mode` to prevent false failures in dry runs
|
||||||
- [Qwen2.5-14B OOM on RTX 3080 Ti (12GB)](05-troubleshooting/gpu-display/qwen-14b-oom-3080ti.md)
|
- [Ansible Fails with Permission Denied While `ssh <alias>` Works (Host Alias Bypass)](05-troubleshooting/ansible-ssh-host-alias-bypass.md) — SSH Host blocks match on literal pattern; `ansible_host: <IP>` bypasses the alias and the IdentityFile never gets applied
|
||||||
|
- [Ghost EmailAnalytics Lag Warning — What It Means and When to Worry](05-troubleshooting/ghost-emailanalytics-lag-warning.md) — explaining the lag counter, `submitted` status, and `fetchMissing end == begin` skip
|
||||||
### Networking
|
- [claude-mem: --setting-sources Empty Arg Bug (Claude Code 2.1.x)](05-troubleshooting/claude-mem-setting-sources-empty-arg.md) — fixing silent pipeline failure when claude-mem 12.1.x spawns Claude Code 2.1.112+
|
||||||
- [Apache Outage: Fail2ban Self-Ban + Missing iptables Rules](05-troubleshooting/networking/fail2ban-self-ban-apache-outage.md)
|
|
||||||
- [Fail2ban & UFW Rule Bloat: 30k Rules Slowing Down a VPS](05-troubleshooting/networking/fail2ban-ufw-rule-bloat-cleanup.md)
|
|
||||||
- [Mail Client Stops Receiving: Fail2ban IMAP Self-Ban](05-troubleshooting/networking/fail2ban-imap-self-ban-mail-client.md)
|
|
||||||
- [Pi-hole AI Blocklist Blocks Claude Desktop (ERR_CONNECTION_REFUSED)](05-troubleshooting/networking/pihole-blocks-claude-desktop.md)
|
|
||||||
- [Tailscale SSH: Unexpected Re-Authentication Prompt](05-troubleshooting/networking/tailscale-ssh-reauth-prompt.md)
|
|
||||||
- [Windows OpenSSH Server (sshd) Stops After Reboot](05-troubleshooting/networking/windows-sshd-stops-after-reboot.md)
|
|
||||||
- [Windows OpenSSH: WSL as Default Shell Breaks Remote Commands](05-troubleshooting/networking/windows-openssh-wsl-default-shell-breaks-remote-commands.md)
|
|
||||||
- [firewalld: Mail Ports Wiped After Reload (IMAP + Webmail Outage)](05-troubleshooting/networking/firewalld-mail-ports-reset.md)
|
|
||||||
- [iOS Tailscale Clients Report HostName="localhost" — Breaks /etc/hosts Generators](05-troubleshooting/networking/tailscale-status-json-hostname-localhost-ios.md)
|
|
||||||
- [rsync over Tailscale: Hung in TCP Teardown After Transfer Completes](05-troubleshooting/networking/rsync-tailscale-teardown-stall.md)
|
|
||||||
|
|
||||||
### Security
|
|
||||||
- [ClamAV Safe Scheduling on Live Servers](05-troubleshooting/security/clamscan-cpu-spike-nice-ionice.md)
|
|
||||||
- [Custom Fail2ban Jail: Apache Directory Scanning & Junk Methods](05-troubleshooting/security/apache-dirscan-fail2ban-jail.md)
|
|
||||||
|
|
||||||
### Storage
|
|
||||||
- [mdadm RAID Recovery After USB Hub Disconnect](05-troubleshooting/storage/mdadm-usb-hub-disconnect-recovery.md)
|
|
||||||
|
|
||||||
### Systemd
|
|
||||||
- [Systemd Session Scope Fails at Login (session-cN.scope)](05-troubleshooting/systemd/session-scope-failure-at-login.md)
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -213,36 +182,57 @@ updated: 2026-05-02T16:45
|
||||||
|
|
||||||
| Date | Article | Domain |
|
| Date | Article | Domain |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 2026-05-02 | [WSL2 Backup via PowerShell Scheduled Task](01-linux/distro-specific/wsl2-backup-powershell.md) | Linux |
|
| 2026-04-19 | [Wake-on-LAN via Router SSH](02-selfhosting/dns-networking/wake-on-lan-router-ssh.md) | Self-Hosting |
|
||||||
| 2026-05-02 | [SSH Config and Key Management](01-linux/networking/ssh-config-key-management.md) | Linux |
|
| 2026-04-18 | [Ghost Email Configuration with Mailgun](02-selfhosting/services/ghost-smtp-mailgun-setup.md) | Self-Hosting |
|
||||||
| 2026-05-02 | [Wake-on-LAN via Router SSH](02-selfhosting/dns-networking/wake-on-lan-router-ssh.md) | Self-Hosting |
|
| 2026-04-18 | [Firewall Hardening with firewalld on Fedora Fleet](02-selfhosting/security/firewalld-fleet-hardening.md) | Self-Hosting |
|
||||||
| 2026-05-02 | [Tuning Netdata Docker Health Alarms to Prevent Update Flapping](02-selfhosting/monitoring/netdata-docker-health-alarm-tuning.md) | Self-Hosting |
|
| 2026-04-18 | [ClamAV Fleet Deployment with Ansible](02-selfhosting/security/clamav-fleet-deployment.md) | Self-Hosting |
|
||||||
| 2026-05-02 | [ClamAV Fleet Deployment with Ansible](02-selfhosting/security/clamav-fleet-deployment.md) | Self-Hosting |
|
| 2026-04-18 | [Ansible: Check Mode False Positives in Verify/Assert Tasks](05-troubleshooting/ansible-check-mode-false-positives.md) | Troubleshooting |
|
||||||
| 2026-05-02 | [Fail2Ban Digest Mode — Fleet-Wide Quiet Alerts](02-selfhosting/security/fail2ban-digest-mode-fleet.md) | Self-Hosting |
|
| 2026-04-18 | [Ghost EmailAnalytics Lag Warning](05-troubleshooting/ghost-emailanalytics-lag-warning.md) | Troubleshooting |
|
||||||
| 2026-05-02 | [Mastodon Instance Tuning](02-selfhosting/services/mastodon-instance-tuning.md) | Self-Hosting |
|
| 2026-04-17 | [Watchtower SMTP via Localhost Postfix Relay](02-selfhosting/docker/watchtower-smtp-localhost-relay.md) | Self-Hosting |
|
||||||
| 2026-05-02 | [Ansible Check Mode False Positives in Verify/Assert Tasks](05-troubleshooting/ansible-check-mode-false-positives.md) | Troubleshooting |
|
| 2026-04-17 | [Fail2ban Custom Jail: Nginx Bad Request Detection](02-selfhosting/security/fail2ban-nginx-bad-request-jail.md) | Self-Hosting |
|
||||||
| 2026-05-02 | [ISP SNI Filtering & Caddy Troubleshooting](05-troubleshooting/isp-sni-filtering-caddy.md) | Troubleshooting |
|
| 2026-04-17 | [Fail2ban Custom Jail: Apache Bad Request Detection](02-selfhosting/security/fail2ban-apache-bad-request-jail.md) | Self-Hosting |
|
||||||
| 2026-05-02 | [Windows OpenSSH: WSL as Default Shell Breaks Remote Commands](05-troubleshooting/networking/windows-openssh-wsl-default-shell-breaks-remote-commands.md) | Troubleshooting |
|
| 2026-04-17 | [SSH Hardening Fleet-Wide with Ansible](02-selfhosting/security/ssh-hardening-ansible-fleet.md) | Self-Hosting |
|
||||||
| 2026-05-02 | [Windows OpenSSH Server (sshd) Stops After Reboot](05-troubleshooting/networking/windows-sshd-stops-after-reboot.md) | Troubleshooting |
|
| 2026-04-17 | [claude-mem: --setting-sources Empty Arg Bug](05-troubleshooting/claude-mem-setting-sources-empty-arg.md) | Troubleshooting |
|
||||||
| 2026-05-02 | [yt-dlp YouTube JS Challenge Fix (Fedora)](05-troubleshooting/yt-dlp-fedora-js-challenge.md) | Troubleshooting |
|
| 2026-04-13 | [Cron Heartbeat False Alarm: /var/run Cleared by Reboot](05-troubleshooting/cron-heartbeat-tmpfs-reboot-false-alarm.md) | Troubleshooting |
|
||||||
| 2026-04-30 | [wp-fail2ban Plugin Logpath on Debian/Ubuntu (auth.log, not syslog)](02-selfhosting/security/wp-fail2ban-logpath-debian-ubuntu.md) | Self-Hosting |
|
| 2026-04-09 | [Fail2ban Custom Jail: Apache PHP Webshell Probe Detection](02-selfhosting/security/fail2ban-apache-php-probe-jail.md) | Self-Hosting |
|
||||||
| 2026-04-30 | [LoRA adapter — GGUF conversion fails with 'config.json not found](05-troubleshooting/gpu-display/lora-adapter-gguf-conversion-fails.md) | Troubleshooting |
|
| 2026-04-08 | [wget/curl: URLs with Special Characters Fail in Bash](05-troubleshooting/wget-url-special-characters.md) | Troubleshooting |
|
||||||
| 2026-04-29 | [iOS Tailscale Clients Report HostName="localhost" — Breaks /etc/hosts Generators](05-troubleshooting/networking/tailscale-status-json-hostname-localhost-ios.md) | Troubleshooting |
|
| 2026-04-07 | [SSH Config & Key Management](01-linux/networking/ssh-config-key-management.md) | Linux |
|
||||||
| 2026-04-29 | [Python smtplib: Missing Date/Message-ID Headers Break Mail Clients](05-troubleshooting/python-smtplib-missing-rfc-headers.md) | Troubleshooting |
|
| 2026-04-07 | [Windows OpenSSH: WSL Default Shell Breaks Remote Commands](05-troubleshooting/networking/windows-openssh-wsl-default-shell-breaks-remote-commands.md) | Troubleshooting |
|
||||||
| 2026-04-28 | [Ubuntu dist-upgrade Quarantines Third-Party Repos](05-troubleshooting/ubuntu-dist-upgrade-repo-quarantine.md) | Troubleshooting |
|
| 2026-04-07 | [Windows OpenSSH Server (sshd) Stops After Reboot](05-troubleshooting/networking/windows-sshd-stops-after-reboot.md) | Troubleshooting |
|
||||||
| 2026-04-26 | [Fantastical MCP Server: Permission Denied on Launch (macOS Quarantine)](05-troubleshooting/fantastical-mcp-permission-denied.md) | Troubleshooting |
|
| 2026-04-03 | [Ansible: ansible.cfg Ignored on WSL2 Windows Mounts](05-troubleshooting/ansible-wsl2-world-writable-mount-ignores-cfg.md) | Troubleshooting |
|
||||||
| 2026-04-25 | [rsync over Tailscale: Hung in TCP Teardown After Transfer Completes](05-troubleshooting/networking/rsync-tailscale-teardown-stall.md) | Troubleshooting |
|
| 2026-04-02 | [Fail2ban Custom Jail: WordPress Login Brute Force](02-selfhosting/security/fail2ban-wordpress-login-jail.md) | Self-Hosting |
|
||||||
| 2026-04-25 | [Ollama: `ollama run` with Piped Stdin Bypasses Chat Template + SYSTEM Prompt](05-troubleshooting/ollama-chat-template-pipe-stdin-bypass.md) | Troubleshooting |
|
| 2026-04-02 | [Mastodon Instance Tuning](02-selfhosting/services/mastodon-instance-tuning.md) | Self-Hosting |
|
||||||
| 2026-04-24 | [Fantastical Google Sync Error Flood — Phantom Calendars Fixed via syncselect](05-troubleshooting/fantastical-google-phantom-calendar-syncselect.md) | Troubleshooting |
|
| 2026-04-02 | [mdadm — Rebuilding a RAID Array After Reinstall](01-linux/storage/mdadm-raid-rebuild.md) | Linux |
|
||||||
| 2026-04-23 | [Pi-hole DoH / DoT Bypass Defense](02-selfhosting/dns-networking/pihole-doh-dot-bypass-defense.md) | Self-Hosting |
|
| 2026-04-02 | [Fedora Networking & Kernel Troubleshooting](05-troubleshooting/fedora-networking-kernel-recovery.md) | Troubleshooting |
|
||||||
| 2026-04-22 | [Pi-hole v6 Adlist Management via SQL](02-selfhosting/dns-networking/pihole-v6-adlist-management.md) | Self-Hosting |
|
| 2026-04-02 | [Ventoy: Multi-Boot USB Tool](03-opensource/dev-tools/ventoy.md) | Open Source |
|
||||||
| 2026-04-22 | [Pi-hole v6 Group Management: Per-Client DNS Rules](02-selfhosting/dns-networking/pihole-v6-group-management.md) | Self-Hosting |
|
| 2026-04-02 | [rsync Backup Patterns](02-selfhosting/storage-backup/rsync-backup-patterns.md) (updated — Glacier Deep Archive) | Self-Hosting |
|
||||||
| 2026-04-22 | [Mastodon DB Maintenance — Statuses, Accounts, and VACUUM](02-selfhosting/services/mastodon-db-maintenance.md) | Self-Hosting |
|
| 2026-04-02 | [yt-dlp: Video Downloading](03-opensource/media-creative/yt-dlp.md) (updated — subtitles, temp fix) | Open Source |
|
||||||
| 2026-04-22 | [Mastodon Federation — Domain Blocks, Silencing, and FediSeer](02-selfhosting/services/mastodon-federation.md) | Self-Hosting |
|
| 2026-04-02 | [OBS Studio Setup & Encoding](04-streaming/obs/obs-studio-setup-encoding.md) (updated — captions plugin, VLC capture) | Streaming |
|
||||||
| 2026-04-22 | [Pi-hole AI Blocklist Blocks Claude Desktop (ERR_CONNECTION_REFUSED)](05-troubleshooting/networking/pihole-blocks-claude-desktop.md) | Troubleshooting |
|
| 2026-04-02 | [Linux Server Hardening Checklist](02-selfhosting/security/linux-server-hardening-checklist.md) (updated — SpamAssassin) | Self-Hosting |
|
||||||
| 2026-04-21 | [Ansible Fails with Permission Denied While `ssh <alias>` Works (Host Alias Bypass)](05-troubleshooting/ansible-ssh-host-alias-bypass.md) | Troubleshooting |
|
| 2026-03-23 | [Ansible: Vault Password File Not Found](05-troubleshooting/ansible-vault-password-file-missing.md) | Troubleshooting |
|
||||||
| 2026-04-20 | [Claude Code Remote Control — Mobile Access to a Persistent Host Session](02-selfhosting/services/claude-code-remote-control.md) | Self-Hosting |
|
| 2026-03-18 | [Deploying Netdata to a New Server](02-selfhosting/monitoring/netdata-new-server-setup.md) | Self-Hosting |
|
||||||
| 2026-04-19 | [AWS S3 Cost Management](02-selfhosting/cloud/aws-s3-cost-management.md) | Self-Hosting |
|
| 2026-03-18 | [Tuning Netdata Docker Health Alarms](02-selfhosting/monitoring/netdata-docker-health-alarm-tuning.md) | Self-Hosting |
|
||||||
|
| 2026-03-17 | [Ollama Drops Off Tailscale When Mac Sleeps](05-troubleshooting/ollama-macos-sleep-tailscale-disconnect.md) | Troubleshooting |
|
||||||
|
| 2026-03-17 | [Windows OpenSSH Server (sshd) Stops After Reboot](05-troubleshooting/networking/windows-sshd-stops-after-reboot.md) | Troubleshooting |
|
||||||
|
| 2026-03-16 | [Standardizing unattended-upgrades with Ansible](02-selfhosting/security/ansible-unattended-upgrades-fleet.md) | Self-Hosting |
|
||||||
|
| 2026-03-16 | [WSL2 Training Environment Rebuild (Fedora 43)](01-linux/distro-specific/wsl2-rebuild-fedora43-training-env.md) | Linux |
|
||||||
|
| 2026-03-16 | [WSL2 Backup via PowerShell Scheduled Task](01-linux/distro-specific/wsl2-backup-powershell.md) | Linux |
|
||||||
|
| 2026-03-15 | [firewalld: Mail Ports Wiped After Reload](05-troubleshooting/networking/firewalld-mail-ports-reset.md) | Troubleshooting |
|
||||||
|
| 2026-03-15 | [Plex 4K Codec Compatibility (Apple TV)](04-streaming/plex/plex-4k-codec-compatibility.md) | Streaming |
|
||||||
|
| 2026-03-15 | [mdadm RAID Recovery After USB Hub Disconnect](05-troubleshooting/storage/mdadm-usb-hub-disconnect-recovery.md) | Troubleshooting |
|
||||||
|
| 2026-03-15 | [yt-dlp: Video Downloading](03-opensource/media-creative/yt-dlp.md) | Open Source |
|
||||||
|
| 2026-03-14 | [SELinux: Fixing Dovecot Mail Spool Context (/var/vmail)](05-troubleshooting/selinux-dovecot-vmail-context.md) | Troubleshooting |
|
||||||
|
| 2026-03-14 | [Gitea Actions Runner: Boot Race Condition Fix](05-troubleshooting/gitea-runner-boot-race-network-target.md) | Troubleshooting |
|
||||||
|
| 2026-03-14 | [Mail Client Stops Receiving: Fail2ban IMAP Self-Ban](05-troubleshooting/networking/fail2ban-imap-self-ban-mail-client.md) | Troubleshooting |
|
||||||
|
| 2026-03-14 | [SearXNG: Private Self-Hosted Search](03-opensource/alternatives/searxng.md) | Open Source |
|
||||||
|
| 2026-03-14 | [FreshRSS: Self-Hosted RSS Reader](03-opensource/alternatives/freshrss.md) | Open Source |
|
||||||
|
| 2026-03-14 | [Gitea: Self-Hosted Git](03-opensource/alternatives/gitea.md) | Open Source |
|
||||||
|
| 2026-03-14 | [yt-dlp: Video Downloading](03-opensource/media-creative/yt-dlp.md) | Open Source |
|
||||||
|
| 2026-03-13 | [Vaultwarden: Self-Hosted Password Manager](03-opensource/privacy-security/vaultwarden.md) | Open Source |
|
||||||
|
| 2026-03-13 | [Gemini CLI Manual Update](05-troubleshooting/gemini-cli-manual-update.md) | Troubleshooting |
|
||||||
|
| 2026-03-13 | [rmlint: Duplicate File Scanning](03-opensource/productivity/rmlint-duplicate-scanning.md) | Open Source |
|
||||||
|
| 2026-03-13 | [SnapRAID & MergerFS Storage Setup](01-linux/storage/snapraid-mergerfs-setup.md) | Linux |
|
||||||
|
| 2026-03-13 | [Qwen2.5-14B OOM on RTX 3080 Ti (12GB)](05-troubleshooting/gpu-display/qwen-14b-oom-3080ti.md) | Troubleshooting |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue