NJ Naman Jain ← Back
Work / Bahnscanner
Case study  ·  02

Bahnscanner — a cheaper way to search Deutsche Bahn, hosted on a Raspberry Pi in my flat.

A self-hosted fare scanner for the German rail network. Search a single route, or pick Everywhere and let it rank every reachable station by price across a whole flexible month.

Bahnscanner web app: search interface with From / To / When / Travellers fields and filter chips. Bahnscanner Everywhere search: a list of European cities with the cheapest fares for a flexible month. Bahnscanner destination search: the cheapest day-by-day fares for a chosen route.

Fig. 01 The search interface at bahnscanner.de. The killer feature: pick Everywhere as a destination, then a flexible month, and the scanner returns the cheapest city you can reach on any day of that month.

~5,000 Monthly users
1 Raspberry Pi 5
€0 Cloud bill
24/7 Uptime, from my apartment
i.

The itch

The DB website tells you the price of your route, on your dates. What it doesn't tell you is: where is the cheapest place I can go from Berlin next month, on any day?

That second question is the one I actually ask. A spontaneous weekend trip. A cheap excuse to visit a new city. A flexible Friday-to-Sunday for €19 each way, somewhere I haven't been. DB's search makes you guess a destination first; I wanted the destination to fall out of the search.

ii.

What it does

  1. 01

    Single-route search, but better

    Pick a From and To pair like any other fare tool. Add filters for ICE, IC/EC, Regional or Night services. Optionally apply a BahnCard 25 or 50 discount across every result.

  2. 02

    Everywhere mode

    Set the destination to Everywhere and the engine fans out across every reachable station from your origin, returning a price-ranked list. Pair it with a flexible month and you see the cheapest reachable city across that whole window.

  3. 03

    Flexible-month round trips

    For a single destination, set both outbound and return to flexible months and the scanner computes round-trip totals for every day-pair, surfacing the cheapest combinations.

  4. 04

    Coverage map

    A separate view shows which stations the scanner currently knows about and how stale the cached fares are.

iii.

Hosted on a Pi

The whole site — frontend, API, scheduler, fare cache — runs on a single Raspberry Pi 5 sitting on my desk.

Around 5,000 people a month hit bahnscanner.de, and every request is served from that little board in Berlin. A Cloudflare tunnel exposes it to the open internet so I don't need to punch holes in my router, and the only running cost is the few watts it pulls from the wall.

Self-hosting on a Pi forced a kind of discipline I enjoy: every dependency justified, every background job small enough to recover from a power blip, every cache entry sized to fit on an SD card without burning through write cycles.

A Raspberry Pi 5 on a wooden desk with a USB-C power cable plugged in, flanked by two toy cars.
Fig. 03 The whole stack lives on this. A Raspberry Pi 5 in my flat, scraping fares overnight and serving the UI to the open internet. The toy cars are not load-bearing.
iv.

How it's built

A Python backend talks to Deutsche Bahn's APIs, caches fares aggressively in a local store, and exposes a FastAPI service. A small React frontend renders the search UI and the tips inline.

The interesting engineering is in the Everywhere search: a naive implementation would issue hundreds of fare queries per session and get rate-limited within seconds. Two caching strategies keep the API responsive. First, user-search caching: if user A searches a route, user B's identical query for the next 30 minutes is served straight from the cache. Second, a warm-cache sidecar continuously refreshes results for popular routes and big-city pairs — Berlin, Munich, Frankfurt, Hamburg — so the most common queries are already hot when they arrive. The user sees a sub-second response; the work happens in the background.

Frontend React · Vite · static, served by the Pi
API FastAPI · uvicorn behind nginx
Cache Redis on the Pi's SD card · TTL'd fare snapshots
Edge Cloudflare Tunnel · TLS · DDoS shielding
Ops systemd · GitHub Actions deploys