<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Freshrss – Serverküche</title><link>https://serverkueche.de/en/tags/freshrss/</link><description>Freshrss – Neueste Beiträge von Serverküche</description><generator>Hugo</generator><language>en-US</language><managingEditor>feedback@serverkueche.de (Serverküche)</managingEditor><webMaster>feedback@serverkueche.de (Serverküche)</webMaster><copyright>2026 Serverküche</copyright><lastBuildDate>Sat, 05 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://serverkueche.de/en/tags/freshrss/index.xml" rel="self" type="application/rss+xml"/><item><title>FreshRSS: Your Own RSS Reader</title><link>https://serverkueche.de/en/tutorials/freshrss-rss-reader/</link><pubDate>Sat, 05 Sep 2026 00:00:00 +0000</pubDate><author>feedback@serverkueche.de (Serverküche)</author><guid>https://serverkueche.de/en/tutorials/freshrss-rss-reader/</guid><description>All your news sources in one place, no algorithm and no tracking: FreshRSS as a self-hosted RSS reader behind Traefik – with mobile app sync and backup.</description><content:encoded><![CDATA[<p>RSS is the best news format most people have forgotten: you subscribe to sources directly, with no algorithm, no ads and no one watching what you read. FreshRSS gathers all your sources in one self-hosted place – and even syncs with the RSS apps on your phone.</p>
<h2 id="what-are-we-building">What are we building?</h2>
<p>Your own RSS reader with <strong>FreshRSS</strong> (v1.29.1) behind <a href="/en/tutorials/traefik-reverse-proxy/">Traefik</a>, collecting your news sources and keeping them fresh via cron in the background. By the end you read tech news, blogs, YouTube channels and podcasts in one place, grouped into categories – and can connect mobile apps like Reeder or FeedMe via the built-in Google Reader API. FreshRSS is refreshingly lightweight: SQLite is enough, no separate database needed.</p>
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>A server with <a href="/en/tutorials/traefik-reverse-proxy/">Traefik</a> running and <a href="/en/tutorials/docker-compose-basics/">Docker Compose</a></li>
<li>A <a href="/en/tutorials/connect-domain-to-server/">subdomain pointing at the server</a> – <code>YOUR_DOMAIN</code> below (e.g. <code>rss.YOUR_DOMAIN</code>)</li>
</ul>
<div class="not-prose my-6 overflow-hidden rounded-xl border border-paprika-200 bg-paprika-50 dark:border-paprika-800 dark:bg-paprika-900/20"
     data-track-content data-content-name="Affiliate-Box · /en/tutorials/freshrss-rss-reader/" data-content-piece="VPS 1000 G12">
  <div class="flex items-center justify-between border-b border-paprika-200 bg-paprika-100 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-paprika-700 dark:border-paprika-800 dark:bg-paprika-900/40 dark:text-paprika-300">
    <span>🍳 Recommendation</span>
    <span title="Links marked with * are affiliate links.">Ad</span>
  </div>
  <div class="flex flex-col gap-4 p-4 sm:flex-row sm:items-center sm:justify-between">
    <div>
      <p class="text-lg font-bold text-slate-900 dark:text-white">VPS 1000 G12</p>
      <p class="mt-1 text-sm text-slate-600 dark:text-slate-300">4 vCores · 8 GB RAM · 256 GB NVMe</p>
      <p class="mt-1 text-sm font-semibold text-paprika-700 dark:text-paprika-400">from €10.36/month</p>
      <p class="mt-2 text-sm text-slate-600 dark:text-slate-400">FreshRSS is frugal – the smallest VPS handles many feeds.</p>
    </div>
    <a href="https://www.netcup.com/en/server/vps/vps-1000-g12-iv-12m?ref=44083" rel="sponsored noopener" target="_blank"
   data-track-event="Affiliate|netcup: Affiliate-Box|VPS 1000 G12 · {page}"
   class="inline-flex shrink-0 items-center justify-center rounded-lg bg-paprika-600 px-5 py-2.5 font-semibold text-white transition-colors hover:bg-paprika-700">
  Go to netcup →
</a>

  </div><div class="px-4 pb-4"><p class="not-prose my-3 flex flex-wrap items-center gap-x-2 gap-y-1 rounded-lg border border-herb-500/40 bg-herb-50 px-3 py-2 text-sm text-slate-700 dark:bg-herb-900/20 dark:text-slate-200">
  <span>💶 <strong>5 € voucher</strong> for new netcup customers:</span><code data-track-voucher="36nc17844976032"
        class="rounded bg-white px-2 py-0.5 font-mono text-sm font-semibold text-herb-800 dark:bg-slate-800 dark:text-herb-400">36nc17844976032</code>
  <span class="text-xs text-slate-500 dark:text-slate-400">(new customers only, no domains)</span>
</p></div>
</div>

