Skip to content

Deploying Traccar on an Ubuntu VPS with PostgreSQL and Caddy

Published: at 12:00 AM

In this guide I’ll walk through a complete, reproducible deployment of Traccar on an Ubuntu VPS, using:

The goal is that you can start from a fresh server and, by following the steps in order, end up with a production-ready Traccar instance that survives reboots and is reasonably secure.

Table of contents

Open Table of contents

1. Prerequisites

Before you type a single command, make sure you have:

Once this checklist is done, you’re ready to prepare the system.


2. System preparation

We’ll start by bringing the system up to date, setting some basic metadata (hostname, timezone), and creating a non-root user for day‑to‑day operations.

Step 2.1 — Update packages and install required utilities

sudo apt update
sudo apt install -y unzip curl

Step 2.2 — (Optional) Set hostname

Set the server hostname to match your domain (for example traccar.example.com) or a short name like fleet.

sudo hostnamectl set-hostname traccar.example.com

To use a short hostname instead (for example fleet), run:

sudo hostnamectl set-hostname fleet

Step 2.3 — (Optional) Set timezone

Replace Africa/Nairobi with your timezone (for example America/New_York, Europe/London).

sudo timedatectl set-timezone Africa/Nairobi

Create a dedicated user for deployment and give it sudo access. Run these as root or your initial sudo user:

sudo adduser deploy
sudo usermod -aG sudo deploy

Switch to the deploy user for the rest of the steps (from Section 3 onward). Either open a new SSH session as deploy, or run:

sudo su - deploy

From here on, run all following commands as deploy (using sudo when needed), or use sudo -u deploy if you prefer to stay in another session.


3. PostgreSQL installation and database setup

Traccar ships with an embedded database by default, but for anything beyond casual testing you’ll want PostgreSQL. In this section we’ll install PostgreSQL, create a dedicated user and database, and verify connectivity.

Step 3.1 — Install PostgreSQL

sudo apt update
sudo apt install -y postgresql postgresql-client

Step 3.2 — Start and enable PostgreSQL

sudo systemctl start postgresql
sudo systemctl enable postgresql

Step 3.3 — Create database user and database

Replace YOUR_SECURE_PASSWORD with a strong password. You’ll use this user and database for Traccar.

First, open the PostgreSQL prompt:

sudo -u postgres psql

At the postgres=# prompt, run the following (replace YOUR_SECURE_PASSWORD):

CREATE ROLE traccar WITH LOGIN PASSWORD 'YOUR_SECURE_PASSWORD';
CREATE DATABASE traccar OWNER traccar;
\q

Step 3.4 — Verify connection

Confirm that the traccar user can connect to the traccar database. When prompted, enter the password you set above.

psql -U traccar -d traccar -h localhost -c '\conninfo'

You should see connection info for database traccar. If it fails, check that the password is correct and that PostgreSQL is running.


4. Traccar installation (Linux installer)

We’ll use the official Linux installer, which installs Traccar under /opt/traccar and registers a systemd service.

Step 4.1 — Download the installer

Get the latest Linux x64 installer from the official download page (links to GitHub releases). Replace the version in the URL below if a newer release is available:

cd /tmp
# Use the current version from https://www.traccar.org/download/ (for example 6.11.1)
wget https://github.com/traccar/traccar/releases/download/v6.11.1/traccar-linux-64-6.11.1.zip

If you prefer a direct “latest” link, check the download page for the current Linux x64 filename and version.

Step 4.2 — Unzip and run the installer

unzip traccar-linux-64-*.zip
sudo ./traccar.run

The installer places Traccar under /opt/traccar and registers a systemd service named traccar.

Step 4.3 — Configure Traccar to use PostgreSQL

Edit the Traccar configuration file:

sudo nano /opt/traccar/conf/traccar.xml

Find the default H2 database entries:

<entry key='database.driver'>org.h2.Driver</entry>
<entry key='database.url'>jdbc:h2:./data/database</entry>
<entry key='database.user'>sa</entry>
<entry key='database.password'></entry>

Replace them with the following (use the same password you set in Step 3.3):

<entry key='database.driver'>org.postgresql.Driver</entry>
<entry key='database.url'>jdbc:postgresql://localhost/traccar</entry>
<entry key='database.user'>traccar</entry>
<entry key='database.password'>YOUR_SECURE_PASSWORD</entry>

