En résumé
Les mêmes fonctionnalités qu’avec Docker, mais depuis les sources : vous clonez le dépôt, installez les dépendances Node.js et Python, puis une commande lance le backend et le frontend ensemble. C’est la méthode pour développer sur Linkr, avec rechargement à chaud.
Prérequis
- Node.js 20+ et npm (nodejs.org).
- Python 3.12+ — vérifiez avec
python3 --version(python --versionsur Windows). - Git.
- Environ 1,5 Go d’espace disque.
Installation
Toutes les commandes se lancent depuis la racine du dépôt.
Cloner le dépôt et installer les dépendances
git clone https://framagit.org/interhop/linkr/linkr.git
cd linkr
npm install
python3 -m venv apps/api/.venv
source apps/api/.venv/bin/activate
pip install -e "apps/api[dev]" git clone https://framagit.org/interhop/linkr/linkr.git
cd linkr
npm install
python -m venv apps\api\.venv
apps\api\.venv\Scripts\Activate.ps1
pip install -e "apps/api[dev]" Créer les fichiers de configuration
Un pour le backend, un pour le frontend.
cp apps/api/.env.example apps/api/.env
cp apps/web/.env.example apps/web/.env.localGénérer la clé secrète
Copiez la valeur affichée, puis collez-la dans apps/api/.env à la place de dev-secret-change-in-production.
python3 -c "import secrets; print(secrets.token_urlsafe(48))" python -c "import secrets; print(secrets.token_urlsafe(48))" Lancer Linkr
Attendez les lignes « Uvicorn running » et « VITE ready », puis ouvrez http://localhost:3000 et suivez l’assistant de configuration. Ctrl+C arrête tout.
npm run dev:all C'est installé
Linkr tourne. Les sections suivantes sont à consulter au besoin : réglages, installation sur une machine distante, déploiement sans Docker, dépannage.
Ce que font ces étapes
- L’environnement virtuel (
apps/api/.venv) isole les dépendances Python de Linkr du reste de votre machine. Pour un déploiement PostgreSQL, installezapps/api[dev,postgres]à la place deapps/api[dev]. apps/web/.env.localbascule l’application en mode serveur : il définitVITE_API_URL=http://localhost:8000. Sans lui, le frontend reste en client-only.- La clé secrète signe les jetons de connexion et chiffre les mots de passe des bases enregistrées. Le backend refuse de démarrer tant que la clé d’exemple est en place. Gardez-la ensuite stable : la changer déconnecte tout le monde et rend illisibles les mots de passe déjà enregistrés.
npm run dev:alllance le backend et le frontend dans le même terminal, chaque ligne de journal préfixée par sa source (webouapi).
Sur Windows, dans un nouveau terminal
L’environnement virtuel n’est actif que dans le terminal où vous l’avez activé. Sur macOS et Linux, npm run dev:all le retrouve tout seul ; sur Windows, réactivez-le avant de lancer Linkr (apps\api\.venv\Scripts\Activate.ps1).
L’assistant de premier démarrage
La toute première ouverture ne présente pas la page de connexion mais un assistant en trois étapes — il n’y a encore aucun utilisateur. Les visites suivantes affichent la page de connexion habituelle.
Base de données
L'assistant affiche la base que le serveur utilise. Cet écran est en lecture seule : la base se configure côté serveur via LINKR_DATABASE_URL, et elle est créée automatiquement. Pour en changer, modifiez la configuration serveur et redémarrez.
Créer un compte administrateur
Ce sera le premier compte administrateur de l'instance. Renseignez un nom d'utilisateur et un mot de passe. Dans un build de développement les champs sont pré-remplis avec admin / admin ; un build de production démarre avec des champs vides.
Données par défaut
Dernière étape : installer l'espace de démonstration, qui contient une base OMOP, des alignements de concepts, un pipeline ETL et des projets d'exemple. Cliquez sur « Installer et terminer », ou sur « Démarrer à vide » pour partir d'une instance vierge. Ce choix n'est pas définitif : le contenu s'installe ou se supprime plus tard depuis la page Catalogue.
Créer l'administrateur en ligne de commande
Pour une installation scriptée, l'assistant peut être court-circuité en appelant directement l'API :
curl localhost:8000/api/v1/setup/status
curl -X POST localhost:8000/api/v1/setup/initialize \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"un-mot-de-passe-solide"}' La première commande répond {"needs_setup": true} tant que l'instance n'est pas initialisée.
Les réglages du backend
Les trois réglages qui comptent, dans apps/api/.env :
LINKR_DATA_DIR— le dossier où Linkr range tout : la base SQLite et les fichiers volumineux (Parquet, pièces jointes, fichiers de l’IDE). Par défaut~/.linkr. C’est ce dossier que l’on sauvegarde.LINKR_DATABASE_URL— laissez-le commenté pour un SQLite dans le dossier de données (mono-utilisateur, le défaut). Décommentez-le et renseignez-le pour PostgreSQL.LINKR_SECRET_KEY— signe les jetons de connexion et chiffre les mots de passe des bases enregistrées. À remplacer avant tout démarrage (étape 3).
Un quatrième réglage compte dès que vous sortez des ports par défaut : LINKR_CORS_ORIGINS doit contenir l’adresse exacte du frontend (http://localhost:3000 dans le fichier d’exemple). Si vous servez le frontend sur un autre port, mettez-le à jour, sinon le navigateur bloquera les appels à l’API.
La base est créée automatiquement au premier démarrage, et les migrations sont appliquées à chaque lancement.
Lancer les deux processus séparément
npm run dev:all convient dans la majorité des cas. Pour suivre les journaux de chaque côté isolément, ou redémarrer l’un sans l’autre, ouvrez deux terminaux :
# Terminal 1 — backend
npm run dev:api
# Terminal 2 — frontend
npm run dev:web Repasser en client-only le temps d'un lancement
Une fois apps/web/.env.local créé, chaque npm run dev:web démarre en mode serveur. Pour lancer le frontend en client-only sans toucher à ce fichier :
npm run dev:clientLa variable est forcée à vide le temps de cette exécution. Pratique pour vérifier comment une fonctionnalité se comporte sans backend.
Installer sur une machine distante
Tout ce qui précède suppose que le navigateur et Linkr tournent sur la même machine. Si vous développez dans un conteneur VS Code, sur une machine virtuelle ou sur un serveur distant, le navigateur est ailleurs : quatre réglages, tous dans apps/web/.env.local, sont alors nécessaires. Sans eux, la page reste blanche ou affiche Blocked request.
WEB_HOST— par défaut, le serveur de développement n’écoute que surlocalhost, c’est-à-dire l’intérieur de la machine : rien ne sort. Mettez0.0.0.0pour qu’il accepte les connexions extérieures.WEB_ALLOWED_HOSTS— le serveur refuse les requêtes dont il ne reconnaît pas le nom de domaine, une protection contre le DNS rebinding. Un proxy qui expose Linkr souschu-exemple.frse fait donc rejeter avec le messageBlocked request. This host is not allowed.Indiquez le nom attendu, séparé par des virgules s’il y en a plusieurs ; un point initial couvre les sous-domaines (.chu-exemple.fr).BASE_PATH— à renseigner uniquement si l’application est servie sous un sous-chemin, par exemplehttps://chu-exemple.fr/conteneur-3612/, et que le proxy ne retire pas ce préfixe. Il préfixe alors les fichiers de l’application et les adresses internes.WEB_PORT— le port d’écoute, si3000n’est pas celui que vous exposez.
WEB_HOST=0.0.0.0
WEB_ALLOWED_HOSTS=chu-exemple.fr
BASE_PATH=/conteneur-3612/
WEB_PORT=4321
VITE_API_URL doit devenir relatif
C’est l’erreur la plus coûteuse de cette configuration, parce qu’elle ne produit aucun message clair. Le fichier d’exemple contient VITE_API_URL=http://localhost:8000 : une adresse absolue, que le navigateur résout depuis sa propre machine. Depuis un poste distant, localhost désigne ce poste, pas le conteneur — l’application se charge, puis chaque appel à l’API échoue.
Remplacez-la par une adresse relative :
VITE_API_URL=/Les appels passent alors par le serveur de développement, qui les transmet lui-même au backend. Comme ils partent de la même origine que la page, LINKR_CORS_ORIGINS n’a pas besoin d’être modifié.
Si le rechargement automatique tourne en boucle
Lorsqu’un proxy gère le HTTPS, la page se charge en https sur le port 443 alors que le rechargement automatique tente de se connecter en ws sur le port de développement. La connexion échoue, indéfiniment. Trois variables la rattrapent :
WEB_HMR_PROTOCOL=wss
WEB_HMR_CLIENT_PORT=443
WEB_HMR_HOST=chu-exemple.frL’application fonctionne sans elles — seul le rechargement à chaque modification est perdu.
Savoir si le proxy retire le préfixe
BASE_PATH ne se devine pas : mal réglé dans un sens comme dans l’autre, aucun fichier de l’application ne se charge. Pour trancher, lancez un petit serveur qui affiche le chemin qu’il reçoit, sur le port que vous exposez :
python3 -c "
from http.server import BaseHTTPRequestHandler, HTTPServer
class H(BaseHTTPRequestHandler):
def do_GET(s):
s.send_response(200); s.end_headers()
s.wfile.write(f'PATH={s.path}\nHOST={s.headers.get(\"Host\")}\n'.encode())
HTTPServer(('0.0.0.0',4321),H).serve_forever()
"Ouvrez ensuite l’adresse complète dans votre navigateur. Si la réponse affiche PATH=/conteneur-3612/, le préfixe est conservé : renseignez BASE_PATH. Si elle affiche PATH=/, le proxy l’a retiré : laissez BASE_PATH vide. La ligne HOST= vous donne au passage la valeur exacte à placer dans WEB_ALLOWED_HOSTS.
Ces réglages sont réservés au développement
WEB_HOST, WEB_ALLOWED_HOSTS et les variables WEB_HMR_* ne s’appliquent qu’au serveur de développement. Une mise en production passe par Docker, où nginx écoute déjà sur toutes les interfaces ; seul le sous-chemin s’y configure, via l’argument de construction BASE_PATH. Et WEB_ALLOWED_HOSTS=true, qui désactive entièrement la vérification du domaine, ne convient qu’à un réseau privé : il rouvre la faille que cette vérification protège.
Déployer sans Docker
Sur un serveur, gardez trois choses séparées : le code (le dépôt cloné), les données (un dossier dédié que vous sauvegardez) et les secrets (jamais lisibles par tous). Le plus simple reste Docker ; pour une installation système, systemd avec un fichier d’environnement en chmod 600 est le schéma recommandé :
sudo install -d -o linkr -g linkr /var/lib/linkr
python3 -c "import secrets; print(secrets.token_urlsafe(48))"
# /etc/systemd/system/linkr-api.service
[Service]
User=linkr
WorkingDirectory=/opt/linkr/apps/api
EnvironmentFile=/etc/linkr/linkr.env
ExecStart=/opt/linkr/apps/api/.venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000
Dans /etc/linkr/linkr.env (en chmod 600), au minimum : LINKR_DATA_DIR, LINKR_SECRET_KEY et LINKR_CORS_ORIGINS (l’adresse publique du frontend, sans quoi le navigateur bloquera les appels à l’API).
Sauvegardez le dossier de données
En mode serveur, tout ce que produisent vos utilisateurs vit dans LINKR_DATA_DIR — la base applicative et l’ensemble des fichiers. C’est le seul dossier à sauvegarder, mais il est indispensable : le dépôt de code ne contient aucune donnée.
Structure du dépôt
Le dépôt est un monorepo Turborepo :
apps/web/— frontend React + Vite (l’application principale).apps/api/— backend FastAPI (Python).packages/default-plugins/— plugins d’analyse inclus par défaut (Tableau descriptif, Constructeur de graphiques, etc.).packages/linkr-format/— schémas et validateur du format d’export.docker/— configurations Docker.docs/— documentation interne du projet (différente de la documentation utilisateur que vous lisez ici).
Commandes utiles
| Commande | Effet |
|---|---|
npm install | Installe toutes les dépendances du monorepo. |
npm run dev:web | Lance le frontend en dev (port 3000). |
npm run dev:client | Lance le frontend en client-only, même si VITE_API_URL est défini. |
npm run dev:api | Lance le backend FastAPI (port 8000). |
npm run dev:all | Lance les deux à la fois (nécessite npm install à la racine). |
npm run data:fetch | Télécharge les données de démonstration dans le dossier de seed. |
npm run build | Produit le build de production de tous les workspaces. |
cd apps/web && npm run preview | Sert localement le build de production. |
Dépannage
npm install échoue. Vérifiez que vous utilisez bien Node.js 20+ (node -v). Si vous avez plusieurs versions de Node.js, utilisez nvm use 20.
python : command not found. Sur macOS et Linux, la commande s’appelle python3 ; sur Windows, c’est python. Choisissez l’onglet de votre système dans les étapes ci-dessus.
pip install refuse la version de Python. Le backend demande Python 3.12 ou plus (python3 --version). Sur une version antérieure, l’installation s’arrête sur un message de compatibilité : installez une version plus récente, puis recréez l’environnement virtuel.
Windows refuse d’exécuter Activate.ps1. PowerShell bloque les scripts par défaut. Autorisez-les pour votre compte avec Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, puis relancez l’activation.
Le backend s’arrête sur LINKR_SECRET_KEY is still the insecure default. apps/api/.env contient encore la clé d’exemple. Générez-en une et collez-la dans le fichier — voir l’étape 3. Pour un simple essai en local, LINKR_DEBUG=true dans le même fichier lève aussi le blocage — jamais sur une machine accessible depuis le réseau.
Port 3000 déjà pris. Le script de dev vous propose automatiquement un autre port, ou fermez le processus qui l’occupe (lsof -i :3000 sur macOS/Linux).
Blocked request. This host is not allowed. Le serveur de développement ne reconnaît pas le nom de domaine par lequel vous l’appelez. Ajoutez ce nom à WEB_ALLOWED_HOSTS dans apps/web/.env.local — voir « Installer sur une machine distante » plus haut.
Depuis une machine distante, la page ne s’ouvre pas du tout. Le serveur n’écoute que sur localhost : ajoutez WEB_HOST=0.0.0.0. Si la page s’ouvre mais reste vide et que les fichiers de l’application renvoient des erreurs 404, c’est BASE_PATH qui est en cause — renseigné alors qu’il ne devrait pas l’être, ou l’inverse.
Depuis une machine distante, la page s’affiche mais rien ne se charge. Les appels à l’API partent vers http://localhost:8000, que le navigateur résout sur votre poste et non sur la machine distante. Mettez VITE_API_URL=/ dans apps/web/.env.local.
L’application affiche la page de connexion alors que vous vouliez le mode client-only. C’est que VITE_API_URL est défini, généralement dans apps/web/.env.local. Videz-le, ou lancez npm run dev:client.
Le frontend ne joint pas le backend. Vérifiez d’abord que l’API répond (curl localhost:8000/api/v1/health). Si elle répond mais que le navigateur affiche des erreurs de type CORS, c’est que LINKR_CORS_ORIGINS ne contient pas l’adresse exacte du frontend — le port compte.
Pour aller plus loin
- Créer votre premier projet : Votre premier projet.
- Comprendre ce que chaque mode permet : Modes de déploiement.