<h2 id="step-by-step">Step by step</h2>
<h3 id="step-1-create-the-compose-file">Step 1: Create the Compose file</h3>
<p>FreshRSS keeps everything in a <code>data</code> directory (SQLite database, config, cache). Create the project:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p /opt/freshrss <span class="o">&amp;&amp;</span> <span class="nb">cd</span> /opt/freshrss</span></span></code></pre></div>
</div>
<p>The <code>compose.yaml</code> – replace <code>YOUR_DOMAIN</code>:</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">freshrss</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">freshrss/freshrss:1.29.1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">./data:/var/www/FreshRSS/data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">./extensions:/var/www/FreshRSS/extensions</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">TZ</span><span class="p">:</span><span class="w"> </span><span class="l">Europe/Berlin</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">CRON_MIN</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;13,43&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">networks</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">proxy]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.enable=true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.freshrss.rule=Host(`YOUR_DOMAIN`)&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.freshrss.entrypoints=websecure&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.freshrss.tls.certresolver=le&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.services.freshrss.loadbalancer.server.port=80&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">networks</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">proxy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">external</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
</div>
<p><code>CRON_MIN</code> is a nice touch of the official image: it starts an internal cron that refreshes the feeds automatically at the given minutes (here 13 and 43 of every hour) – you need no external timer.</p>
<h3 id="step-2-start">Step 2: Start</h3>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose up -d</span></span></code></pre></div>
</div>
<p>Check that FreshRSS responds with valid HTTPS (the 302 is the redirect to the install wizard):</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -sI https://YOUR_DOMAIN/ <span class="p">|</span> head -1</span></span></code></pre></div>
</div>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">HTTP/2 302</span></span></code></pre></div>
</div>
<h3 id="step-3-the-install-wizard">Step 3: The install wizard</h3>
<p>Open <code>https://YOUR_DOMAIN/</code> in the browser. The wizard walks you through setup in five steps – language, system check, database, account:</p>
<p><figure class="my-6"><img src="/en/tutorials/freshrss-rss-reader/frss-wizard_hu_ade8b900c09d624f.webp" srcset="/en/tutorials/freshrss-rss-reader/frss-wizard_hu_3d26f45d8eb05b74.webp 480w, /en/tutorials/freshrss-rss-reader/frss-wizard_hu_ade8b900c09d624f.webp 768w, /en/tutorials/freshrss-rss-reader/frss-wizard_hu_69a6f8b46a7324a3.webp 1200w, /en/tutorials/freshrss-rss-reader/frss-wizard_hu_4d8802b8f5411f56.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/freshrss-rss-reader/frss-wizard_hu_84c7e7cbce5e6374.webp"
    alt="The FreshRSS install wizard, step 1: language selection with version 1.29.1" title="The install wizard guides you through language, system check, database and admin account"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">The install wizard guides you through language, system check, database and admin account</figcaption></figure></p>
<p>Choose <strong>SQLite</strong> as the database type (no further details needed), <strong>form-based</strong> authentication and create your administrator account with a strong password. After the last step you&rsquo;re logged in.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Alternative: setup from the command line
  </p>
  <div class="prose-kitchen text-sm">To script the initial setup without a browser: <code>docker compose exec -u www-data freshrss ./cli/do-install.php --default-user admin --auth-type form --db-type sqlite --language en</code>, then <code>./cli/create-user.php --user admin --password 'YOUR_PASSWORD'</code>. Handy for reproducible setups – for getting started the graphical wizard is more convenient.</div>
