Tg
Applications Azure

Traccar on Ubuntu 24.04 on Azure User Guide

| Product: Traccar GPS Tracking on Ubuntu 24.04 LTS on Azure

Overview

Traccar is the reference open source GPS tracking and fleet telematics server. It receives position reports from vehicle trackers, asset tags and phones, stores them with a complete history, and turns them into live maps, trip replay, geofences, scheduled and on-demand reports, event notifications, and driver and maintenance records. Everything the web interface does is also available through a full REST API.

Traccar understands more than two hundred device protocols. This image ships a small, explicitly documented set of protocol listeners rather than all of them, and Step 9 shows you how to enable the one your own trackers speak.

The cloudimg image delivers Traccar 6.15.3 on Ubuntu 24.04, served over HTTPS, backed by PostgreSQL, with an empty database and every secret generated on the first boot of your VM. Backed by 24/7 cloudimg support.

What is included:

  • Traccar 6.15.3 at /opt/traccar, run by systemd as the unprivileged traccar user on Ubuntu's own OpenJDK 21 runtime, with its web application bound to 127.0.0.1:8082 only
  • The Traccar web interface, served by nginx over HTTPS on port 443 with a certificate generated for your VM; port 80 only redirects to HTTPS (plus a plain /healthz for load balancer probes)
  • PostgreSQL 16 on the loopback address only, holding devices, positions, users and reports
  • Three device-protocol listeners enabled by default — osmand on 5055 (the Traccar Client phone app), teltonika on 5027 and gt06 on 5023 — with every other protocol disabled in the configuration
  • No default login and no open enrolment: the administrator account is created, with a random password, on your VM's first boot, before the web interface is allowed to start
  • postgresql, traccar and nginx systemd services, enabled and active

Traccar is a trademark of its respective owner. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them. This image packages the unmodified open source software, which is distributed under the Apache License 2.0.

The Traccar sign-in screen served over HTTPS

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) runs Traccar comfortably for a small to medium fleet; choose a larger size for hundreds of devices reporting at short intervals. Network security group inbound rules: 22/tcp from your management network, 443/tcp for the web interface, optionally 80/tcp (which only redirects to HTTPS), and the device-protocol port your trackers use — 5055/tcp for the Traccar Client app, 5027/tcp for Teltonika hardware, 5023/tcp for GT06-family trackers.

Step 1: Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Traccar 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 HTTPS (443). Then select Review + create and Create. Add the device-protocol port your trackers use as an extra inbound rule once the VM exists (Step 9).

Step 2: Deploy from the Azure CLI

az vm create \
  --resource-group my-resource-group \
  --name my-traccar \
  --image cloudimg:traccar-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_rsa.pub \
  --public-ip-sku Standard \
  --os-disk-delete-option Delete \
  --nic-delete-option Delete

Then open the ports you need:

az vm open-port --resource-group my-resource-group --name my-traccar --port 443 --priority 1001
az vm open-port --resource-group my-resource-group --name my-traccar --port 5055 --priority 1002

Step 3: Connect to your VM

ssh azureuser@<vm-ip>

The login user is azureuser (or whichever administrator name you chose at deployment). The image carries no build-time account and no password login.

Step 4: Confirm the Traccar stack is running

First boot takes about a minute: it generates this VM's database password, TLS certificate and administrator password, creates an empty database, and only then allows nginx to start. Until it finishes, the web interface is deliberately not reachable.

sudo systemctl is-active postgresql postgresql@16-main traccar nginx
active
active
active
active

postgresql.service on Ubuntu is a wrapper that reports active as soon as it has dispatched, so postgresql@16-main — the cluster that actually holds your data — is checked separately.

Check the runtime and versions:

java -version
openjdk version "21.0.12" 2026-07-21
OpenJDK Runtime Environment (build 21.0.12+8-1-24.04-Ubuntu)

Traccar runs on Ubuntu's own OpenJDK package rather than a bundled runtime, so unattended-upgrades keeps the JVM patched along with the rest of the system.

The Traccar stack running, with the Java, PostgreSQL and nginx versions

Step 5: Check what the network can reach

sudo /usr/local/sbin/traccar-port-check.sh
off-box TCP exactly [22 80 443 5023 5027 5055]; Traccar web 127.0.0.1:8082; PostgreSQL loopback
TRACCAR_PORTS_OK

