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.
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.
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.
What it does
-
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.
-
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.
-
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.
-
04
Coverage map
A separate view shows which stations the scanner currently knows about and how stale the cached fares are.
Fig. 02 Placeholder for a short screen recording of Bahnscanner — searching a route, switching to Everywhere mode, and watching the cheapest cities surface.
Hosted on a Pi
The whole site — frontend, API, scheduler, fare cache — runs on a single Raspberry Pi 5 sitting on my desk.
Around 2,500 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 NVMe SSD without burning through write cycles.
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. Everything is containerised with Docker Compose so a fresh Pi can be brought up with one command.
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. Instead, the scanner runs scheduled batch jobs overnight, caches results with a short freshness window, and serves from cache for the interactive search. The user sees a sub-second response; the work happens off-peak.
What I'd do next
Bahnscanner answers where cheaply, but not how. I'd like to add multi-leg journeys, IC bus alternatives, and a weekly digest that quietly emails me the cheapest available weekends from my home station — the version of this tool that uses me rather than the other way around.