Deploy Stringer

Self-hosted RSS reader with no social feed or algorithm

Deploy Stringer

Just deployed

Just deployed

stringer-scheduler

gridalpha/stringer-railway

Just deployed

/var/lib/postgresql/data

Deploy and Host Stringer on Railway

Stringer is a self-hosted, anti-social RSS reader: one account, the feeds you chose, nothing else. No recommendation engine, no social graph, no "stories you might like" — just a fast, keyboard-driven inbox for the open web. Self-host Stringer and your subscription list, read state and starred articles live in your own PostgreSQL database rather than somebody's analytics pipeline.

Deploy Stringer on Railway and you get the production shape rather than a single box. The stringer service runs the Rails application and is the only one with a public URL. stringer-worker fetches and parses feeds in the background, so a slow site never blocks a page load. stringer-scheduler runs the cron that refreshes every five minutes and prunes old read articles nightly. All three use a managed Postgres service holding every feed, story and preference. The admin account is created before the app accepts its first request, so the sign-up form is never open to a stranger who finds the URL first.

Stringer web, worker and scheduler services around Railway Postgres

Getting Started with Stringer on Railway

Open the stringer service's public URL and you land on a login form. Sign in with the username and password you set in STRINGER_USERNAME and STRINGER_PASSWORD at deploy time — that account is created during the first boot and marked admin, and /setup/password closes the moment it exists. There are no default credentials to change afterwards.

Your first real action is adding a feed. Click the orange + button and paste a site URL — Stringer discovers the feed from an ordinary homepage. The subscription saves immediately and the fetch goes to the worker, so you return to your unread list at once and articles appear within seconds. Or use Import in the footer to upload an OPML file exported from Feedly, Inoreader or NewsBlur.

To confirm everything is wired up, open Feeds after a minute: each subscription should show a green dot and an unread count. A red dot means that one site failed to respond, not that the deployment is broken. Press ? for the shortcuts — j/k move between stories, Enter opens one in place, s stars it. Stringer also serves the Fever API at /fever, so Reeder, Unread and other Fever clients sync against it.

Stringer unread list mixing Hacker News, The Verge and GitHub stories A Hacker News story expanded in place above the unread list Three subscribed feeds with green status and unread counts GoodJob dashboard showing the scheduled feed fetch succeeded

About Hosting Stringer

Stringer is a Rails 8 application on PostgreSQL, Hotwire and GoodJob. It is deliberately small — an unread list, a reading pane, a starred archive, a feed manager — which is why it self-hosts well: no search cluster, no cache tier, no object storage.

  • Feed discovery from a plain site URL, plus OPML import and export
  • Keyboard-first reading with a shortcut overlay on ?
  • Starred articles kept indefinitely, read articles pruned on your schedule
  • A Fever API clone at /fever for third-party mobile clients
  • Interface translations for German, Spanish, French, Japanese, Dutch and more
  • SSRF protection on every outbound fetch, including each redirect

The Railway deployment splits the roles Stringer's own image bundles into one container: stringer serves HTTP and owns migrations, stringer-worker fetches and parses, stringer-scheduler runs the polling and cleanup schedules.

Why Deploy Stringer on Railway

Railway handles the parts you do not want to run:

  • Managed PostgreSQL with backups, no tuning required
  • A TLS public URL for the web service; worker and scheduler stay private
  • Health checks on all three services, background processes included
  • Per-service scaling, so the worker grows without the web tier

Common Use Cases

  • A personal reading inbox replacing Feedly or Inoreader, without handing over your subscription list
  • Tracking competitor blogs, release notes and changelogs on a shared account
  • A stable Fever API endpoint so phone and laptop share read state

Dependencies for Stringer

  • stringer — the Rails web application, built from gridalpha/stringer-railway on top of stringerrss/stringer:latest
  • stringer-worker — the same image running GoodJob as a background job processor
  • stringer-scheduler — the same image running GoodJob's cron
  • Postgres — managed ghcr.io/railwayapp-templates/postgres-ssl:18

Environment Variables Reference

VariableServicePurpose
STRINGER_USERNAMEstringerUsername for the admin account created on first boot
STRINGER_PASSWORDstringerPassword for that account
DATABASE_URLall threeConnection string for the managed Postgres service
SECRET_KEY_BASEall threeSigns the session cookie; must not change
ENCRYPTION_PRIMARY_KEYall threeEncrypts the stored Fever API key; must not change
FETCH_FEEDS_CRONstringer-schedulerHow often feeds are polled, default every five minutes
CLEANUP_AFTER_DAYSstringer-schedulerAge at which read, unstarred articles are deleted
GOOD_JOB_MAX_THREADSstringer-workerConcurrent feed fetches, default 5

