- JavaScript 61.9%
- CSS 28.2%
- HTML 9.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| deploy | ||
| public | ||
| src | ||
| .gitignore | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| server.js | ||
City Map (2GIS-style)
A self-hosted web map with a 2GIS-like layout: search bar, category browsing (cafes, pharmacies, ATMs, etc.), a results list, and a clean map view. Built with Node.js + Express on the backend and vanilla JS + Leaflet on the frontend — no build step, so it runs on a plain Ubuntu server with nothing but Node installed.
Included, per your notes:
- Geolocation prompt – a custom "Turn on your location" modal appears on first visit, explaining why, before the real browser permission dialog fires. There's also a locate button on the map for later. Dismissal is remembered per-browser so it won't nag every visit.
- Visit logging – every page load and API call is logged with
timestamp, IP, method, path, user agent, and referer to
logs/visits.log(one JSON object per line).
How it works
- Map tiles come from OpenStreetMap (free, no API key).
- The search box proxies to the free Nominatim geocoding API.
- Category chips (cafes, pharmacies, ATMs...) proxy to the free Overpass API, queried live for whatever's inside the current map view.
- Your Express server sits between the browser and these APIs, so you can swap either one for a paid provider later without touching the frontend.
Requirements
Ubuntu with Node.js 18 or newer:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
node -v # should print v18+
Setup
unzip 2gis-style-map.zip
cd 2gis-style-map
npm install
npm start # -> http://your-server-ip:3000
For local development with auto-restart on file changes:
npm run dev
Configuration
public/js/config.js– default map center/zoom and the category chip list. Center defaults to Moscow; changeDEFAULT_CENTERto your city's[lat, lon].src/routes/search.js– update theUser-Agentcontact email. Nominatim's usage policy requires a real identifier and can block requests that don't have one.
Logs
Each line in logs/visits.log looks like:
{"time":"2026-09-08T12:00:00.000Z","ip":"203.0.113.4","method":"GET","path":"/","userAgent":"Mozilla/5.0 ...","referer":null}
The folder is created automatically on first run. Static assets
(css/js/images) aren't logged — only page loads and API calls — so the
file stays readable. Watch it live with tail -f logs/visits.log.
One heads-up: IP addresses count as personal data under GDPR, which
matters if you're serving EU visitors. If this goes live, it's worth a
line in a privacy policy plus rotating/deleting old logs rather than
keeping them forever — deploy/logrotate.example is a ready-made config
for that.
Running it in production on Ubuntu
See the deploy/ folder:
mapapp.service– a systemd unit so the app survives reboots and restarts itself if it crashes.nginx.conf.example– reverse proxy config so you can put a domain and HTTPS (viacertbot --nginx) in front of port 3000.logrotate.example– keeps the visit log from growing forever.
Scaling beyond the free APIs
Nominatim and Overpass's public instances are rate-limited — fine for low
or moderate traffic, a demo, or an internal tool, but not for heavy
production use. If this gets real traffic, the options are to self-host
Nominatim/Overpass or switch to a paid provider (MapTiler, LocationIQ,
Mapbox). Either way, you'd only need to change the two files under
src/routes/.
Where to take it next
- Swap
logs/visits.logfor a small SQLite/Postgres table if you want to query or filter visits later. - Add a "favorites" or "recently viewed" list using the same localStorage pattern as the geolocation prompt.
- Add routing/directions — OSRM has a free public API with the same rate-limit caveats as Nominatim/Overpass.