Save and exit (in nano: Ctrl+O, Enter, Ctrl+X).

Step 4.4 — Start and enable the Traccar service

sudo systemctl start traccar
sudo systemctl enable traccar

Step 4.5 — Verify Traccar is running

systemctl status traccar

Optional: check that the web interface responds locally:

curl -s -o /dev/null -w "%{http_code}" http://localhost:8082

You should see 200 or 302.

Default web login is usually admin / admin. Change this password immediately after first login.


5. Ensure Traccar restarts on reboot

We’ve enabled the service already, but it’s cheap to double‑check this behaviour and verify it persists across reboots.

Step 5.1 — Enable Traccar to start on boot

If you already ran this in Step 4.4, it is safe to run again:

sudo systemctl enable traccar

Step 5.2 — (Optional) Reboot and verify

To confirm Traccar comes up after a reboot:

sudo reboot

After reconnecting via SSH:

systemctl status traccar
curl -s -o /dev/null -w "%{http_code}" http://localhost:8082

Traccar should be active and return 200 or 302.


6. Caddy installation (Ubuntu/Debian)

We’ll use the official Caddy package to terminate TLS, handle HTTP/HTTPS redirects, and proxy traffic to Traccar.

Step 6.1 — Install prerequisites

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

Step 6.2 — Add the Caddy repository

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list

Make the new keyring and list readable:

sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list

Step 6.3 — Install Caddy

sudo apt update
sudo apt install -y caddy

Step 6.4 — Enable and start Caddy

sudo systemctl enable caddy
sudo systemctl start caddy

Step 6.5 — Verify Caddy

caddy version
systemctl status caddy

7. Caddy reverse proxy and automatic HTTPS

Now we’ll wire your domain to Traccar through Caddy. Caddy will:

This assumes DNS for traccar.example.com points to this server and ports 80 and 443 are open.

Step 7.1 — Edit the Caddyfile

sudo nano /etc/caddy/Caddyfile

Step 7.2 — Add the site block

Replace any existing content (or add below it) with the following. This config proxies the domain to Traccar; Caddy handles HTTPS and WebSockets automatically. The :80 block redirects all HTTP traffic on port 80 to HTTPS.

:80 {
    redir https://traccar.example.com{uri} permanent
}

traccar.example.com {
    reverse_proxy localhost:8082
}

Caution: Redirecting all HTTP on port 80 can break GPS devices or clients that send data via plain HTTP on port 80 and do not follow redirects or support HTTPS. Most Traccar device protocols use dedicated TCP ports (for example 5055, 5013), not HTTP on 80. If you have devices that report via HTTP on port 80, remove the :80 { ... } block and keep only the traccar.example.com { ... } block.

Save and exit (Ctrl+O, Enter, Ctrl+X).

Step 7.3 — Reload Caddy

sudo systemctl reload caddy

If you prefer a full restart:

sudo systemctl restart caddy

Step 7.4 — Notes


UFW (Uncomplicated Firewall) gives you a simple front‑end to iptables. We’ll keep SSH open, allow HTTP/HTTPS for Caddy, and explicitly avoid exposing PostgreSQL.

Step 8.1 — Allow SSH first (critical)

Do this before enabling UFW. If you skip this, you may lose SSH access after ufw enable.

sudo ufw allow 22
# If SSH runs on a custom port, use that instead, for example:
# sudo ufw allow 2222/tcp

Step 8.2 — Allow HTTP and HTTPS

sudo ufw allow 80
sudo ufw allow 443

Step 8.3 — (Optional) Allow device ports for GPS / Traccar Client

If devices or the Traccar Client app will connect from the internet, open the required ports (for example 5055 for Traccar Client, 5013 for H02). Add only what you need:

sudo ufw allow 5055/tcp
sudo ufw allow 5013/tcp

Step 8.4 — Enable UFW

When prompted, type y and press Enter.

sudo ufw enable

Step 8.5 — Check firewall status

sudo ufw status

Leave PostgreSQL (port 5432) closed to the internet; the app connects to the database over localhost only.


9. Verification and post‑deploy checks

At this point you have PostgreSQL, Traccar, Caddy, and UFW configured. Now we’ll verify that everything survives a reboot and that the public endpoint works as expected.

Step 9.1 — Reboot the server

