Applications Azure

Reitti on Ubuntu 24.04 on Azure User Guide

| Product: Reitti on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Reitti on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Reitti is an open source personal location tracking and analysis application. It ingests the location history you already produce, live positions from the OwnTracks phone app, GPX track files, and a Google Takeout export of your Maps timeline, and turns the raw stream of points into something you can read: detected visits, the trips between them, and the significant places you return to, laid out on an interactive map and a day by day timeline. The name comes from the Finnish word for route or path.

The cloudimg image ships the free and open source, AGPL-3.0 licensed Reitti application, run the officially supported way as the upstream containers pinned by image digest: the Reitti Spring Boot app, a PostgreSQL 17 + PostGIS 3.5 spatial database, a Redis cache and a map tile cache that proxies map tiles so browsing your history does not hammer a public tile service. All images are captured into the VM, so your instance starts in seconds. Because Reitti ships upstream with a built in admin / admin login, nothing here ships with a working default: the admin password is rotated to a unique random value on the first boot of each VM, a unique database password and cache password are generated, and the public web door is held closed until that rotation has completed and been proven. Backed by 24/7 cloudimg support.

Reitti is a trademark of its respective owner. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the Reitti project or dedicatedcode. It ships the free and open source AGPL-3.0 licensed self hosted software, unmodified.

The docker, reitti and nginx services all active, and the four compose containers (reitti app, PostGIS, Redis and the tile cache) running and healthy

What is included:

  • Reitti v5.1.0 (the AGPL-3.0 licensed Spring Boot application), pinned by image digest
  • PostgreSQL 17 with the PostGIS 3.5 spatial extension, pinned by image digest, for the location database
  • Redis for the application cache and distributed locks, pinned by image digest
  • A map tile cache that proxies and caches OpenStreetMap tiles, pinned by image digest
  • Docker Engine with the app, database, cache and tile cache published to the loopback interface only, fronted by nginx on port 80
  • reitti-firstboot.service, reitti.service, reitti-postboot.service and nginx.service as systemd units, enabled and active on boot
  • A per instance admin password (rotated away from the upstream admin default), a unique database password and a unique cache password, generated per VM on first boot and never baked into the image
  • The public web door held closed until the per instance admin rotation is proven, an empty database on first boot, and no working default login
  • Ubuntu 24.04 LTS base with latest security patches applied at build time
  • Azure Linux Agent for seamless cloud integration and SSH key injection
  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • Active Azure subscription, SSH public key, VNet + subnet in target region
  • Subscription to the Reitti listing on Azure Marketplace

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is a sensible starting point for a personal timeline. For large imports (years of history, a full Google Takeout) or heavier processing use Standard_D2s_v5 or larger. NSG inbound: allow 22/tcp from your management network and 80/tcp for the web UI from the networks that use it.

Step 1: Deploy from the Azure Portal

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Reitti 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.

Step 2: Deploy from the Azure CLI

RG="reitti-prod"; LOCATION="eastus"; VM_NAME="reitti-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/reitti-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name reitti-vnet --address-prefix 10.100.0.0/16 --subnet-name reitti-subnet --subnet-prefix 10.100.1.0/24
az network nsg create -g "$RG" --name reitti-nsg
az network nsg rule create -g "$RG" --nsg-name reitti-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name reitti-nsg --name allow-http --priority 110 \
  --destination-port-ranges 80 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name reitti-vnet --subnet reitti-subnet --nsg reitti-nsg --public-ip-sku Standard

Step 3: Connect to your VM

ssh azureuser@<vm-ip>

Step 4: Confirm the services are running

The stack runs as four containers (the Reitti app, PostGIS, Redis and the map tile cache) under one reitti.service, fronted by nginx. Confirm the services are active and see the containers:

sudo systemctl is-active docker reitti nginx
sudo docker ps --format 'table {{.Names}}\t{{.Status}}'

You will see the services report active and the four containers healthy. Only the Reitti app is published, to 127.0.0.1:8090; PostGIS, Redis and the tile cache have no host port at all. nginx on :80 is the single public front door and proxies to the app, including the WebSocket/SSE live location stream.

Step 5: Read the per instance credentials

Reitti ships upstream with a built in admin account whose password is the well known default admin. On the first boot of this VM that password was rotated to a unique random value, a unique database password and cache password were generated, and the values were written to a root only file. The public :80 door is deliberately held closed until that rotation completes, so the default is never reachable over the network. Read the credentials:

sudo cat /root/reitti-credentials.txt

The file (mode 0600 root:root) holds ADMIN_USERNAME and ADMIN_PASSWORD (the account you sign in to the web UI with), plus WEB_URL and VM_IP. None of these ship in the image; every value is unique to this VM, so no two instances share a credential and there is no working default login.

The reitti-credentials.txt file at mode 0600 root root with the per VM admin username and password (password masked), the web URL and the VM IP, and a note that they are generated uniquely on first boot with the admin default rotated away

Step 6: Verify the security model

The login page and the health endpoint are reachable without authentication, but every application page requires a logged in session, and the upstream default admin / admin no longer works. Confirm that the login page and health endpoint are live, that the app root is protected when unauthenticated, that the default login is rejected, and that the per instance admin credential authenticates:

