Mapforge is an open source web application that lets you create and share your places, tracks and events as GeoJSON layers on top of different base maps. It uses MapLibre GL JS as its map library and supports both desktop and mobile.
The browser connects to the server via WebSockets, so that changes are immediately synced to all clients. This enables collaborative editing and sharing real-time maps.
The main instance is running at mapforge.org, see self-hosting how to run your own. Check the changelog for recent changes.
- Create maps with your own data on top of various available base maps.
- Draw shapes and style them: Add pictures, customize colors, symbols, labels, (3D) polygons and more
- Import your data from GeoJSON, GPX and KML
- Collaborative, real-time editing, synchronized via WebSockets
- Share maps and embed on your own web page
- Desktop and mobile UI
- User login with Google or Github account
- Integration with Overpass API for custom OpenStreetMap queries
- PWA support and available as Android app
- Record your track with the µlogger API
GeoJSON layers can be styled using an extended version of the
GeoJSON /
Mapbox simplestyle spec.
See docs/tutorials/geojson_style_spec.md for supported attributes.
Overpass API layers can be added to a map, allowing custom queries and display of OpenStreetMap data.
See docs/tutorials/overpass_layers.md for details.
Mapforge is built as a Progressive Web App (PWA), see docs/tutorials/app.md.
An Android app that wraps the PWA is available in the Play Store:
Mapforge Android App
The latest image is available from ghcr.io/mapforge-org/mapforge:main.
You can also build your own image locally from the repository with: podman build -t mapforge .
Before running the application container, make sure MongoDB and Redis are running. For example with Podman:
podman run -d --name mongo \
-v <local_dir>:/data/db \
-p 27017:27017 \
mongo:7.0
podman run -d --name redis \
-p 6379:6379 \
redisA minimal example using the GitHub Container Registry image:
podman run \
-e SECRET_KEY_BASE=e3c9f2... \
-e DEVELOPER_LOGIN_ENABLED=true \
-e HTTP_PORT=3001 \
-e SSL=false \
--network=host \
ghcr.io/mapforge-org/mapforge:mainTo enable geolocation-based centering of maps, mount the MaxMind GeoLite2 database:
podman run ... -v /path/on/host/GeoLite2-City.mmdb:/rails/db/GeoLite2-City.mmdb ...SECRET_KEY_BASE— Rails secret key (must be set in production)DEVELOPER_LOGIN_ENABLED— optional local developer login (only enable this in test instances)HTTP_PORT— HTTP port inside the container (default: 3000)SSL— set totrueif your container is running behind a TLS terminating reverse proxy (default: true)MONGO_URL— MongoDB connection string (default:localhost:27017)REDIS_URL— Redis URL for Action Cable (default:redis://localhost:6379/1)OPENROUTESERVICE_KEY— API key for routing features with openrouteservice.orgGITHUB_CLIENT_ID,GITHUB_CLIENT_SECRET— GitHub OAuth credentialsGOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET— Google OAuth credentialsDEFAULT_MAP— default base map identifier (default: versatilesColorful)
Mapforge is build with a Ruby on Rails backend and uses Maplibre and Stimulus on the frontend.
Example for openSUSE (Debian package names in parentheses):
zypper in proj-devel # (libproj-dev) for building rgeo-proj4
zypper in proj # (proj-bin) for running rgeo-proj4
zypper in imlib2 imlib2-devel # (libimlib2, libimlib2-dev) to resize screenshots
zypper in ImageMagick # (imagemagick) for dragonfly image processing
zypper in npm # for running eslint
bundleTo resolve users’ client IPs to coordinates for centering new maps, download the MaxMind GeoLite2 database and save it as:
db/GeoLite2-City.mmdb
bin/thrust rails serverIn development, environment variables (see above) can be set in .env.development.
The first user that logs in is automatically made admin.
Available base maps can be customized in:
app/javascript/maplibre/basemaps.js
-
Import a map from a Mapforge export:
bin/rake seed:mapforge_file['db/seeds/examples/fosdem.json'] -
Import a map from GeoJSON (samples in
db/seeds):bin/rake seed:geojson_file['db/seeds/examples/germany_areas.geojson']More GeoJSON example files: exploratory.io
-
Take screenshots of updated maps for preview:
MAPFORGE_HOST=<host> bin/rake maps:screenshots
-
Animate a marker along a line:
bin/rake animation:path[<map_id>,<line_id>,<point_id>]
Linters:
bin/rubocop
npm install
npm run lint:css
npm run lint:jsFix JavaScript style with ESLint:
npm run fix:jsRun the test suite:
bundle exec rspecGitHub Actions workflows run these checks automatically. You can run them locally with act, for example:
act -j testTo build the Android app yourself using Bubblewrap:
npm install -g @bubblewrap/cli
# init is only needed on the first run
bubblewrap init --manifest=http://localhost:3000/manifest.json
bubblewrap buildTo establish trust between the app and the website, host a file
.well-known/assetlinks.json containing the SHA256 fingerprint of the app signing key.
-
Get the fingerprint of the local key:
keytool -list -v -keystore android.keystore
-
Get the fingerprint of the production key in the Play Console:
Setup → App Integrity → App Signing → Settings
Then add the fingerprint(s) to assetlinks.json using the
Digital Asset Links generator or:
bubblewrap fingerprint add