sudo reboot

Step 9.2 — After reconnect: confirm services are enabled

systemctl is-enabled traccar caddy

Both should show enabled.

Step 9.3 — Check service status

systemctl status traccar
systemctl status caddy

Both should be active (running).

Step 9.4 — Open the web interface

In a browser, go to:

https://your-domain.example.com

You should see the Traccar login page over HTTPS. Log in with the default credentials (for example admin / admin) and change the admin password immediately.

Step 9.5 — Post‑deploy checklist


10. Optional: Running Traccar as non‑root

The deploy user (Section 2.4) is for you — the person who SSHs in and runs sudo. This section is about the Traccar service itself: we’ll make it run as a dedicated system user (traccar) instead of root.

If the Traccar process is ever compromised, this limits damage.

Step 10.1 — Create a system user for Traccar

sudo useradd -r -s /bin/false traccar

Step 10.2 — Set ownership of the Traccar directory

sudo chown -R traccar:traccar /opt/traccar

Step 10.3 — Create systemd drop‑in directory

sudo mkdir -p /etc/systemd/system/traccar.service.d

Step 10.4 — Add drop‑in configuration

sudo nano /etc/systemd/system/traccar.service.d/run-as-user.conf

Paste the following:

[Service]
User=traccar
Group=traccar

Save and exit (Ctrl+O, Enter, Ctrl+X).

Step 10.5 — Reload systemd and restart Traccar

sudo systemctl daemon-reload
sudo systemctl restart traccar

Step 10.6 — Verify

systemctl status traccar

The process should now run as user traccar. For more options, see Traccar — Running as non‑root user.


11. Optional: Using TimescaleDB for location history

TimescaleDB is a PostgreSQL extension that improves storage and query performance for time‑series data (like position history). It’s worth considering once your fleet grows.

Step 11.1 — Add the TimescaleDB PPA (Ubuntu)

sudo add-apt-repository ppa:timescale/timescaledb-ppa
sudo apt update

Step 11.2 — Install TimescaleDB for your PostgreSQL version

Check your PostgreSQL major version:

psql --version

Install the matching package (replace 14 with your major version if different, for example 15 or 16):

sudo apt install -y timescaledb-2-postgresql-14

If prompted by the installer, accept the option to run timescaledb-tune.

Step 11.3 — Tune and restart PostgreSQL (if not done by installer)

Run the tuning utility (it may add shared_preload_libraries automatically):

sudo timescaledb-tune --quiet --yes

Required: TimescaleDB must be in PostgreSQL’s shared_preload_libraries. If timescaledb-tune did not add it, add it manually:

sudo nano /etc/postgresql/14/main/postgresql.conf

Add or ensure this line exists (use your PostgreSQL version path if different, for example 15 or 16 instead of 14):

shared_preload_libraries = 'timescaledb'

Then restart PostgreSQL:

sudo systemctl restart postgresql

Step 11.4 — Enable the extension in the traccar database

sudo -u postgres psql -d traccar -c "CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;"

Step 11.5 — Note on Traccar config

