Mo
Applications Azure

MOTIS on Ubuntu 24.04 on Azure User Guide

| Product: MOTIS on Ubuntu 24.04 LTS on Azure

Overview

MOTIS is the open source multimodal journey planning engine that powers large scale public planners such as Transitous. It imports OpenStreetMap street data together with GTFS public transport timetables into an on disk dataset, then serves a JSON routing API and a map based web interface on a single port. It computes optimal door to door itineraries that combine walking and public transport, with departures, arrivals, transfers and a drawn route on the map.

The MOTIS server is a single self contained native binary that serves both the REST API and the bundled web app. It runs behind nginx as a reverse proxy on port 80. The engine listens on 127.0.0.1:8080 and binds to the loopback interface only, so the only public surface is nginx.

MOTIS is a public by design, read only service: it exposes only routing, geocoding, map tile and health GET endpoints. There is no login, no administrator account and no mutating endpoint, so no credentials ship in the image or are generated at first boot. On the first boot of every deployed VM a one shot service resolves the VM public address, writes an instance info file to /root/motis-info.txt, records the bootstrap ready marker, and starts the engine and the front door. The engine unit is gated on that marker, so it never serves before first boot has completed.

MOTIS journey planner rendering a Hauptbahnhof to Oberwiehre itinerary on the Freiburg OpenStreetMap basemap

What is included:

  • MOTIS 2.11.1 server (single native binary, bundles the web UI and map tile profiles) at /var/lib/motis/motis
  • nginx reverse proxy on :80 in front of the MOTIS engine on loopback :8080, with version disclosure suppressed
  • A small ready to explore sample dataset baked into the image: a central Freiburg OpenStreetMap extract (© OpenStreetMap contributors, Open Database License ODbL) paired with a compact synthetic GTFS demonstration timetable (CC0), so the planner answers real journeys on first boot
  • motis.service and nginx.service as systemd units, enabled and active, plus a motis-firstboot.service one shot that runs once per VM
  • The engine runs as a dedicated non root motis service account with no shell and no sudo
  • A fully patched Ubuntu 24.04 LTS security baseline at capture time, with unattended security updates enabled
  • 24/7 cloudimg support

Key facts: platform Ubuntu 24.04 LTS on Azure, default SSH user azureuser, application home /var/lib/motis, web UI and API on port 80, engine loopback on 8080.

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point for the bundled sample region. A larger region or a real country feed needs more memory and disk, so scale the VM size and OS disk to the dataset you import. NSG inbound: allow 22/tcp from your management network and 80/tcp (plus 443/tcp once you place your own TLS terminator in front) from the networks your users will reach the planner on.

Step 1 — Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for MOTIS by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + create and Create. First boot initialisation takes a few seconds after the VM starts.

Step 2 — Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name motis \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name motis --port 80 --priority 1010

Step 3 — Connect to your VM

ssh azureuser@<vm-public-ip>

Look up the public IP at any time with az vm show -d -g <your-rg> -n motis --query publicIps -o tsv.

Step 4 — Verify the MOTIS stack

Two systemd services make up the stack. Confirm both are active and that the engine binds loopback only while nginx serves the public port:

systemctl is-active motis nginx
ss -tln | grep -E ':80 |:8080 '

Both lines read active, and the socket list shows nginx on 0.0.0.0:80 with the MOTIS engine bound to 127.0.0.1:8080 only:

active
active
LISTEN 0  511        0.0.0.0:80    0.0.0.0:*
LISTEN 0  128      127.0.0.1:8080  0.0.0.0:*
LISTEN 0  511          [::]:80        [::]:*

The two systemd services active and the MOTIS engine bound to loopback only

Step 5 — Open the journey planner

Browse to http://<vm-public-ip>/. The MOTIS web UI opens with the journey planner on the left and the map on the right. Enter a start and destination (or click two points on the map) and MOTIS plans the connections, showing departure, arrival, transfers, duration and the drawn route.

The MOTIS journey planner and the Freiburg OpenStreetMap map on first open

A journey with a change and longer walking legs is planned the same way; MOTIS chooses the fastest multimodal option and lists earlier and later alternatives:

A second planned journey across the sample network with walking and tram legs

Step 6 — Plan journeys over the routing API

The same routing is available as a JSON REST API. The plan endpoint takes a fromPlace and toPlace (a lat,lng pair or a stop id) and returns ranked itineraries. The radius parameter uses transit stops within that many metres of each coordinate:

curl -s 'http://127.0.0.1/api/v6/plan?fromPlace=47.9990,7.8410&toPlace=47.9900,7.8640&radius=1000&time=2026-08-10T06:00:00Z' \
  | jq '{itineraries: (.itineraries | length), first: (.itineraries[0] | {startTime, endTime, duration, transfers})}'

