
Self-host Reitti on Netcup — your own Google Timeline on a 10 € VPS
TL;DR: Running Reitti on Netcup in 5 minutes
Self-host Reitti on a Netcup VPS to keep a decade of GPS traces out of Google's Timeline and off whatever Apple decides to call the feature next quarter. Reitti is a self-hosted Google Timeline alternative that ingests location data from OwnTracks, GPSLogger, Overland, Home Assistant, or plain GPX and Google Takeout exports, then renders the result as an interactive timeline of visits and trips on a map you own.
- What it is: a Java/Spring Boot application backed by PostGIS, with a built-in tile cache and Redis-driven background processing.
- Competes with: Google Timeline, Apple's Location History, Dawarich, OwnTracks Recorder.
- Hosting profile: modest. Reitti default ships with four containers and runs comfortably in 4 GB RAM for a single household.
- Mobile path: install OwnTracks, GPSLogger, or Overland and point them at the API — no first-party app needed.
- License: MIT. The 4.x line is current; releases land on Docker Hub on a fast cadence.
Install on a fresh Debian 12 box once Docker is in place:
mkdir -p /opt/reitti && cd /opt/reitti
wget https://raw.githubusercontent.com/dedicatedcode/reitti/refs/heads/main/docker-compose.yml
docker compose up -d
Primary pick: VPS 1000 G12 — 4 vCore, 8 GB DDR5 ECC, 256 GB NVMe, around €10.37/month. Plenty of headroom for the JVM, PostGIS, and a year of family GPS traces, with room for the inevitable second self-hosted service that creeps onto the same box.
- First month free:
5799nc17800061380 - Second code:
5799nc17804382700 - Third code:
5799nc17800061382
Introduction
Google quietly retired the cloud-side of Timeline in 2024 and pushed the data on-device, which sounds privacy-friendly until the first phone reset wipes ten years of "where did we eat in Lisbon" out of existence. Apple never had a real timeline view in the first place. The actually-useful thing — a map you can scrub through, with visits clustered into places and trips between them — has always been a bolt-on, and it disappears when the platform decides it should.
Reitti is the self-hosted version of that bolt-on. It does not record your phone in the background; it ingests data from clients that already do, and turns the firehose into a timeline. Plug in OwnTracks, GPSLogger, Overland, or Home Assistant on the mobile side. Drop in a Google Takeout export to backfill the past. Reitti detects visits, identifies trips, recognises significant places, and lets you browse the result by day or by map region.
A Netcup VPS is the quiet boring place where this kind of service belongs. EU jurisdiction, NVMe everywhere, ECC DDR5 on the G12 line, and prices that have not been redirected through three layers of hyperscaler reseller. Reitti's footprint is small enough to share a box with two or three other personal services without anything noticing.
By the end of this article: a working Reitti instance behind HTTPS, mobile clients pushing live location data into it, a one-shot Google Takeout import to seed the history, and a clear answer for which Netcup tier you actually need.
What is Reitti?
Reitti is a self-hosted personal location tracking and analysis platform. It takes raw GPS points from one or more sources, clusters them into stays at significant places, fills in the trips between those places (with rough transport-mode detection — walking, cycling, driving), and exposes the result through a web UI built around an interactive map and timeline. The name is Finnish for "route" or "path".
Architecture
The default Docker Compose stack is four services:
reitti— the Spring Boot Java application, listening on port 8080. This is the API and the web UI in one process. Background jobs (visit detection, trip building, geocoding lookups) run inside this container too.postgis— PostgreSQL 17 with PostGIS 3.5 spatial extensions. All location points, places, trips, users, and API tokens live here. The spatial index is what makes "everywhere I have been within 500 m of this point" cheap.redis— Redis 7. Used as a job queue and cache for asynchronous processing — reverse-geocoding requests, batch imports, scheduled tasks.tile-cache— a small nginx-based caching proxy for OpenStreetMap tiles, so the upstream tile servers are not hammered every time the map pans. Reitti's web UI talks to this directly.
There is no message broker beyond Redis in the current 4.x line, no separate ML container, no per-tenant Postgres. Reitti is unfussy by design.
Reverse geocoding — the one architectural choice that matters
Reitti needs to translate raw lat/lon into something readable like "Café Hawelka, Vienna". It supports three setups: Photon only (run a local Photon container alongside the app and disable everything else), hybrid (Photon as primary, fall back to public Nominatim or other providers), or external only (drop Photon entirely and configure one or more remote geocoders under Settings → Geocoding).
Self-hosting Photon for the full planet is heavy — Komoot's published guidance is roughly 70–160 GB of disk for the worldwide index and 64 GB RAM for comfortable operation. That is not a personal-VPS workload. The realistic path on Netcup is the external-only mode: use a public Nominatim endpoint, or stand up a regional Photon on a separate box. The default docker-compose.yml does not include Photon, which lines up with that recommendation.
How big does the data get
A phone reporting via OwnTracks at default cadence produces a few hundred to a few thousand points per day. PostGIS compresses these down efficiently — a single user with five years of dense history is a low-single-digit-GB database, not a hundred. The tile cache fills slowly with whatever map regions you actually browse; it does not pre-render the planet. Disk pressure on a personal Reitti install comes from imports (Google Takeout JSON for ten years lands around 200 MB to 1 GB, then is parsed into rows) more than from steady-state usage.
The license is MIT, which means there is no AGPL-style obligation to publish modifications, and forks are unrestricted. Maintained by dedicatedcode on GitHub.
How to use Reitti
Day-to-day, Reitti is a passive piece of infrastructure. The phone app pushes points; the timeline accumulates. The interesting work happens in the first week of setup.
Core concepts
- User: an account on the instance. Multi-user is supported and each user's data is isolated; admins can create more accounts under settings. The first user is
admin:admin— change that in the first sixty seconds. - API token: a per-user secret used by mobile clients to authenticate. Generate one under Settings → API Tokens. Each device gets its own token so you can revoke a lost phone without invalidating the rest.
- Visit: a cluster of GPS points the engine has decided represents a stay at one place. Reitti groups them automatically based on dwell time and spatial radius.
- Trip: the path between two visits, with a coarse transport mode (walk, bike, drive) inferred from speed and the shape of the trace.
- Significant place: a place visited often enough that the engine names it — home, the office, the gym. You can rename them and merge duplicates from the UI.
- Geocoding service: an external endpoint Reitti queries to put human-readable labels on coordinates. Configure under Settings → Geocoding; multiple services can be stacked with automatic failover.
Day-to-day workflow
After import, the timeline view is the home page. Pick a date, see the day's visits and trips on a map plus a vertical strip of stays with durations. The live mode auto-refreshes incoming data — combined with fullscreen mode, it doubles as a slightly self-indulgent kiosk display of "where is everyone right now".
Multi-user view layers your housemates' tracks on the same map, which is useful for "who walked the dog last" and dangerous for marriages. Reitti also integrates with Immich: if you run an Immich photo server and connect it, photos taken at a place show up next to the relevant visit on the timeline.
Mobile clients and integrations
There is no first-party Reitti app — by design. The supported integrations are:
- OwnTracks (iOS + Android) — privacy-focused, battery-efficient, talks to Reitti via its HTTP recorder protocol.
- GPSLogger (Android) — lightweight, configurable, talks to Reitti's REST API via custom URL.
- Overland (iOS) — minimal background tracker, REST-API based.
- Home Assistant — push device tracker state into Reitti as another data source.
- Custom uploaders — the REST API is documented and used by
immich-go-style tools for bulk ingestion.
Pick whichever already runs on your phone. Going through the mobile-app integration guide for the chosen client is the only fiddly part of the setup.
Backup and operational reality
What matters for restore:
- The PostGIS database. This is everything — points, visits, trips, places, users, tokens. Use
pg_dumpagainst the postgis container; do not snapshot the data directory of a running PostgreSQL. - The
reitti-datavolume. Holds persistent application state outside the database (uploaded files, internal caches that you do not want to rebuild from scratch). - The
docker-compose.ymland any.envoverrides. Trivial to replace, annoying to forget.
The tile-cache-data and redis-data volumes are reproducible — you can lose them and Reitti will rebuild them silently. Skip them in the backup script and the daily archive stays small.
Quick Start Guide
Six steps from a fresh Netcup VPS to a working Reitti instance with HTTPS, automatic restart, and a mobile client wired up.
1. Provision the box
Sign up for the VPS 1000 G12 at netcup.com using coupon 5799nc17718015261 for one free month. Pick Debian 12 as the image, paste in your SSH public key, and skip the password option entirely. Once the VPS is up, SSH in and harden the basics:
# /etc/ssh/sshd_config.d/00-hardening.conf
PasswordAuthentication no
PermitRootLogin prohibit-password
KbdInteractiveAuthentication no
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Reboot, reconnect, and confirm sshd came back cleanly before closing the previous session.
2. Install Docker
Reitti is shipped as a Docker Compose bundle. There is a Maven build path for developers, but the deployment story everyone uses is the published dedicatedcode/reitti:latest image.
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker compose version
docker compose version should print v2.20 or newer. The official compose uses health-check depends_on conditions that older versions do not parse.
3. Install Reitti
Pull the upstream compose file and start the stack:
mkdir -p /opt/reitti && cd /opt/reitti
wget https://raw.githubusercontent.com/dedicatedcode/reitti/refs/heads/main/docker-compose.yml
The default file uses reitti:reitti as the Postgres credentials. Override that before the first start by writing an .env next to the compose file:
# /opt/reitti/.env
POSTGIS_USER=reitti
POSTGIS_PASSWORD=<openssl rand -hex 24>
POSTGIS_DB=reittidb
TZ=Europe/Berlin
Wire the env into the compose by adding env_file: .env to both the reitti and postgis services, or replace the inline POSTGIS_PASSWORD: reitti lines with POSTGIS_PASSWORD: ${POSTGIS_PASSWORD}. Then bring it up:
docker compose up -d
docker compose ps
After about a minute all four containers (reitti, postgis, redis, tile-cache) should be healthy. The web UI is now answering on http://<server-ip>:8080. Do not leave it on a public IP at port 8080 — front it with HTTPS first.
4. Put Caddy in front
Caddy fetches a Let's Encrypt cert on first contact and renews it without a cron job. One file, one daemon, no expiry surprises.
apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -fsSL 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable.gpg
echo "deb [signed-by=/usr/share/keyrings/caddy-stable.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main" > /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install -y caddy
Replace /etc/caddy/Caddyfile:
reitti.example.com {
reverse_proxy localhost:8080
}
systemctl reload caddy. Within thirty seconds https://reitti.example.com answers with the Reitti login page.
5. First-run hardening
Open the URL, log in with admin:admin, and change both the username display and the password under the user menu. Then do these in order, all under Settings:
- Generate an API token for each mobile device under Settings → API Tokens. Copy the token straight into the OwnTracks / GPSLogger / Overland config — you cannot retrieve it later.
- Configure geocoding under Settings → Geocoding. The cheapest path is one external Nominatim endpoint with a sensible rate limit; leave Photon disabled unless you have a separate large box for it.
- Set
ADVERTISE_URIin the env to the public HTTPS URL if you plan to use multi-instance federation later. Optional now, awkward to change later if links have already been shared.
For the mobile side, point your chosen client at the public URL with the API token. The Reitti docs cover the per-app config — OwnTracks needs the HTTP recorder URL set; GPSLogger needs a custom URL action with the right field mapping; Overland just needs the URL and a token.
6. Backups and restart
The compose file already sets restart: unless-stopped on the tile cache; add restart: unless-stopped to the other three services so a reboot brings the stack back without intervention. Then drop a daily PostGIS dump:
# /etc/cron.daily/reitti-db-backup
#!/bin/sh
set -e
mkdir -p /srv/reitti/backups
docker compose -f /opt/reitti/docker-compose.yml exec -T postgis \
pg_dump -U reitti reittidb | gzip > /srv/reitti/backups/db-$(date +\%F).sql.gz
find /srv/reitti/backups -name 'db-*.sql.gz' -mtime +14 -delete
chmod +x /etc/cron.daily/reitti-db-backup and you have a 14-day rolling local backup. Add a restic job to push the daily archive plus the reitti-data named volume off-site and the disaster-recovery story is done.
For the historical-import path: download Google Takeout (Maps → Timeline), zip it up locally, then upload via Settings → Import Data → Google Takeout. A decade of dense history takes a few minutes to ingest on the VPS 1000 G12; the visits-and-trips pipeline runs after the raw import finishes.
Choosing the Right Netcup Server for cheap Reitti hosting
Reitti's resource curve is gentler than most self-hosted apps in this category. The Java process is the heaviest tenant and is happy with a 1–2 GB heap; PostGIS for personal-scale data wants a few hundred MB; Redis is a rounding error. The decision below is mostly about how much GPS history you plan to keep, whether the box is shared with other services, and whether you ever want to flirt with a self-hosted Photon.
VPS 500 G12 — the absolute minimum if Reitti is the only thing on the box
Specs: 2 vCore, 4 GB DDR5 ECC, 128 GB NVMe, traffic included. Around €5.91/month (verify on netcup.com).
4 GB is enough for a single-user Reitti install with the default four-container stack, an external geocoder, and nothing else running. The 128 GB NVMe is overkill for the database itself but tight if you ever intend to keep large Google Takeout archives, photo backups via Immich integration, or other services on the same host.
Good fit if: one user, no Photon, the box exists solely for Reitti, and you are willing to migrate to a larger tier in a year if the data grows. There is no dedicated VPS 500 coupon — the €5-off-any-order code applies to this tier.
Coupons (the €5-off-any-order code applies here):
36nc1771801554036nc1771801554536nc17718015549
VPS 1000 G12 — recommended for most Reitti deployments
Specs: 4 vCore, 8 GB DDR5 ECC, 256 GB NVMe, traffic included. Around €10.37/month (verify on netcup.com).
This is the tier the article was written around. 8 GB RAM gives the JVM room to breathe under import bursts, leaves space for PostGIS to keep its working set in memory, and absorbs the second or third self-hosted service you will inevitably co-locate. 256 GB NVMe is enough for the database, the tile cache, and a meaningful chunk of complementary data on the same box.
Good fit if: a household instance with two to five users, or a single user who plans to run Reitti alongside Vaultwarden, Forgejo, or a small Immich.
Coupons:
5799nc178000613815799nc177746185505799nc17800061380
VPS 2000 G12 — when Reitti shares the box with heavier neighbours
Specs: 8 vCore, 16 GB DDR5 ECC, 512 GB NVMe, traffic included. Around €19.25/month (verify on netcup.com).
Step up to this tier when Reitti is one of several services and one of the others has real appetite — Immich with smart-search enabled, a Mastodon single-user instance, a Forgejo with CI runners, or a Postgres-backed Mealie. 16 GB RAM keeps every JVM and Postgres process resident at the same time without page-cache thrashing during simultaneous load. The extra vCores also matter for parallel Google Takeout imports that span multiple users.
Coupons:
5800nc178026540915800nc177180152325800nc17718015233
RS 1000 G12 — when sustained CPU under load actually matters
Specs: 4 dedicated AMD EPYC 9645 cores, 8 GB DDR5 ECC, 256 GB NVMe. Around €12.79/month (verify on netcup.com).
Same RAM and disk as the VPS 1000 G12, but the cores are dedicated rather than oversubscribed. For typical Reitti use this is overkill — the JVM is rarely CPU-bound. The case for the Root Server is consistent latency under contention: a kiosk-mode live view that updates every few seconds while the household is also pushing simultaneous OwnTracks updates, or a multi-user instance where someone is always running an import. The dedicated EPYC 9645 cores stop the burstable VPS scheduler from being the variable in your tail latency.
Coupons (Root Server codes give two free months):
5159nc177180154445159nc177180154405997nc17800061380
Comparison
| Offer | vCPU | RAM | NVMe | Approx. price |
|---|---|---|---|---|
| VPS 500 G12 | 2 | 4 GB | 128 GB | €5.91/mo |
| VPS 1000 G12 | 4 | 8 GB | 256 GB | €10.37/mo |
| VPS 2000 G12 | 8 | 16 GB | 512 GB | €19.25/mo |
| RS 1000 G12 | 4 dedicated | 8 GB | 256 GB | €12.79/mo |
If you are trying Reitti for the first time, on your own data, with no other workloads on the box, take VPS 500 G12 and accept that you may upgrade in a year. If you are running it for a household or planning to keep it long-term alongside other personal services, take VPS 1000 G12 — it is the answer for most readers. If Reitti is one of several Postgres-backed services on the same machine, take VPS 2000 G12 and stop worrying about contention. If you specifically care about latency stability under bursty load, the dedicated cores of RS 1000 G12 are worth the extra three euros.
A note on the heavy path: if you genuinely want a self-hosted Photon geocoder for the entire planet, neither the VPS line nor the small Root Servers are enough — Photon's worldwide index wants 64 GB RAM and around 160 GB of disk for the index alone. That is RS 8000 G12 territory at minimum, and the right call there is usually to put Photon on its own dedicated box and let your Reitti install continue to live cheaply. Web hosting is not in scope for Reitti at all — it needs a Java daemon, a PostGIS server, and Redis, none of which run on shared PHP hosting.
Conclusion
A working Reitti instance on a Netcup VPS 1000 G12 lands at roughly €10.37/month after the first free month from 5799nc17804382700, with 256 GB of NVMe headroom and 8 GB of RAM that will outlast the patience of whichever family member declared they wanted to "see all our trips on a map". Drop in OwnTracks or GPSLogger on the phone side, point a Caddy reverse proxy at port 8080, and the timeline starts filling itself the moment the first GPS point arrives.
If you want a few euros off the first invoice on any product — including a second box for that Photon experiment — the €5-off-any-order coupon 36nc17718015548 stacks separately from the VPS-specific code at checkout.
Things to keep an eye on once it is up: the daily PostGIS dump's file size (a sudden jump usually means a new bulk import is still re-processing into visits and trips), the geocoding-service rate limits (public Nominatim has tight quotas that Reitti's batch processor can blow through during a Takeout import), and the 4.x release notes — Reitti ships often, schema migrations happen, and the upgrade flow is "stop, pull, up" not "in-place hot reload". Read the changelog before each compose pull and the boring stuff stays boring.
The route history is yours, the bytes are yours, and the bill is one fixed line item per month. That is the whole point.