Installation
Deux chemins : binaire Node natif (le plus rapide à essayer) ou
docker compose(le plus propre pour la prod). Les deux marchent identiquement — choisis selon ton serveur.

À quoi ça sert
Trackily est livré en deux saveurs :
- Binaire
pkg— un seul fichiertrackilyqui contient Node.js + le code + les assets. Tu copies, tu lances, c'est plié. Idéal pour un VPS simple ou pour tester en local. - Docker Compose —
trackily+postgres+ (optionnellement) Caddy pour le SSL auto. C'est le mode recommandé pour la prod parce que la base est isolée, les certs persistent, et undocker compose up -dsuffit pour repartir après reboot.
Dans les deux cas, la base PostgreSQL est gérée par toi (Trackily ne ship pas Postgres en dur dans le binaire). Trackily ouvre la connexion via DATABASE_URL, applique toutes les migrations au boot (table par table, idempotent) et crée le user admin si la table users est vide.
Pré-requis
| Composant | Version mini | Notes |
|---|---|---|
| Node.js | 22.14.0 | Requis seulement pour le mode binaire / dev. Le mode Docker ship Node dans l'image. |
| PostgreSQL | 14 | 16-alpine recommandé. Neon, Supabase et Render fonctionnent (SSL est auto-détecté via l'URL). |
| RAM | 1 GB | 2 GB recommandés si tu utilises l'AI landing builder. |
| Ports | 3000 | + 80/443 si tu actives AUTO_SSL=true (Caddy reverse proxy). |
Variables d'environnement
Trackily lit son .env au boot via dotenv. Voici les variables qui comptent vraiment :
# ─── Obligatoires ───────────────────────────
DATABASE_URL=postgres://trackily:secret@localhost:5432/trackily
ADMIN_PASSWORD=ChangeMoiUnMotDePasseLong # ≥ 8 caractères, sinon refus de démarrer
# ─── Recommandées ───────────────────────────
PORT=3000 # défaut 3000
BASE_URL=https://tracker.exemple.com # URL publique (utilisée pour les postbacks, magic links, etc.)
SECRETS_MASTER_KEY= # 32 bytes hex ; chiffre les API keys en DB (AES-256-GCM)
LICENSE_KEY= # voir « Licence et modes de fonctionnement » ci-dessous
LICENSE_SERVER_URL=https://license.trackily.online # défaut ; doit rester le serveur officiel (réponses signées)
# ─── Sécurité ───────────────────────────────
ADMIN_CSP_STRICT=true # CSP stricte avec nonces sur /admin (recommandé)
# ─── Docker / Caddy ─────────────────────────
AUTO_SSL=true # active Caddy + Let's Encrypt sur les ports 80/443
DB_PASSWORD=trackily_secure_2024 # mot de passe Postgres (utilisé par docker-compose)
ADMIN_PASSWORDest vérifié au boot : moins de 8 caractères ou variable manquante =[FATAL]et le process s'arrête. C'est volontaire pour éviter de booter avec un défaut faible. Voirserver.js:626.
SECRETS_MASTER_KEY: si elle est absente, le code retombe surADMIN_PASSWORDpour dériver la clé de chiffrement. Ça marche, mais changer le mot de passe admin rendrait alors tous les secrets stockés indéchiffrables. Définis-la explicitement (openssl rand -hex 32) — le script d'installation le fait automatiquement.
LICENSE_SERVER_URLaccepte uniquement le serveur officiel en pratique : depuis la vérification de signature, chaque verdict de licence est signé en Ed25519 et validé côté client contre une clé publique intégrée au binaire. Un serveur tiers ne peut pas produire une signature acceptée — l'instance passera en mode restreint. Ne change cette variable que si le support te le demande.
DATABASE_URLest nettoyé automatiquement (les paramètressslmodeetchannel_bindingsont retirés et reconstruits selon l'hôte). Voirdatabase.js:4.
Si l'URL contient
neon.tech,supabase,render.comousslmode=require, le SSL est activé en moderejectUnauthorized: false. Pour un Postgres self-hosted dans le même réseau, laisseDATABASE_URLsanssslmode— la connexion sera en clair (LAN privé).
Option A — Binaire natif
C'est le chemin le plus court pour tester.
# 1. Cloner / récupérer le repo
git clone https://github.com/ton-org/trackily.git
cd trackily
# 2. Installer les deps
npm install
# 3. Configurer .env
cat > .env <<EOF
DATABASE_URL=postgres://trackily:secret@localhost:5432/trackily
ADMIN_PASSWORD=MonMotDePasseLongEtFort
PORT=3000
BASE_URL=http://localhost:3000
EOF
# 4. Préparer la base (Postgres doit déjà tourner)
createdb -U postgres trackily
# 5. Lancer
npm start
Au premier boot tu verras dans les logs :
[DB] Applying migrations…
[DB] Migration v1 applied
[DB] Migration v2 applied
… (jusqu'à la dernière version)
[DB] Seeded built-in cloaking workflow: "VPN Blocker (Built-in)"
[Auth] Admin user seeded: admin@trackily.local
[License] Valid — Plan: pro | Expires: 29/06/2027 | Features: 21
[License] Hub response signature verified
[Automizer] Starting rule engine (60s interval)
[Trackily] Listening on http://localhost:3000
Sans clé de licence, la ligne [License] diffère selon le mode de lancement :
# depuis les sources (dev) — toutes les fonctionnalités
[License] No LICENSE_KEY set — running in development mode (all features)
# binaire distribué — mode restreint, le tracking tourne
[License] No LICENSE_KEY — RESTRICTED mode: Automizer and AI optimisation are
disabled. Add your license key in Settings → License to unlock…
Ouvre http://localhost:3000/admin → voir Première connexion.
Mode dev (auto-reload)
npm run dev
Lance le serveur avec node --watch — chaque modif d'un .js redémarre Trackily. Utile pour développer un MCP tool ou tweaker un template.
Build d'un binaire standalone
npm run build:linux # binaire Linux x64
npm run build:mac # binaire macOS x64
npm run build:all # les deux
Sort un fichier dist/trackily (~50 MB compressé GZip) qui n'a besoin que de DATABASE_URL et ADMIN_PASSWORD dans l'env pour tourner. Pas de node_modules à shipper.
Option B — Docker Compose
Recommandé pour la prod. Fichier livré dans dist/docker-compose.yml :
version: "3.8"
services:
trackily:
build: .
restart: always
ports:
- "${PORT:-3000}:3000"
- "80:80" # Requis pour AUTO_SSL=true
- "443:443" # Requis pour AUTO_SSL=true
env_file: .env
depends_on:
- postgres
volumes:
- trackily-data:/app/data
- caddy-data:/data # Certs Caddy (persistants)
postgres:
image: postgres:16-alpine
restart: always
environment:
POSTGRES_DB: trackily
POSTGRES_USER: trackily
POSTGRES_PASSWORD: ${DB_PASSWORD:-trackily_secure_2024}
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
trackily-data:
caddy-data:
Lancer
cd dist/
cat > .env <<EOF
DATABASE_URL=postgres://trackily:trackily_secure_2024@postgres:5432/trackily
ADMIN_PASSWORD=MonMotDePasseLongEtFort
DB_PASSWORD=trackily_secure_2024
BASE_URL=https://tracker.exemple.com
AUTO_SSL=true
EOF
docker compose up -d
docker compose logs -f trackily
Le Dockerfile (récap)
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
ca-certificates curl debian-keyring debian-archive-keyring \
apt-transport-https gnupg && \
# install Caddy depuis le repo officiel
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg && \
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list && \
apt-get update && apt-get install -y caddy
WORKDIR /app
COPY trackily /app/trackily
COPY public /app/public
COPY Caddyfile /app/Caddyfile
COPY start.sh /app/start.sh
RUN chmod +x /app/trackily /app/start.sh
EXPOSE 3000 80 443
CMD ["/app/start.sh"]
L'image embarque Caddy pour faire reverse proxy + SSL automatique Let's Encrypt. Si AUTO_SSL=false (ou non défini), Caddy n'est pas lancé et Trackily écoute directement sur ${PORT}.
Le start.sh
#!/bin/bash
set -e
if [ "${AUTO_SSL}" = "true" ]; then
echo "[Trackily] Auto-SSL activé — Caddy sur ports 80/443"
caddy start --config /app/Caddyfile --adapter caddyfile
else
echo "[Trackily] Auto-SSL désactivé — Trackily direct sur ${PORT:-3000}"
fi
exec /app/trackily
Licence et modes de fonctionnement
Trackily ne se bloque jamais brutalement. Une licence absente, expirée ou révoquée fait glisser l'instance le long d'une échelle, et le tracking continue de tourner à chaque échelon.
| Mode | Ce qui marche | Ce qui s'arrête |
|---|---|---|
| full | tout | — |
| restricted | tracking, admin, rapports | Automizer, Traffic AI, fonctions premium |
| read_only (après 3 j) | tracking, consultation | toute écriture dans l'admin |
| locked (après 14 j) | tracking | l'admin, sauf login et renouvellement |
Le plan de données n'est jamais coupé.
/c,/s,/lpet les postbacks répondent dans tous les modes, y comprislocked. Une campagne en cours ne perd jamais un clic à cause d'un problème de licence.
Sans LICENSE_KEY :
- Binaire distribué → démarre en
restricted. Le tracking et l'admin fonctionnent, les moteurs payants non. Colle ta clé dans Settings → License pour débloquer. - Depuis les sources (dev) → toutes les fonctionnalités, inchangé.
Si le serveur de licences est injoignable, l'instance continue sur son dernier verdict connu pendant 72 h (période de grâce), puis dégrade. Une panne réseau ne coupe donc pas ton tracker.
Le hub est réinterrogé toutes les 6 h : une licence renouvelée reprend effet sans redémarrage.
Le premier boot en détail
Trackily fait beaucoup au démarrage. Dans l'ordre :
- Charge
.envviadotenv. - Vérifie
ADMIN_PASSWORD— fatal si < 8 caractères. - Connecte Postgres via
pg.Pool. Si la base n'existe pas, ça plante avec un message explicite. - Applique les migrations une par une. Chaque migration vérifie sa propre version dans la table
schema_migrationset skip si déjà appliquée. Tu peux relancer Trackily 100 fois — rien ne sera dupliqué. - Seed les données built-in :
- Le workflow de cloaking "VPN Blocker (Built-in)" (voir
database.js:3931). - Le user admin
admin@trackily.localavec le mot de passe deADMIN_PASSWORD(voirdatabase.js:3248). - Les conversion types Keitaro-style (lead, sale, rebill, etc.).
- Le workflow de cloaking "VPN Blocker (Built-in)" (voir
- Vérifie la licence via
license-client.js: charge d'abord le dernier verdict en cache (pour survivre à un hub injoignable au démarrage), interroge le serveur, vérifie la signature Ed25519 du verdict, puis applique le mode correspondant. Le boot ne s'interrompt jamais à cause de la licence — il démarre dans le mode approprié et le log l'annonce. - Démarre les moteurs autorisés par le plan — Automizer (boucle 60s, voir
automizer.js:16) et l'optimisation IA ne se lancent qu'en modefull. - Enregistre les outils Autopilot/MCP (~205 tools — voir MCP).
- Écoute sur
PORT.
Postgres : trois setups recommandés
Postgres local (binaire ou Docker single-container)
DATABASE_URL=postgres://trackily:secret@localhost:5432/trackily
Le plus simple. Sauvegardes via pg_dump cron.
Postgres managé (Neon / Supabase / Render)
DATABASE_URL=postgres://user:pass@ep-cool-name.neon.tech/trackily?sslmode=require
Trackily détecte le hostname et active automatiquement SSL. Aucune autre conf à faire.
Postgres dans le même Docker network (mode docker compose)
DATABASE_URL=postgres://trackily:trackily_secure_2024@postgres:5432/trackily
Le hostname postgres est résolu par le DNS interne de Docker. Pas de SSL nécessaire (LAN privé).
Erreurs courantes
[FATAL] ADMIN_PASSWORD env var is required and must be at least 8 characters— t'as oubliéADMIN_PASSWORDdans.env, ou il fait moins de 8 caractères. Refus volontaire de booter.error: password authentication failed for user "trackily"— le user Postgres existe mais le mot de passe ne matche pas. VérifieDATABASE_URLvs lePOSTGRES_PASSWORDdu container.ECONNREFUSED 127.0.0.1:5432— Postgres n'est pas démarré ou n'écoute pas sur l'adresse.pg_isready -h localhostpour vérifier.- Port 80/443 déjà pris quand
AUTO_SSL=true— un Nginx ou Apache local mange déjà les ports. Soit tu arrêtes l'autre service, soit tu désactives Caddy et tu mets Trackily derrière ton reverse proxy existant. - Tables vides après reboot — si tu utilises Docker sans volume nommé pour Postgres, les données disparaissent. Le
docker-compose.ymlfourni utilise un volumepgdataexprès pour éviter ça. RESTRICTED modealors que ta licence est valide — l'instance n'a pas pu joindre le serveur de licences au démarrage et n'avait aucun verdict en cache (première installation). Vérifie que le serveur sort bien vershttps://license.trackily.online(pare-feu, proxy). Le tracking fonctionne pendant ce temps ; corrige la sortie réseau et redémarre.SIGNATURE CHECK FAILEDdans les logs — le verdict reçu n'est pas signé par le serveur officiel. Presque toujours unLICENSE_SERVER_URLmodifié, ou un proxy qui réécrit la réponse. Remets la valeur par défaut.License bound to different instance— la clé est déjà activée sur un autre serveur. Une licence = une instance. Contacte le support pour la ré-associer (Rebind) si tu as migré de machine.- Téléchargement
403pendantinstall.sh— la licence est expirée, suspendue ou révoquée : les mises à jour sont coupées. Renouvelle depuis le portail.
Télémétrie
Ton instance communique avec le serveur de licences (LICENSE_SERVER_URL). Voici ce qui est transmis.
Données opérationnelles — clé de licence, identifiant d'instance, hostname, IP serveur, version, disponibilité, et des compteurs agrégés (clics, campagnes actives, utilisateurs, conversions, revenu total). C'est ce qui maintient ta licence valide, déclenche les notifications de mise à jour et permet au support de reproduire un bug.
Benchmark d'offres anonyme — nom de l'offre, domaine de destination, réseau, geo, et par jour : conversions et revenu. Ces données alimentent un benchmark des offres qui performent sur l'ensemble du parc.
Une offre n'est affichée qu'à partir de 5 instances distinctes qui la font tourner, et le benchmark ne montre jamais quel compte fait tourner quelle offre. Les données de tes visiteurs et de tes leads (emails, IP, informations personnelles) ne sont jamais transmises.
Voir aussi
- Première connexion — créer le premier mot de passe, login, dashboard
- Vue d'ensemble — l'architecture une fois tout démarré
- Settings — General — où changer
BASE_URL, timezone, etc. depuis l'UI - Cloaking — index — comment attacher la workflow VPN Blocker à ta première campagne