diff --git a/05-troubleshooting/security/castopod-broadcast-not-on-mastodon.md b/05-troubleshooting/security/castopod-broadcast-not-on-mastodon.md new file mode 100644 index 0000000..c62a81f --- /dev/null +++ b/05-troubleshooting/security/castopod-broadcast-not-on-mastodon.md @@ -0,0 +1,154 @@ +--- +title: "Castopod Posts Don't Appear on Mastodon โ€” Diagnosing the Federation Path" +domain: troubleshooting +category: security +tags: [castopod, mastodon, fediverse, activitypub, federation, notifications] +status: published +created: 2026-05-10 +updated: 2026-05-10 +--- + +# Castopod Posts Don't Appear on Mastodon โ€” Diagnosing the Federation Path + +## ๐Ÿ›‘ Problem + +You publish a podcast episode (or a standalone post) on Castopod. The Castopod admin shows it went out fine. But on the Mastodon account that you *expected* to see it from โ€” your own personal account, an account that follows your podcast, a colleague's โ€” the post never shows up. Or it shows up in the home timeline but the notification bell never rings. + +Three different failure modes hide behind "I didn't get the post." This article walks the diagnostic chain that distinguishes them. + +--- + +## ๐Ÿ”ฌ The four checks, in order + +Run these in sequence. The first one that fails tells you what's actually wrong. + +### Check 1 โ€” Did Castopod create the post? + +On the Castopod host: + +```sh +mysql -u $CP_DB_USER -p$CP_DB_PASS $CP_DB_NAME --binary-as-hex -e " + SELECT HEX(id), actor_id, LEFT(message,80), episode_id, published_at, created_at + FROM cp_fediverse_posts + ORDER BY created_at DESC LIMIT 5 +" +``` + +If your post isn't here at all, Castopod didn't generate it. That's a Castopod-side bug โ€” check `writable/logs/log-.log`, verify the per-minute task scheduler is firing (`php spark tasks:list` should show `Last Run` for `fediverse-broadcast`), and confirm the cron exists: + +```sh +sudo crontab -u www-data -l | grep tasks:run +# expect: * * * * * php /var/www/html/castopod/spark tasks:run >> /dev/null 2>&1 +``` + +### Check 2 โ€” Did Castopod queue and deliver the activity? + +```sh +mysql -u $CP_DB_USER -p$CP_DB_PASS $CP_DB_NAME --binary-as-hex -e " + SELECT HEX(id), actor_id, type, status, scheduled_at, created_at + FROM cp_fediverse_activities + WHERE type='Create' + ORDER BY created_at DESC LIMIT 10 +" +``` + +The `status` column tells you everything: + +| Status | Meaning | +|---|---| +| `queued` | Sitting in the queue, broadcast task hasn't run yet (or is bogged down) | +| `processing` | In-flight | +| `delivered` | All follower inboxes returned 2xx | +| `failed` | One or more inbox POSTs returned non-2xx, gave up after retries | + +If `status='delivered'`, Castopod has done its job โ€” and yet someone says they didn't see the post. Move to Check 3. + +### Check 3 โ€” Are they actually a follower? + +The single most common cause of "I didn't see it." Federation only delivers `Create` activities to **followers** (and to anyone explicitly mentioned). Interacting with a post (favourite, boost) does NOT establish a follow relationship. + +On the Castopod host: + +```sh +mysql -u $CP_DB_USER -p$CP_DB_PASS $CP_DB_NAME -e " + SELECT a.username, a.domain, f.created_at + FROM cp_fediverse_follows f + JOIN cp_fediverse_actors a ON a.id = f.actor_id + ORDER BY f.created_at DESC +" +``` + +`cp_fediverse_follows.actor_id` is the **follower** (remote actor); `target_actor_id` is your local podcast actor. If the user's `username@domain` isn't in this list, they don't follow your podcast, and the Create activity was never sent to their inbox. + +Cross-check from the Mastodon side (if you control both): + +```sh +sudo -u postgres psql mastodon_production -t -A -c " + SELECT a.username, a.domain + FROM follows f + JOIN accounts a ON a.id = f.target_account_id + WHERE f.account_id = + AND a.domain = '' +" +``` + +Empty result on both sides = they're not following. **Resolution: have them search `@yourpodcast@yourdomain.tld` in their Mastodon and click Follow.** + +A subtler corner of this check: `accounts WHERE domain=''` returning 0 rows on the Mastodon side means Mastodon has never even webfingered your podcast actor. The user may have *thought* they followed at some point, but it never went through (e.g., they typed the handle wrong, or the follow request errored). + +### Check 4 โ€” Is "didn't see it" a notification problem, not a delivery problem? + +Even after a successful follow, the post lands in the **home timeline** by default. Mastodon **notifications** (the bell icon, the unread badge) fire for a specific list of activity types โ€” and "new post from someone I follow" isn't one of them. Notifications fire for: + +- Mentions (`@you` in the post body) +- Follows (someone follows you) +- Favourites of your posts +- Boosts of your posts +- Polls ending +- Status edits (post you favourited was edited) +- Admin alerts + +So even with delivery working perfectly and the follow in place, "I didn't get a notification on my account" is the expected state for a regular podcast post. Three ways to make notifications happen: + +1. **Bell icon on the followed profile.** Mastodon UI: open the followed account's profile โ†’ click the bell. Enables per-account post notifications. Now every new post from that account raises a notification. +2. **`@`-mention in the post.** Have Castopod include `@you@yourdomain.tld` in the post text. Mention activities always raise notifications regardless of follow/bell state. (You may not control the post text on someone else's Castopod, but you control your own.) +3. **Cross-post via a different actor.** If you also run a Mastodon account for the show, post manually from there and `@`-mention the audience accounts you want to page. + +--- + +## ๐Ÿงช Worked example + +A real case: someone running a podcast on Castopod 2.0.0-next.4 expected a new episode's auto-post to appear on their personal Mastodon. It didn't. + +- Check 1 โ†’ post present in `cp_fediverse_posts`, episode_id correct โœ“ +- Check 2 โ†’ matching `cp_fediverse_activities` row, `type='Create'`, `status='delivered'` โœ“ +- Check 3 โ†’ 8 followers in `cp_fediverse_follows`, none from the personal Mastodon's domain โœ— + +Outcome: the user wasn't following their own podcast. They had been favouriting and boosting its posts (which doesn't require following), and assumed those interactions implied a follow. Resolution: search-and-follow from the personal Mastodon. After the follow propagated, future broadcasts arrived as expected. + +The post itself never raised a notification (only landed in home timeline). They later enabled the bell icon on the podcast profile and started getting notified on new episodes. + +--- + +## ๐Ÿงญ When this isn't the answer + +If Check 3 shows the person IS a follower but they still didn't receive the post: + +- **Check their inbox** if you have access: Mastodon nginx access log: + ```sh + sudo grep '' /var/log/nginx/access.log | grep inbox + ``` + Expect a `POST /users//inbox HTTP/2.0 202` from the Castopod IP shortly after `published_at`. No POST = Castopod didn't deliver despite claiming `status='delivered'` (rare; check Castopod's HTTP signing config and any outbound firewall on the Castopod host). + +- **Check Sidekiq** on Mastodon for `ActivityPub::ProcessingWorker` failures around the activity timestamp. + +- **Check domain blocks**: `SELECT * FROM domain_blocks WHERE domain = ''` on Mastodon. A silenced or suspended domain on either end would explain everything. + +--- + +## ๐Ÿ“š References + +- ActivityPub spec โ€” [Delivery semantics](https://www.w3.org/TR/activitypub/#delivery): `Create` activities go to actors in `to`/`cc`/`bcc`/`audience`; for public posts that resolves to the actor's followers collection. +- Mastodon notification types: `app/models/notification.rb` โ€” `TYPES` constant +- Castopod fediverse module: `modules/Fediverse/Commands/Broadcast.php` (the per-minute task) and `modules/Fediverse/Models/ActivityModel.php` (queue model) +- Related: [Castopod: Stale Federated Avatar URLs After Remote Profile Updates](castopod-stale-federated-avatar.md) โ€” sister article, also Castopod fediverse module diff --git a/SUMMARY.md b/SUMMARY.md index dd96751..80881c9 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,6 +1,6 @@ --- created: 2026-04-02T16:03 -updated: 2026-05-08T01:08 +updated: 2026-05-10T00:10 --- * [Home](index.md) * [Linux & Sysadmin](01-linux/index.md) @@ -77,6 +77,7 @@ updated: 2026-05-08T01:08 * [Custom Fail2ban Jail: Apache Directory Scanning](05-troubleshooting/security/apache-dirscan-fail2ban-jail.md) * [Tuning Netdata `web_log_1m_successful` for Redirect-Heavy WordPress Sites](05-troubleshooting/security/netdata-web-log-successful-redirect-heavy-tuning.md) * [Castopod: Stale Federated Avatar URLs After Remote Profile Updates](05-troubleshooting/security/castopod-stale-federated-avatar.md) + * [Castopod Posts Don't Appear on Mastodon โ€” Diagnosing the Federation Path](05-troubleshooting/security/castopod-broadcast-not-on-mastodon.md) * [Nextcloud AIO Unhealthy 20h After Nightly Update](05-troubleshooting/docker/nextcloud-aio-unhealthy-20h-stuck.md) * [n8n Behind Reverse Proxy: X-Forwarded-For Trust Fix](05-troubleshooting/docker/n8n-proxy-trust-x-forwarded-for.md) * [Docker & Caddy Recovery After Reboot (Fedora + SELinux)](05-troubleshooting/docker-caddy-selinux-post-reboot-recovery.md) diff --git a/index.md b/index.md index 8747c10..d10b82a 100644 --- a/index.md +++ b/index.md @@ -1,13 +1,13 @@ --- created: 2026-04-06T09:52 -updated: 2026-05-08T01:08 +updated: 2026-05-10T00:10 --- # MajorLinux Tech Wiki โ€” Index > A growing reference of Linux, self-hosting, open source, streaming, and troubleshooting guides. Written by MajorLinux. Used by MajorTwin. > -> **Last updated:** 2026-05-08 -> **Article count:** 108 +> **Last updated:** 2026-05-10 +> **Article count:** 109 ## Domains @@ -17,7 +17,7 @@ updated: 2026-05-08T01:08 | ๐Ÿ  Self-Hosting & Homelab | `02-selfhosting/` | 39 | | ๐Ÿ”“ Open Source Tools | `03-opensource/` | 10 | | ๐ŸŽ™๏ธ Streaming & Podcasting | `04-streaming/` | 2 | -| ๐Ÿ”ง General Troubleshooting | `05-troubleshooting/` | 45 | +| ๐Ÿ”ง General Troubleshooting | `05-troubleshooting/` | 46 | --- @@ -202,6 +202,7 @@ updated: 2026-05-08T01:08 - [Custom Fail2ban Jail: Apache Directory Scanning & Junk Methods](05-troubleshooting/security/apache-dirscan-fail2ban-jail.md) - [Tuning Netdata `web_log_1m_successful` for Redirect-Heavy WordPress Sites](05-troubleshooting/security/netdata-web-log-successful-redirect-heavy-tuning.md) - [Castopod: Stale Federated Avatar URLs After Remote Profile Updates](05-troubleshooting/security/castopod-stale-federated-avatar.md) +- [Castopod Posts Don't Appear on Mastodon โ€” Diagnosing the Federation Path](05-troubleshooting/security/castopod-broadcast-not-on-mastodon.md) ### Storage - [mdadm RAID Recovery After USB Hub Disconnect](05-troubleshooting/storage/mdadm-usb-hub-disconnect-recovery.md) @@ -216,6 +217,7 @@ updated: 2026-05-08T01:08 | Date | Article | Domain | |---|---|---| +| 2026-05-10 | [Castopod Posts Don't Appear on Mastodon โ€” Diagnosing the Federation Path](05-troubleshooting/security/castopod-broadcast-not-on-mastodon.md) | Troubleshooting | | 2026-05-08 | [Castopod: Stale Federated Avatar URLs After Remote Profile Updates](05-troubleshooting/security/castopod-stale-federated-avatar.md) | Troubleshooting | | 2026-05-08 | [Tuning Netdata `web_log_1m_successful` for Redirect-Heavy WordPress Sites](05-troubleshooting/security/netdata-web-log-successful-redirect-heavy-tuning.md) | Troubleshooting | | 2026-05-07 | [Mastodon โ€” The `--prune-profiles` Trap and How to Recover](02-selfhosting/services/mastodon-prune-profiles-trap.md) | Self-Hosting |