Skip to content

Podcast RSS Feeds

Kieran edited this page Jul 11, 2024 · 2 revisions

Note

The below steps may not be required depending on your podcast app. If your podcast app doesn't rely on 3rd party servers for its core functionality, you might be able to use a VPN instead. If a VPN works for you, skip to the Putting it all together section below

RSS Feeds can be used to bring your content from Pinchflat into your favourite podcast app/RSS reader, but it takes a little setup to do so securely:

Pre-requisites

  • Your Pinchflat instance is accessible outside your network via an unchanging domain. I'm leaving this as an exercise to the reader
    • It works best to use a reverse proxy or similar - I use NGINX Proxy Manager on UnRAID
    • You can probably use a CF Tunnel but you will be streaming media which is against CF's ToS. Do what you will, but don't say I didn't tell ya'!
    • You may need to serve the site over https (but you really should, anyway)

Option 1: HTTP Basic Authentication

Since your Pinchflat instance will need to be accessible from the outside world, it's essential that you add some level of authentication. Seriously, it'd be silly to not secure the app. To do so, add both the BASIC_AUTH_USERNAME and BASIC_AUTH_PASSWORD environment variables to your docker run command or Docker container manager.

For example:

docker run
  -p 8945:8945 \
  -v /host/path/to/config:/config \
  -v /host/path/to/downloads:/downloads \
  -e BASIC_AUTH_USERNAME=admin \
  -e BASIC_AUTH_PASSWORD=CHANGEME \
  ghcr.io/kieraneglin/pinchflat:latest

It's recommended to use the app-provided authentication rather than any authentication provided by your reverse proxy unless you know what you're doing. See the next step for the reason why.

Important

Test that opening the app makes you enter these credentials before moving on.

Exposing feed endpoints

"Wait! I can't serve content to my podcast app now!", you're saying. And you're right!

A requirement of working with your podcast app is that the endpoints for reading the XML feed, getting the feed assets (like cover image), and streaming media are accessible via an unchanging URL that requires no configuration. Essentially, these routes need to live 100% outside of the app's authentication. All routes are protected by default, but if you want to exclude these routes from authentication simply set the EXPOSE_FEED_ENDPOINTS env var to any value. Here's an example of what we have so far:

docker run
  -p 8945:8945 \
  -v /host/path/to/config:/config \
  -v /host/path/to/downloads:/downloads \
  -e BASIC_AUTH_USERNAME=admin \
  -e BASIC_AUTH_PASSWORD=CHANGEME \
  -e EXPOSE_FEED_ENDPOINTS=yes \
  ghcr.io/kieraneglin/pinchflat:latest

Option 2: using your existing authentication solution

If you're doing it this way, I'm going to assume you're pretty technical so this will be extremely high level.

Essentially, you need to add authentication to all routes except the "feed" endpoints. These endpoints handle serving XML, images, media. You can find those routes in the router by searching for pipe_through :feeds.

Here's an example NGINX location block that works at the time of this writing:

location ~* (^/sources/[^/]+/feed(_image)?|^/media/[^/]+/(stream|episode_image))(\.[a-zA-Z0-9]+)?$ {
    # You may want to add more here depending on your setup
    proxy_pass $forward_scheme://$server:$port;
}

Security (or: "Security")

This is a technical digression that doesn't impact setup, but it's good to be aware of the security implications of what you're doing.

Internally the app uses numeric IDs to reference resources (eg: in the route sources/59/media/660 I'm talking about the 59 and the 660). If this is how we served data to the RSS feed, it would be trivially easy for an attacker to use an enumeration/forced browsing approach to start looking through the content you've downloaded. After all, they'd just need to try swapping 660 for 661 then 662, etc. This application is fairly low-stakes, but I'd rather not invite that possibility in the first place.

To mitigate this, any external URLs reference media via a universally unique identifier (UUID). This isn't perfect security since anyone who knows the URL for media can access it, but it makes it essentially impossible to guess a URL in the first place.

Putting it all together

By now you should have done the following:

  • Set up a reverse proxy (or similar) so you can access Pinchflat from the internet via your custom domain
  • Added authentication via HTTP Basic auth
  • Excluded the RSS/streaming-related endpoints from authentication so your podcast app can access the data

Almost done! Now, you just need to add your RSS feed to your podcast app:

  • ⚠️ Visit Pinchflat from your custom domain or VPN when performing the next steps ⚠️
  • Create a new source and download some content
  • When viewing the source, click "Actions" along the top then "Copy RSS Feed"
  • Enter that feed URL into your podcast app
  • That's it!

Well done! Like I said, this is a beta feature and RSS/XML can be very finicky. Please let me know if you encounter any problem by creating a GitHub issue!