An open API service indexing awesome lists of open source software.

https://github.com/thekoma/rpodder

A modern, self-hostable gpodder.net replacement written in Rust. Sync podcast subscriptions and episode progress across all your devices.
https://github.com/thekoma/rpodder

axum docker gpodder kubernetes oidc podcast podcast-sync postgresql prometheus rest-api rust self-hosted sqlite sso svelte

Last synced: 2 months ago
JSON representation

A modern, self-hostable gpodder.net replacement written in Rust. Sync podcast subscriptions and episode progress across all your devices.

Awesome Lists containing this project

README

          


rpodder logo

rpodder

A modern, fast, gpodder.net-compatible podcast sync server written in Rust.


CI
Latest Release
Image Size
License: AGPL-3.0
Rust Edition 2024
Database: PostgreSQL | SQLite
Frontend: Svelte 5
API: gpodder compatible
Arch: amd64 | arm64
Deploy: Docker | K8s
Docs
Self-hosted: Raspberry Pi ready
SSO: OIDC / OAuth2


rpodder screenshot

Sync your podcast subscriptions and episode progress across [AntennaPod](https://antennapod.org), [gPodder](https://gpodder.github.io), [Kasts](https://apps.kde.org/kasts/), and any client that supports the [gpodder.net API](https://gpoddernet.readthedocs.io/).

## Features

- **Full gpodder API** — subscriptions, episode actions, devices, sync groups, settings, favorites, chapters, podcast lists
- **Web UI** — built-in Svelte 5 + Tailwind interface for browsing, searching, and managing podcasts
- **User roles** — admin/user system with first-user auto-admin, full user management panel
- **SSO/OAuth2** — OIDC single sign-on (Authentik, Keycloak, etc.) with group-based admin mapping
- **Registration control** — open, closed, or invite-only (email activation)
- **Password management** — self-service change/reset via email, admin set/reset, SSO-friendly
- **HTTPS upgrade suggestions** — detects HTTP subscriptions with HTTPS alternatives, proposes upgrade
- **Multi-format** — JSON, OPML, and TXT for subscription import/export
- **Dual database** — PostgreSQL for scale, SQLite for self-hosting
- **Feed indexing** — automatic feed fetching, parsing, fuzzy search, podcast directory
- **Dynamic migrations** — reads all `*.up.sql` from migrations directory, no hardcoded filenames
- **Privacy** — private/paid feeds (with tokens in URL) hidden from public directory
- **Lightweight** — single binary with embedded UI, low memory footprint

## Quickstart

### SQLite (self-hosted)

```bash
# Build
cargo build --release

# Initialize database and create an admin user
./target/release/rpodder migrate
./target/release/rpodder user create myuser mypassword --admin

# Start the server
./target/release/rpodder serve
```

The server starts on `http://localhost:3005`. Point your podcast app at this URL.

### Docker (SQLite)

```bash
docker compose --profile sqlite up -d
# Create a user
docker compose exec rpodder-sqlite rpodder user create myuser mypassword --admin
```

### Docker (PostgreSQL)

```bash
docker compose --profile release up -d
```

## Configuration

All settings can be set via environment variables or a TOML config file:

| Env var | Default | Description |
|---------|---------|-------------|
| `RPODDER_DATABASE_URL` | `sqlite://rpodder.db` | Database connection URL |
| `RPODDER_HOST` | `127.0.0.1` | Bind address |
| `RPODDER_PORT` | `3005` | Bind port |
| `RPODDER_RUN_MIGRATIONS` | `false` | Run migrations on startup |
| `RPODDER_REGISTRATION` | `open` | `open` / `closed` / `invite` |
| `RPODDER_SMTP_HOST` | | SMTP server for email features |
| `RPODDER_OAUTH_ISSUER_URL` | | OIDC issuer URL for SSO |
| `RPODDER_OAUTH_CLIENT_ID` | | OAuth2 client ID |
| `RPODDER_OAUTH_CLIENT_SECRET` | | OAuth2 client secret |
| `RPODDER_OAUTH_ADMIN_GROUP` | | OIDC group name for admin role |
| `RPODDER_BASE_URL` | | Public URL for OAuth callbacks and emails |
| `RPODDER_PODCASTINDEX_KEY` | | [Podcast Index](https://podcastindex.org/) API key (free) |
| `RPODDER_PODCASTINDEX_SECRET` | | Podcast Index API secret |

Or use a config file: `rpodder -c config.toml serve`

See [`config/rpodder.example.toml`](config/rpodder.example.toml) for an example.

## CLI

```
rpodder serve # Start the server
rpodder migrate # Run database migrations
rpodder user create # Create a user
rpodder user create --admin # Create an admin user
rpodder user delete # Deactivate a user
rpodder repair # Rebuild FTS5 index (SQLite)
```

## Client Setup

### AntennaPod
Settings → Synchronization → Choose provider → gpodder.net
Server: `http://your-server:3005` • Username/Password as created above

### Kasts (KDE)
Settings → Synchronization → Custom server
`http://your-server:3005`

### gPodder Desktop
Preferences → gpodder.net → Server URL: `http://your-server:3005`

## API Endpoints

| Endpoint | Description |
|----------|-------------|
| `POST /api/2/auth/{user}/login.json` | Login (HTTP Basic Auth) |
| `GET/PUT /subscriptions/{user}/{device}.{json,opml,txt}` | Subscription sync |
| `GET/POST /api/2/subscriptions/{user}/{device}.json` | Delta subscription sync |
| `GET/POST /api/2/episodes/{user}.json` | Episode action sync |
| `GET/POST /api/2/devices/{user}/{device}.json` | Device management |
| `GET /api/2/me` | Current user info |
| `POST /api/2/me/password` | Change password |
| `GET /api/2/me/upgrades` | HTTPS upgrade suggestions |
| `POST /api/2/register` | Public registration |
| `POST /api/2/password-reset` | Request password reset |
| `GET /search.json?q=...` | Podcast search |
| `GET /toplist/{count}.json` | Top podcasts |
| `GET /api/admin/users` | Admin: list users |
| `GET /api/admin/stats` | Admin: server statistics |
| `GET /health` | Health check |

See [`docs/API_REFERENCE.md`](docs/API_REFERENCE.md) for the complete API surface.

## Systemd

```bash
sudo cp target/release/rpodder /usr/local/bin/
sudo cp config/rpodder.service /etc/systemd/system/
sudo useradd -r -s /bin/false rpodder
sudo mkdir -p /var/lib/rpodder /usr/share/rpodder
sudo cp -r migrations /usr/share/rpodder/
sudo chown rpodder:rpodder /var/lib/rpodder
sudo systemctl enable --now rpodder
```

## License

AGPL-3.0-or-later