Deployment guide

Traccar

Overview

Traccar is the reference open-source GPS tracking and fleet telematics server. It receives position reports from vehicle trackers, asset tags and phones, and stores them with a complete history. It turns that history 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.

This SecureAnyCloud image delivers Traccar 6.15.3 on Ubuntu 24.04, served over HTTPS and backed by PostgreSQL. The database starts empty, and every secret is generated on the first boot of your VM.

What you get:

  • 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, and also serves 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, with every other protocol disabled in the configuration: osmand on 5055 (the Traccar Client phone app), teltonika on 5027 and gt06 on 5023
  • No default login and no open enrollment. 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
  • 24/7 SecureAnyCloud support

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.

Prerequisites

  • An active Azure subscription, an SSH key pair, and a VNet and subnet in the target region
  • Standard_B2s (2 vCPU, 4 GiB RAM), which runs Traccar comfortably for a small to medium fleet. Choose a larger size for hundreds of devices that report at short intervals.
  • Network security group inbound rules for 22/tcp from your management network, 443/tcp for the web interface, and optionally 80/tcp, which only redirects to HTTPS
  • An inbound rule for the device-protocol port your trackers use: 5055/tcp for the Traccar Client app, 5027/tcp for Teltonika hardware, or 5023/tcp for GT06-family trackers
1

Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Traccar by SecureAnyCloud 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. Once the VM exists, add the device-protocol port your trackers use as an extra inbound rule (Step 9).

2

Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:traccar-ubuntu-24-04:default:latest
az vm create \
  --resource-group my-resource-group \
  --name my-traccar \
  --image sac1647283583153: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
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.

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 first boot 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. For that reason, the previous commands check postgresql@16-main, the cluster that actually holds your data, 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.

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, because nginx is the only web door. 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
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. None of these values exists in the image. Each one is generated on this VM's first boot, before the web interface is allowed to serve a single request.

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 stays empty until you add a device in Step 8.

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 }

Then 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 }
8

Add your first tracker

Every tracker identifies itself to Traccar by a unique identifier, usually its IMEI, which is 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, enter its identifier and save.

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. Do not use https://<vm-ip> as the server address, because that is the web interface. Enter http://<vm-ip>:5055 as the server URL, because the app uses port 5055. 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, which shows fix time, position, speed and total distance.

9

Enable the protocol your trackers speak

Traccar supports over two hundred device protocols. This image deliberately enables only three. A marketplace image that opens two hundred unauthenticated listeners is a security liability, and 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, use the following commands.

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

Wherever your mobile operator allows it, restrict each protocol rule to the address ranges your trackers report from. Device protocols are unauthenticated by design, and the device identifier is the only credential. 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.

10

Run reports

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

The same data is available through the API. The following commands continue 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.

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. Stop nginx for the issuance and start it again afterward, 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.

12

Add more users

Self-registration is disabled on this image, so nobody who finds your VM can enroll 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 enrollment, 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.

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. The first account that ever exists on your instance is therefore yours, with a random 24-character password.
  • The front door stays shut until first boot finishes. nginx.service does not start until first boot has written /var/lib/sac/data/traccar.bootstrap-ready, and traccar.service does not start until first boot has written this VM's database password. Service ordering alone would not be enough, because it would still let the application start if first boot were slow or failed.
  • Self-registration is off. The setting 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 and sets X-Forwarded-For and X-Real-IP from the real connection address, so a caller cannot forge the address Traccar records. nginx also 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. Your browser fetches map tiles, not 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
14

Back up your data

Everything Traccar stores (devices, users, positions, geofences and reports) lives in the traccar PostgreSQL database. Uploaded media lives in /opt/traccar/media, and the configuration lives 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, for example in an Azure storage account or a managed backup vault.

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 makes it 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).

unattended-upgrades applies operating system security updates automatically, including 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

SecureAnyCloud provides 24/7 support for this image, covering deployment, tracker onboarding, additional device protocols, TLS certificates and custom domains, database tuning, backups and scaling. Contact us at secureanycloud.com.

Deploy on Azure

Launch Traccar GPS Tracking on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure