Geopulse - Selfhosted Alternative To Google Timeline - Big Updates
Geopulse - Selfhosted Alternative To Google Timeline - Big Updates
Introduction
In today’s privacy‑conscious era, many homelab enthusiasts and DevOps practitioners are looking for alternatives to cloud‑centric location‑tracking services. The recent surge of interest in self‑hosted solutions has turned tools like GeoPulse into essential components of a privacy‑first infrastructure. If you have ever felt uneasy about entrusting Google with a detailed timeline of your movements, you are not alone. This guide walks you through the latest developments in GeoPulse, explains why it matters for a modern self‑hosted stack, and provides a step‑by‑step walkthrough of installation, configuration, and operational best practices.
By the end of this post you will understand:
- The core purpose of GeoPulse and how it differs from commercial timeline services.
- The evolution of the project from its early versions to the current v1.33.0 release.
- The prerequisites required to run GeoPulse in a homelab environment.
- Detailed installation and configuration procedures, including Docker‑specific commands that respect Jekyll templating constraints.
- Strategies for security hardening, performance tuning, and long‑term maintenance.
- Common troubleshooting techniques and where to find reliable external resources.
Whether you are managing a personal homelab, a small office network, or a larger edge‑computing deployment, the information below will help you evaluate GeoPulse as a viable, open‑source alternative to Google Timeline and integrate it smoothly into your existing infrastructure.
Understanding the Topic
What is GeoPulse?
GeoPulse is an open‑source, self‑hosted service that ingests GPS‑derived location data, normalizes it, and stores it in a time‑series database for later querying. Unlike Google Timeline, which aggregates location history on Google’s servers, GeoPulse keeps all data under your control, offering full transparency and compliance with data‑privacy regulations.
Key functional blocks include:
- Data ingestion – Accepts JSON or CSV payloads from mobile clients, IoT gateways, or custom scripts.
- Time‑series storage – Uses SQLite or PostgreSQL (configurable) to maintain a chronological record of points.
- Query API – Provides RESTful endpoints for retrieving filtered location histories, supporting pagination and sorting.
- Visualization – Optional web UI that renders maps and timelines using OpenStreetMap tiles.
Historical Development
The project began as a hobby experiment in early 2022, initially released as v1.0 with a single‑file Docker image. Since then, the maintainer community has contributed over 250 commits, pushing the version number to v1.33.0. Each release introduced refinements such as:
- Support for multi‑arch Docker images (amd64, arm64).
- Integration with Prometheus metrics for health monitoring.
- Enhanced CSV import capabilities.
- Introduction of a migration layer for SQLite‑to‑PostgreSQL upgrades.
The GitHub repository now sits at nearly 1,000 stars, reflecting growing adoption in the self‑hosted ecosystem.
Core Features and Capabilities
| Feature | Description | Benefit |
|---|---|---|
| Privacy‑first design | All data stored on‑premises; no external telemetry. | Eliminates third‑party data exposure. |
| Multi‑backend storage | Configurable SQLite (default) or PostgreSQL for larger deployments. | Scales from homelab to small‑business use cases. |
| OpenAPI‑compatible API | REST endpoints follow OpenAPI 3.0 spec. | Easy integration with third‑party clients. |
| Docker‑native deployment | Official images tagged with semantic versions. | Simplifies CI/CD pipelines and version control. |
| Prometheus exporter | Exposes /metrics for scraping. | Enables proactive monitoring and alerting. |
| Web UI (optional) | Minimalist frontend built with React and Leaflet. | Provides quick visual inspection of location history. |
Pros and Cons
Pros
- Full control over data residency and retention policies.
- Transparent codebase; community‑driven development.
- Lightweight Docker image (< 150 MB) suitable for resource‑constrained devices.
- Active release cadence with backward‑compatible version bumps.
Cons
- No built‑in end‑to‑end encryption for data in transit (requires TLS termination at the reverse proxy).
- UI is functional but not as feature‑rich as commercial alternatives.
- Requires manual setup of reverse proxy and TLS certificates for external access.
Use Cases and Scenarios
- Personal homelab – Track family members’ commutes without relying on Google services.
- Edge IoT deployments – Collect location data from fleet vehicles or delivery drones.
- Privacy‑focused research – Analyze movement patterns while complying with GDPR or CCPA.
- Educational labs – Demonstrate time‑series databases and API design in a controlled environment.
Comparison to Alternatives
| Solution | Hosting Model | Primary Language | Database | Notable Limitation |
|---|---|---|---|---|
| GeoPulse | Self‑hosted (Docker) | Go | SQLite / PostgreSQL | Limited UI polish |
| OpenTracks | Self‑hosted (Java) | Java | SQLite | No built‑in API |
| Strava API (self‑hosted) | Self‑hosted (Node) | Node.js | MySQL | Primarily sports‑focused |
| Google Timeline (cloud) | Cloud‑only | – | Proprietary | Data stored on Google servers |
GeoPulse stands out for its balance of simplicity, configurability, and community support, making it a strong candidate for anyone seeking a privacy‑centric timeline service.
Prerequisites
System Requirements
| Component | Minimum Specification | Recommended Specification |
|---|---|---|
| CPU | 1 vCPU | 2 vCPUs |
| RAM | 1 GB | 2 GB |
| Storage | 2 GB SSD | 10 GB SSD (for long‑term history) |
| OS | Linux (Ubuntu 22.04, Debian 12) | Any modern 64‑bit Linux distribution |
| Network | Outbound internet access for Docker pulls | Static public IP or dynamic DNS for external access |
Required Software
- Docker Engine ≥ 24.0 (Community Edition)
- Docker Compose ≥ 2.20 (optional, but recommended)
curlandjqfor API testingnginxorcaddyas a reverse proxy (for TLS termination)certbotor equivalent for automated TLS certificate issuance
Network and Security Considerations
- Port exposure – The GeoPulse container listens on port 8080 internally; external traffic must be routed through a reverse proxy.
- Firewall rules – Allow inbound traffic only on ports 80 and 443 for HTTP/HTTPS, and restrict access to management ports (e.g., 2375) to trusted hosts.
- User permissions – Run the container under a non‑root user (
$CONTAINER_USER) to limit privilege escalation.
Pre‑Installation Checklist
- Verify Docker Engine is up‑to‑date (
docker version). - Create a dedicated system user for running containers (
adduser --system --group geopulse). - Reserve a directory for persistent data (
mkdir -p /opt/geopulse/data). - Generate TLS certificates for your domain (
certbot certonly --standalone -d geopulse.example.com). - Ensure DNS A record points to your server’s public IP.
Installation & Setup
Pulling the Official Image
The maintainer publishes multi‑arch images tagged with the semantic version. The following command fetches the latest stable release (v1.33.0) and stores it in a local repository:
1
docker pull ghcr.io/geopulse/geopulse:$CONTAINER_IMAGE
$CONTAINER_IMAGEresolves tov1.33.0at runtime, ensuring you always pull the intended version.
Docker Run Command
Below is a production‑ready docker run invocation that incorporates best practices for restart policy, resource limits, and environment variable configuration:
1
2
3
4
5
6
7
8
9
10
11
docker run -d \
--name $CONTAINER_NAME \
--restart unless-stopped \
--cpus="1.5" \
--memory="1g" \
-p 8080:8080 \
-e DATABASE_URL="postgres://geopulse:password@postgres:5432/geopulse?sslmode=disable" \
-e ENABLE_UI=true \
-e LOG_LEVEL=info \
-v /opt/geopulse/data:/app/data \
$CONTAINER_IMAGE
Explanation of key flags:
--restart unless-stopped– Guarantees automatic recovery after host reboots.--cpusand--memory– Constrain resource usage to prevent contention with other services.-p 8080:8080– Maps the internal HTTP port to the host’s port 8080; the reverse proxy will handle external routing.DATABASE_URL– Points to a PostgreSQL instance; adjust credentials and hostnames as needed.ENABLE_UI– Enables the optional web UI; set tofalsefor API‑only deployments.-v /opt/geopulse/data:/app/data– Persists location data across container upgrades.
Docker Compose Alternative
For environments that already use Compose, the following docker-compose.yml snippet provides a declarative approach:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
version: "3.9"
services:
geopulse:
image: ghcr.io/geopulse/geopulse:$CONTAINER_IMAGE
container_name: $CONTAINER_NAME
restart: unless-stopped
ports:
- "8080:8080"
environment:
DATABASE_URL: "postgres://geopulse:password@postgres:5432/geopulse?sslmode=disable"
ENABLE_UI: "true"
LOG_LEVEL: "info"
volumes:
- /opt/geopulse/data:/app/data
deploy:
resources:
limits:
cpus: "1.5"
memory: "1g"
Replace $CONTAINER_IMAGE, $CONTAINER_NAME, and other placeholders with concrete values before applying.
Initializing the Database
If you opt for PostgreSQL, run the following migration command after the container starts:
1
docker exec -it $CONTAINER_NAME geopulse db migrate --url $DATABASE_URL
The command executes the built‑in migration tool, creating necessary tables and indexes. Subsequent upgrades can be performed with the same command, ensuring schema compatibility across versions.
Verifying the Deployment
Health check – Query the
/healthendpoint to confirm the service is operational:1
curl -s http://localhost:8080/health | jq .
Expected output includes
"status":"ok"and a version field matching$CONTAINER_IMAGE.API test – Retrieve a sample location record (replace with your own auth token if applicable):
1
curl -H "Authorization: Bearer $API_TOKEN" http://localhost:8080/api/v1/locations?limit=5
UI access – Navigate to
https://geopulse.example.com/ui(orhttp://localhost:8080/uifor local testing) to view the interactive map.
If any of these steps fail, consult the container logs (docker logs $CONTAINER_NAME) for detailed error messages.
Common Installation Pitfalls
| Issue | Symptom | Resolution |
|---|---|---|
| Port conflict | bind: address already in use | Change host port mapping (-p 8081:8080) and update reverse proxy configuration. |
| Database connection failure | connection refused | Verify that the PostgreSQL container is reachable (docker network inspect <network>). |
| Missing environment variables | undefined variable errors in logs | Double‑check .env file or Compose environment section for typos. |
| Permission denied on data volume | permission denied when mounting | Ensure the host directory is owned by the container user (chown -R 1000:1000 /opt/geopulse/data). |
Configuration & Optimization
Configuration File Overview
GeoPulse reads a YAML file located at /app/config/config.yaml. Below is a representative example with inline comments:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# /app/config/config.yaml
server:
port: 8080
read_timeout: 30s
write_timeout: 30s
database:
type: postgres
url: "postgres://geopulse:password@postgres:5432/geopulse?sslmode=disable"
auth:
jwt_secret: "a-very-long-random-string"
token_expiration: "24h"
storage:
path: "/app/data"
max_file_size_mb: 250
ui:
enable: true
map_style: "osm-bright"
logging:
level: "info"
output: "stdout"
format: "json"
Key sections explained:
- server – Controls the HTTP server’s binding and timeout behavior. Adjust
read_timeoutfor large payloads. - database – Determines the backend; switch to SQLite by setting
type: sqliteand providing apath. - auth – Configures JWT signing; use a strong secret generated via
openssl rand -hex 32. - storage – Governs file‑based limits; increasing
max_file_size_mballows longer retention periods. - ui – Toggles the optional web UI and selects a map style.
- logging – Switches between human‑readable and JSON formats; JSON is preferred for log aggregation tools.
Security Hardening
TLS Termination – Terminate TLS at the reverse proxy (nginx or caddy) and forward only plain HTTP to the container. Example nginx snippet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
server { listen 443 ssl; server_name geopulse.example.com; ssl_certificate /etc/letsencrypt/live/geopulse.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/geopulse.example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
Rate Limiting – Apply per‑IP request caps to mitigate abuse:
1 2 3
limit_req_zone $binary_remote_addr zone=geopulse_limit:10m rate=30r/m; location /api/ { limit_req zone=geopulse_limit burst=