FleetOps ↗ Live
A real-time fleet management system — from GPS hardware to web dashboard — built entirely in Rust.
The problem
Fleet operators needed to track vehicles in real time, with reliable data transmission from moving hardware to a central server. Existing solutions were either expensive SaaS platforms with lock-in, or open-source tools that couldn't be customised for the client's specific compliance and infrastructure requirements. The system also needed to run securely on low-cost embedded hardware mounted in vehicles.
What we built
A complete fleet management platform across five Rust binaries in a single Cargo workspace:
- Tracker — a Rust binary targeting Raspberry Pi. Reads NMEA sentences from a serial GPS, packages each fix into a
TrackerPacket, compresses with Zstd, encrypts with AES-256-GCM, and fires it over UDP. The release profile is tuned for binary size (opt-level = "s") so it fits comfortably on the Pi. - UDP Ingestor — receives encrypted packets, decrypts and decompresses on the critical path using
rkyvzero-copy deserialization, validates freshness (rejects packets older than 60 seconds), resolves the vehicle ID from a Moka in-memory cache backed by PostgreSQL, and writes the location as a PostGISGEOGRAPHYpoint. Per-IP rate limiting viagovernorand a semaphore cap prevent overload. - API — an Axum REST server with JWT authentication, fine-grained RBAC using bitflags (permissions like
MANAGE_USERS,DASHBOARD_ACCESS), Redis-backed token revocation, and PostGIS spatial queries for proximity searches and bounding-box lookups. - Admin frontend — a Leptos single-page application compiled to WebAssembly via Trunk. Same language as the backend, same types shared through the workspace. JWT stored in an HTTP-only cookie with automatic token refresh.
- Infrastructure — Podman Quadlets (rootless, systemd-managed containers) on Hetzner. Nginx handles SSL termination, reverse proxying for the API, and UDP load balancing across multiple ingestor instances. Forgejo Actions deploys staging on every push to
developand production on release frommain.
Key technical decisions
GPS fixes are fire-and-forget. UDP eliminates TLS handshakes and TCP overhead on the embedded side, keeping the tracker simple and the latency low.
Authenticated encryption on every packet means a rogue server cannot inject fake location data. Zstd compression at level 3 roughly halves payload size with negligible CPU cost.
On the ingestor's hot path, deserializing without allocating keeps throughput high when multiple packets arrive simultaneously.
Storing coordinates as GEOGRAPHY points unlocks ST_DWithin proximity queries and bounding-box lookups with proper index support — no home-grown geospatial math required.
Sharing types between the API and the admin panel via the workspace means the compiler catches mismatches before they reach staging. No TypeScript, no runtime surprises.
Rootless Podman containers managed by systemd restart automatically on crash and survive reboots with no daemon required. Read-only root filesystems reduce the blast radius of any compromise.