| backend | ||
| docs | ||
| mobile | ||
| .gitignore | ||
| README.md | ||
Privacy Maps
A privacy-first Google Maps alternative. No tracking, no accounts, no third-party API calls. All services are self-hosted.
Stack: Flutter (mobile) · Rust/Actix-web (backend) · PostgreSQL/PostGIS · Martin (tiles) · Photon (geocoding) · OSRM (routing)
Project Structure
maps/
├── docs/ # Specs, architecture, API contracts, data model
├── backend/ # Rust API gateway + Docker Compose for all services
│ ├── scripts/ # Data import scripts
│ └── initdb/ # PostgreSQL init SQL (runs on first startup)
└── mobile/ # Flutter app
Backend Setup
Requirements
- Docker or Podman + Compose
- ~50 GB free disk (for OSM data, OSRM graphs, Photon index)
- ARM64 (Raspberry Pi) or amd64 host
1. First-time setup
cd backend
# Build the custom images (PostGIS arm64 + importer toolchain)
podman compose build
# Start PostgreSQL first — extensions are enabled automatically on first start
podman compose up -d postgres
# Wait until ready
podman compose exec postgres pg_isready -U maps
2. Import data (first time)
Run each script individually rather than update_all.sh on first setup — the download takes ~6 minutes and you only need it once.
# Step 1: Download OSM PBF extract (~1.2 GB for Netherlands, ~6 min)
podman compose run --rm importer /app/scripts/01_download.sh
# Step 2: Import tile data into PostGIS (~10-20 min)
podman compose run --rm importer /app/scripts/02_import_tiles.sh
# Step 3: Import POI data into PostGIS
podman compose run --rm importer /app/scripts/03_import_pois.sh
# Step 4: Download Photon geocoding index (~2.3 GB for Netherlands)
podman compose run --rm importer /app/scripts/04_import_geocoding.sh
# Step 5: Preprocess OSRM routing graphs — run on the HOST, not in the container
# Builds a local ARM64 OSRM image on first run (~30-60 min), then preprocesses
# car/foot/bicycle profiles. Subsequent runs skip the image build.
bash backend/scripts/05_import_routing_host.sh ~/dev/maps/data
# Step 6: Register offline regions in the database
podman compose run --rm importer /app/scripts/06_build_offline_packages.sh
To change the country for step 4, use the full country name:
PHOTON_COUNTRY=germany podman compose run --rm importer /app/scripts/04_import_geocoding.sh
3. Start all services
podman compose up -d --scale importer=0
After startup, restart the services that depend on the imported data:
podman compose restart martin
podman compose restart osrm-driving osrm-walking osrm-cycling
4. Weekly data refresh
Use update_all.sh for scheduled updates. It re-downloads the PBF only if the file has changed on the server (wget -N), then reimports everything. Note: OSRM preprocessing is not included — run it separately on the host if routing data has changed.
podman compose run --rm importer /app/scripts/update_all.sh
# If routing data changed, also run on the host:
bash backend/scripts/05_import_routing_host.sh ~/dev/maps/data
podman compose restart osrm-driving osrm-walking osrm-cycling
To refresh only specific data (e.g. tiles changed but routing didn't):
podman compose run --rm importer /app/scripts/01_download.sh
podman compose run --rm importer /app/scripts/02_import_tiles.sh
podman compose restart martin
Service ports
| Service | Port | Description |
|---|---|---|
| backend | 8080 | Rust API gateway |
| postgres | 5432 | PostGIS database |
| redis | 6379 | Tile/route cache |
| martin | 3001 | Vector tile server |
| photon | 2322 | Geocoding (search) |
| osrm-driving | 5000 | Car routing |
| osrm-walking | 5001 | Walking routing |
| osrm-cycling | 5002 | Cycling routing |
Mobile App Setup
cd mobile
flutter pub get
dart run build_runner build --delete-conflicting-outputs
flutter run
On first launch, go to Settings and enter your backend URL (e.g. http://your-pi-ip:8080).
Troubleshooting
PostGIS extension error — The postgres container must be recreated to pick up the init scripts:
podman compose down postgres
podman compose up -d postgres
Podman short-name error — All images use full docker.io/ registry paths. If you see this on another service, prefix its image with docker.io/.
Exec format error on Pi — The postgres image is built locally from postgis.Dockerfile using arm64v8/postgres as base. Run podman compose build postgres to rebuild it.
OSRM exec format error — osrm/osrm-backend is amd64-only. The project uses osrm-arm64.Dockerfile to build a native ARM64 image. Run podman compose build osrm-driving (builds once, shared by all three OSRM services) or let 05_import_routing_host.sh build it automatically.
Attribution
- Map data © OpenStreetMap contributors (ODbL)
- Routing: OSRM (BSD-2)
- Geocoding: Photon (Apache 2.0)
- Tile server: Martin (MIT/Apache 2.0)