adalanDocumentation
Collaborateurs

Publier une application

Un POC dynamique en Node, Python ou PHP, un agent IA avec sa clé d’API, une base PostgreSQL : l’application se construit depuis son Dockerfile et tourne sous votre compte.

Conditions

  • Un Dockerfile à la racine du dossier envoyé.
  • L’application écoute sur 0.0.0.0, au port donné par la variable PORT, qui vaut 8080.
  • Elle dispose de 512 Mo de mémoire, d’un demi-processeur et de 256 processus. Un Space compte au plus 3 applications.
  • L’image se construit et le conteneur tourne sous votre compte, sans droits d’administration ; les images comptent dans votre quota.
  • L’application n’est joignable que par son adresse, https://spaces.adalan.ai/durand/projet/.

Servie sous son chemin

Comme un site, l’application vit sous /durand/projet/. Le serveur retire ce préfixe avant de lui passer la requête : elle reçoit /, /api/items… comme si elle était à la racine. Le préfixe lui est donné de deux façons :

  • la variable d’environnement BASE_PATH, par exemple /durand/agent-rh ;
  • l’en-tête X-Forwarded-Prefix de chaque requête.

L’adresse de l’application, /durand/projet/, lui arrive comme / : c’est son serveur qui choisit la page d’accueil. Apache (images php:…-apache) et le serveur intégré de PHP (php -S 0.0.0.0:8080) ouvrent index.php, à défaut index.html, à la racine comme dans chaque dossier.

Dans ses pages et son JavaScript, les liens sont relatifs (api/items, static/app.css) ou préfixés par BASE_PATH, jamais /api/items. Le serveur ramène sous le chemin de l’application ses redirections vers /… et les cookies qu’elle pose pour /.

CadricielRéglage
FastAPIFastAPI(root_path=os.environ.get("BASE_PATH", ""))
Flaskapp.wsgi_app = ProxyFix(app.wsgi_app, x_prefix=1), puis url_for pour les liens
ExpressLiens relatifs dans les gabarits et les appels fetch

Deux Dockerfile de départ

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
# server.js : app.listen(process.env.PORT || 8080, "0.0.0.0")
CMD ["node", "server.js"]
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]

Secrets et réglages

Jamais de clé d’API dans le code ni dans l’image : le serveur refuse d’ailleurs les fichiers .env. Les variables se règlent à part, par l’entrée standard, pour que la valeur n’apparaisse dans aucune ligne de commande :

printf 'OPENAI_API_KEY=%s\n' "$CLE" | ssh adalan adalan env agent-rh --stdin
BesoinCommande
Lister les variables, sans leurs valeursssh adalan adalan env agent-rh
Définir un réglage non secretssh adalan adalan env agent-rh MODELE=rapide
Retirer une variablessh adalan adalan env agent-rh --unset NOM

Chaque changement relance l’application. Dans claude.ai, donnez la clé à Claude en lui demandant de la régler comme variable de l’application : il passe par l’outil set_app_env, qui ne renvoie jamais les valeurs.

Si l’application a besoin de sa clé pour démarrer, le premier envoi peut échouer faute de clé. Réglez la clé avec env --stdin : l’application se relance avec elle.

Envoyer

COPYFILE_DISABLE=1 tar -czf - -C dossier . | ssh adalan adalan deploy agent-rh --type docker

La construction peut prendre quelques minutes au premier envoi. La commande construit l’image, lance le conteneur et vérifie qu’il répond. Si la nouvelle version échoue, la précédente est remise en service et le journal s’affiche. --protect et --interne s’ajoutent comme pour un site.

Base de données

ssh adalan adalan db create agent-rh

La commande crée une base PostgreSQL dédiée, ajoute à l’application les variables DATABASE_URL, PGHOST, PGPORT, PGUSER, PGPASSWORD et PGDATABASE, puis la relance. L’application crée ses tables elle-même, au démarrage ou par ses migrations. Relancer la commande change le mot de passe de la base. Une base ne sert qu’une application : elle disparaît avec elle.

Application en accès interne

Publiée avec --interne, l’application ne reçoit que des visiteurs connectés : collaborateurs avec leur compte Microsoft adalan, freelances inscrits dans Grace avec un code reçu par e-mail. Chaque requête porte leur identité :

  • X-Adalan-Email : l’adresse du visiteur ;
  • X-Adalan-Name : son nom, encodé en URL ;
  • X-Adalan-Auth : sa connexion, microsoft (collaborateur) ou email (freelance).

Ces en-têtes ne peuvent pas venir du navigateur : le serveur retire ceux qu’un client enverrait. L’application peut s’en servir pour personnaliser l’accueil, tracer les actions ou réserver une page aux collaborateurs, sans gérer de mots de passe. _adalan/sso/logout, sous l’adresse du site, déconnecte le visiteur.

Une application protégée par mot de passe reçoit seulement X-Adalan-Auth: password. Un script y accède avec curl -u adalan:mot-de-passe.

Diagnostic

ssh adalan adalan logs agent-rh --lines 100
SymptômeQue faire
construction de l'image en échecLire les dernières lignes affichées (dépendance introuvable, commande en erreur), corriger, republier.
la nouvelle version ne répond pasVérifier que l’application écoute sur 0.0.0.0 et le port PORT ; lire le journal. La version précédente reste en ligne.
Pages sans styles, appels d’API en 404Liens absolus dans les pages ou le JavaScript : les rendre relatifs, ou les préfixer par BASE_PATH.
Erreur 502L’application s’est arrêtée ou ne répond plus : lire le journal, puis republier.

Le stockage du navigateur (localStorage) est commun à tous les sites de la plateforme, qui partagent la même adresse. Une application n’y range rien de confidentiel.