Deployment Dependencies

Hardware Requirements for Self-Hosting Stringer

ResourceMinimumRecommended
CPU0.5 vCPU across all services1–2 vCPU
RAM1 GB total2 GB total
Storage1 GB in Postgres5 GB for a large archive
RuntimeRuby 4.0, PostgreSQL 14+Ruby 4.0, PostgreSQL 18

The dominant cost is database rows, which grow with the number of feeds and how long read articles are kept. Lowering CLEANUP_AFTER_DAYS keeps it small; starred articles are never pruned.

Self-Hosting Stringer Outside Railway

Stringer publishes a Docker image, but it ships without its compiled CSS and JavaScript — its build never installs the Node toolchain — so running it yourself means building the assets first. These are shell commands to build and start it from source against a local PostgreSQL:

git clone https://github.com/stringer-rss/stringer.git && cd stringer
bundle install
pnpm install && pnpm build && pnpm build:css
export DATABASE_URL="postgres://stringer:secret@localhost/stringer_live"
for k in SECRET_KEY_BASE ENCRYPTION_PRIMARY_KEY \
         ENCRYPTION_DETERMINISTIC_KEY ENCRYPTION_KEY_DERIVATION_SALT; do
  export $k=$(openssl rand -hex 32)
done
bundle exec rails db:migrate assets:precompile
bundle exec puma -C ./config/puma.rb

To run the published image instead, start PostgreSQL beside it and pass the same four secrets:

docker run -p 8080:8080 \
  -e DATABASE_URL=postgres://postgres:changeme@db/stringer \
  -e SECRET_KEY_BASE=$(openssl rand -hex 64) \
  -e ENCRYPTION_PRIMARY_KEY=$(openssl rand -hex 32) \
  -e ENCRYPTION_DETERMINISTIC_KEY=$(openssl rand -hex 32) \
  -e ENCRYPTION_KEY_DERIVATION_SALT=$(openssl rand -hex 32) \
  stringerrss/stringer:latest

The Railway template does all of this for you, asset build included.

Is Stringer Free to Self-Host?

Stringer is open source under the MIT licence, with no paid tier, no feature gate and no account to register. The only cost on Railway is infrastructure: three small services and a managed PostgreSQL database. For one reader following a few hundred feeds that is a small monthly bill, against roughly $6–$10 a month for Feedly Pro or Inoreader Supporter.

FAQ

What is Stringer?

Stringer is a self-hosted RSS and Atom reader written in Ruby on Rails. It gives one user a fast, keyboard-driven unread list for the sites they subscribe to — no social features, no algorithmic ranking, no tracking.

What does this Railway template deploy?

Four services: stringer (the web application, with a public URL), stringer-worker (fetches feeds in the background), stringer-scheduler (the cron triggering refreshes and cleanup) and Postgres.

Why does the template include a PostgreSQL database?

Stringer stores subscriptions, every fetched article, read and starred state, and your account in PostgreSQL. There is no file-based mode, so the database is the only persistent state — a Railway backup captures the whole reader.

Why are the worker and scheduler separate services?

Fetching a feed means an HTTP request to somebody else's server, which can be slow or hang. Running that outside the web process keeps the interface responsive, and lets you raise GOOD_JOB_MAX_THREADS on its own.

How do I use Stringer with a mobile RSS client?

In any Fever-compatible client — Reeder, Unread, Fiery Feeds — set the server to https://your-domain/fever, the username to stringer and the password to your own. Read and starred state syncs both ways.

How often does Stringer check for new articles?

Every five minutes by default. Change FETCH_FEEDS_CRON on stringer-scheduler to any cron expression — 0 * * * * for hourly — and redeploy that service.

Can more than one person use the same deployment?

Stringer is built for a single reader, and sign-ups close once the first account exists. A household or team can share one login, but there are no per-user feed lists.


Template Content

More templates in this category

View Template
Rocky Linux
Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀

codestorm
47
View Template
Foundry Virtual Tabletop
A Self-Hosted & Modern Roleplaying Platform

Lucas
71
View Template
Letta Code Remote
Run a Letta Code agent 24/7. No inbound ports, just deploy.

Letta
51