Container Fundamentals
Overview
PinePods ships as a single Docker image that runs several cooperating processes under a lightweight process supervisor. Everything an instance needs at runtime — the web UI, the main API, the gpodder sync server, and the reverse proxy — lives in that one container. It talks to two external services you provide: a database (PostgreSQL or MySQL/MariaDB) and a Valkey/Redis cache.
This page documents how the container is put together and what a "native" (non-Docker) deployment would need to replicate.
PinePods used to run a Python/FastAPI backend supervised by supervisord, with feed
refreshes driven by cron. That is no longer the case. The backend is now a Rust
(Axum) API, processes are supervised by Horust,
and background jobs run on an internal scheduler — there is no cron and no Python runtime
in the final image.
Core Components
1. Frontend — Rust / Yew (WebAssembly)
- Built with the Yew framework and compiled to WebAssembly (WASM) with Trunk.
- Shipped as static files (HTML/JS/WASM/CSS) and served directly by nginx from
/var/www/html. There is no Node.js server involved. - The desktop and mobile clients are separate apps; this is the browser UI.
2. Backend — Rust API (Axum)
The main backend is a compiled Rust binary, pinepods-api. It handles:
- All data and business logic (
/api/*endpoints) - Podcast feed parsing, refresh, and downloads
- User management, authentication, and OIDC
- RSS feed generation (
/api/feed/*) - WebSocket connections for real-time updates and task progress
- Background job scheduling — feed refreshes and nightly maintenance run on an internal scheduler inside this process (no cron)
It listens on port 8032 inside the container and is reached through nginx; it is not exposed directly.
3. gpodder API — Go
A separate Go binary, gpodder-api, implements the gpodder.net sync protocol so apps
like AntennaPod can sync subscriptions and episode actions with PinePods. It listens on
port 8042 and shares the same database as the Rust API.
4. Database setup tool — pinepods-db-setup
Schema creation, migrations, and validation are performed by a small standalone binary,
pinepods-db-setup. It is written in Python but compiled to a single executable with
PyInstaller at build time, so the runtime image contains no Python interpreter. It runs
once on every startup before the services launch, is idempotent, and supports both
PostgreSQL and MySQL/MariaDB.
5. Database layer (external)
Supports PostgreSQL (recommended) and MySQL/MariaDB. Stores users, podcast and episode metadata, listening history, playlists, settings, queue, downloads, and gpodder sync state. You run this yourself (or via the bundled Helm/Compose examples); it is not part of the PinePods image.