Page 1 : Installation
Depuis la fin 2024, Google a discrètement sabordé l'un des rares trucs sympas qu'il nous offrait gratuitement : l'accès à l'historique de ses trajets depuis un navigateur PC. Désormais, « Vos trajets » ne vit plus que sur votre téléphone, les données sont stockées localement sur l'appareil, et la version web a tout bonnement disparu. Aucune annonce fracassante, juste une fonctionnalité qui s'évapore, à la Google. Et clairement pour le quadra que je suis, l'écran du téléphone, c'est vraiment moins pratique qu'un 24 pouces !
C'est en cherchant une alternative que je suis tombé sur Dawarich, un projet open source qui se présente comme « votre alternative auto-hébergeable à Google Timeline ». Le principe : vous installez ça sur votre propre serveur, vous importez votre historique Google, et vous retrouvez une interface web complète pour consulter vos trajets depuis n'importe quel navigateur. Avec, en prime, un tracking continu automatique via une app mobile.
Parce que ça m'a tenu éveillé plusieurs heures, et parce que j'ai documenté chaque piège au fur et à mesure, voici le tuto complet pour installer Dawarich sur un NAS Synology avec accès HTTPS via un sous-domaine perso chez OVH.
Prérequis
Ce tuto suppose que vous avez :
- Un NAS Synology sous DSM 7 ou supérieur
- Le Container Manager installé (l'ancienne appli Docker de Synology)
- Un accès SSH au NAS
- Un domaine chez OVH
- acme.sh déjà installé sur le NAS (si ce n'est pas le cas, consultez le tutoriel d'Anthony Jacob)
Si vous avez déjà suivi ma brève sur FreshRSS, vous avez tout ce qu'il faut. La procédure est similaire dans l'esprit, un peu plus complexe dans les détails car Dawarich tourne sur 4 containers interdépendants au lieu d'un seul.
Étape 1 : Créer les dossiers dans File Station
Dans File Station, naviguez jusqu'à /volume1/docker/ et créez la structure suivante :
/volume1/docker/dawarich/
├── db/ ← données PostgreSQL
├── db_shared/ ← données partagées base de données
├── redis/ ← cache Redis
├── public/ ← fichiers statiques de l'interface
├── storage/ ← fichiers importés
└── watched/ ← dossier d'import automatique
Étape 2 : Créer le docker-compose.yml
Dawarich ne se déploie pas comme un container unique : il en fait tourner quatre en parallèle. La base de données PostGIS, le cache Redis, l'application Rails, et Sidekiq pour les tâches de fond. C'est pour ça qu'on passe par le mode Projet du Container Manager plutôt que par l'interface graphique classique.
Créez le fichier /volume1/docker/dawarich/docker-compose.yml :
name: dawarich
services:
dawarich_db:
image: postgis/postgis:17-3.5-alpine
container_name: dawarich_db
shm_size: 1G
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d dawarich_development"]
interval: 10s
retries: 5
start_period: 30s
timeout: 10s
volumes:
- /volume1/docker/dawarich/db:/var/lib/postgresql/data
- /volume1/docker/dawarich/db_shared:/var/shared
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: UnMotDePasseSolide
POSTGRES_DB: dawarich_development
dawarich_redis:
image: redis:7.4-alpine
container_name: dawarich_redis
command: redis-server --stop-writes-on-bgsave-error no --save ""
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "redis-cli ping || exit 1"]
volumes:
- /volume1/docker/dawarich/redis:/data
dawarich_app:
image: freikin/dawarich:latest
container_name: dawarich_app
restart: unless-stopped
depends_on:
dawarich_db:
condition: service_healthy
dawarich_redis:
condition: service_healthy
ports:
- "3765:3000"
volumes:
- /volume1/docker/dawarich/public:/var/app/public
- /volume1/docker/dawarich/storage:/var/app/storage
- /volume1/docker/dawarich/watched:/var/app/tmp/imports/watched
env_file:
- .env
environment:
- LANG=fr_FR.UTF-8
- LC_ALL=fr_FR.UTF-8
- RAILS_LOCALE=fr
entrypoint: web-entrypoint.sh
command: bin/rails server -b 0.0.0.0 -p 3000
dawarich_sidekiq:
image: freikin/dawarich:latest
container_name: dawarich_sidekiq
restart: unless-stopped
depends_on:
dawarich_db:
condition: service_healthy
dawarich_redis:
condition: service_healthy
volumes:
- /volume1/docker/dawarich/public:/var/app/public
- /volume1/docker/dawarich/storage:/var/app/storage
- /volume1/docker/dawarich/watched:/var/app/tmp/imports/watched
env_file:
- .env
environment:
- LANG=fr_FR.UTF-8
- LC_ALL=fr_FR.UTF-8
- RAILS_LOCALE=fr
entrypoint: sidekiq-entrypoint.sh
command: bundle exec sidekiq
Le port 3765 est arbitraire, choisissez-en un autre s'il est déjà occupé sur votre NAS.
⚠️ Note sur la ligne command de Redis : les deux options --stop-writes-on-bgsave-error no --save "" sont indispensables sur NAS Synology. Sans elles, Redis panique s'il n'arrive pas à écrire son snapshot sur le disque et bloque toutes les écritures, y compris les jobs d'import. Le --save "" désactive les snapshots RDB : Redis n'est ici qu'une file de jobs temporaires, pas une base de données à persister sur disque.
Créez ensuite le fichier /volume1/docker/dawarich/.env dans le même dossier :
RAILS_ENV=development
APPLICATION_HOSTS=trajets.votredomaine.fr,localhost
APPLICATION_PROTOCOL=http
TIME_ZONE=Europe/Paris
LANG=fr
MIN_MINUTES_SPENT_IN_CITY=60
BACKGROUND_PROCESSING_CONCURRENCY=15
DATABASE_HOST=dawarich_db
DATABASE_USERNAME=postgres
DATABASE_PASSWORD=UnMotDePasseSolide
DATABASE_NAME=dawarich_development
REDIS_URL=redis://dawarich_redis:6379/0
⚠️ Point important : laissez APPLICATION_PROTOCOL=http même si l'accès public sera en HTTPS. La terminaison SSL est gérée par le reverse proxy DSM, si vous mettez https ici, vous obtenez une boucle de redirection infinie qui casse tout. Voilà, je vous ai épargné 20 minutes de debug.
Étape 3 : Lancer le projet dans Container Manager
Dans Container Manager, allez dans Projets → Créer :
- Nom du projet : dawarich
- Chemin : /volume1/docker/dawarich
- Quand DSM demande quoi faire du fichier existant : "Utiliser le docker-compose.yml existant"
- Sur l'écran "Paramètres du portail Web" : décochez "Configurer le portail Web via Web Station", vous n'en avez pas besoin, le reverse proxy DSM s'en chargera
- Cliquez Terminer
Les images se téléchargent, les containers démarrent. Attendez 3 à 5 minutes. Les quatre containers (dawarich_db, dawarich_redis, dawarich_app, dawarich_sidekiq) doivent tous passer en vert. Il est normal que dawarich_app reste en attente quelques instants : il attend que la base de données soit prête avant de démarrer.
Testez en local : http://IP-de-votre-NAS:3765 doit afficher la page de connexion Dawarich.
Étape 4 : Entrée DNS chez OVH
Avant de demander un certificat, il faut que le domaine pointe quelque part. Dans votre espace client OVH, deux options selon votre configuration :
Si vous utilisez le DNS standard OVH (zone DNS) : Domaines → votredomaine.fr → Zone DNS → Ajouter une entrée A avec trajets comme sous-domaine et votre IP publique comme cible.
Si vous utilisez DynHost (comme c'est mon cas pour gérer une IP qui peut changer) : Domaines → votredomaine.fr → DynHost → Ajouter un DynHost avec trajets comme sous-domaine. Pensez aussi à mettre à jour votre script de mise à jour DynHost pour inclure ce nouveau sous-domaine.
Attendez quelques minutes que le DNS se propage, puis vérifiez avec un ping trajets.votredomaine.fr.
Étape 5 : Certificat Let's Encrypt via acme.sh
Puisque notre NAS est derrière un reverse proxy, on ne peut pas utiliser le challenge HTTP intégré à DSM, il a besoin que le port 80 soit directement accessible, ce qui n'est pas toujours le cas. On passe donc par le DNS challenge via l'API OVH, qui ne nécessite aucune ouverture de port. Deux situations possibles selon votre historique.
Scénario A : Vous avez déjà acme.sh et des clés API OVH (par exemple pour FreshRSS)
Bonne nouvelle : une seule clé API OVH suffit pour tous vos sous-domaines du même compte. Les droits /domain/zone/* couvrent toute la zone DNS, inutile d'en créer de nouvelles. Connectez-vous en SSH avec votre utilisateur acme.sh et lancez directement :
./acme.sh --issue
-d trajets.votredomaine.fr
--dns dns_ovh
--server letsencrypt
--keylength 2048
acme.sh récupère automatiquement les clés OVH déjà enregistrées dans son fichier account.conf. Pas besoin de les ré-exporter.
Scénario B : Vous partez de zéro (première installation)
Il faut d'abord créer les clés API OVH sur eu.api.ovh.com/createToken/. Les droits nécessaires sont :
- GET /auth/time
- GET /domain
- GET /domain/zone/*
- GET /domain/zone/*/record
- PUT /domain/zone/*/record/*
- POST /domain/zone/*/record
- POST /domain/zone/*/refresh
- DELETE /domain/zone/*/record/* ← ne pas oublier celui-ci
⚠️ Mettez la durée de validité sur Unlimited. Avec "1 day", vos clés expirent le lendemain et le renouvellement automatique dans 90 jours échoue silencieusement.
⚠️ Le droit DELETE /domain/zone/*/record/* est celui que les gens oublient le plus souvent. Sans lui, acme.sh crée bien l'enregistrement TXT de validation mais ne peut pas le supprimer ensuite, ce qui fait échouer la vérification avec une erreur cryptique "Add txt record error". Si vous avez cette erreur, c'est presque certainement ça.
Puis lancez :
export OVH_AK="votre_application_key"
export OVH_AS="votre_application_secret"
export OVH_CK="votre_consumer_key"
./acme.sh --issue
-d trajets.votredomaine.fr
--dns dns_ovh
--server letsencrypt
--keylength 2048
Déploiement du certificat sur DSM (commun aux deux scénarios)
Une fois le certificat généré, déployez-le sur DSM. Le point important ici : nommez explicitement le certificat avec SYNO_CERTIFICATE pour éviter qu'il n'écrase un certificat existant (FreshRSS par exemple).
export SYNO_USERNAME='votre_user_admin_dsm'
export SYNO_PASSWORD='MotDePasseAdmin'
export SYNO_HOSTNAME="votre_quickid.synology.me"
export SYNO_SCHEME="https"
export SYNO_PORT="5001"
export SYNO_CERTIFICATE="trajets.votredomaine.fr"
export SYNO_CREATE=1
./acme.sh --deploy
--home /var/services/homes/VotreUser/.acme.sh/
-d trajets.votredomaine.fr
--deploy-hook synology_dsm
Le paramètre SYNO_CREATE=1 force la création d'un nouveau certificat plutôt que le remplacement d'un existant. Sans lui, si votre account.conf contient un SYNO_CERTIFICATE par défaut hérité d'une installation précédente, le déploiement écrase le mauvais certificat.
Ajoutez ensuite ces deux commandes à votre tâche planifiée existante pour le renouvellement automatique tous les 90 jours.
Étape 6 : Reverse proxy DSM
Dans Panneau de configuration → Portail de connexion → Proxy inversé → Créer :
| Champ | Valeur |
|---|---|
| Protocole source | HTTPS |
| Hostname source | trajets.votredomaine.fr |
| Port source | 443 |
| Protocole destination | HTTP |
| Hostname destination | localhost |
| Port destination | 3765 |
Dans l'onglet En-têtes personnalisés, cliquez Créer → WebSocket pour ajouter les deux headers WebSocket automatiquement. Dawarich en a besoin pour les mises à jour en temps réel de l'interface.
Étape 7 : Assigner le certificat (LE piège qui m'a coûté 2 heures)
C'est l'étape que personne ne mentionne dans les tutos, et c'est pourtant elle qui a failli me faire abandonner. Vous avez un certificat valide, un reverse proxy correctement configuré, et pourtant votre navigateur affiche une erreur SSL avec le certificat par défaut de Synology. Explication : DSM ne sert pas automatiquement le bon certificat au bon service. Il faut lui dire explicitement.
Allez dans Panneau de configuration → Sécurité → Certificat. Cliquez sur le bouton Paramètres (en haut à droite). Dans la liste qui s'affiche, trouvez la ligne correspondant à trajets.votredomaine.fr et sélectionnez dans la colonne "Certificat" votre certificat Let's Encrypt dédié. Appliquez.
C'est tout. Et pourtant c'est ça qui m'a bloqué le plus longtemps. Les certificats étaient parfaitement générés et déployés depuis le début, ils n'étaient juste pas assignés au bon service. DSM continuait à servir son certificat Synology par défaut, d'où l'erreur SSL.
Test final
Pour vérifier que tout est en ordre, depuis un terminal :
curl -I https://trajets.votredomaine.fr
Vous devez obtenir HTTP/2 200. Dans Firefox : aucune erreur SSL, cadenas fermé dans la barre d'adresse. Si vous voyez encore une alerte de sécurité malgré tout, videz le cache SSL du navigateur avec Ctrl+Shift+R, Firefox est parfois têtu sur ce point.
Premier accès et import de l'historique Google
Naviguez sur https://trajets.votredomaine.fr. Les identifiants par défaut sont demo@dawarich.app / password. Changez le mot de passe immédiatement dans les paramètres du compte.
Pour importer votre historique Google, il faut d'abord l'exporter depuis votre téléphone. Et c'est là que Google a fait fort en termes d'ergonomie inversée.
Sur Android, ils ont sorti le bouton d'export de l'application Google Maps pour l'enterrer dans les paramètres système :
- Quittez Google Maps et ouvrez l'application Paramètres de votre téléphone
- Appuyez sur Position (ou Localisation)
- Appuyez sur Services de localisation
- Cherchez et sélectionnez Vos trajets (ou Google - Vos trajets)
- Vous trouverez enfin l'option Exporter les données de vos trajets
Sur iOS, c'est heureusement resté dans Google Maps : photo de profil → Paramètres → Confidentialité et localisation → Exporter les données de vos trajets.
Le fichier généré s'appelle Timeline.json sur Android ou location-history.json sur iOS. Transférez-le sur votre PC puis importez-le dans Dawarich via le menu Import de l'interface web. Dawarich accepte les deux formats sans manipulation.
Cas des gros fichiers : le mur de la RAM
L'interface web fonctionne très bien pour les fichiers légers. En revanche, si vous avez plusieurs années d'historique, votre fichier peut dépasser les 100 Mo, et là, les ennuis commencent. Sur un NAS équipé de 2 Go de RAM comme le DS220+, j'ai découvert à mes dépens qu'il ne suffit pas de contourner le timeout du navigateur : c'est le NAS lui-même qui capitule.
Le symptôme est traître : l'import reste bloqué sur "Created" dans l'interface, le compteur de points reste désespérément à zéro, et les logs de dawarich_sidekiq affichent des erreurs Connection timed out sur Redis. La cause est mécanique : le parser JSON de Ruby charge l'intégralité du fichier en mémoire avant de commencer à le traiter. Un fichier de 94 Mo peut ainsi réclamer plus d'1 Go de RAM rien que pour être lu, ce qui, sur un NAS qui fait déjà tourner DSM, PostgreSQL et Redis, provoque un freeze en règle et la coupure en cascade des containers Docker.
La solution n'est pas de compresser le fichier, mais de le découper. On passe d'un seul bloc indigeste à une série de petits fichiers que le NAS peut traiter séquentiellement, sans jamais saturer la mémoire.
Étape A : Préparer le script de conversion
Autre surprise de taille : Google a silencieusement changé le format de ses exports en 2024. L'ancien format utilisait une clé locations avec des coordonnées en entiers (latitudeE7, longitudeE7) et des timestamps en millisecondes. Le nouveau format, lui, s'appelle semanticSegments et stocke les coordonnées sous forme de chaînes de caractères ("45.763523°, 4.853053°") réparties dans plusieurs types d'entrées : timelinePath pour les points de trajet, visit pour les lieux visités, activity pour les déplacements, et position pour les positions brutes. Dawarich ne reconnaît pas ce nouveau format nativement, il faut donc le convertir avant l'import.
Voici le script Python qui s'occupe des deux opérations à la fois : conversion du format Google 2024 vers le format locations attendu par Dawarich, et découpage en fichiers de 20 000 points :
import json
import os
import sys
from datetime import datetime, timezone
INPUT_FILE = "histo.json"
OUTPUT_DIR = "chunks"
POINTS_PER_FILE = 20000
def parse_latlng(s):
if not s:
return None
cleaned = s.replace('°', '').replace(' ', '')
parts = cleaned.split(',')
if len(parts) != 2:
return None
try:
lat = float(parts[0])
lng = float(parts[1])
if not (-90 <= lat <= 90) or not (-180 <= lng <= 180):
return None
return int(lat * 1e7), int(lng * 1e7)
except ValueError:
return None
def parse_timestamp(ts_str):
if not ts_str:
return None
try:
ts_clean = ts_str.replace('Z', '+00:00')
dt = datetime.fromisoformat(ts_clean)
return int(dt.timestamp() * 1000)
except Exception:
return None
def ts_to_iso(ts_ms):
dt = datetime.fromtimestamp(ts_ms / 1000, tz=timezone.utc)
return dt.strftime('%Y-%m-%dT%H:%M:%S.000Z')
def extract_points_from_segment(segment):
points = []
if 'timelinePath' in segment:
for path_point in segment['timelinePath']:
coords = parse_latlng(path_point.get('point'))
ts_ms = parse_timestamp(path_point.get('time'))
if coords and ts_ms:
lat_e7, lng_e7 = coords
points.append({
"latitudeE7": lat_e7, "longitudeE7": lng_e7,
"timestamp": ts_to_iso(ts_ms), "accuracy": 50
})
if 'visit' in segment:
visit = segment['visit']
top = visit.get('topCandidate', {})
coords = parse_latlng(top.get('placeLocation', {}).get('latLng'))
ts_start = parse_timestamp(segment.get('startTime'))
ts_end = parse_timestamp(segment.get('endTime'))
if coords and ts_start:
lat_e7, lng_e7 = coords
ts_ms = ts_start if not ts_end else (ts_start + ts_end) // 2
points.append({
"latitudeE7": lat_e7, "longitudeE7": lng_e7,
"timestamp": ts_to_iso(ts_ms), "accuracy": 100
})
if 'activity' in segment:
activity = segment['activity']
for loc_key, time_key in [('start', 'startTime'), ('end', 'endTime')]:
coords = parse_latlng(activity.get(loc_key, {}).get('latLng'))
ts_ms = parse_timestamp(segment.get(time_key))
if coords and ts_ms:
lat_e7, lng_e7 = coords
points.append({
"latitudeE7": lat_e7, "longitudeE7": lng_e7,
"timestamp": ts_to_iso(ts_ms), "accuracy": 50
})
if 'position' in segment:
pos = segment['position']
coords = parse_latlng(pos.get('LatLng'))
ts_ms = parse_timestamp(pos.get('timestamp'))
if coords and ts_ms:
lat_e7, lng_e7 = coords
point = {
"latitudeE7": lat_e7, "longitudeE7": lng_e7,
"timestamp": ts_to_iso(ts_ms),
"accuracy": int(pos.get('accuracyMeters', 50))
}
if 'altitudeMeters' in pos:
point['altitude'] = pos['altitudeMeters']
points.append(point)
return points
def convert_and_split(input_file, output_dir, points_per_file):
print(f"Chargement de {input_file}...")
with open(input_file, 'r', encoding='utf-8') as f:
data = json.load(f)
segments = data.get('semanticSegments', [])
print(f"{len(segments)} segments trouvés. Extraction en cours...")
all_points = []
for i, segment in enumerate(segments):
all_points.extend(extract_points_from_segment(segment))
if (i + 1) % 5000 == 0:
print(f" ... {i+1}/{len(segments)} segments ({len(all_points)} points)")
all_points.sort(key=lambda p: p.get('timestamp', ''))
seen = set()
unique_points = []
for p in all_points:
key = (p['timestamp'], p['latitudeE7'], p['longitudeE7'])
if key not in seen:
seen.add(key)
unique_points.append(p)
print(f"{len(unique_points)} points uniques après dédoublonnage.")
os.makedirs(output_dir, exist_ok=True)
for i, start in enumerate(range(0, len(unique_points), points_per_file)):
chunk = {"locations": unique_points[start:start + points_per_file]}
filename = os.path.join(output_dir, f"dawarich_part_{i:04d}.json")
with open(filename, 'w', encoding='utf-8') as f:
json.dump(chunk, f, ensure_ascii=False, separators=(',', ':'))
print(f" ✅ {filename} ({len(chunk['locations'])} points)")
print(f"nTerminé : {i+1} fichiers créés dans /{output_dir}/")
if __name__ == "__main__":
convert_and_split(
sys.argv[1] if len(sys.argv) > 1 else INPUT_FILE,
sys.argv[2] if len(sys.argv) > 2 else OUTPUT_DIR,
int(sys.argv[3]) if len(sys.argv) > 3 else POINTS_PER_FILE
)
Lancez-le depuis votre PC (Python 3.7+ requis, aucune dépendance externe) :
python convert_google.py
Le script produit une série de fichiers dawarich_part_0000.json, dawarich_part_0001.json, etc. dans un sous-dossier chunks/. Chaque fichier pèse environ 3 Mo une fois minifié, une taille que le NAS digère sans effort. La minification (suppression des espaces inutiles dans le JSON) réduit le poids des fichiers d'environ 80% sans perdre aucune donnée de géolocalisation.
Étape B : Déposer les fichiers dans le dossier watched
Copiez l'ensemble des fichiers chunks/ directement dans le dossier watched de votre installation :
/volume1/docker/dawarich/watched/
Vous pouvez le faire via File Station par glisser-déposer, ou via SSH avec scp depuis votre PC.
Étape C : Vérifier que Redis est opérationnel
Si vous avez suivi l'étape 2 de ce tuto et copié le docker-compose.yml tel quel, Redis est déjà correctement configuré grâce aux options --stop-writes-on-bgsave-error no --save "" dans la ligne command. Ces options sont persistantes : elles survivent aux redémarrages du NAS et des containers.
Si vous avez une installation existante avec l'ancien docker-compose.yml, vérifiez que la ligne a bien été mise à jour, puis appliquez la modification :
cd /volume1/docker/dawarich
sudo docker compose stop dawarich_redis
sudo docker compose rm -f dawarich_redis
sudo rm -f /volume1/docker/dawarich/redis/dump.rdb
sudo docker compose up -d dawarich_redis
Pour confirmer que Redis est sain avant de lancer l'import :
sudo docker exec dawarich_redis redis-cli config get stop-writes-on-bgsave-error
# doit retourner : no
sudo docker exec dawarich_redis redis-cli ping
# doit retourner : PONG
Sur le système hôte, ajoutez également cette commande pour éviter les avertissements mémoire de Redis :
sudo sysctl vm.overcommit_memory=1
Étape D : Lancer les imports en mode "Bulldozer" (la méthode qui fonctionne sur DS220+)
L'interface web et les commandes d'import classiques utilisent Sidekiq et Redis. Sur un NAS avec peu de RAM comme le DS220+, c'est la recette assurée pour un crash. On va donc utiliser le "mode Bulldozer" : on court-circuite la file d'attente pour exécuter les tâches directement en mémoire, une par une.
Ouvrez un terminal SSH et lancez ce script unique. Il va scanner votre dossier, ignorer ce qui est déjà fait, et traiter le reste avec une pause de 30 secondes entre chaque fichier pour laisser le NAS "respirer" :
sudo docker exec -it dawarich_app bin/rails runner "
user = User.find_by(email: 'votre@email.fr')
dir = '/var/app/tmp/imports/watched'
Dir.glob("#{dir}/dawarich_part_*.json").sort.each do |path|
name = File.basename(path)
# On saute ce qui est déjà terminé
if Import.exists?(user: user, name: name, status: 'completed')
puts "⏭️ Déjà fait : #{name}"
next
end
# Nettoyage des anciennes tentatives bloquées
Import.where(user: user, name: name).destroy_all
import = Import.new(name: name, user: user, source: :google_records)
import.file.attach(io: File.open(path), filename: name, content_type: 'application/json')
if import.save
puts "n🚀 Traitement de #{name}..."
begin
# Le secret : perform_now au lieu de perform_later
Import::ProcessJob.perform_now(import.id)
import.reload
puts "✅ Terminé : #{name} → #{import.points_count || 0} points."
# Crucial pour la survie de la RAM sur le NAS
sleep 30
rescue => e
puts "❌ Erreur sur #{name} : #{e.message}"
end
end
end
puts "n🏆 Import global terminé !"
"
Contrairement à la méthode officielle qui envoie les données dans Redis (le maillon faible sur NAS), perform_now exécute le code directement dans le processus Rails.
- Zéro concurrence : on traite un fichier à la fois, séquentiellement.
- Zéro dépendance Redis : on ne dépend plus de la stabilité du cache pour l'import.
- Gestion de la RAM : le
sleep 30permet au Garbage Collector de Ruby de libérer la mémoire vive entre chaque chunk. - Reprise automatique : si le script est interrompu, il reprend là où il en était au prochain lancement grâce au contrôle du statut
completed.
Pour vérifier l'avancement de vos points en temps réel dans un autre terminal :
sudo docker exec dawarich_app bin/rails runner "puts User.find_by(email: 'votre@email.fr').points.count"
Étape E : Méthode alternative via Sidekiq (serveurs avec plus de RAM)
Si votre machine dispose de suffisamment de RAM (4 Go ou plus), vous pouvez utiliser la méthode originale basée sur Sidekiq, plus rapide car elle traite plusieurs fichiers en parallèle. Pour chaque fichier chunk, lancez :
sudo docker exec -it dawarich_app bin/rails
"import:big_file[/var/app/tmp/imports/watched/dawarich_part_0000.json,votre@email.fr]"
Conservez bien les guillemets autour de la commande, sans eux, le terminal interprète mal les crochets. Attendez que le premier fichier soit entièrement traité avant de lancer le suivant. Vous pouvez suivre la progression en temps réel avec :
sudo docker logs -f dawarich_sidekiq
Faites Ctrl+C pour quitter la vue des logs. Si vous avez de nombreux fichiers à importer, le script bash import_chunks.sh suivant automatise cette attente et enchaîne les imports sans intervention manuelle :
#!/bin/bash
# import_chunks.sh
# Usage : bash import_chunks.sh votre@email.fr
EMAIL="${1:-votre@email.fr}"
WATCHED_DIR="/volume1/docker/dawarich/watched"
CONTAINER="dawarich_app"
CHECK_INTERVAL=30
MAX_WAIT=7200
GREEN=' 33[0;32m'
YELLOW=' 33[1;33m'
RED=' 33[0;31m'
NC=' 33[0m'
echo "=================================================="
echo " Import automatique Dawarich"
echo " Email : $EMAIL"
echo " Dossier : $WATCHED_DIR"
echo "=================================================="
FILES=$(ls -1 "$WATCHED_DIR"/dawarich_part_*.json 2>/dev/null | sort)
if [ -z "$FILES" ]; then
echo -e "${RED}Aucun fichier dawarich_part_*.json trouvé dans $WATCHED_DIR${NC}"
exit 1
fi
TOTAL=$(echo "$FILES" | wc -l)
echo -e "n$TOTAL fichiers trouvésn"
COUNT=0
for FILEPATH in $FILES; do
FILENAME=$(basename "$FILEPATH")
COUNT=$((COUNT + 1))
echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "[$COUNT/$TOTAL] Import de $FILENAME"
echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
POINTS_BEFORE=$(sudo docker exec "$CONTAINER"
bin/rails runner "puts User.find_by(email: '$EMAIL')&.points&.count.to_i"
2>/dev/null | tail -1)
POINTS_BEFORE=${POINTS_BEFORE:-0}
echo " Points avant import : $POINTS_BEFORE"
sudo docker exec "$CONTAINER"
bin/rails "import:big_file[/var/app/tmp/imports/watched/$FILENAME,$EMAIL]"
if [ $? -ne 0 ]; then
echo -e "${RED} Erreur lors du lancement de $FILENAME — on continue dans 10s${NC}"
sleep 10
continue
fi
echo " Job créé. Attente du traitement par Sidekiq..."
ELAPSED=0
LAST_POINTS=$POINTS_BEFORE
STABLE_COUNT=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
sleep $CHECK_INTERVAL
ELAPSED=$((ELAPSED + CHECK_INTERVAL))
PENDING=$(sudo docker exec dawarich_redis
redis-cli llen "queue:default" 2>/dev/null | tr -d '[:space:]')
PENDING=${PENDING:-0}
POINTS_NOW=$(sudo docker exec "$CONTAINER"
bin/rails runner "puts User.find_by(email: '$EMAIL')&.points&.count.to_i"
2>/dev/null | tail -1)
POINTS_NOW=${POINTS_NOW:-0}
ADDED=$((POINTS_NOW - POINTS_BEFORE))
echo " ${ELAPSED}s | Points ajoutés : $ADDED | Jobs en attente : $PENDING"
if [ "$POINTS_NOW" = "$LAST_POINTS" ] && [ "$PENDING" = "0" ]; then
STABLE_COUNT=$((STABLE_COUNT + 1))
if [ $STABLE_COUNT -ge 2 ]; then
echo -e "${GREEN} Import terminé : $ADDED points ajoutés.${NC}"
break
fi
else
STABLE_COUNT=0
fi
LAST_POINTS=$POINTS_NOW
done
if [ $ELAPSED -ge $MAX_WAIT ]; then
echo -e "${RED} Timeout atteint pour $FILENAME. On passe au suivant.${NC}"
fi
echo " Pause de 15 secondes avant le prochain fichier..."
sleep 15
done
echo ""
echo -e "${GREEN}=================================================="
echo " Tous les imports sont terminés !"
echo -e "==================================================${NC}"
TOTAL_POINTS=$(sudo docker exec "$CONTAINER"
bin/rails runner "puts User.find_by(email: '$EMAIL')&.points&.count.to_i"
2>/dev/null | tail -1)
echo " Total de points dans Dawarich : $TOTAL_POINTS"
bash import_chunks.sh votre@email.fr
Commandes utiles :
Si vous avez des soucis d'imports :
Nettoyer les imports ratés et bloqués :
sudo docker exec -it dawarich_app bin/rails runner "
failed = Import.where(status: [:failed, :created, :processing])
puts "#{failed.count} imports à supprimer"
failed.destroy_all
puts 'Nettoyé.'
"
Vider la file Redis des jobs fantômes :
sudo docker exec dawarich_redis redis-cli flushdb
Vérifier que Redis est sain :
sudo docker exec dawarich_redis redis-cli config get stop-writes-on-bgsave-error
# doit retourner : no
sudo docker exec dawarich_redis redis-cli ping
# doit retourner : PONG
Si le config get retourne yes, c'est que le container Redis a été recréé sans prendre en compte le docker-compose.yml modifié. Dans ce cas :
sudo docker compose -f /volume1/docker/dawarich/docker-compose.yml stop dawarich_redis
sudo docker compose -f /volume1/docker/dawarich/docker-compose.yml rm -f dawarich_redis
sudo rm -f /volume1/docker/dawarich/redis/dump.rdb
sudo docker compose -f /volume1/docker/dawarich/docker-compose.yml up -d dawarich_redis
Tracking automatique continu
L'import de l'historique passé, c'est bien. Mais le vrai intérêt de Dawarich, c'est de continuer à enregistrer vos trajets automatiquement, comme Google le faisait. Pour ça, installez l'application Dawarich (disponible sur iOS et Android), configurez l'URL de votre instance et la clé API que vous trouverez dans les paramètres de votre compte Dawarich. L'application tourne en fond et envoie vos positions automatiquement, avec un impact minimal sur la batterie.
Et voilà : vos données de trajets sont de nouveau accessibles depuis un navigateur PC, hébergées chez vous, sans pub, sans revente de données, et avec un renouvellement automatique qui ne vous demandera plus jamais rien. Le tout pour le prix d'un peu d'électricité supplémentaire sur votre NAS.