A local-first, self-hostable maps stack. Built on OpenStreetMap data and FOSS components, designed to run on hardware you control with zero outbound API calls at runtime.
Atlas is the maps engine that powers Dawarich, packaged so it stands on its own — install it on your own box, plug your own clients into the API.
Map search loads matches across the installed Photon dataset and groups them into numbered clusters. Zoom or click a cluster to explore; Show all fits the full result set. See search behavior and limits.
| Search | Routing |
|---|---|
![]() |
![]() |
| POIs | Settings |
![]() |
![]() |
git clone https://github.com/dawarich-app/atlas.git
cd atlas
docker compose up -dThat's it — no .env file required. The app auto-generates a SECRET_KEY_BASE on first boot (persisted to data/app/.secret_key_base) and stores its data in a local SQLite file under data/app/.
Two knobs you may need:
DOCKER_GID — the in-app control plane talks to the host docker socket as
the nobody user via this supplementary group (default 999). If the Settings
panel shows a "Control plane degraded" banner, set it to the socket's group and
recreate the container:
# Linux
echo "DOCKER_GID=$(stat -c %g /var/run/docker.sock)" >> .env
# macOS (OrbStack / Docker Desktop) — the socket maps as gid 0
echo "DOCKER_GID=0" >> .env
docker compose up -d appPUID / PGID — the uid:gid Atlas runs as, and the owner it gives its own
data directories on boot: ./data/app plus the region dirs ./data/{osm,gtfs,otp,tiles}
(default 65534:65534, i.e. nobody). Other services under ./data keep their
own ownership — whosonfirst, for instance, runs as ${UID:-1001}.
On a NAS the appdata share usually belongs to someone else — Unraid uses
99:100, Synology and QNAP differ — and Atlas will refuse to start with a
message naming the directories rather than looping on "Permission denied". Set
them to the share's owner:
stat -c '%u %g' ./data/app # whoever owns it on the host
printf 'PUID=99\nPGID=100\n' >> .env
docker compose up -d appVisit http://localhost:8484. The map page is live as soon as Caddy and Atlas come up. Open the Settings tab in the side panel to toggle Search / Routing / POIs / Transit and pick the active region. Save & apply — the app downloads the region data, merges it with osmium, and restarts the ingest services, with live progress in the panel.
To pin a specific region preset up front (instead of picking in the UI), copy one into .env before booting:
cp regions/berlin.env .env
docker compose up -dSee .env.example for the optional overrides (custom SECRET_KEY_BASE, external Postgres via DATABASE_URL, admin credentials, basemap URL).
City scale boots in minutes; country takes hours of background ingest; planet takes days.
Every operational topic has a dedicated page on the website. The README is intentionally thin — anything that's not in the table below lives there.
| Topic | Where to read |
|---|---|
| What it is, capability list, response envelope | Introduction |
| Clone → boot → data layers, admin panel auth, offline basemap | Quickstart |
| First-run features, data selection and installation progress | Setup wizard |
| Search areas, category filters, clusters and completeness | Search and places |
| Endpoints, journey times and transport details | Directions |
| MOTIS / OTP selection and GTFS / GTFS-RT sources | Transit engines · Transport data |
| Version upgrades, backups and rollback | Upgrading |
| Design principles, tech stack, topology, Go sidecar, Nominatim decision | Architecture |
| Region presets, multi-region auto-merge, scaling tables (Germany / France / USA / planet) | Regions |
| Compose profiles, graceful degradation, ports | Compose profiles |
| Full OpenAPI spec (Redoc-rendered) | Public API · Admin API |
Docs source: dawarich-app/atlas-website.
The app is the Phoenix application in app-phoenix/. It serves
the map UI, admin Settings, the public + admin JSON APIs, and the control plane
(the former Go atlas-control sidecar is absorbed into it — Phoenix execs
docker compose against the host daemon directly). CI runs on GitHub Actions
(.github/workflows/):
| Job | Trigger | Output |
|---|---|---|
test-phoenix |
push / PR touching app-phoenix/** |
mix test --include parity (incl. byte-diff parity gate against the Rails goldens) + credo |
test-config |
push / PR touching deployment files or bootstrap scripts | Deployment, Placeholder bootstrap and release-note checks |
build-app |
published release or manual dispatch on its tag, after tests pass | ghcr.io/dawarich-app/atlas/app:0.6.1, :0.6, :latest, :sha-<sha> (amd64+arm64) |
test-rails |
push / PR touching app/** |
RSpec — the legacy Rails app (app/) is retained only as the parity reference for the golden capture; it is no longer built or shipped |
Compose defaults consume the app tag directly — docker compose up -d against a fresh checkout pulls from GHCR with no auth.
latest tracks stable releases. A push to main alone does not publish a GHCR
image. A dated version at the top of CHANGELOG.md triggers the release workflow;
it verifies the version against mix.exs and runs Phoenix and deployment tests
before tagging. An Unreleased section does not publish anything.
See upgrading and rolling back before moving an existing installation to 0.6.1. Update the checkout as well as the image: Compose and the Placeholder startup script are part of the release.
Override the image when iterating locally:
APP_IMAGE=atlas-app:dev docker compose build app
APP_IMAGE=atlas-app:dev APP_PULL_POLICY=never docker compose up -d- Phoenix app (the shipped app):
app-phoenix/README.md - Legacy Rails app (parity reference only):
app/README.md
End-user documentation source lives in the separate atlas-website repo — open PRs against the docs there.
Dawarich Atlas is licensed under the GNU Affero General Public License v3.0 (LICENSE) — the same license as Dawarich. Anyone running Atlas as a service must publish their modifications under the same license.
Upstream components retain their own licenses: OSM data is ODbL; Protomaps and MapLibre are BSD-3; Valhalla is MIT; Photon, Overpass and OpenTripPlanner are LGPL-3.0 or AGPL-3.0; Rails is MIT.



