From acfa08fc2ef54dfcee7655202b03f19ac1e52516 Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Sun, 12 Apr 2026 16:15:52 -0400 Subject: [PATCH] traccar: init --- configuration.nix | 2 ++ service-configs.nix | 12 +++++++ services/traccar.nix | 84 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 services/traccar.nix diff --git a/configuration.nix b/configuration.nix index 79f0159..3c0fdf6 100644 --- a/configuration.nix +++ b/configuration.nix @@ -73,6 +73,8 @@ ./services/harmonia.nix ./services/ddns-updater.nix + + ./services/traccar.nix ]; # Hosts entries for CI/CD deploy targets diff --git a/service-configs.nix b/service-configs.nix index 4cb200d..6623924 100644 --- a/service-configs.nix +++ b/service-configs.nix @@ -197,6 +197,14 @@ rec { port = 5500; proto = "tcp"; }; + traccar_web = { + port = 8082; + proto = "tcp"; + }; + traccar_tracking = { + port = 5056; + proto = "tcp"; + }; }; }; @@ -330,6 +338,10 @@ rec { dataDir = services_dir + "/trilium"; }; + traccar = { + domain = "traccar.${https.domain}"; + }; + media = { moviesDir = torrents_path + "/media/movies"; tvDir = torrents_path + "/media/tv"; diff --git a/services/traccar.nix b/services/traccar.nix new file mode 100644 index 0000000..36f7b71 --- /dev/null +++ b/services/traccar.nix @@ -0,0 +1,84 @@ +{ + pkgs, + service_configs, + lib, + ... +}: +{ + imports = [ + (lib.serviceMountWithZpool "traccar" service_configs.zpool_ssds [ + "/var/lib/traccar" + ]) + (lib.serviceFilePerms "traccar" [ + "Z /var/lib/traccar 0700 traccar traccar" + ]) + ]; + + users.users.traccar = { + isSystemUser = true; + group = "traccar"; + home = "/var/lib/traccar"; + description = "Traccar GPS Tracking"; + }; + users.groups.traccar = { }; + + # PostgreSQL database (auto-created, peer auth via Unix socket) + services.postgresql = { + ensureDatabases = [ "traccar" ]; + ensureUsers = [ + { + name = "traccar"; + ensureDBOwnership = true; + } + ]; + }; + + services.traccar = { + enable = true; + + # The JDBC URL contains '$' (Java inner class) and '&' (query param + # separator) which break the NixOS module's XML generator + envsubst. + # Route it through environmentFile so envsubst replaces $TRACCAR_DB_URL + # with the literal value, and use & for valid XML (the XML parser + # decodes it back to & for JDBC). + environmentFile = pkgs.writeText "traccar-db-env" '' + TRACCAR_DB_URL=jdbc:postgresql:///traccar?socketFactory=org.newsclub.net.unix.AFUNIXSocketFactory$FactoryArg&socketFactoryArg=${service_configs.postgres.socket}/.s.PGSQL.5432 + ''; + + settings = { + web.port = toString service_configs.ports.private.traccar_web.port; + + # PostgreSQL via Unix socket (peer auth, junixsocket is bundled) + database = { + driver = "org.postgresql.Driver"; + url = "$TRACCAR_DB_URL"; + user = "traccar"; + password = ""; + }; + + # Only enable OsmAnd protocol (phone app). Prevents Traccar from + # opening 200+ default protocol ports that conflict with other services. + protocols.enable = "osmand"; + osmand.port = toString service_configs.ports.private.traccar_tracking.port; + }; + }; + + # Disable DynamicUser so we can use peer auth with PostgreSQL + systemd.services.traccar = { + after = [ "postgresql.service" ]; + requires = [ "postgresql.service" ]; + serviceConfig = { + DynamicUser = lib.mkForce false; + User = "traccar"; + Group = "traccar"; + }; + }; + + # Route tracking requests (OsmAnd protocol) through Caddy for TLS. + # The phone app connects via HTTPS instead of a separate plain port. + services.caddy.virtualHosts."${service_configs.traccar.domain}".extraConfig = '' + @tracking query id=* + reverse_proxy @tracking :${toString service_configs.ports.private.traccar_tracking.port} + reverse_proxy :${toString service_configs.ports.private.traccar_web.port} + ''; +}