</div>
<h3 id="step-4-subscribe-to-your-first-feeds">Step 4: Subscribe to your first feeds</h3>
<p>Click <strong>Subscription management → Add a feed or category</strong> at the top left. Enter a source&rsquo;s feed URL (e.g. <code>https://www.heise.de/rss/heise-atom.xml</code>) and assign it to a category. FreshRSS detects the feed format automatically. After adding several sources the management view looks like this:</p>
<p><figure class="my-6"><img src="/en/tutorials/freshrss-rss-reader/frss-subs_hu_668ae170dd3e3d81.webp" srcset="/en/tutorials/freshrss-rss-reader/frss-subs_hu_3a955ae903bbcb7b.webp 480w, /en/tutorials/freshrss-rss-reader/frss-subs_hu_668ae170dd3e3d81.webp 768w, /en/tutorials/freshrss-rss-reader/frss-subs_hu_d7b83a452ed18056.webp 1200w, /en/tutorials/freshrss-rss-reader/frss-subs_hu_dd25b39ac9f770d.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/freshrss-rss-reader/frss-subs_hu_41d9e4b0ad19db6b.webp"
    alt="The FreshRSS subscription management with feeds in the News and Uncategorized categories" title="Subscription management: feeds grouped into categories, with import/export and statistics"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Subscription management: feeds grouped into categories, with import/export and statistics</figcaption></figure></p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Bring existing feeds via OPML
  </p>
  <div class="prose-kitchen text-sm">Switching from another reader (Feedly, Inoreader, old Google Reader)? Export an <strong>OPML file</strong> there and import it under &ldquo;Import / Export&rdquo;. All your subscriptions move over in one click – including the category structure.</div>
</div>
<h3 id="step-5-reading">Step 5: Reading</h3>
<p>Back in the reading view, FreshRSS collects articles from all sources chronologically, grouped by category. Unread counters per feed, stars for favorites, full-text search – it&rsquo;s all there:</p>
<p><figure class="my-6"><img src="/en/tutorials/freshrss-rss-reader/frss-read_hu_32e47ce72da844d5.webp" srcset="/en/tutorials/freshrss-rss-reader/frss-read_hu_e056ca3657c63c39.webp 480w, /en/tutorials/freshrss-rss-reader/frss-read_hu_32e47ce72da844d5.webp 768w, /en/tutorials/freshrss-rss-reader/frss-read_hu_254dd068f2a21d3a.webp 1200w, /en/tutorials/freshrss-rss-reader/frss-read_hu_48a83f2154c7163e.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/en/tutorials/freshrss-rss-reader/frss-read_hu_224c4bc1c01d15a6.webp"
    alt="The FreshRSS reading view with recent articles from heise online and t3n, grouped in categories" title="The reading view: all sources in one place, with unread counters and search"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">The reading view: all sources in one place, with unread counters and search</figcaption></figure></p>
<h3 id="step-6-connect-mobile-apps-optional">Step 6: Connect mobile apps (optional)</h3>
<p>FreshRSS speaks the <strong>Google Reader API</strong>, so many mobile apps can use it as a sync backend. Enable it under <strong>Settings → Profile → External access via API</strong> and set a separate API password there. In the app (e.g. Reeder, FeedMe, NetNewsWire) choose &ldquo;FreshRSS&rdquo; or &ldquo;Google Reader API&rdquo;, enter <code>https://YOUR_DOMAIN/api/greader.php</code>, your username and the API password – and keep reading in sync on the go.</p>
<h2 id="when-things-go-wrong">When things go wrong</h2>
<div class="troubleshoot not-prose">
<p><strong>The wizard reports write-permission errors on the <code>data</code> folder.</strong> The container runs as <code>www-data</code> (UID 33). With a bind-mounted <code>./data</code> the permissions must match: <code>chown -R 33:33 /opt/freshrss/data</code> (see <a href="/en/tutorials/linux-users-and-permissions/">Users &amp; permissions</a>).</p>
<p><strong>Feeds don&rsquo;t refresh automatically.</strong> Check whether <code>CRON_MIN</code> is set and the internal cron is running: <code>docker compose logs freshrss | grep -i cron</code>. You can trigger a refresh anytime with the refresh button at the top right or <code>docker compose exec -u www-data freshrss ./cli/actualize-user.php --user admin</code>.</p>
<p><strong>A feed stays empty / is marked &ldquo;inactive&rdquo;.</strong> The source doesn&rsquo;t serve valid RSS/Atom, or the URL is an HTML page instead of the feed. Many sites hide the feed – search the page source for <code>application/rss+xml</code>. Under &ldquo;Statistics → Inactive feeds&rdquo; you&rsquo;ll find problem sources gathered.</p>
<p><strong>Login fails even though the password is correct.</strong> FreshRSS encrypts the password in the browser (JavaScript). If JavaScript is disabled or the connection isn&rsquo;t really HTTPS (certificate warning), the login fails. Via Traefik HTTPS is guaranteed – check the certificate if in doubt.</p>
<p><strong>Articles are missing after an update.</strong> FreshRSS purges old articles after a configurable period (default: a few weeks). That&rsquo;s intentional and keeps the database small; raise the retention per feed in its settings if needed.</p>

</div>

<h2 id="maintenance--backups">Maintenance &amp; backups</h2>
<ul>
<li><strong>Updates.</strong> Occasionally bump the image tag (<code>freshrss/freshrss:1.29.1</code>) to the new version and <code>docker compose up -d</code>; FreshRSS migrates its database automatically at start. The project announces larger jumps in the release notes – usually there&rsquo;s nothing else to do. Your normal <a href="/en/tutorials/keep-docker-stack-updated/">update process</a> handles the rest.</li>
<li><strong>Backup.</strong> The entire state lives in the <code>data</code> folder (SQLite database + config). Add it to your <a href="/en/tutorials/restic-backups/">Restic backup</a> – then subscriptions, categories and read markers are safe. Additionally a regular <strong>OPML export</strong> of your feed list makes a human-readable, reader-independent backup.</li>
<li><strong>Low effort.</strong> FreshRSS is a &ldquo;set it up once, then it just runs&rdquo; service. The only recurring task is curating your feed list – prune dead sources under &ldquo;Inactive feeds&rdquo;, subscribe to new ones.</li>
</ul>
]]></content:encoded></item></channel></rss>