No change to /opt/traccar/conf/traccar.xml is required; keep using the same PostgreSQL URL (jdbc:postgresql://localhost/traccar).

For a preconfigured Docker setup, see Traccar Docker Compose with TimescaleDB.


12. Optional: Device ports and firewall for GPS/devices

The web interface is served over HTTPS via Caddy (port 443). GPS trackers and the Traccar Client app use raw TCP on separate ports (for example 5055 for Traccar Client, 5013 for H02). Caddy’s reverse proxy is HTTP/HTTPS only and cannot proxy these device protocols; devices must reach the server directly by IP and port.

Step 12.1 — Open device ports (UFW)

Open only the ports you need for your device types. Common examples:

sudo ufw allow 5055/tcp
sudo ufw allow 5013/tcp
sudo ufw reload

Step 12.2 — If the VPS is behind a router/NAT

Forward the same ports (for example 5055, 5013) from your router to the VPS’s local IP. There is no generic command for this; configure your router’s port‑forwarding rules.

Step 12.3 — Configure the device or Traccar Client

Use the server address your-domain.example.com (or the VPS public IP) and the correct port for the protocol, for example:

Step 12.4 — Reference


13. Updating the Traccar platform

When a new Traccar release ships, you rarely want to rebuild from scratch. This section covers in‑place upgrades using the Linux installer.

These steps apply when a new release is available (for example from 6.11.x to 6.12.x).

If you run Traccar 4.0 or later, you can usually upgrade directly to the latest release. For older versions, see Upgrading Traccar.

Step 13.1 — Check the current version

Check the official download page for the current Linux x64 release (for example 6.12.1 as of early 2026).

Step 13.2 — Create backups (required)

PostgreSQL database — Critical. Create a backup before upgrading. This uses the postgres OS user so no password is needed (peer auth):

sudo mkdir -p /var/backups
sudo -u postgres pg_dump traccar | gzip | sudo tee /var/backups/traccar-pre-upgrade-$(date +%Y%m%d-%H%M).sql.gz > /dev/null

Config file — If you modified traccar.xml, back it up to /var/backups (the installer may overwrite /opt/traccar/conf/):

sudo cp /opt/traccar/conf/traccar.xml /var/backups/traccar.xml.backup-$(date +%Y%m%d)

Media folder — Only if /opt/traccar/web/media exists (for example you added custom logos):

[ -d /opt/traccar/web/media ] && sudo cp -r /opt/traccar/web/media /var/backups/traccar-media-$(date +%Y%m%d)

Step 13.3 — Stop Traccar and download the new release

sudo systemctl stop traccar
cd /tmp
# Replace 6.12.1 with the version from https://www.traccar.org/download/
wget https://github.com/traccar/traccar/releases/download/v6.12.1/traccar-linux-64-6.12.1.zip
unzip traccar-linux-64-*.zip

Step 13.4 — Run the installer

The Linux .run installer upgrades in place and replaces binaries. The installer may overwrite config files during some upgrades, so the backups in Step 13.2 are essential.

sudo ./traccar.run

Step 13.5 — Restore custom config or media (if needed)

If the upgrade overwrote your config, restore from backup (replace YYYYMMDD with your backup date):

sudo cp /var/backups/traccar.xml.backup-YYYYMMDD /opt/traccar/conf/traccar.xml

Restore the media folder if you backed it up and it was overwritten (replace YYYYMMDD with your backup date):

sudo mkdir -p /opt/traccar/web/media
sudo cp -r /var/backups/traccar-media-YYYYMMDD/* /opt/traccar/web/media/

Step 13.6 — Start Traccar and verify

sudo systemctl start traccar
systemctl status traccar
curl -s -o /dev/null -w "%{http_code}" http://localhost:8082

You should see active (running) and HTTP 200 or 302. Log in to the web interface and confirm devices and data look correct.

Step 13.7 — Upgrade notes



15. Optional: Production hardening and operations

For a one‑off hobby project you can stop earlier. For anything that might grow or handle real‑world data, invest a little extra time here.

15.1 — Backups

PostgreSQL: Schedule regular dumps of the traccar database. Create a backup directory, then add a daily cron as root (for example at 02:00). Use sudo -u postgres so the dump runs as the postgres OS user (peer auth, no password needed):

sudo mkdir -p /var/backups
sudo crontab -e
# Add:
# 0 2 * * * sudo -u postgres /usr/bin/pg_dump traccar | gzip > /var/backups/traccar-$(date +\%Y\%m\%d).sql.gz

Rotate or delete old backups periodically (for example keep 7 or 30 days) to avoid filling disk.

Config: Periodically copy /opt/traccar/conf/traccar.xml and any customizations to a safe location.

15.2 — Automatic security updates (Ubuntu)

Reduce exposure to known vulnerabilities by enabling unattended security upgrades:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Choose “Yes” to enable automatic security updates. Optionally edit /etc/apt/apt.conf.d/50unattended-upgrades to tune which updates are applied.

15.4 — Fail2ban (optional)

To limit brute‑force attempts on SSH (and optionally on Caddy/HTTP), install Fail2ban:

sudo apt install -y fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Configure jails in /etc/fail2ban/jail.local as needed (for example sshd enabled by default on many setups).

15.5 — Production checklist summary

ItemSection / action
Default admin password changed9.5
PostgreSQL + config backups scheduled15.1
UFW enabled with SSH allowed first8
Traccar running as non-root (optional)10
TimescaleDB for larger deployments (optional)11
Automatic security updates15.2
SSH hardened (keys, no root password)15.3
Fail2ban (optional)15.4