Déployer en production
Ce guide fait tourner Apollia comme un service de longue durée sur un serveur Linux : un binaire optimisé, un gestionnaire de service, une posture réseau durcie, et les vérifications à effectuer après chaque déploiement. Il suppose que vous savez déjà compiler et exécuter le daemon en local ; si ce n'est pas le cas, commencez par Installer et exécuter le runtime.
Le répertoire packaging/ du dépôt prépare ce dont un paquet de bureau a
besoin, le bundle Python embarqué et le binaire llama-server ; le paquet de
bureau lui-même est assemblé par Tauri via
crates/apollia-desktop/scripts/bundle-cli.sh. Ni l'un ni l'autre ne produit
un daemon serveur. Pour un serveur, vous compilez le binaire depuis les sources
et l'encapsulez dans votre système d'init, ce que fait ce guide.
Compiler un binaire optimisé
cargo build -p apollia-cli --release
Le résultat est target/release/apollia-os. Installez-le à l'endroit où
votre service le trouvera :
sudo install -m 755 target/release/apollia-os /usr/local/bin/apollia-os
Exécuter sous systemd
Aucun fichier d'unité n'est fourni dans le dépôt ; vous en écrivez un qui
encapsule les commandes réelles start et stop. Exécutez le daemon sous un
utilisateur dédié sans privilèges, afin qu'un agent ne puisse pas lire le
reste du système.
# /etc/systemd/system/apollia.service
[Unit]
Description=Apollia OS runtime
After=network.target
[Service]
Type=simple
User=apollia
Group=apollia
ExecStart=/usr/local/bin/apollia-os start --port 7771
ExecStop=/usr/local/bin/apollia-os stop
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
sudo useradd --system --home /var/lib/apollia --shell /usr/sbin/nologin apollia
sudo systemctl daemon-reload
sudo systemctl enable --now apollia
sudo systemctl status apollia
Durcir la posture réseau
-
Par défaut : loopback plus jeton. L'API TCP écoute par défaut sur
127.0.0.1, et les appelants TCP doivent présenter le jeton porteur écrit dans~/.apollia/api-tokenau premier démarrage (le socket Unix repose sur une confiance locale). Pour une intégration sur la même machine, conservez l'écoute sur loopback et laissez[api].require_token = true. -
Exposez-le via TLS, jamais en clair. Pour joindre le daemon depuis une autre machine, le runtime peut terminer lui-même le TLS : définissez
[api].tls_certet[api].tls_keydansapollia.toml(les deux, ou aucun des deux) et l'écouteur TCP sert directement du HTTPS, sans composant supplémentaire à exploiter. Autre possibilité : conserver l'écoute sur loopback et placer devant un proxy inverse qui termine le TLS, en le faisant suivre vers127.0.0.1:7771. Dans les deux cas, gardez le jeton porteur obligatoire. -
Les écoutes non sécurisées échouent immédiatement. Écouter sur une adresse non-loopback avec
require_token = falseest refusé au démarrage, si bien qu'un port public n'est jamais exposé sans authentification par accident. Gardez l'exigence de jeton active pour toute interface exposée. -
Protégez le fichier du jeton.
~/.apollia/api-token, pour l'utilisateur du service, donne un contrôle total sur le runtime. Gardez-le lisible uniquement par cet utilisateur. -
Prérequis de sandboxing (Linux), qui entrent en conflit avec l'utilisateur sans privilèges ci-dessus.
bash_executoretpython_executorisolent leur processus enfant avecunshare --pid --mount --fork. Ces options sont appelées sans--user, ce qui nécessiteCAP_SYS_ADMIN: activer les espaces de noms utilisateur non privilégiés sur l'hôte ne l'accorde pas. Sous un serviceUser=apolliaclassique, les deux exécuteurs échouent, et rien ne s'exécute hors de l'espace de noms. Le refus parvient à l'appelant sous la forme du code de sortie du programme lui-même, et non d'une erreur de bac à sable distincte : ne le lisez pas comme un signal de refus par défaut.Choisissez-en une, en connaissance de cause :
- accorder la capacité à l'unité,
AmbientCapabilities=CAP_SYS_ADMINplusCapabilityBoundingSet=CAP_SYS_ADMIN, et conserver l'utilisateur sans privilèges ; - ou fonctionner sans les deux outils d'exécution de code, en les
désactivant dans
[tools]; - ou accepter qu'ils échoueront au moment de l'appel.
Exécuter le service en tant que root pour obtenir cette capacité échange un outil confiné contre un daemon non confiné, ce qui est l'inverse de ce qu'il faut faire.
- accorder la capacité à l'unité,
Proxy inverse avec terminaison TLS
Si votre infrastructure termine déjà le TLS en amont (Caddy, nginx, un
ingress), laissez [api].tls_cert / [api].tls_key non définis, gardez le
daemon sur loopback, et faites suivre vers 127.0.0.1:7771.
apollia.example.com {
reverse_proxy 127.0.0.1:7771
# SSE : désactiver la mise en tampon pour les points de terminaison de streaming
reverse_proxy /api/v1/tasks/*/stream 127.0.0.1:7771 {
flush_interval -1
}
reverse_proxy /api/v1/mailbox/stream 127.0.0.1:7771 {
flush_interval -1
}
reverse_proxy /api/v1/sessions/*/stream 127.0.0.1:7771 {
flush_interval -1
}
reverse_proxy /api/v1/events 127.0.0.1:7771 {
flush_interval -1
}
}
server {
listen 443 ssl;
server_name apollia.example.com;
ssl_certificate /etc/ssl/apollia/fullchain.pem;
ssl_certificate_key /etc/ssl/apollia/privkey.pem;
location / {
proxy_pass http://127.0.0.1:7771;
proxy_set_header Authorization $http_authorization;
}
# SSE : streaming sans mise en tampon
location ~ ^/api/v1/(tasks/.*/stream|sessions/.*/stream|mailbox/stream|events)$ {
proxy_pass http://127.0.0.1:7771;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
}
}
Les points de terminaison de streaming GET /api/v1/tasks/{id}/stream,
GET /api/v1/sessions/{id}/stream, GET /api/v1/mailbox/stream et
GET /api/v1/events envoient les événements au fil de l'eau. Sans
désactivation de la mise en tampon, le proxy les retient jusqu'à la fermeture
de la réponse, et l'hôte ne voit rien en direct. La même précaution
s'applique côté client sous TLS natif : ne mettez pas la réponse en tampon.
Vérifier après déploiement
# Disponibilité. La route de santé est le seul chemin de l'API servi sans le
# jeton porteur ; elle ne révèle que le marqueur de produit et la version.
curl -s http://127.0.0.1:7771/api/v1/health
# {"status":"ok","product":"apollia-os","version":"<version du runtime>"}
# État du runtime et des agents
apollia-os status
# De bout en bout : construire le paquet de départ, l'installer et exécuter son agent.
apollia-os package new postcheck
apollia-os package build postcheck
apollia-os package install postcheck-0.1.0.apo
apollia-os run postcheck "post-deploy check"
Les mêmes informations que lit la CLI sont disponibles via HTTP pour une intégration côté hôte ; voir la référence de l'API HTTP.
Exploiter le service en cours d'exécution
-
Journaux. Suivez le journal du runtime avec
apollia-os logs --follow, ou lisez le journal du service avecjournalctl -u apollia -f. -
Cache de plans. Les exécutions orchestrées mettent leurs plans en cache. Inspectez-le ou videz-le pour diagnostiquer une planification obsolète :
apollia-os plan cache statsapollia-os plan cache clear --confirm -
Audit. Chaque action gouvernée est enregistrée dans un journal signé et chaîné par hachage. Lisez-le et vérifiez-le avec le flux d'audit.
Mettre à jour
git pull
cargo build -p apollia-cli --release
sudo systemctl stop apollia
sudo install -m 755 target/release/apollia-os /usr/local/bin/apollia-os
sudo systemctl start apollia
Inférence locale sur un serveur
Pour servir des modèles GGUF locaux sur le serveur, rendez llama-server
(le llama.cpp amont) disponible pour le daemon : celui-ci le lance et le
supervise, et le trouve via le PATH de l'utilisateur du service.
Installez-le une fois, là où le service s'exécute, exactement comme décrit
dans Installer et exécuter le runtime.
Le traitement par lots continu et l'appel d'outils natif sont intégrés à ce
moteur, si bien qu'un seul backend local sert déjà des requêtes concurrentes ;
voir Tirer le meilleur parti de l'inférence locale.
Voir aussi
- Installer et exécuter le runtime pour le détail de la compilation.
- La référence CLI pour toutes les commandes opérationnelles.
- Auditer et vérifier une exécution pour le flux de responsabilisation.