.env
.env
Déploiement d'Ekylibre sur un serveur unique avec HTTPS automatique via Caddy + Let's Encrypt. Cette variante convient lorsque vous gérez ce serveur uniquement pour Ekylibre. Pour héberger plusieurs apps sur le même hôte, voir Docker prod Dokploy.
Avoir validé les prérequis communs :
80 et 443 ouverts publiquementexample.com + *.example.com) pointant vers le serveursysctl vm.overcommit_memory=1 appliqué.env
git clone -b 5.0-beta https://github.com/ekylibre/ekylibre.git
cd ekylibre
cp docker/prod/.env.dist docker/prod/.env
Éditer docker/prod/.env et renseigner au minimum :
| Variable | Description |
|---|---|
HOST_DOMAIN_NAME |
Nom de domaine (sans protocole ni sous-domaine), ex: ekylibre.example.com
|
LETSENCRYPT_EMAIL |
Email pour les notifications Let's Encrypt |
SECRET_KEY_BASE |
À générer : openssl rand -hex 64
|
ADMIN_USERNAME / ADMIN_PASSWORD
|
Accès HTTP Basic à /admin
|
DB_PASSWORD |
Mot de passe PostgreSQL fort (20+ caractères) |
Sécurité : après édition,
chmod 600 docker/prod/.env. Ce fichier contient des secrets et est gitignored.
L'image Ekylibre est publiée sur GHCR par le workflow .github/workflows/build-prod-image.yml à chaque push sur main ou 5.0-beta. Aucun build local n'est nécessaire en production :
docker compose -f docker/prod/docker-compose.yml pull
Images tirées :
ghcr.io/ekylibre/ekylibre/app:latest (Rails + Sidekiq, image partagée)caddy:2-alpine (reverse-proxy)kartoza/postgis:13 (PostgreSQL)redis:7-alpinePinner une version stable : éditer
EKYLIBRE_IMAGE_TAGdans.env(ex:EKYLIBRE_IMAGE_TAG=v5.0.0).
L'image GHCR embarque les plugins publics listés dans docker/prod/Gemfile.prod (banking, qonto, baqio, ednotif, planning, samsys, traccar, weenat, sencrop, hve, idea, hajimari, viti, etc.). Pour ajouter / retirer un plugin, éditer ce fichier et déclencher un nouveau build.
Toujours au HEAD de la branche : chaque build ré-interroge GitHub et installe le dernier commit de la branche déclarée pour chaque plugin. Voir le détail technique dans docker/prod/README.md § 2.
Plugins privés ou path-local : builder localement :
docker build -f docker/prod/Dockerfile -t ghcr.io/ekylibre/ekylibre/app:local .
EKYLIBRE_IMAGE_TAG=local docker compose -f docker/prod/docker-compose.yml up -d
Pour ce cas, adapter docker/prod/Dockerfile (retirer le rm -f Gemfile.local) et fournir votre Gemfile.local.
docker compose -f docker/prod/docker-compose.yml up -d
Suivre les logs du service app :
docker compose -f docker/prod/docker-compose.yml logs -f app
Au premier démarrage, le container app :
db:create)db:migrate)lexicon:load) — 5 à 10 minutes
Attendre le message ==START PUMA== avant de tester.
Caddy provisionne les certificats Let's Encrypt automatiquement au premier accès HTTPS sur chaque sous-domaine.
Browser ─HTTPS─► Caddy :443 (cert LE par sous-domaine)
│ termine TLS, provisionne on-demand via ACME
│
├─► example.com → app:3000 (landing)
├─► duke.example.com → duke-api:8000 (Duke, optionnel)
└─► *.example.com (tenants) → app:3000
Browser ─HTTP─► Caddy :80 (challenge HTTP-01 + redirect HTTPS)
Le Caddyfile utilise on_demand_tls pour ne pas provisionner de cert sur des hostnames bidons :
on_demand_tls {
ask http://app:3000/health
}
À chaque sous-domaine inédit, Caddy interroge /health de Rails avant de demander un cert LE. Cela protège du rate-limit Let's Encrypt (50 certs/semaine/domaine racine).
# 1. Healthcheck applicatif
curl -I https://example.com/health
# → HTTP/2 200
# 2. Page de connexion
curl -I https://example.com/
# → HTTP/2 302 (redirection vers /users/sign_in)
# 3. Cert présenté pour un tenant
curl -I https://acme.example.com/
# Premier hit : ~10s (challenge ACME), puis 302 → /sign-in
# 4. Voir les certs déjà obtenus par Caddy
docker compose -f docker/prod/docker-compose.yml exec caddy \
ls /data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/
./docker/prod/scripts/tenant-init.sh acme admin@acme.com 'MotDePasseFort!'
Le tenant est accessible sur https://acme.example.com après quelques secondes (provisioning du cert TLS).
Charger des données de démo (optionnel) :
docker compose -f docker/prod/docker-compose.yml exec -e TENANT=acme app \
bundle exec rake first_run FOLDER=demo
| Service | Image | Rôle | Port hôte |
|---|---|---|---|
app |
ghcr.io/ekylibre/ekylibre/app:latest |
Serveur Rails (Puma) | (interne 3000) |
sidekiq |
(même image) | Worker de jobs | — |
caddy |
caddy:2-alpine |
Reverse-proxy HTTPS |
80 / 443
|
db |
kartoza/postgis:13 |
PostgreSQL + PostGIS | non exposé |
redis |
redis:7-alpine |
Cache + Sidekiq | non exposé |
Vérifier que les ports
5432,6379,11434ne sont pas exposés sur l'hôte (ss -tln).
# Arrêter
docker compose -f docker/prod/docker-compose.yml down
# Logs
docker compose -f docker/prod/docker-compose.yml logs -f app sidekiq
# Shell + console Rails
docker compose -f docker/prod/docker-compose.yml exec app bash
docker compose -f docker/prod/docker-compose.yml exec app bundle exec rails c
# Mise à jour applicative (image latest)
docker compose -f docker/prod/docker-compose.yml pull
docker compose -f docker/prod/docker-compose.yml up -d
Les migrations sont rejouées automatiquement par startup.sh. Le lexicon n'est rechargé que si .lexicon-version a changé.
Backup manuel :
docker compose -f docker/prod/docker-compose.yml exec db \
pg_dump -U ekylibre eky_production > backup_$(date +%F).sql
Cron quotidien avec rotation 7 jours :
0 3 * * * cd /path/to/ekylibre && docker compose -f docker/prod/docker-compose.yml exec -T db pg_dump -U ekylibre eky_production > backups/db_$(date +\%F).sql && find backups -name 'db_*.sql' -mtime +7 -delete
Restauration :
docker compose -f docker/prod/docker-compose.yml exec -T db \
psql -U ekylibre eky_production < backup_2026-06-12.sql
chmod 600 docker/prod/.env après chaque éditionADMIN_PASSWORD et DB_PASSWORD : 20+ caractères, générés aléatoirementss -tln : seuls 80 et 443 doivent être ouverts publiquementpull + up -d)uploads, caddy-data (certificats)Duke est un assistant chatbot agricole packagé en image publique GHCR. Activation en 3 étapes (configuration .env + recreate db + démarrage Duke). Procédure détaillée dans docker/prod/README.md §10.
./docker/prod/scripts/duke-up.sh
Avec LLM local (Ollama) :
./docker/prod/scripts/duke-up.sh --with-local-llm
Ollama avec
mistral-nemo(12B) est très lent sur CPU. Réservé aux serveurs GPU NVIDIA.
Voir Résolution de problèmes — notamment :
/health non joignable, rate-limit LE)SECRET_KEY_BASE is empty./docker/prod/scripts/lexicon-reload.sh
db pg_isready
.env
Voir docker/prod/.env.dist pour la liste exhaustive. Variables groupées en sections :
RAILS_ENV, HOST_DOMAIN_NAME, ADMIN_*, SECRET_KEY_BASE, Puma tuningDB_*
REDIS_URL
LETSENCRYPT_EMAIL
MINIO_* (optionnel)ELASTIC_APM_ACTIVE (optionnel)DUKE_*, EKYLIBRE_DB_DSN, HASH_SECRET, clés LLM, OLLAMA_*
Pour héberger plusieurs apps sur le même serveur, voir Docker prod Dokploy.
Cette documentation est open-source. Aidez-nous à l'améliorer en ouvrant une issue ou une pull request.