The response contains real itineraries with real departure and arrival times computed from the timetable:

{
  "itineraries": 5,
  "first": {
    "startTime": "2026-08-10T06:00:00Z",
    "endTime": "2026-08-10T06:08:00Z",
    "duration": 480,
    "transfers": 0
  }
}

A real routing query returning an itinerary with departure and arrival times

Geocoding turns a place name into coordinates and stop ids:

curl -s 'http://127.0.0.1/api/v1/geocode?text=Bertoldsbrunnen' | jq -c '.[0] | {name, type, lat, lon}'

Step 7 — Health and per VM instance info

The health endpoint reports whether MOTIS has completed a full cycle over its configured feeds:

curl -s -o /dev/null -w 'health: HTTP %{http_code}\n' http://127.0.0.1/api/v1/health

Every VM writes an instance info file on first boot with its own reachable URL and the read only, public by design note:

sudo cat /root/motis-info.txt

The health endpoint answering 200 and the per VM instance info file

Step 8 — The sample dataset and its licenses

The image ships a small demonstration dataset so the planner works out of the box. The attribution and licensing are recorded on the VM:

cat /var/lib/motis/DATA-LICENSES.txt

The street and map data is an extract of OpenStreetMap, © OpenStreetMap contributors, licensed under the Open Database License (ODbL). The public transport timetable is a synthetic demonstration GTFS feed authored by cloudimg and released under CC0; it does not represent any real transit service.

The data license and attribution notice shipped with the sample dataset

Step 9 — Import your own region

To plan real journeys for your own area, replace the sample data with a real OpenStreetMap extract (for example from Geofabrik) and one or more real GTFS feeds, then rebuild the on disk dataset. This is a one time build step, run as the motis service account:

# Download an OpenStreetMap extract for your region and one or more GTFS feeds into /var/lib/motis, then:
cd /var/lib/motis
sudo -u motis ./motis config your-region.osm.pbf your-feed.gtfs.zip
sudo -u motis ./motis import
sudo systemctl restart motis

Use a valid, current timetable: a feed whose service calendar does not cover upcoming dates will contain no trips to plan. Size the VM to the region, as larger areas need more memory and disk to import and serve.

Server Components

Component Version Path
MOTIS engine (binary + web UI + tile profiles) 2.11.1 /var/lib/motis/motis
nginx reverse proxy distribution /etc/nginx/sites-available/cloudimg-motis
MOTIS config generated /var/lib/motis/config.yml
Imported dataset generated /var/lib/motis/data/

Filesystem Layout

Path Description
/ Root filesystem
/var/lib/motis MOTIS home: binary, bundled UI, config, OSM extract, GTFS feed and imported data/ folder
/var/lib/motis/DATA-LICENSES.txt OpenStreetMap (ODbL) and timetable (CC0) attribution
/root/motis-info.txt Per VM instance info written at first boot
/var/lib/cloudimg/motis-firstboot.done First boot bootstrap ready marker

Managing the service

systemctl status motis --no-pager
sudo systemctl restart motis
journalctl -u motis -n 50 --no-pager

Security

MOTIS is deployed here as a public by design, read only routing service. Confirm the posture on your VM:

  • The engine runs as the non root motis service account with no shell and no sudo.
  • It binds 127.0.0.1:8080 only; the sole public surface is nginx on port 80, with version disclosure suppressed.
  • There is no login, administrator account, token or mutating endpoint; only routing, geocoding, map and health GET endpoints are served.
  • The engine unit is gated on the first boot bootstrap ready marker, so it will not serve before first boot completes.

Restrict inbound 80/tcp to the networks that should reach the planner, and place your own TLS terminator in front for HTTPS. Keep 22/tcp limited to your management network.

Troubleshooting

The web UI does not load. Check both services with systemctl is-active motis nginx. If motis is not active, inspect journalctl -u motis -n 100 --no-pager. The engine only starts once the first boot marker exists at /var/lib/cloudimg/motis-firstboot.done.

A routing query returns no itineraries. The bundled feed covers a wide calendar, but a feed you import yourself must have service dates that include the time you query. Verify with the geocode endpoint that your start and destination resolve to stops or coordinates inside the imported region.

Health returns HTTP 400. MOTIS reports 400 until it has completed a full first cycle over every configured feed. With the static sample feed and no realtime sources it settles at 200 shortly after start.

Support

For assistance, contact cloudimg support:

  • Email: support@cloudimg.co.uk
  • Response Time: 24/7 with a guaranteed 24 hour response SLA
  • Website: https://cloudimg.co.uk