Deploy Stringer
Self-hosted RSS reader with no social feed or algorithm
stringer-worker
Just deployed
stringer
Just deployed
stringer-scheduler
Just deployed
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.

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.

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
/feverfor 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-railwayon top ofstringerrss/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
| Variable | Service | Purpose |
|---|---|---|
STRINGER_USERNAME | stringer | Username for the admin account created on first boot |
STRINGER_PASSWORD | stringer | Password for that account |
DATABASE_URL | all three | Connection string for the managed Postgres service |
SECRET_KEY_BASE | all three | Signs the session cookie; must not change |
ENCRYPTION_PRIMARY_KEY | all three | Encrypts the stored Fever API key; must not change |
FETCH_FEEDS_CRON | stringer-scheduler | How often feeds are polled, default every five minutes |
CLEANUP_AFTER_DAYS | stringer-scheduler | Age at which read, unstarred articles are deleted |
GOOD_JOB_MAX_THREADS | stringer-worker | Concurrent feed fetches, default 5 |
Deployment Dependencies
- Source: github.com/stringer-rss/stringer (MIT)
- Image: hub.docker.com/r/stringerrss/stringer
- Runtime: Ruby 4.0, Rails 8.1, PostgreSQL 18
Hardware Requirements for Self-Hosting Stringer
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 0.5 vCPU across all services | 1–2 vCPU |
| RAM | 1 GB total | 2 GB total |
| Storage | 1 GB in Postgres | 5 GB for a large archive |
| Runtime | Ruby 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
stringer-worker
gridalpha/stringer-railwaystringer
gridalpha/stringer-railwaystringer-scheduler
gridalpha/stringer-railway