Add multiarch Docker support and GHCR publishing

- Implement multiarch Dockerfile supporting linux/amd64 and linux/arm64
- Optimize Dockerfile with better layer caching and reduced image size
- Update CI/CD pipeline to use Docker Buildx for multiarch builds
- Add GitHub Container Registry (GHCR) as second publishing target
- Configure automatic tagging (latest, branch name, commit SHA)
- Add QEMU emulation support for cross-platform builds
- Enable GitHub Actions layer caching for faster builds
- Completely revamp README with comprehensive documentation
- Add professional badges (build status, Docker Hub, GHCR, license, Python)
- Include detailed setup instructions for Docker Hub and GHCR
- Add Docker Compose example and configuration table
- Document multiarch build process and state persistence
This commit is contained in:
aserper
2025-12-12 23:17:58 -05:00
parent 89b298253a
commit 70a23fdb75
4 changed files with 263 additions and 27 deletions

View File

@@ -5,16 +5,55 @@ on:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v1
- name: Build & Push Image
run: |
echo "${{ secrets.DH_PASSWORD }}" | docker login -u "amitserper" --password-stdin
docker build -t amitserper/masto-rss .
docker push amitserper/masto-rss
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: amitserper
password: ${{ secrets.DH_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
amitserper/masto-rss
ghcr.io/aserper/masto-rss
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push multiarch image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@@ -4,14 +4,15 @@ FROM alpine:3.18
# Set the working directory inside the container
WORKDIR /app
# Copy the entire current directory into the container at /app
# Install Python dependencies in a single layer
RUN apk add --no-cache python3 py3-pip
# Copy requirements first for better layer caching
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
# Copy the application code
COPY . /app
# Install any Python dependencies
RUN apk add python3
RUN apk add py3-pip
RUN pip install -r requirements.txt
# Run Python script
CMD ["python", "main.py"]

220
README.md
View File

@@ -1,20 +1,216 @@
# Masto-rss
![Masto-RSS Header](header.jpg)
A simple Mastodon bot written in python that posts updates from an RSS feed to a Mastodon account.
This project is meant to be built to a docker container, so all of the options need to be set as environment variables:
# Masto-RSS
MASTODON_CLIENT_ID = Mastodon client ID
[![Build Status](https://img.shields.io/github/actions/workflow/status/aserper/masto-rss/masto-rss.yml?style=for-the-badge&logo=github&label=Build)](https://github.com/aserper/masto-rss/actions/workflows/masto-rss.yml)
[![Docker Hub](https://img.shields.io/badge/docker%20hub-amitserper%2Fmasto--rss-blue?style=for-the-badge&logo=docker&logoColor=white)](https://hub.docker.com/r/amitserper/masto-rss)
[![GHCR](https://img.shields.io/badge/ghcr.io-masto--rss-blue?style=for-the-badge&logo=docker&logoColor=white)](https://github.com/aserper/masto-rss/pkgs/container/masto-rss)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-yellow.svg?style=for-the-badge)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/downloads/)
[![GitHub stars](https://img.shields.io/github/stars/aserper/masto-rss.svg?style=social)](https://github.com/aserper/masto-rss)
MASTODON_CLIENT_SECRET = Mastodon client secret
A simple, lightweight Mastodon bot that automatically posts updates from RSS feeds to the Fediverse. Built with Python and designed to run seamlessly in Docker with multiarch support (amd64 & arm64).
MASTODON_ACCESS_TOKEN = Mastodon access token
## Features
MASTODON_INSTANCE_URL = Mastodon instance URL
- Automatically monitors RSS/Atom feeds and posts new items to Mastodon
- Persistent state tracking to avoid duplicate posts
- Configurable post visibility (public, unlisted, private, direct)
- Lightweight Alpine-based Docker image
- Multiarch support (amd64 & arm64) for broad compatibility
- Continuous monitoring with configurable check intervals
RSS_FEED_URL = URL of RSS/xml feed
## Quick Start
TOOT_VISIBILITY = 'public', 'unlisted', 'private', or 'direct'
### Using Docker (Recommended)
The best way to use this project is by using [its docker container](https://hub.docker.com/r/amitserper/masto-rss)
When using docker, make a bind mount between /state on the container to whatever directory you want on your machine in order to keep the state of the feeds that were already posted
![image](https://github.com/aserper/masto-rss/actions/workflows/masto-rss.yml/badge.svg)
The easiest way to run Masto-RSS is using the pre-built multiarch Docker images available on both Docker Hub and GitHub Container Registry.
#### Pull from Docker Hub
```bash
docker pull amitserper/masto-rss:latest
```
#### Pull from GitHub Container Registry
```bash
docker pull ghcr.io/aserper/masto-rss:latest
```
#### Run the Bot
```bash
docker run -d \
--name masto-rss-bot \
-e MASTODON_CLIENT_ID="your_client_id" \
-e MASTODON_CLIENT_SECRET="your_client_secret" \
-e MASTODON_ACCESS_TOKEN="your_access_token" \
-e MASTODON_INSTANCE_URL="https://mastodon.social" \
-e RSS_FEED_URL="https://example.com/feed.xml" \
-e TOOT_VISIBILITY="public" \
-e CHECK_INTERVAL="300" \
-v /path/to/state:/state \
amitserper/masto-rss:latest
```
> **Important:** Use a bind mount for `/state` to persist the list of processed feed items across container restarts.
### Using Docker Compose
Create a `docker-compose.yml`:
```yaml
version: '3.8'
services:
masto-rss:
image: amitserper/masto-rss:latest
# Or use GHCR: ghcr.io/aserper/masto-rss:latest
container_name: masto-rss-bot
restart: unless-stopped
environment:
MASTODON_CLIENT_ID: "your_client_id"
MASTODON_CLIENT_SECRET: "your_client_secret"
MASTODON_ACCESS_TOKEN: "your_access_token"
MASTODON_INSTANCE_URL: "https://mastodon.social"
RSS_FEED_URL: "https://example.com/feed.xml"
TOOT_VISIBILITY: "public"
CHECK_INTERVAL: "300"
volumes:
- ./state:/state
```
Then run:
```bash
docker-compose up -d
```
## Configuration
All configuration is done via environment variables:
| Variable | Description | Required | Example |
|----------|-------------|----------|---------|
| `MASTODON_CLIENT_ID` | Mastodon application client ID | Yes | `abc123...` |
| `MASTODON_CLIENT_SECRET` | Mastodon application client secret | Yes | `xyz789...` |
| `MASTODON_ACCESS_TOKEN` | Mastodon access token | Yes | `token123...` |
| `MASTODON_INSTANCE_URL` | URL of your Mastodon instance | Yes | `https://mastodon.social` |
| `RSS_FEED_URL` | URL of the RSS/Atom feed to monitor | Yes | `https://example.com/feed.xml` |
| `TOOT_VISIBILITY` | Post visibility level | Yes | `public`, `unlisted`, `private`, or `direct` |
| `CHECK_INTERVAL` | Seconds between feed checks | Yes | `300` (5 minutes) |
### Getting Mastodon API Credentials
1. Log into your Mastodon instance
2. Go to **Settings****Development****New Application**
3. Give it a name (e.g., "RSS Bot")
4. Set scopes to `write:statuses`
5. Save and copy the client ID, client secret, and access token
## Building from Source
### Build Locally
```bash
git clone https://github.com/aserper/masto-rss.git
cd masto-rss
docker build -t masto-rss .
```
### Build Multiarch Images
```bash
# Set up buildx
docker buildx create --use
# Build for both architectures
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t yourusername/masto-rss:latest \
--push \
.
```
## Running Without Docker
If you prefer to run the bot directly with Python:
```bash
# Clone the repository
git clone https://github.com/aserper/masto-rss.git
cd masto-rss
# Install dependencies
pip install -r requirements.txt
# Set environment variables
export MASTODON_CLIENT_ID="your_client_id"
export MASTODON_CLIENT_SECRET="your_client_secret"
export MASTODON_ACCESS_TOKEN="your_access_token"
export MASTODON_INSTANCE_URL="https://mastodon.social"
export RSS_FEED_URL="https://example.com/feed.xml"
export TOOT_VISIBILITY="public"
export CHECK_INTERVAL="300"
# Run the bot
python main.py
```
> **Note:** When running without Docker, the bot stores its state in `/state/processed_entries.txt`. Make sure this directory exists or modify [main.py](main.py#L15) to use a different path.
## How It Works
1. The bot fetches the RSS feed at regular intervals (defined by `CHECK_INTERVAL`)
2. For each feed item, it checks if the item's URL has been processed before
3. If the item is new, it posts to Mastodon with the format: `{title}\n\n{link}`
4. The item URL is saved to prevent duplicate posts
5. The process repeats indefinitely
## Architecture
- **Base Image:** Alpine Linux 3.18 (minimal footprint)
- **Python Version:** 3.10+
- **Platforms:** linux/amd64, linux/arm64
- **Dependencies:** feedparser, mastodon.py (see [requirements.txt](requirements.txt))
## State Persistence
The bot maintains state in `/state/processed_entries.txt` to track which feed items have already been posted. This prevents duplicate posts across restarts.
**Important:** Always mount `/state` as a volume to preserve this state file.
## CI/CD
The project uses GitHub Actions for automated multiarch builds and deployments:
- Builds on every push to `main`
- Creates images for both amd64 and arm64 architectures
- Automatically pushes to Docker Hub and GitHub Container Registry
- Uses Docker layer caching for faster builds
See [.github/workflows/masto-rss.yml](.github/workflows/masto-rss.yml) for the full pipeline.
## Contributing
Contributions are welcome! Feel free to:
- Report bugs by opening an issue
- Submit pull requests for improvements
- Suggest new features or enhancements
## License
This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details.
## Support
If you find this project useful, please consider giving it a star on GitHub!
## Links
- [Docker Hub Repository](https://hub.docker.com/r/amitserper/masto-rss)
- [GitHub Container Registry](https://github.com/aserper/masto-rss/pkgs/container/masto-rss)
- [Source Code](https://github.com/aserper/masto-rss)
- [Issues](https://github.com/aserper/masto-rss/issues)

BIN
header.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB