home.social

#utvonaltervezes — Public Fediverse posts

Live and recent posts from across the Fediverse tagged #utvonaltervezes, aggregated by home.social.

  1. Self-Hosted Google Maps egy Raspberry Pi-n

    Mindig is lenyűgözött az a gondolat, hogy a saját négy falunk között is fusson egy olyan térkép szolgáltatás, ami nem függ az internetkapcsolattól. Egy olyan „Google Maps”, ami a saját gépemen fut, a saját adataimat használja, és akkor is működik, ha épp nincs net. Az inspiration a N.O.M.A.D. (Network of Offline Mapping and Discovery) projektből jött, akik egy teljes offline szolgáltatás stack-et álmodtak meg. Az ő nyomdokaikon haladva építettem meg a saját verziómat, ami egy Raspberry Pi-n fut, Docker konténerekben, és teljes Magyarországot lefedi.

    A hardver – Mi ez a gép?

    A szolgáltatás a xorp-archive.xorp.hu nevű gépemen fut, ami nem egy átlagos Raspberry Pi. Egy Raspberry Pi ARM64 architektúrájú eszköz, 8 GB RAM-mal, NVMe HAT kiegészítővel és egy 1 TB-os Crucial CT1000E100SSD8 NVMe SSD-vel. Ez nem a régi SD kártyás megoldás – az NVMe sebessége és megbízhatósága nélkülözhetetlen egy ilyen adatigényes stack működtetéséhez. A gép Ubuntu 24.04 LTS-t futtat, a kernel pedig a Raspberry Pi-hez optimalizált 6.8.0-1057-raspi.

    1. ábra: A Raspberry Pi NVMe HAT-tal és SSD-vel. A képen a Raspberry Pi 5, a ráhelyezett M.2 HAT+ és az NVMe SSD látható.

    Az ötlet – Miért építsünk offline térképet?

    A válasz egyszerű: szabadság. Amikor nincs internet, vagy korlátozott a sávszélesség, a legtöbb térkép szolgáltatás használhatatlanná válik. Gondoljunk csak egy kirándulásra a Pilisbe, egy külföldi utazásra roaming nélkül, vagy épp egy olyan helyzetre, ahol az adatvédelem miatt nem szeretnénk külső szolgáltatókra bízni magunkat. Egy offline térkép ezekre mind megoldást nyújt.

    A stack négy fő komponensből áll, amelyek Docker konténerekben futnak:

    • OSM Tile Server – a térkép csempék (tile-ok) kiszolgálása
    • Photon – címkeresés, geokódolás
    • GraphHopper – útvonaltervezés (autó, bicikli, gyalogos)
    • GraphHopper PT – tömegközlekedési útvonaltervezés (MÁV, Volánbusz, BKK)
    • MapLibre GL UI – a webes felület, ami összefogja az egészet

    Az architektúra áttekintése

    Minden kérés egyetlen belépési ponton, a map-ui konténeren keresztül történik, ami egy Nginx reverse proxyként szolgál. Ez nemcsak egyszerűbbé teszi a konfigurációt, hanem kiküszöböli a CORS problémákat is, hiszen a böngésző számára minden kérés ugyanarról az origin-ről érkezik.

    Böngésző → port 8090
      └── Nginx (map-ui konténer)
           ├── /tile/{z}/{x}/{y}.png → OSM (8081)
           ├── /photon/api → Photon (2322)
           ├── /graphhopper/route → GraphHopper (8989)
           └── /graphhopper-pt/route → GraphHopper PT (8989)

    A Docker Compose – Minden együtt

    A teljes stack egyetlen docker-compose-osm-extended.yml fájlban van definiálva. Lássuk a lényeget (az IP címeket és elérési utakat természetesen megváltoztattam a valóságban):

    services:
      osm-import:
        image: overv/openstreetmap-tile-server
        container_name: osm-import
        command: import
        shm_size: 1gb
        environment:
          THREADS: 4
          UPDATES: enabled
        volumes:
          - /home/osm/data/hungary-latest.osm.pbf:/data/region.osm.pbf
          - /home/osm/data/hungary.poly:/data/region.poly
          - osm-db:/data/database
          - osm-tiles:/data/tiles
    
      osm:
        image: overv/openstreetmap-tile-server
        container_name: osm
        command: run
        shm_size: 1gb
        ports:
          - 8081:80
        environment:
          UPDATES: enabled
          THREADS: 4
          REPLICATION_URL: https://planet.openstreetmap.org/replication/minute/
        volumes:
          - osm-db:/data/database
          - osm-tiles:/data/tiles
    
      photon:
        image: local/photon:1.1.0
        container_name: photon
        command: ["-listen-ip", "0.0.0.0", "-cors-any"]
        ports:
          - 2322:2322
        volumes:
          - /home/osm/photon:/data/photon
    
      graphhopper:
        image: local/graphhopper:9.1
        container_name: graphhopper
        ports:
          - 8989:8989
        volumes:
          - /home/osm/graphhopper:/data
          - /home/osm/data/hungary-latest.osm.pbf:/data/region.osm.pbf
    
      graphhopper-pt:
        image: local/graphhopper:9.1
        container_name: graphhopper-pt
        ports:
          - 8991:8989
        volumes:
          - /home/osm/graphhopper-pt:/data
          - /home/osm/data/hungary-latest.osm.pbf:/data/region.osm.pbf
          - /home/osm/gtfs:/data/gtfs:ro
        entrypoint: ["java", "-Xmx6g", "-jar", "/app/graphhopper-web.jar", "server", "/app/config.yml"]
    
      map-ui:
        image: local/osm-ui:1.0
        container_name: map-ui
        ports:
          - 8090:80
        volumes:
          - /root/osm-ui:/usr/share/nginx/html:ro
          - /home/osm/map-ui/conf/default.conf:/etc/nginx/conf.d/default.conf:ro

    1. OpenStreetMap Tile Server – A térkép alapja

    Az overv/openstreetmap-tile-server Docker image egy előre összeállított környezet, ami tartalmazza az Apache webszervert, a renderd-et (a csempe renderelő démont), a PostgreSQL-t PostGIS kiegészítővel, és a mod_tile-t, ami a csempe kiszolgálásért felel. Ez a négy komponens együtt teszi lehetővé, hogy a nyers OpenStreetMap adatokból szép, böngészhető térképi csempéket (tile-okat) kapjunk.

    Az import folyamat

    Minden egy PBF fájllal kezdődik – ez a Protocol Buffer Binary Format, az OpenStreetMap adatok tömörített formátuma. Nekünk a Magyarországra vonatkozó kivonatra van szükségünk, ami a geofabrik.de-ról szerezhető be. Ez a fájl a /home/osm/data/hungary-latest.osm.pbf elérési úton található.

    Az import az osm-import konténer egyszeri futtatásával történik:

    # Első importálás (csak egyszer kell)
    docker compose -f docker-compose-osm-extended.yml run --rm osm-import
    
    # Ha frissíteni kell a PBF-et, töröljük a régi adatbázist és újraimportálunk
    docker compose -f docker-compose-osm-extended.yml down
    # ... új PBF letöltése ...
    docker compose -f docker-compose-osm-extended.yml run --rm osm-import
    docker compose -f docker-compose-osm-extended.yml up -d osm

    A konténer a shm_size: 1gb beállítással fut, mert az importálás és a renderelés során rengeteg megosztott memóriára van szükség a gyorsítótárazáshoz. Ez egy kritikus beállítás – ha kicsi a shared memory, a renderelés rendkívül lassú lesz.

    3. ábra: Az OSM tile server folyamatos frissítése – a docker compose logs kimenete mutatja az osm2pgsql importálást és a percenkénti diff letöltést.

    Folyamatos frissítés

    A legmenőbb funkció a beépített incrementális frissítés. Az UPDATES: enabled környezeti változó hatására a konténer percenként letölti a minute diff fájlokat a planet.openstreetmap.org-ról. Ez azt jelenti, hogy a térképünk gyakorlatilag valós időben frissül – ha valaki módosít egy utat az OSM-ben, az pár percen belül megjelenik a saját szerverünkön is. Természetesen ha nincs internet, a script egyszerűen csendben meghibásodik, és a konténer tovább szolgálja a már meglévő csempéket.

    2. Photon – Címkeresés geokódolással

    A Photon egy nyílt forráskódú geokódoló motor, ami az OpenStreetMap adatokra épül. A mi stackünkben a local/photon:1.1.0 image fut, ami egy Magyarországra szabott adatbázissal dolgozik. Ez nem a teljes világ – csak Magyarország, ami jelentősen csökkenti a keresési időt és a tárhely igényt.

    A Photon adatbázis frissítése egy /root/photon-import.sh script segítségével történik, ami hetente egyszer fut (vasárnap 11:30-kor a cron-ban).

    A script működése:

    1. Letölti a legújabb Magyarország Photon dump fájlt(zst tömörítésben) a graphhopper.com-ról
    2. Ellenőrzi a metaadatokat (ETag, last-modified) – ha nem változott, kihagyja a letöltést
    3. Leállítja a Photon konténert
    4. Egy ideiglenes Docker konténerben dekompresszálja és importálja az adatbázist
    5. Frissíti a szimbolikus linket az új import könyvtárra
    6. Újraindítja a Photon konténert
    7. Ellenőrzi a szolgáltatás állapotát egy egyszerű API hívással
    # A Photon import script lényege (egyszerűsítve):
    docker run --rm \
      --entrypoint sh \
      -v /home/osm/photon:/data/photon \
      -v /home/osm/photon-dumps:/data/dumps \
      local/photon:1.1.0 \
      -lc "zstd -d --stdout /data/dumps/photon-dump-hungary.jsonl.zst \
           | java -Xms2g -Xmx4g -jar /app/photon.jar import \
             -import-file - -data-dir /data/photon/imports/20260603200523"
    
    # A szimbolikus link frissítése:
    ln -sfn /home/osm/photon/imports/20260603200523 /home/osm/photon/photon_data

    Az importált adatbázisok verziózott könyvtárakba kerülnek (/home/osm/photon/imports/20260603200523/), így mindig vissza lehet térni egy régebbi verzióhoz, ha valami elromlana. Egy szimbolikus link (photon_data -> imports/20260603200523/) mutat az aktuális verzióra.

    4. ábra: Címkeresés a Photon segítségével – „Eger, Dobó tér” keresése és megjelenítése a térképen.

    3. GraphHopper – Útvonaltervezés (autó, bicikli, gyalogos)

    A GraphHopper egy nagy teljesítményű, nyílt forráskódú útvonaltervező motor, ami az OpenStreetMap úthálózatára épül. A mi stackünkben a local/graphhopper:9.1 image fut, 4 GB RAM allokációval.

    A GraphHopper három útvonal profilt támogat:

    • car – autós közlekedés, figyelembe veszi az egyirányú utcákat, sebességkorlátozásokat, út típusokat
    • bike – biciklis közlekedés, preferálja a kerékpárutakat, kerüli a főútvonalakat
    • foot – gyalogos közlekedés, használja a járdákat, gyalogutakat, lépcsőket

    A konfiguráció /home/osm/graphhopper/config.yml-ban található:

    graphhopper:
      datareader.file: /data/region.osm.pbf
      graph.location: /data/graph-cache
    
      profiles:
        - name: car
        - name: bike
        - name: foot
    
      profiles_ch:
        - profile: car
        - profile: bike
        - profile: foot
    
      graph.dataaccess.default_type: RAM_STORE
    
    server:
      application_connectors:
        - type: http
          port: 8989
          bind_host: 0.0.0.0

    A Contraction Hierarchies (CH) egy előfeldolgozási technika, ami drámaian felgyorsítja az útvonal keresést. Az autó és bicikli profilokhoz CH-t használunk, ami az első induláskor 5-10 perc előfeldolgozást igényel, de utána a lekérések ezredmásodpercek alatt teljesülnek.

    5. ábra: Autós útvonaltervezés a GraphHopper segítségével – Budapestről Debrecenbe (231,5 km, 2 óra 12 perc).

    4. GraphHopper PT – Tömegközlekedési útvonaltervezés

    Ez a stack talán legmenőbb komponense. A GraphHopper PT (Public Transport) egy speciális konfigurációja a GraphHopper-nak, ami nemcsak az OSM úthálózatot, hanem a menetrendi adatokat (GTFS) is felhasználja a tömegközlekedési útvonaltervezéshez.

    GTFS adatforrások

    Három GTFS adatforrást használunk, amelyek Magyarország teljes tömegközlekedését lefedik:

    SzolgáltatóForrásMéretFrissítésMÁV (Magyar Államvasutak)mavcsoport.hu (Basic Auth)~5 MBNapontaVolánbusz (Helyközi buszok)opendata.utas.hu~110 MBNapontaBKK (Budapesti Közlekedési Központ)go.bkk.hu~55 MBHetente

    A MÁV regisztrációs kálvária

    A MÁV GTFS elérése sajnos nem nyilvános – a mavcsoport.hu/gtfs oldalon kell regisztrálni, ahol egy rövid adatkezelési hozzájárulás után kapunk Basic Auth felhasználónevet és jelszót. A regisztráció egyszerű, de a mai napig nem értem, miért kell ez egy nyílt GTFS adatfolyamhoz – a MÁV indoklása szerint azért, hogy „tudják, hányan és milyen célra használják az adataikat”. Nos, a mi célunk egyértelmű: jobb tömegközlekedési információt adni a felhasználóknak.

    A Volánbusz és a BKK szerencsére nyíltan, mindenféle regisztráció nélkül elérhető – köszönet érte!

    A GTFS szinkronizáló script

    A /root/gtfs-sync.sh script naponta (hajnali 3:30-kor) letölti mindhárom GTFS fájlt, majd újraindítja a graphhopper-pt konténert, hogy az új menetrend alapján újraépítse a gráfot. Ez a folyamat 2-5 percet vesz igénybe – ezalatt a tömegközlekedési útvonaltervezés nem elérhető.

    # A GTFS szinkronizáló script lényege (egyszerűsítve):
    # MÁV letöltés (Basic Auth-val)
    curl -sSf -u "user:password" \
      -o /home/osm/gtfs/mav_gtfs.zip \
      "https://www.mavcsoport.hu/gtfs/gtfsMavMenetrend.zip"
    
    # Volánbusz letöltés
    curl -sSf -o /home/osm/gtfs/volanbusz_gtfs.zip \
      "https://opendata.utas.hu/public-gtfs/volanbusz_gtfs.zip"
    
    # BKK letöltés
    curl -sSf -o /home/osm/gtfs/bkk_gtfs.zip \
      "https://go.bkk.hu/api/static/v1/public-gtfs/budapest_gtfs.zip"
    
    # GraphHopper PT újraindítása az új menetrendek betöltéséhez
    docker restart graphhopper-pt

    Érdekesség, hogy a GraphHopper PT konfigurációja egyszerre három GTFS fájlt is be tud tölteni – a gtfs.file paraméterben vesszővel felsorolva:

    graphhopper:
      gtfs.file: /data/gtfs/mav_gtfs.zip,/data/gtfs/volanbusz_gtfs.zip,/data/gtfs/bkk_gtfs.zip
      # ...és az OSM fájl a gyalogos kapcsolatokhoz

    Ez azért fontos, mert a tömegközlekedési útvonaltervezésnél nem elég a menetrend – tudni kell, hogyan jutok el a buszmegállóhoz gyalog, amihez pontosan az OSM adataira van szükség.

    6. ábra: Tömegközlekedési útvonaltervezés a GraphHopper PT segítségével – Egerből a Budapest-Keleti pályaudvarra, átszállás nélkül, 2 óra 33 perc alatt.

    5. A Webes Felület – MapLibre GL UI

    A felhasználói felület MapLibre GL JS-re épül, ami a Mapbox GL JS nyílt forráskódú továbbfejlesztett változata. A map-ui konténer egy Nginx Alpine image, ami a statikus fájlokat szolgálja ki és proxy-zik a háttérszolgáltatások felé.

    Ami különösen fontos: minden JavaScript és CSS fájl lokálisan van tárolva a /root/osm-ui/vendor/ könyvtárban. Nincs CDN függőség, nincs Google Fonts, nincs unpkg – ha elmegy az internet, a felület továbbra is teljesen működőképes marad.

    A UI funkciói

    • Térkép nézet – raszteres csempék MapLibre GL-lel, teljes képernyős interakció
    • Keresés – autocomplete címkeresés a Photon segítségével, kattintásra odarepülés
    • Útvonaltervezés – A→B útvonal négy módban: autó, bicikli, gyalogos, tömegközlekedés
    • Kanyarról-kanyarra navigáció – összecsukható lista az útvonal panelen, bármelyik kanyarra kattintva odarepül a térkép
    • Több alternatíva – tömegközlekedésnél több útvonal közül választhatunk indulási/idő szerint
    • Járat jelvények – színkódolt jelvények a különböző járatokhoz (busz=kék, villamos=sárga, metró=piros, vasút=lila, stb.)
    • Rétegek váltása – OSM (alap) és Műhold (ESRI World Imagery) között
    • Offline érzékelés – a műhold réteg automatikusan letiltódik, ha nincs internet

    7. ábra: A teljes webes felület – a térkép, keresés és útvonaltervezés használata lépésről lépésre.

    Offline audit – Mi működik internet nélkül?

    Ez a projekt egyik legfontosabb szempontja. Lássuk, mi a helyzet:

    Teljesen offline (nincs szükség internetre)

    • Térképi csempék – a PostgreSQL adatbázisból renderelve (Magyarország OSM PBF)
    • Címkeresés – Photon a lokális Magyarország dump-ot használja
    • Útvonaltervezés – GraphHopper ugyanazt a lokális PBF-et olvassa
    • Tömegközlekedés – GraphHopper PT a lokálisan szinkronizált GTFS menetrendekkel
    • MapLibre GL JS/CSS/root/osm-ui/vendor/ könyvtárból (nincs CDN)
    • Összes HTML/JS/CSS – nincs külső font, nincs Google Fonts, nincs külső API hívás
    • Nginx proxy – minden upstream cél localhost vagy konténer név

    Internetet igényel

    • Műhold réteg (ESRI World Imagery) – opcionális, kikapcsolható
    • OSM tile frissítések – minute diff letöltések (ha elérhető a net, különben csendben hibázik)
    • Photon adatfrissítés – heti dump letöltés graphhopper.com-ról
    • GTFS adatok – napi menetrend letöltés

    Üzemeltetés – Cron feladatok

    A rendszer üzemeltetése nagyrészt automatizált. Három cron job gondoskodik a frissítésekről:

    # Heti Photon adatbázis frissítés (vasárnap 11:30)
    30 11 * * 0 /root/photon-import.sh >> /var/log/photon-import.log 2>&1
    
    # Napi GTFS szinkronizáció (hajnali 3:30)
    30 3  * * * /root/gtfs-sync.sh >> /var/log/gtfs-sync.log 2>&1

    Az OSM konténer beépített frissítése percenként fut a konténeren belül, nem cron-on keresztül.

    Ismert korlátok

    • Hiányzó házszámok a Photon keresésben – a Magyarország Photon dump nem tartalmazza az OSM házszintű címkéit. Ez nem hiba, hanem adatkorlát.
    • Street View nem elérhető – nincs gyakorlati, önállóan üzemeltethető alternatíva (a Mapillary internetet igényel, a Google Street View pedig API kulcsot és internetet).
    • GraphHopper frissítése kézi – amikor az OSM PBF frissül, a GraphHopper graph cache-t manuálisan kell törölni (vagy újraindítani a konténert).
    • Transit gráf újraépítés – GTFS frissítéskor 2-5 percig nem elérhető a tömegközlekedési útvonaltervezés.
    • GTFS adatok időszerűsége – a menetrendek olyan frissek, amilyen friss az utolsó szinkronizáció (maximum 24 óra késés).

    Zárszó

    Ez a projekt számomra a szoftveres szabadság egyik legszebb példája. Egy olcsó, kis fogyasztású Raspberry Pi-n fut egy teljes értékű térkép szolgáltatás, ami semmilyen külső függőséggel nem rendelkezik. A nyílt forráskódú OpenStreetMap közösség munkája, a Photon, a GraphHopper és a MapLibre projectek lehetővé teszik, hogy bárki a saját kezébe vegye a térképezést.

    A forráskód és a konfigurációk természetesen elérhetők a saját infrastruktúrámon. Ha bárki szeretne egy hasonló rendszert építeni, a N.O.M.A.D. projekt remek kiindulási alap, és az itt leírt konfigurációk is szabadon felhasználhatók.

    Következő lépésként szeretném kiterjeszteni a szolgáltatást Szlovákiára, Romániára, Ausztriára, Szlovéniára és Horvátországra is – a Kárpát-medence teljes lefedésére. Továbbá tervben van egy útnyitás (road closure) támogatás is, ahol a felhasználók jelezhetik az aktuális lezárásokat, tereléseket, ami aztán az összes felhasználó számára megjelenne.

    Ha kérdésetek van, vagy kipróbáltátok a megoldást és elakadtatok, nyugodtan szóljatok!

    #útvonaltervezés #BKK #Docker #GraphHopper #GTFS #MapLibre #MÁV #offline #OpenStreetMap #OSM #Photon #RaspberryPi #térkép #tömegközlekedés #Volánbusz
  2. Self-Hosted Google Maps egy Raspberry Pi-n

    Mindig is lenyűgözött az a gondolat, hogy a saját négy falunk között is fusson egy olyan térkép szolgáltatás, ami nem függ az internetkapcsolattól. Egy olyan „Google Maps”, ami a saját gépemen fut, a saját adataimat használja, és akkor is működik, ha épp nincs net. Az inspiration a N.O.M.A.D. (Network of Offline Mapping and Discovery) projektből jött, akik egy teljes offline szolgáltatás stack-et álmodtak meg. Az ő nyomdokaikon haladva építettem meg a saját verziómat, ami egy Raspberry Pi-n fut, Docker konténerekben, és teljes Magyarországot lefedi.

    A hardver – Mi ez a gép?

    A szolgáltatás a xorp-archive.xorp.hu nevű gépemen fut, ami nem egy átlagos Raspberry Pi. Egy Raspberry Pi ARM64 architektúrájú eszköz, 8 GB RAM-mal, NVMe HAT kiegészítővel és egy 1 TB-os Crucial CT1000E100SSD8 NVMe SSD-vel. Ez nem a régi SD kártyás megoldás – az NVMe sebessége és megbízhatósága nélkülözhetetlen egy ilyen adatigényes stack működtetéséhez. A gép Ubuntu 24.04 LTS-t futtat, a kernel pedig a Raspberry Pi-hez optimalizált 6.8.0-1057-raspi.

    1. ábra: A Raspberry Pi NVMe HAT-tal és SSD-vel. A képen a Raspberry Pi 5, a ráhelyezett M.2 HAT+ és az NVMe SSD látható.

    Az ötlet – Miért építsünk offline térképet?

    A válasz egyszerű: szabadság. Amikor nincs internet, vagy korlátozott a sávszélesség, a legtöbb térkép szolgáltatás használhatatlanná válik. Gondoljunk csak egy kirándulásra a Pilisbe, egy külföldi utazásra roaming nélkül, vagy épp egy olyan helyzetre, ahol az adatvédelem miatt nem szeretnénk külső szolgáltatókra bízni magunkat. Egy offline térkép ezekre mind megoldást nyújt.

    A stack négy fő komponensből áll, amelyek Docker konténerekben futnak:

    • OSM Tile Server – a térkép csempék (tile-ok) kiszolgálása
    • Photon – címkeresés, geokódolás
    • GraphHopper – útvonaltervezés (autó, bicikli, gyalogos)
    • GraphHopper PT – tömegközlekedési útvonaltervezés (MÁV, Volánbusz, BKK)
    • MapLibre GL UI – a webes felület, ami összefogja az egészet

    Az architektúra áttekintése

    Minden kérés egyetlen belépési ponton, a map-ui konténeren keresztül történik, ami egy Nginx reverse proxyként szolgál. Ez nemcsak egyszerűbbé teszi a konfigurációt, hanem kiküszöböli a CORS problémákat is, hiszen a böngésző számára minden kérés ugyanarról az origin-ről érkezik.

    Böngésző → port 8090
      └── Nginx (map-ui konténer)
           ├── /tile/{z}/{x}/{y}.png → OSM (8081)
           ├── /photon/api → Photon (2322)
           ├── /graphhopper/route → GraphHopper (8989)
           └── /graphhopper-pt/route → GraphHopper PT (8989)

    A Docker Compose – Minden együtt

    A teljes stack egyetlen docker-compose-osm-extended.yml fájlban van definiálva. Lássuk a lényeget (az IP címeket és elérési utakat természetesen megváltoztattam a valóságban):

    services:
      osm-import:
        image: overv/openstreetmap-tile-server
        container_name: osm-import
        command: import
        shm_size: 1gb
        environment:
          THREADS: 4
          UPDATES: enabled
        volumes:
          - /home/osm/data/hungary-latest.osm.pbf:/data/region.osm.pbf
          - /home/osm/data/hungary.poly:/data/region.poly
          - osm-db:/data/database
          - osm-tiles:/data/tiles
    
      osm:
        image: overv/openstreetmap-tile-server
        container_name: osm
        command: run
        shm_size: 1gb
        ports:
          - 8081:80
        environment:
          UPDATES: enabled
          THREADS: 4
          REPLICATION_URL: https://planet.openstreetmap.org/replication/minute/
        volumes:
          - osm-db:/data/database
          - osm-tiles:/data/tiles
    
      photon:
        image: local/photon:1.1.0
        container_name: photon
        command: ["-listen-ip", "0.0.0.0", "-cors-any"]
        ports:
          - 2322:2322
        volumes:
          - /home/osm/photon:/data/photon
    
      graphhopper:
        image: local/graphhopper:9.1
        container_name: graphhopper
        ports:
          - 8989:8989
        volumes:
          - /home/osm/graphhopper:/data
          - /home/osm/data/hungary-latest.osm.pbf:/data/region.osm.pbf
    
      graphhopper-pt:
        image: local/graphhopper:9.1
        container_name: graphhopper-pt
        ports:
          - 8991:8989
        volumes:
          - /home/osm/graphhopper-pt:/data
          - /home/osm/data/hungary-latest.osm.pbf:/data/region.osm.pbf
          - /home/osm/gtfs:/data/gtfs:ro
        entrypoint: ["java", "-Xmx6g", "-jar", "/app/graphhopper-web.jar", "server", "/app/config.yml"]
    
      map-ui:
        image: local/osm-ui:1.0
        container_name: map-ui
        ports:
          - 8090:80
        volumes:
          - /root/osm-ui:/usr/share/nginx/html:ro
          - /home/osm/map-ui/conf/default.conf:/etc/nginx/conf.d/default.conf:ro

    1. OpenStreetMap Tile Server – A térkép alapja

    Az overv/openstreetmap-tile-server Docker image egy előre összeállított környezet, ami tartalmazza az Apache webszervert, a renderd-et (a csempe renderelő démont), a PostgreSQL-t PostGIS kiegészítővel, és a mod_tile-t, ami a csempe kiszolgálásért felel. Ez a négy komponens együtt teszi lehetővé, hogy a nyers OpenStreetMap adatokból szép, böngészhető térképi csempéket (tile-okat) kapjunk.

    Az import folyamat

    Minden egy PBF fájllal kezdődik – ez a Protocol Buffer Binary Format, az OpenStreetMap adatok tömörített formátuma. Nekünk a Magyarországra vonatkozó kivonatra van szükségünk, ami a geofabrik.de-ról szerezhető be. Ez a fájl a /home/osm/data/hungary-latest.osm.pbf elérési úton található.

    Az import az osm-import konténer egyszeri futtatásával történik:

    # Első importálás (csak egyszer kell)
    docker compose -f docker-compose-osm-extended.yml run --rm osm-import
    
    # Ha frissíteni kell a PBF-et, töröljük a régi adatbázist és újraimportálunk
    docker compose -f docker-compose-osm-extended.yml down
    # ... új PBF letöltése ...
    docker compose -f docker-compose-osm-extended.yml run --rm osm-import
    docker compose -f docker-compose-osm-extended.yml up -d osm

    A konténer a shm_size: 1gb beállítással fut, mert az importálás és a renderelés során rengeteg megosztott memóriára van szükség a gyorsítótárazáshoz. Ez egy kritikus beállítás – ha kicsi a shared memory, a renderelés rendkívül lassú lesz.

    3. ábra: Az OSM tile server folyamatos frissítése – a docker compose logs kimenete mutatja az osm2pgsql importálást és a percenkénti diff letöltést.

    Folyamatos frissítés

    A legmenőbb funkció a beépített incrementális frissítés. Az UPDATES: enabled környezeti változó hatására a konténer percenként letölti a minute diff fájlokat a planet.openstreetmap.org-ról. Ez azt jelenti, hogy a térképünk gyakorlatilag valós időben frissül – ha valaki módosít egy utat az OSM-ben, az pár percen belül megjelenik a saját szerverünkön is. Természetesen ha nincs internet, a script egyszerűen csendben meghibásodik, és a konténer tovább szolgálja a már meglévő csempéket.

    2. Photon – Címkeresés geokódolással

    A Photon egy nyílt forráskódú geokódoló motor, ami az OpenStreetMap adatokra épül. A mi stackünkben a local/photon:1.1.0 image fut, ami egy Magyarországra szabott adatbázissal dolgozik. Ez nem a teljes világ – csak Magyarország, ami jelentősen csökkenti a keresési időt és a tárhely igényt.

    A Photon adatbázis frissítése egy /root/photon-import.sh script segítségével történik, ami hetente egyszer fut (vasárnap 11:30-kor a cron-ban).

    A script működése:

    1. Letölti a legújabb Magyarország Photon dump fájlt(zst tömörítésben) a graphhopper.com-ról
    2. Ellenőrzi a metaadatokat (ETag, last-modified) – ha nem változott, kihagyja a letöltést
    3. Leállítja a Photon konténert
    4. Egy ideiglenes Docker konténerben dekompresszálja és importálja az adatbázist
    5. Frissíti a szimbolikus linket az új import könyvtárra
    6. Újraindítja a Photon konténert
    7. Ellenőrzi a szolgáltatás állapotát egy egyszerű API hívással
    # A Photon import script lényege (egyszerűsítve):
    docker run --rm \
      --entrypoint sh \
      -v /home/osm/photon:/data/photon \
      -v /home/osm/photon-dumps:/data/dumps \
      local/photon:1.1.0 \
      -lc "zstd -d --stdout /data/dumps/photon-dump-hungary.jsonl.zst \
           | java -Xms2g -Xmx4g -jar /app/photon.jar import \
             -import-file - -data-dir /data/photon/imports/20260603200523"
    
    # A szimbolikus link frissítése:
    ln -sfn /home/osm/photon/imports/20260603200523 /home/osm/photon/photon_data

    Az importált adatbázisok verziózott könyvtárakba kerülnek (/home/osm/photon/imports/20260603200523/), így mindig vissza lehet térni egy régebbi verzióhoz, ha valami elromlana. Egy szimbolikus link (photon_data -> imports/20260603200523/) mutat az aktuális verzióra.

    4. ábra: Címkeresés a Photon segítségével – „Eger, Dobó tér” keresése és megjelenítése a térképen.

    3. GraphHopper – Útvonaltervezés (autó, bicikli, gyalogos)

    A GraphHopper egy nagy teljesítményű, nyílt forráskódú útvonaltervező motor, ami az OpenStreetMap úthálózatára épül. A mi stackünkben a local/graphhopper:9.1 image fut, 4 GB RAM allokációval.

    A GraphHopper három útvonal profilt támogat:

    • car – autós közlekedés, figyelembe veszi az egyirányú utcákat, sebességkorlátozásokat, út típusokat
    • bike – biciklis közlekedés, preferálja a kerékpárutakat, kerüli a főútvonalakat
    • foot – gyalogos közlekedés, használja a járdákat, gyalogutakat, lépcsőket

    A konfiguráció /home/osm/graphhopper/config.yml-ban található:

    graphhopper:
      datareader.file: /data/region.osm.pbf
      graph.location: /data/graph-cache
    
      profiles:
        - name: car
        - name: bike
        - name: foot
    
      profiles_ch:
        - profile: car
        - profile: bike
        - profile: foot
    
      graph.dataaccess.default_type: RAM_STORE
    
    server:
      application_connectors:
        - type: http
          port: 8989
          bind_host: 0.0.0.0

    A Contraction Hierarchies (CH) egy előfeldolgozási technika, ami drámaian felgyorsítja az útvonal keresést. Az autó és bicikli profilokhoz CH-t használunk, ami az első induláskor 5-10 perc előfeldolgozást igényel, de utána a lekérések ezredmásodpercek alatt teljesülnek.

    5. ábra: Autós útvonaltervezés a GraphHopper segítségével – Budapestről Debrecenbe (231,5 km, 2 óra 12 perc).

    4. GraphHopper PT – Tömegközlekedési útvonaltervezés

    Ez a stack talán legmenőbb komponense. A GraphHopper PT (Public Transport) egy speciális konfigurációja a GraphHopper-nak, ami nemcsak az OSM úthálózatot, hanem a menetrendi adatokat (GTFS) is felhasználja a tömegközlekedési útvonaltervezéshez.

    GTFS adatforrások

    Három GTFS adatforrást használunk, amelyek Magyarország teljes tömegközlekedését lefedik:

    SzolgáltatóForrásMéretFrissítésMÁV (Magyar Államvasutak)mavcsoport.hu (Basic Auth)~5 MBNapontaVolánbusz (Helyközi buszok)opendata.utas.hu~110 MBNapontaBKK (Budapesti Közlekedési Központ)go.bkk.hu~55 MBHetente

    A MÁV regisztrációs kálvária

    A MÁV GTFS elérése sajnos nem nyilvános – a mavcsoport.hu/gtfs oldalon kell regisztrálni, ahol egy rövid adatkezelési hozzájárulás után kapunk Basic Auth felhasználónevet és jelszót. A regisztráció egyszerű, de a mai napig nem értem, miért kell ez egy nyílt GTFS adatfolyamhoz – a MÁV indoklása szerint azért, hogy „tudják, hányan és milyen célra használják az adataikat”. Nos, a mi célunk egyértelmű: jobb tömegközlekedési információt adni a felhasználóknak.

    A Volánbusz és a BKK szerencsére nyíltan, mindenféle regisztráció nélkül elérhető – köszönet érte!

    A GTFS szinkronizáló script

    A /root/gtfs-sync.sh script naponta (hajnali 3:30-kor) letölti mindhárom GTFS fájlt, majd újraindítja a graphhopper-pt konténert, hogy az új menetrend alapján újraépítse a gráfot. Ez a folyamat 2-5 percet vesz igénybe – ezalatt a tömegközlekedési útvonaltervezés nem elérhető.

    # A GTFS szinkronizáló script lényege (egyszerűsítve):
    # MÁV letöltés (Basic Auth-val)
    curl -sSf -u "user:password" \
      -o /home/osm/gtfs/mav_gtfs.zip \
      "https://www.mavcsoport.hu/gtfs/gtfsMavMenetrend.zip"
    
    # Volánbusz letöltés
    curl -sSf -o /home/osm/gtfs/volanbusz_gtfs.zip \
      "https://opendata.utas.hu/public-gtfs/volanbusz_gtfs.zip"
    
    # BKK letöltés
    curl -sSf -o /home/osm/gtfs/bkk_gtfs.zip \
      "https://go.bkk.hu/api/static/v1/public-gtfs/budapest_gtfs.zip"
    
    # GraphHopper PT újraindítása az új menetrendek betöltéséhez
    docker restart graphhopper-pt

    Érdekesség, hogy a GraphHopper PT konfigurációja egyszerre három GTFS fájlt is be tud tölteni – a gtfs.file paraméterben vesszővel felsorolva:

    graphhopper:
      gtfs.file: /data/gtfs/mav_gtfs.zip,/data/gtfs/volanbusz_gtfs.zip,/data/gtfs/bkk_gtfs.zip
      # ...és az OSM fájl a gyalogos kapcsolatokhoz

    Ez azért fontos, mert a tömegközlekedési útvonaltervezésnél nem elég a menetrend – tudni kell, hogyan jutok el a buszmegállóhoz gyalog, amihez pontosan az OSM adataira van szükség.

    6. ábra: Tömegközlekedési útvonaltervezés a GraphHopper PT segítségével – Egerből a Budapest-Keleti pályaudvarra, átszállás nélkül, 2 óra 33 perc alatt.

    5. A Webes Felület – MapLibre GL UI

    A felhasználói felület MapLibre GL JS-re épül, ami a Mapbox GL JS nyílt forráskódú továbbfejlesztett változata. A map-ui konténer egy Nginx Alpine image, ami a statikus fájlokat szolgálja ki és proxy-zik a háttérszolgáltatások felé.

    Ami különösen fontos: minden JavaScript és CSS fájl lokálisan van tárolva a /root/osm-ui/vendor/ könyvtárban. Nincs CDN függőség, nincs Google Fonts, nincs unpkg – ha elmegy az internet, a felület továbbra is teljesen működőképes marad.

    A UI funkciói

    • Térkép nézet – raszteres csempék MapLibre GL-lel, teljes képernyős interakció
    • Keresés – autocomplete címkeresés a Photon segítségével, kattintásra odarepülés
    • Útvonaltervezés – A→B útvonal négy módban: autó, bicikli, gyalogos, tömegközlekedés
    • Kanyarról-kanyarra navigáció – összecsukható lista az útvonal panelen, bármelyik kanyarra kattintva odarepül a térkép
    • Több alternatíva – tömegközlekedésnél több útvonal közül választhatunk indulási/idő szerint
    • Járat jelvények – színkódolt jelvények a különböző járatokhoz (busz=kék, villamos=sárga, metró=piros, vasút=lila, stb.)
    • Rétegek váltása – OSM (alap) és Műhold (ESRI World Imagery) között
    • Offline érzékelés – a műhold réteg automatikusan letiltódik, ha nincs internet

    7. ábra: A teljes webes felület – a térkép, keresés és útvonaltervezés használata lépésről lépésre.

    Offline audit – Mi működik internet nélkül?

    Ez a projekt egyik legfontosabb szempontja. Lássuk, mi a helyzet:

    Teljesen offline (nincs szükség internetre)

    • Térképi csempék – a PostgreSQL adatbázisból renderelve (Magyarország OSM PBF)
    • Címkeresés – Photon a lokális Magyarország dump-ot használja
    • Útvonaltervezés – GraphHopper ugyanazt a lokális PBF-et olvassa
    • Tömegközlekedés – GraphHopper PT a lokálisan szinkronizált GTFS menetrendekkel
    • MapLibre GL JS/CSS/root/osm-ui/vendor/ könyvtárból (nincs CDN)
    • Összes HTML/JS/CSS – nincs külső font, nincs Google Fonts, nincs külső API hívás
    • Nginx proxy – minden upstream cél localhost vagy konténer név

    Internetet igényel

    • Műhold réteg (ESRI World Imagery) – opcionális, kikapcsolható
    • OSM tile frissítések – minute diff letöltések (ha elérhető a net, különben csendben hibázik)
    • Photon adatfrissítés – heti dump letöltés graphhopper.com-ról
    • GTFS adatok – napi menetrend letöltés

    Üzemeltetés – Cron feladatok

    A rendszer üzemeltetése nagyrészt automatizált. Három cron job gondoskodik a frissítésekről:

    # Heti Photon adatbázis frissítés (vasárnap 11:30)
    30 11 * * 0 /root/photon-import.sh >> /var/log/photon-import.log 2>&1
    
    # Napi GTFS szinkronizáció (hajnali 3:30)
    30 3  * * * /root/gtfs-sync.sh >> /var/log/gtfs-sync.log 2>&1

    Az OSM konténer beépített frissítése percenként fut a konténeren belül, nem cron-on keresztül.

    Ismert korlátok

    • Hiányzó házszámok a Photon keresésben – a Magyarország Photon dump nem tartalmazza az OSM házszintű címkéit. Ez nem hiba, hanem adatkorlát.
    • Street View nem elérhető – nincs gyakorlati, önállóan üzemeltethető alternatíva (a Mapillary internetet igényel, a Google Street View pedig API kulcsot és internetet).
    • GraphHopper frissítése kézi – amikor az OSM PBF frissül, a GraphHopper graph cache-t manuálisan kell törölni (vagy újraindítani a konténert).
    • Transit gráf újraépítés – GTFS frissítéskor 2-5 percig nem elérhető a tömegközlekedési útvonaltervezés.
    • GTFS adatok időszerűsége – a menetrendek olyan frissek, amilyen friss az utolsó szinkronizáció (maximum 24 óra késés).

    Zárszó

    Ez a projekt számomra a szoftveres szabadság egyik legszebb példája. Egy olcsó, kis fogyasztású Raspberry Pi-n fut egy teljes értékű térkép szolgáltatás, ami semmilyen külső függőséggel nem rendelkezik. A nyílt forráskódú OpenStreetMap közösség munkája, a Photon, a GraphHopper és a MapLibre projectek lehetővé teszik, hogy bárki a saját kezébe vegye a térképezést.

    A forráskód és a konfigurációk természetesen elérhetők a saját infrastruktúrámon. Ha bárki szeretne egy hasonló rendszert építeni, a N.O.M.A.D. projekt remek kiindulási alap, és az itt leírt konfigurációk is szabadon felhasználhatók.

    Következő lépésként szeretném kiterjeszteni a szolgáltatást Szlovákiára, Romániára, Ausztriára, Szlovéniára és Horvátországra is – a Kárpát-medence teljes lefedésére. Továbbá tervben van egy útnyitás (road closure) támogatás is, ahol a felhasználók jelezhetik az aktuális lezárásokat, tereléseket, ami aztán az összes felhasználó számára megjelenne.

    Ha kérdésetek van, vagy kipróbáltátok a megoldást és elakadtatok, nyugodtan szóljatok!

    #útvonaltervezés #BKK #Docker #GraphHopper #GTFS #MapLibre #MÁV #offline #OpenStreetMap #OSM #Photon #RaspberryPi #térkép #tömegközlekedés #Volánbusz