In this guide I’ll walk through a complete, reproducible deployment of Traccar on an Ubuntu VPS, using:
- PostgreSQL as the primary database
- Caddy as a reverse proxy with automatic HTTPS
- A dedicated domain,
traccar.example.com
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
- 2. System preparation
- 3. PostgreSQL installation and database setup
- 4. Traccar installation (Linux installer)
- 5. Ensure Traccar restarts on reboot
- 6. Caddy installation (Ubuntu/Debian)
- 7. Caddy reverse proxy and automatic HTTPS
- 8. Firewall (optional but recommended)
- 9. Verification and post‑deploy checks
- 10. Optional: Running Traccar as non‑root
- 11. Optional: Using TimescaleDB for location history
- 12. Optional: Device ports and firewall for GPS/devices
- 13. Updating the Traccar platform
- 14. References and links
- 15. Optional: Production hardening and operations
1. Prerequisites
Before you type a single command, make sure you have:
- Ubuntu server (22.04 LTS recommended) with sudo access
- Domain:
traccar.example.comwith an A (and optionally AAAA) DNS record pointing to your VPS public IP - Ports 80 and 443 open and reachable from the internet (for Caddy and Let’s Encrypt)
- Optionally, you’ll later open device ports (for example 5055, 5013) if GPS devices or the Traccar Client app will connect from the internet — see Section 12
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
Step 2.4 — Create a deploy user (recommended)
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:
- Terminate HTTPS using Let’s Encrypt certificates
- Proxy traffic for
traccar.example.comtolocalhost:8082 - Handle redirects from HTTP to HTTPS
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 thetraccar.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
- Automatic HTTPS: Caddy will request and renew a Let’s Encrypt certificate for
traccar.example.com. Ensure the domain’s A/AAAA record points to this VPS and that ports 80 and 443 are reachable. - WebSockets: Caddy’s
reverse_proxysupports WebSocket by default, which the Traccar web UI and mobile app use.
8. Firewall (optional but recommended)
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
- Change the default Traccar admin password.
- Plan regular backups of the PostgreSQL
traccardatabase and of/opt/traccar/conf(and data if stored there). - For production, consider the optional steps in Section 15 (hardening, backups, updates).
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:
- Traccar Client app:
your-domain.example.com, port5055 - H02 devices:
your-domain.example.com, port5013
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
- Do not copy
default.xmlfrom old versions; use onlytraccar.xmlfor custom config. - Database schema changes are applied automatically on startup for PostgreSQL.
- For release notes and new features, see the Traccar blog (for example Traccar 6.12).
14. References and links
- Traccar Download — Current release and version
- Traccar Upgrading — Official upgrade guide
- Traccar Linux Installation
- Traccar Install on DigitalOcean — Comparison guide; this article uses PostgreSQL instead of the embedded DB
- Traccar PostgreSQL
- Traccar Secure Connection (Caddy)
- Caddy Install
- Caddy Automatic HTTPS
- Traccar Run as non-root
- Traccar Identify protocol / devices
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.3 — SSH hardening (recommended before or after deploy)
- Use SSH key authentication and disable password login once keys work: in
/etc/ssh/sshd_configsetPasswordAuthentication noandPermitRootLogin no(orprohibit-password) if you use a non-root sudo user. - Restart SSH after changes:
sudo systemctl restart sshd(orsshon some systems). Keep a second session open to test login before closing the first.
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
| Item | Section / action |
|---|---|
| Default admin password changed | 9.5 |
| PostgreSQL + config backups scheduled | 15.1 |
| UFW enabled with SSH allowed first | 8 |
| Traccar running as non-root (optional) | 10 |
| TimescaleDB for larger deployments (optional) | 11 |
| Automatic security updates | 15.2 |
| SSH hardened (keys, no root password) | 15.3 |
| Fail2ban (optional) | 15.4 |