That is the complete off-box surface of this image: SSH, the HTTPS front door, the HTTP redirect, and the three device-protocol listeners. Traccar's own web application listens on 127.0.0.1:8082 and is never directly reachable — nginx is the only web door — and PostgreSQL is bound to loopback.

sudo ss -Hltn | awk '{print $4}' | sort -t: -k2 -n | paste -sd'  '
[::]:22 [::]:443 [::]:80 [::ffff:127.0.0.1]:8082 0.0.0.0:22 127.0.0.53%lo:53 127.0.0.54:53 0.0.0.0:80 0.0.0.0:443 *:5023 *:5027 *:5055 127.0.0.1:5432

The exact off-box listening set and the shipped protocol allow-list

Step 6: Retrieve the first-boot credentials

sudo stat -c '%A %U:%G %n' /root/traccar-credentials.txt
-rw------- root:root /root/traccar-credentials.txt
sudo cat /root/traccar-credentials.txt

The file records this VM's web address, the administrator login and the password generated for it. Nothing in it exists in the image — every value is minted on this VM's first boot, before the web interface is allowed to serve a single request.

The per-VM credentials file, root-only, written on first boot

Step 7: Sign in

Open https://<vm-ip>/ in a browser. The certificate is generated for your VM and is self-signed, so the browser warns on the first visit; Step 11 shows how to install a certificate for a real domain name.

Sign in as admin with the password from Step 6. You land on the live map. A fresh instance has no devices yet, so the fleet list is empty until you add one in Step 8.

The Traccar live map showing the fleet and each device's status

You can confirm the same thing from the command line without a browser. The server's public settings show that self-registration is closed:

curl -sk https://127.0.0.1/api/server \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print(json.dumps({k: d[k] for k in ("id","registration","readonly","deviceReadonly")}, indent=2))'
{
  "id": 1,
  "registration": false,
  "readonly": false,
  "deviceReadonly": false
}

And a real sign-in through the front door, reading the password from your own credentials file rather than typing it:

PASS=$(sudo grep '^TRACCAR_ADMIN_PASSWORD=' /root/traccar-credentials.txt | cut -d= -f2-)
curl -sk -c /tmp/traccar.jar -X POST \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode "email=admin" --data-urlencode "password=$PASS" \
  https://127.0.0.1/api/session \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print(json.dumps({k: d[k] for k in ("id","name","login","email","administrator")}, indent=2))'
{
  "id": 1,
  "name": "Administrator",
  "login": "admin",
  "email": "admin@localhost",
  "administrator": true
}

Step 8: Add your first tracker

Every tracker identifies itself to Traccar by a unique identifier — usually its IMEI, printed on the device or returned by an SMS status command. Register the identifier first; Traccar refuses positions from identifiers it does not know, so an unregistered device cannot inject data into your fleet.

In the web interface choose Settings → Devices → +, give the device a name and enter its identifier, then save.

The device register, showing each tracker's identifier and last known position

The quickest way to see the system working end to end is the official Traccar Client app for Android or iOS, which speaks the osmand protocol already enabled on port 5055. In the app set the server address to https://<vm-ip> — note that the app uses port 5055, so enter http://<vm-ip>:5055 as the server URL — and set the device identifier to the same value you registered. Positions start arriving within a minute and the device turns Online on the map.

Select a device to see its live status card: fix time, position, speed and total distance.

A device's live status card on the map

Step 9: Enable the protocol your trackers speak

Traccar supports over two hundred device protocols. This image deliberately enables only three, because a marketplace image that opens two hundred unauthenticated listeners is a security liability, and because Azure network security groups cap a single VM configuration at one hundred ports. Everything else is disabled in the configuration, not merely firewalled.

Check what is enabled:

sudo grep -E "protocols.enable|\.port'" /opt/traccar/conf/traccar.xml | sed 's/^ *//'
<entry key='web.port'>8082</entry>
<entry key='protocols.enable'>osmand,teltonika,gt06</entry>
<entry key='osmand.port'>5055</entry>
<entry key='teltonika.port'>5027</entry>
<entry key='gt06.port'>5023</entry>

To enable another protocol you need three things: its name added to protocols.enable, a <protocol>.port entry, and the matching inbound rule in your network security group. Traccar's device list gives the protocol name and the conventional port for every supported tracker. For example, to add the h02 protocol on its conventional port 5013:

sudo cp /opt/traccar/conf/traccar.xml /opt/traccar/conf/traccar.xml.bak
sudo sed -i \
  -e "s|<entry key='protocols.enable'>osmand,teltonika,gt06</entry>|<entry key='protocols.enable'>osmand,teltonika,gt06,h02</entry>|" \
  -e "s|</properties>|    <entry key='h02.port'>5013</entry>\n</properties>|" \
  /opt/traccar/conf/traccar.xml
sudo systemctl restart traccar.service
az network nsg rule create \
  --resource-group my-resource-group \
  --nsg-name my-traccar-nsg \
  --name allow-h02 --priority 1010 \
  --protocol Tcp --destination-port-ranges 5013 --access Allow

Restrict each protocol rule to the address ranges your trackers report from wherever your mobile operator allows it. Device protocols are unauthenticated by design — the device identifier is the only credential — so the identifier register from Step 8 and a tight NSG rule are what protect the listener.

To remove a protocol, take its name out of protocols.enable, delete its .port entry, restart traccar.service and remove the NSG rule.

Step 10: Run reports

Choose Reports in the navigation. Route and Positions list every stored fix; Trips and Stops group them into journeys and dwell time; Summary and Chart aggregate distance, engine hours and speed. Pick a device and a period, then select Show.

A route report listing real stored positions with time, coordinates and speed

The same data is available through the API. Continuing with the session cookie from Step 7:

curl -sk -b /tmp/traccar.jar https://127.0.0.1/api/devices \
  | python3 -c 'import json,sys
try:
    devices = json.load(sys.stdin)
except Exception:
    devices = []
