A lightweight, self-hosted bridge that automatically posts new RSS/Atom feed items to Mastodon. Perfect for static site generators like Hugo, Jekyll, or any website with an RSS feed.
- Multi-Feed Support - Monitor multiple RSS/Atom feeds simultaneously
- Flexible Configuration - Customize prepend/append text with emoji support
- Image Support - Automatically extracts and uploads first image from posts
- Template System - Control post format with excerpt length, hashtags, etc.
- Single or Multiple Accounts - Post all feeds to one account, or use different accounts
- SQLite Database - Lightweight tracking of posted items
- Admin Dashboard - Web interface to view posted items and statistics
- Webhook-Based - Trigger from your deployment script
- Shared Hosting Compatible - Just PHP and SQLite required
βββββββββββββββ βββββββββββββββ
β Laptop β β Server β
β β β β
β Hugo Site β β Static HTML β
β β rsync β Files β
β Build βββββββββββββββΆβ β
β β β β
β Deploy β webhook β RSSβMastodonβ
β Script βββββββββββββββΆβ Bridge β
βββββββββββββββ ββββββββ¬βββββββ
β
β Mastodon API
β
βββββββββΌβββββββββ
β Mastodon β
β Instance β
ββββββββββββββββββ
How it works:
- You build and deploy your static site
- Your deploy script calls the webhook
- Bridge checks RSS feeds for new items
- New items are formatted and posted to Mastodon
- People see your posts in their Mastodon timelines
- Replies and interactions happen on Mastodon
- Log into your Mastodon account
- Go to Settings β Development β New Application
- Give it a name like "RSS Bridge"
- Required scopes:
write:statuses,write:media - Copy the access token
Upload the server/ directory to your web server:
scp -r server/* user@example.com:~/public_html/rss-mastodon/Create configuration:
cd ~/public_html/rss-mastodon
cp config.example.php config.php
nano config.phpConfigure your feeds:
'feeds' => [
'blog' => [
'enabled' => true,
'feed_url' => 'https://yourdomain.com/index.xml',
'feed_type' => 'rss',
'mastodon' => [
'instance' => 'https://mastodon.social',
'access_token' => 'YOUR_ACCESS_TOKEN_HERE',
],
'template' => [
'prepend' => 'π New post: ',
'append' => "\n\n#blog",
'include_excerpt' => true,
'excerpt_length' => 200,
],
'images' => [
'enabled' => true,
'extract_first' => true,
'alt_text_source' => 'alt',
],
],
'photos' => [
'enabled' => true,
'feed_url' => 'https://yourdomain.com/photos/index.xml',
'feed_type' => 'rss',
'mastodon' => [
'instance' => 'https://mastodon.social',
'access_token' => 'YOUR_ACCESS_TOKEN_HERE',
],
'template' => [
'prepend' => 'π· ',
'append' => '#photography',
'include_excerpt' => true,
'excerpt_length' => 100,
],
'images' => [
'enabled' => true,
'extract_first' => true,
'alt_text_source' => 'alt',
'required' => true, // Skip posts without images
],
],
],Set a random webhook secret:
# Generate a secure random secret
openssl rand -hex 32Create data directory:
mkdir data
chmod 755 dataOn your laptop, configure the webhook trigger:
cd client/
cp config.example.sh config.sh
nano config.shSet your webhook URL and secret:
WEBHOOK_URL="https://example.com/rss-mastodon/webhook.php"
WEBHOOK_SECRET="your_random_secret_from_config_php"Make the script executable:
chmod +x notify-mastodon.shAdd to your Hugo (or other SSG) deploy script:
#!/bin/bash
# Build site
hugo
# Deploy to server
rsync -avz --delete public/ user@server:/path/to/public_html/
# Trigger Mastodon posting
./path/to/client/notify-mastodon.shTest the webhook:
./client/notify-mastodon.shCheck the admin dashboard:
https://example.com/rss-mastodon/admin.php
Default password: changeme123 (change this in admin.php line 23!)
Each feed supports:
- enabled: Enable/disable the feed
- feed_url: URL to RSS or Atom feed
- feed_type: 'rss' or 'atom'
- instance: Mastodon instance URL (e.g., https://mastodon.social)
- access_token: Your Mastodon access token
- prepend: Text to add before the title (supports emoji! β¨ π π· π¨)
- append: Text to add after the post (great for hashtags)
- include_excerpt: Include excerpt from post content
- excerpt_length: Maximum length of excerpt (characters)
- include_link: Include link to original post
- enabled: Enable/disable image handling
- extract_first: Extract first image from content
- alt_text_source: 'title', 'alt', or 'none'
- required: Skip posts without images if true
- minimum_interval: Minimum minutes between posts from this feed (optional)
- If set to a value greater than 0, posts will be queued and processed gradually
- Prevents flooding your Mastodon feed when multiple items are published at once
- Requires setting up the queue processor (see below)
- Set to 0 or omit for immediate posting (default behavior)
Server:
- PHP 7.4+ with SQLite3, OpenSSL, and cURL extensions
- HTTPS (Mastodon API requires secure connections)
- Write permissions for data directory
Client (Laptop):
- Bash
- curl
Visit https://example.com/rss-mastodon/admin.php to:
- View posted items across all feeds
- See statistics (total posts, recent activity)
- Monitor per-feed post counts
- Access Mastodon URLs for each post
Security: Change the default password in admin.php:23
If you're using the minimum_interval feature to space out posts, you need to set up the queue processor to run periodically.
The queue processor should run every minute (or at your preferred interval). On your server:
# Edit your crontab
crontab -eAdd this line to run the queue processor every minute:
* * * * * /usr/bin/php /path/to/your/server/queue-processor.php >> /path/to/your/server/data/queue.log 2>&1Replace /path/to/your/server/ with the actual path to your installation.
- When the webhook runs, new posts are added to the queue instead of being posted immediately
- The queue processor (run via cron) checks the queue every minute
- For each feed, it checks if enough time has passed since the last post
- If the minimum interval has elapsed, it posts the next item in the queue
- The process repeats, spacing out posts according to your
minimum_intervalsetting
'blog' => [
'enabled' => true,
'feed_url' => 'https://yourdomain.com/index.xml',
// ... other settings ...
'minimum_interval' => 30, // Post at most once every 30 minutes
],
'photos' => [
'enabled' => true,
'feed_url' => 'https://yourdomain.com/photos/index.xml',
// ... other settings ...
'minimum_interval' => 60, // Post photos once per hour
],Check queue status in the log file:
tail -f /path/to/your/server/data/bridge.logOr check the queue directly in the database:
sqlite3 /path/to/your/server/data/posts.db "SELECT * FROM post_queue;"Posts aren't appearing on Mastodon:
- Check the access token has correct permissions
- Verify the webhook is being triggered (check server/data/bridge.log)
- Ensure images are publicly accessible
- Check admin dashboard for errors
- If using
minimum_interval, check that the queue processor cron job is running
Posts are queued but not being posted:
- Verify the cron job is set up correctly:
crontab -l - Check queue processor logs:
tail -f /path/to/data/queue.log - Ensure PHP path in cron is correct (try
which php) - Check that the minimum interval has elapsed since the last post
Webhook returns 403:
- Verify webhook secret matches between client config.sh and server config.php
Images aren't uploading:
- Ensure images are publicly accessible (not behind authentication)
- Check image URLs are using HTTPS
- Verify image formats are supported (JPEG, PNG, GIF, WebP)
Character limit exceeded:
- Reduce excerpt_length in template configuration
- Shorten prepend/append text
- The system will auto-truncate but may cut off content
standalone-fediverse/
βββ server/ # Upload to your web server
β βββ config.example.php # Configuration template
β βββ webhook.php # Main webhook handler
β βββ queue-processor.php # Queue processor (for minimum_interval)
β βββ admin.php # Web dashboard
β βββ database.php # SQLite database management
β βββ feed-parser.php # RSS/Atom parser
β βββ mastodon-client.php # Mastodon API client
β βββ post-formatter.php # Template system
β βββ logger.php # Logging utility
β βββ data/ # Created automatically
β βββ posts.db # SQLite database (includes post_queue table)
β βββ bridge.log # Webhook log file
β βββ queue.log # Queue processor log file
β
βββ client/ # Keep on your laptop
β βββ notify-mastodon.sh # Webhook trigger script
β βββ config.example.sh # Configuration template
β
βββ archive-activitypub/ # Old ActivityPub implementation (reference)
- HTTPS Required - Mastodon API requires secure connections
- Webhook Secret - Prevents unauthorized triggering
- Rate Limiting - Prevents abuse (60 requests/minute default)
- Admin Password - Change default password immediately
- Access Token - Keep your Mastodon token secure
MIT License - Free to use and modify
Built for static site enthusiasts who want to share their content on the Fediverse without complex infrastructure.