A modern, fast, gpodder.net-compatible podcast sync server written in Rust.
Sync your podcast subscriptions and episode progress across AntennaPod, gPodder, Kasts, and any client that supports the gpodder.net API.
- 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.sqlfrom 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
# 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 serveThe server starts on http://localhost:3005. Point your podcast app at this URL.
docker compose --profile sqlite up -d
# Create a user
docker compose exec rpodder-sqlite rpodder user create myuser mypassword --admindocker compose --profile release up -dThe compose profiles above build from this checkout. To run the published image without building, use the deployment methods below.
Production self-hosting uses the published image
ghcr.io/thekoma/rpodder — no build required.
Ready-to-use compose files live in examples/. They import cleanly
into Dockge, Portainer and CasaOS.
# SQLite — simplest, single container
docker compose -f examples/docker-compose.yml up -d
# PostgreSQL — for multi-user instances
cp examples/.env.example examples/.env # then set POSTGRES_PASSWORD
docker compose -f examples/docker-compose.postgres.yml up -dCreate the first admin user:
docker compose -f examples/docker-compose.yml exec rpodder rpodder user create <name> <password> --adminA self-managed chart built on the bjw-s common library
lives in deploy/helm/rpodder/:
helm dependency build deploy/helm/rpodder
helm install rpodder deploy/helm/rpodder \
--set ingress.main.enabled=true \
--set 'ingress.main.hosts[0].host=podcasts.example.com'Defaults to SQLite on a PersistentVolumeClaim; point RPODDER_DATABASE_URL at
PostgreSQL for multi-user. See the chart README.
We're looking into TrueCharts support. Once we've carefully gone through their contribution guidelines, we may add rpodder to the catalog. Until then, use the Helm chart above.
See Systemd below.
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 |
0.0.0.0 |
Bind address |
RPODDER_PORT |
3005 |
Bind port |
RPODDER_RUN_MIGRATIONS |
true |
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 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 for an example.
rpodder serve # Start the server
rpodder migrate # Run database migrations
rpodder user create <username> <password> # Create a user
rpodder user create <username> <password> --admin # Create an admin user
rpodder user delete <username> # Deactivate a user
rpodder repair # Rebuild FTS5 index (SQLite)
Settings → Synchronization → Choose provider → gpodder.net
Server: http://your-server:3005 • Username/Password as created above
Settings → Synchronization → Custom server
http://your-server:3005
Preferences → gpodder.net → Server URL: http://your-server:3005
| 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 for the complete API surface.
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 rpodderAGPL-3.0-or-later