print(json.dumps([{k: d[k] for k in ("id","name","uniqueId","status")} for d in devices], indent=2))'
[
  {
    "id": 1,
    "name": "Delivery Van 1",
    "uniqueId": "864035050000001",
    "status": "online"
  }
]
DEV=$(curl -sk -b /tmp/traccar.jar https://127.0.0.1/api/devices \
  | python3 -c 'import json,sys
try:
    d = json.load(sys.stdin)
except Exception:
    d = []
print(d[0]["id"] if d else "")')
if [ -n "$DEV" ]; then
  curl -sk -b /tmp/traccar.jar "https://127.0.0.1/api/positions?deviceId=$DEV" \
    | python3 -c 'import json,sys
try:
    d = json.load(sys.stdin)
except Exception:
    d = []
print(json.dumps([{k: p[k] for k in ("deviceId","fixTime","latitude","longitude","speed")} for p in d[:1]], indent=2))'
else
  echo "no devices registered yet - add one in Step 8"
fi
[
  {
    "deviceId": 1,
    "fixTime": "2026-09-20T13:37:29.000+00:00",
    "latitude": 51.5426,
    "longitude": -0.0717,
    "speed": 22.5
  }
]

The full API reference is at traccar.org/api-reference. When you have finished, remove the cookie jar with rm -f /tmp/traccar.jar.

Step 11: Use a domain name and your own certificate

Point a DNS A record at your VM's public address, then obtain a certificate and install it where nginx expects it:

sudo apt-get install -y certbot
sudo certbot certonly --standalone -d <your-domain> --agree-tos -m <your-email> --non-interactive
sudo install -o root -g root -m 0640 /etc/letsencrypt/live/<your-domain>/privkey.pem /etc/ssl/traccar/traccar.key
sudo install -o root -g root -m 0644 /etc/letsencrypt/live/<your-domain>/fullchain.pem /etc/ssl/traccar/traccar.crt
sudo nginx -t && sudo systemctl reload nginx

Certbot's standalone mode needs port 80 free, so stop nginx for the issuance and start it again afterwards, or use a DNS challenge. Renewals replace the Let's Encrypt files, so add a deploy hook that repeats the two install commands and reloads nginx.

Step 12: Add more users

Self-registration is disabled on this image: nobody who finds your VM can enrol themselves. Add users yourself from Settings → Users → +, or through the API as the administrator:

curl -sk -b /tmp/traccar.jar -X POST -H 'Content-Type: application/json' \
  --data '{"name":"Dispatcher","email":"dispatch@example.com","password":"<new-password>"}' \
  https://127.0.0.1/api/users

Grant each user access to specific devices from Settings → Users → Show next to the user's row. Leave Admin off for everyday accounts.

If you deliberately want open enrolment, turn it on in Settings → Server → Registration. Do not do this on an instance reachable from the public internet unless you intend anyone to be able to create an account.

Step 13: Security model

  • No default credential. Traccar creates no administrator in a fresh database, but an empty user table makes the first anonymous account creation an administrator. First boot consumes that window itself, on the loopback interface, before nginx is allowed to start — so the first account that ever exists on your instance is yours, with a random 24-character password.
  • The front door stays shut until first boot finishes. nginx.service will not start until first boot has written /var/lib/cloudimg/traccar.bootstrap-ready, and traccar.service will not start until it has written this VM's database password. Neither is ordering alone, which would still let the application start if first boot were slow or failed.
  • Self-registration is off and is re-asserted on every first boot rather than inherited from an upstream default.
  • Traccar is not directly reachable. It binds 127.0.0.1:8082; nginx terminates TLS, sets X-Forwarded-For and X-Real-IP from the real connection address so a caller cannot forge the address Traccar records, clears Forwarded and X-Forwarded-Prefix, and stamps Secure, HttpOnly and SameSite=Lax onto the session cookie.
  • PostgreSQL is loopback-only with a password unique to this VM.
  • No outbound calls by default. Traccar's anonymous usage-statistics upload and its geocoder are both disabled in the shipped configuration. Map tiles are fetched by your browser, not by the server.
  • Device protocols are unauthenticated by design. The device identifier is the credential, so register identifiers deliberately (Step 8) and restrict the protocol port in your NSG (Step 9).

A single command re-checks all of it:

sudo /usr/local/sbin/traccar-selftest.sh
[ports] off-box TCP exactly [22 80 443 5023 5027 5055]; Traccar web 127.0.0.1:8082; PostgreSQL loopback
[ports] TRACCAR_PORTS_OK
[login] per-VM credential authenticates as administrator (200); admin/admin, blank and weak refused
[login] self-registration closed (anonymous POST /api/users -> 400); cookie Secure+HttpOnly+SameSite
[login] TRACCAR_LOGIN_OK
[xff] through nginx Traccar recorded [127.0.0.1], not the forged [203.0.113.77]
[xff] known-bad control (bypassing nginx) recorded [203.0.113.77] as expected
[xff] TRACCAR_XFF_OK
[http] port 80 redirects to HTTPS
[registration] self-registration disabled
TRACCAR_SELFTEST_OK

The appliance self-test proving the per-VM credential works and the defaults are refused

Step 14: Back up your data

Everything Traccar stores — devices, users, positions, geofences, reports — lives in the traccar PostgreSQL database. Uploaded media lives in /opt/traccar/media, and the configuration in /opt/traccar/conf/traccar.xml.

sudo -u postgres pg_dump -Fc traccar > <backup-dir>/traccar-$(date +%F).dump
sudo tar czf <backup-dir>/traccar-config-$(date +%F).tar.gz \
  /opt/traccar/conf/traccar.xml /opt/traccar/media

To restore onto a fresh instance, stop traccar.service, drop and recreate the database, restore with pg_restore, put the configuration back, and start the service again. Keep the dumps off the VM — an Azure storage account or a managed backup vault.

Step 15: Logs, upgrades and maintenance

sudo journalctl -u traccar.service -n 50 --no-pager
sudo tail -n 50 /opt/traccar/logs/tracker-server.log

Traccar's own log records every protocol connection and every decoded message, which is the fastest way to diagnose a tracker that is not reporting: if the device connects but Traccar answers Unknown device, the identifier is not registered (Step 8); if nothing appears at all, the NSG rule or the protocol port is wrong (Step 9).

Operating system security updates are applied automatically by unattended-upgrades, which covers OpenJDK, PostgreSQL and nginx. To upgrade Traccar itself, back up first (Step 14), then replace /opt/traccar with a newer release archive, keeping conf/traccar.xml, and restart the service — Traccar migrates its own schema on start.

sudo systemctl restart traccar.service
sudo systemctl is-active traccar
active

Support

cloudimg provides 24/7 support for this image: deployment, tracker onboarding, enabling additional device protocols, TLS certificates and custom domains, database tuning, backups and scaling. Contact us at cloudimg.co.uk.