ADMIN_PASSWORD=$(sudo grep '^ADMIN_PASSWORD=' /root/reitti-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'login page      (no auth):  %{http_code}\n' http://localhost/login
curl -s -o /dev/null -w 'health          (no auth):  %{http_code}\n' http://localhost/actuator/health
curl -s -o /dev/null -w 'app root        (no auth):  %{http_code}\n' http://localhost/
jar=$(mktemp); curl -s -o /dev/null -c "$jar" --data-urlencode username=admin --data-urlencode password=admin http://localhost/login
curl -s -o /dev/null -w 'default admin/admin (authed root): %{http_code}\n' -b "$jar" http://localhost/
jar2=$(mktemp); curl -s -o /dev/null -c "$jar2" --data-urlencode username=admin --data-urlencode "password=$ADMIN_PASSWORD" http://localhost/login
curl -s -o /dev/null -w 'per instance admin  (authed root): %{http_code}\n' -b "$jar2" http://localhost/
rm -f "$jar" "$jar2"

The login page and health return 200, the app root returns 302 (a redirect to the login page, so it is protected), the default admin / admin session is still redirected 302 (rejected), and only the per instance admin session reaches the app root with 200. This is the security model: no working default login, and the public door only opens after the per instance admin password is set.

curl checks showing the login page and health endpoint returning HTTP 200, the app root returning 302 when unauthenticated, the upstream default admin/admin still redirected 302 as rejected, and only the per instance admin session returning 200

The same round trip is bundled as a single script on the image, which the build and smoke tests run to prove the credential works end to end:

sudo /usr/local/sbin/reitti-roundtrip.sh

The bundled round trip script reporting OK: the login page and health are live, the app root is protected, the default admin/admin is rejected, and the per instance admin credential authenticates a real logged in request

Step 7: Open the web UI and sign in

Browse to http://<vm-ip>/ to reach Reitti. Sign in with the ADMIN_USERNAME (admin) and the per instance ADMIN_PASSWORD from Step 5.

The Reitti sign in page showing the Reitti wordmark, username and password fields and a Remember me option, over a faint map background

Step 8: See your location history on the map

The main view is an interactive map with a day timeline. Once you connect a data source (next step) and Reitti processes the incoming points, your movements are drawn as a track for the selected day, with the detected visits and trips laid out along the timeline. Use the date strip to move between days and the time slider to scrub through a day.

The Reitti map view showing a real OpenStreetMap street map of East London with a GPS track drawn in orange for the selected day, the device avatars in the top left and the day timeline and date strip along the bottom

Step 9: Connect a data source

Open Settings then Integrations to connect where your location comes from. Reitti accepts live data from the OwnTracks and GPSLogger phone apps, the Overland app and an OwnTracks Recorder or MQTT feed, and one off imports of GPX files or a Google Takeout export from Settings then Import Data. Each integration shows a ready made setup URL that already contains this instance's address and the selected API token, so your phone can start sending points in minutes.

The Reitti Integrations settings page showing the Data Ingestion section, GPS tracking frequency guidance, a Data Quality verification control and the settings navigation listing Import Data, Export Data, API Tokens, Places, Visit Sensitivity, Transportation Modes, Map Styles, Geocoding and more

Step 10: Manage devices

Open Settings then Devices to manage the devices that send you location data. Each device has a name, an accent colour used to draw its track on the map, and a show on map toggle, so a multi device household can see each person's movements in their own colour. Add a device to get a token for a new phone, or set a default device for imports.

The Reitti Devices settings page listing a Default device and a Phone device, both enabled and shown on the map, with edit, disable, set as default and delete actions, and an Add Device form with a colour theme picker

Step 11: How data is processed

Reitti waits a short grace period after the last incoming point, then processes unprocessed data in batches: it filters implausible points, clusters stays into visits, connects them into trips, and reverse geocodes them into significant places. Visit sensitivity, transportation modes and the geocoding service are all tunable under Settings. Larger imports are processed in the background, and the Job Status page under Settings shows progress.

Step 12: Data location and backup

All location data lives in the PostGIS database on a Docker volume, and uploaded files live on the Reitti data volume, both on the VM's OS disk. To back up, snapshot the disk from Azure, or dump the database:

sudo docker exec reitti-postgis-1 pg_dump -U reitti reittidb | gzip > reitti-backup-$(date +%F).sql.gz

For a full export of your own history, use Settings then Export Data, which produces GPX or GeoJSON you can take elsewhere.

Step 13: Server components

Component Version / Detail
Application Reitti v5.1.0 (Spring Boot, AGPL-3.0, pinned by image digest)
Database PostgreSQL 17 + PostGIS 3.5 (pinned by image digest)
Cache Redis 7.2 (pinned by image digest)
Tile cache Reitti tile cache v5.1.0 (nginx OSM proxy, pinned by image digest)
Reverse proxy nginx on port 80 (single public front door)
Base image Ubuntu 24.04 LTS, fully patched at build time

Security model

  • No working default login. Reitti's built in admin / admin is rotated to a unique random password on the first boot of every VM, written to /root/reitti-credentials.txt (0600 root:root). The public :80 door is held closed (nginx is ordered after the rotation) until the per instance admin password is set and proven, so the default is never reachable over the network.
  • Unique per instance secrets. The database password and the Redis cache password are generated fresh on first boot; nothing is baked into the image.
  • Loopback only backends. Only the Reitti app is published, to 127.0.0.1:8090; PostGIS, Redis and the tile cache have no host port. nginx on :80 is the single public front door.
  • Empty on first boot. The database and data volumes are captured empty, so no location data from the build ever ships; every VM starts clean.
  • Keep port 80 restricted to the networks that need it, and put Reitti behind your own TLS terminating proxy or the Azure Application Gateway if you expose it beyond a trusted network.

Support

Every cloudimg deployment includes 24/7 support with a guaranteed 24 hour response SLA. Contact support@cloudimg.co.uk.

Reitti is a trademark of its respective owner. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the Reitti project or dedicatedcode.