Sign out cleared ipx's cookies and showed its password page, while Cloudflare Access still vouched for the person: nothing was signed out, and the page looked like the wrong login. /api/me now says, for someone the proxy signed in, where to go instead ([web] sign_out_url, which is /cdn-cgi/access/logout behind Access), and /login sends anyone the proxy vouches for on to their feeds. The header check both use is one function. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TAC7sLVqfKmY6rsTLXzNgk
121 lines
5.7 KiB
Markdown
121 lines
5.7 KiB
Markdown
# Configuration
|
|
|
|
One TOML file, read at startup and re-read whenever the web UI writes to it — most changes take
|
|
effect without a restart. Default location `$XDG_CONFIG_HOME/ipx/config.toml`
|
|
(`~/.config/ipx/config.toml`), overridden with `--config` or `$IPX_CONFIG`.
|
|
|
|
| What | Where | Override |
|
|
|---|---|---|
|
|
| Config | `~/.config/ipx/config.toml` | `--config`, `$IPX_CONFIG` |
|
|
| Database | `~/.local/share/ipx/state.db` | `$IPX_DATA_DIR` |
|
|
| Control socket | `$XDG_RUNTIME_DIR/ipx.sock` | `[general] socket` |
|
|
| Downloads | `[general] download_dir` | — |
|
|
|
|
`~` is expanded in paths. The database is SQLite in WAL mode; back it up by copying `state.db`
|
|
while the daemon is stopped, or with `sqlite3 state.db .backup`.
|
|
|
|
## `[general]`
|
|
|
|
```toml
|
|
[general]
|
|
download_dir = "~/Podcasts"
|
|
socket = "/run/user/1000/ipx.sock"
|
|
schedule = "every 1h" # "every 30m", "every 4h", "2d", "90" (minutes)
|
|
organize = "feed" # "feed" | "date"
|
|
max_total_gb = 50 # 0 = unlimited
|
|
max_age_days = 30 # 0 = keep forever
|
|
max_new_per_check = 3 # per feed, per scan. 0 = unlimited
|
|
media_types = ["audio", "video"]
|
|
```
|
|
|
|
* **`schedule`** — how often feeds are re-checked. A feed's own `<ttl>` still wins when it asks to
|
|
be polled *less* often, and a per-feed `schedule` overrides both. Admin-only from the UI.
|
|
* **`organize`** — `feed` files downloads under the feed's folder; `date` under `YYYY-MM-DD`.
|
|
* **`max_total_gb`** — the reaper deletes to get back under this, oldest first, keeping a 50 MB
|
|
pad. Kept items are never deleted, and a file only counts as read once every subscriber has
|
|
read it. `0` disables it entirely.
|
|
* **`max_age_days`** — items older than this with no file on disk are pruned from the database.
|
|
Kept ones stay. `0` disables it.
|
|
* **`max_new_per_check`** — the cap that stops a new subscription pulling a whole back catalogue.
|
|
`0` means unlimited, which is rarely what you want: subscribing to an OPML of 80 feeds with no cap
|
|
fetched 216 files and 22 GB in one scan.
|
|
* **`media_types`** — top-level MIME types taken automatically. Anything else is still listed and
|
|
can be fetched by hand; blog feeds put each article's header image in an `<enclosure>`, and
|
|
without this the disk fills with artwork. Empty takes everything.
|
|
|
|
## `[torrent]`
|
|
|
|
```toml
|
|
[torrent]
|
|
enabled = true
|
|
seed_ratio = 1.0 # stop seeding at this ratio ...
|
|
seed_time_mins = 60 # ... or after this long, whichever comes first
|
|
port_range = "6881-6889"
|
|
stall_mins = 30 # give up on a torrent making no progress
|
|
```
|
|
|
|
A `.torrent` body is handed to the torrent path whatever MIME type it was advertised as. Torrents
|
|
run on their own tasks (two at a time) so a slow swarm never blocks a scan.
|
|
|
|
## `[web]`
|
|
|
|
```toml
|
|
[web]
|
|
enabled = true
|
|
bind = "0.0.0.0:8099" # 127.0.0.1:8080 by default
|
|
token = "" # generated and saved on first run
|
|
trusted_header = "" # e.g. "Cf-Access-Authenticated-User-Email"
|
|
trusted_proxies = ["127.0.0.1", "::1"]
|
|
auto_create_users = true
|
|
sign_out_url = "" # e.g. "/cdn-cgi/access/logout"
|
|
session_days = 30
|
|
```
|
|
|
|
* **`token`** — the shared secret, which signs in as the **admin**. `?token=…` sets a cookie, so
|
|
you paste it once per browser. It is what the Docker healthcheck and any scripts use.
|
|
* **`trusted_header`** — a header naming the signed-in user, set by whatever fronts ipx. Empty
|
|
disables that path. See [sso.md](sso.md).
|
|
* **`trusted_proxies`** — addresses allowed to assert that header, and the entire security boundary
|
|
for it. Name the proxy, never a subnet.
|
|
* **`auto_create_users`** — create an account the first time the proxy vouches for a new name.
|
|
* **`sign_out_url`** — where Sign out sends someone the proxy signed in: the proxy's own sign-out,
|
|
`/cdn-cgi/access/logout` behind Cloudflare Access. Empty sends them to the sign-in page, where
|
|
the proxy signs them straight back in.
|
|
* **`session_days`** — sign a session out after this long without a request.
|
|
|
|
It is plain HTTP. On a LAN bind everything crosses the network in the clear — and a feed URL can
|
|
itself carry a credential. Put TLS in front of it if that matters.
|
|
|
|
## `[feeds.<id>]`
|
|
|
|
The table key is the feed id: stable, human-readable, and used in paths and the API. `ipx add`
|
|
derives it from the feed title.
|
|
|
|
```toml
|
|
[feeds.atp]
|
|
url = "https://atp.fm/rss"
|
|
folder = "Accidental Tech Podcast" # default: the feed title
|
|
schedule = "every 6h" # overrides [general] for this feed
|
|
media_types = ["audio"] # overrides [general] for this feed
|
|
username = "ray" # HTTP basic auth
|
|
password_env = "IPX_ATP_PASS" # preferred over a literal `password`
|
|
```
|
|
|
|
With more than one account, **`keywords`, `auto_download`, `allow_explicit` and
|
|
`max_new_per_check` live on each person's subscription in the database**, not here — the values in
|
|
config.toml are the fallback for a feed nobody has claimed. The keys above describe the feed itself
|
|
and are the same for everyone. See [users.md](users.md).
|
|
|
|
Feeds derived from a subscribed OPML are **not** written here: the OPML is the source of truth and
|
|
they are re-derived on every scan. Editing one in the UI promotes it to a real config entry.
|
|
|
|
## Environment
|
|
|
|
| Variable | Effect |
|
|
|---|---|
|
|
| `IPX_CONFIG` | Config file path |
|
|
| `IPX_DATA_DIR` | Directory holding `state.db` |
|
|
| `IPX_LOG` | What reaches stderr (`ipx=debug`, `ipx::scan=debug`, …) |
|
|
| `IPX_UI_LOG` | What the in-process log buffer captures for the UI's Log view |
|
|
| `http_proxy` / `https_proxy` | Honoured for feed and enclosure fetches |
|