UltiSuite

La suite numérique souveraine et open source qui remplace vraiment les géants américains

Paris, France

@ultisuite/deploy (0.13.2)

Published 2026-08-20 09:06:48 +00:00 by docker-bot

Installation

@ultisuite:registry=https://gitea.reduav.eu/api/packages/UltiSuite/npm/
npm install @ultisuite/deploy@0.13.2
"@ultisuite/deploy": "0.13.2"

About this package

Installeur et orchestrateur Docker pour la Ultisuite (mail, drive, agenda, IA…) avec UI terminal Ink.

@ultisuite/deploy

Installeur et orchestrateur en ligne de commande pour la Ultisuite — alternative souveraine à Google Workspace (mail, drive, agenda, contacts, visio, photos, IA). Le CLI tire les images Docker précompilées depuis le registry Gitea (pas de clone du code source app), génère la configuration, gère le TLS et pilote la stack Compose depuis une interface terminal (Ink).

Installation

Le package est publié sur le registry npm privé Gitea (org ultisuite), pas sur npmjs.org.

1. Configurer le registry @ultisuite

npm config set @ultisuite:registry https://gitea.reduav.eu/api/packages/ultisuite/npm/
npm config set -- '//gitea.reduav.eu/api/packages/ultisuite/npm/:_authToken' '<token-read:package>'

Le token est un PAT Gitea avec au minimum read:package (token pull d’instance / licence, ou compte robot dédié).

2. Installer le CLI

# Global
npm install -g @ultisuite/deploy@latest

# Ou sans install globale
npx @ultisuite/deploy --help

3. Lancer l’install (mode images)

export ULTI_LICENSE_KEY='ulti_…'          # clé licence instance
# export ULTI_LICENSE_URL='https://license.example.com'  # si hors défaut

ulti-deploy install -y \
  --domain suite.example.com \
  --tls managed-acme \
  --acme-email admin@example.com \
  --version v1.2.3 \
  --license-key "$ULTI_LICENSE_KEY"

Le CLI échange la licence contre un token pull registry, télécharge le deploy-kit, fait docker login + compose pull + upsans --build et sans déposer le source Go/Next sur le serveur.

Doc closed-source détaillée : docs/closed-source-deploy.md.

Mode interne (clone + build)

Réservé aux machines qui ont déjà accès aux repos source :

ulti-deploy install -y --dev-source --domain localhost.test --tls none

Prérequis

  • Linux avec Docker + Docker Compose v2
  • Accès réseau sortant vers gitea.reduav.eu (registry container + npm + API licence)
  • Node ≥ 20 (pour npx / install globale)
  • Droits suffisants sur le répertoire de travail (par défaut /opt/ultisuite)
  • Clé licence ULTI_LICENSE_KEY (mode images)

Commandes

Commande Description
ulti-deploy install Config, TLS, pull images registry, démarrage (ou --dev-source = clone+build)
ulti-deploy doctor Diagnostic complet (Docker, disque, .env, conteneurs, santé backend, pare-feu)
ulti-deploy verify Teste l'accessibilité externe des domaines publics (DNS, TLS, endpoints HTTP)
ulti-deploy security-check Audit sécurité hôte (SSH, pare-feu, sudo, CVE Trivy, outils offensifs) — à lancer sur l'hôte, pas dans un conteneur ; outil partiel, ne remplace pas un audit pro
ulti-deploy upgrade Met à jour images / kit (ou tags git en mode --dev-source)
ulti-deploy migrate-to-images Passe une ancienne install clone+build vers images (supprime le source)
ulti-deploy backup Exporte une archive chiffrée (config, overrides, état, dumps PostgreSQL, object storage)
ulti-deploy restore <archive> Restaure une archive chiffrée puis redémarre la stack
ulti-deploy start / stop / restart / status / logs Cycle de vie de la stack
ulti-deploy privacy-check Smoke RGPD + contrôle anti-fuite source (mode images)

Option globale -w, --workspace <dir> pour cibler un autre répertoire de travail.

Scale (workers, PgBouncer, Meilisearch, Hocuspocus Redis, mail bodies S3, backup RustFS) : voir ulti-backend/docs/scale.md. Overlays modules : meilisearch, pgbouncer (--enable-module …).

Mode non-interactif & dry-run

install, upgrade, backup et restore acceptent un mode sans wizard Ink — obligatoire pour les agents et l'automatisation CI :

# Installation prod (ACME + images)
ulti-deploy install -y \
  --domain suite.example.com \
  --tls managed-acme --acme-email admin@example.com \
  --hosts-mode subdomain \
  --version v1.2.3 \
  --license-key "$ULTI_LICENSE_KEY" \
  --enable-module ai --enable-module mailEdge

# Config JSON (partiel) + surcharges CLI
ulti-deploy install -y --config ./deploy.json --enable-module jitsi --license-key "$ULTI_LICENSE_KEY"

# Dry-run : génère .env + overrides, sans Docker
ulti-deploy install -y --dry-run --domain suite.example.com --tls none --license-key "$ULTI_LICENSE_KEY"

# Profil cell (shard hyperscale) — cellId + router URL obligatoires
# Prérequis : control plane déjà up (ulti-router). Voir runbook hyperscale.
# ULTIROUTER_ADMIN_TOKEN : via envOverrides JSON / .env (pas un flag CLI).
ulti-deploy install -y \
  --domain cell1.example.com \
  --tls managed-acme --acme-email admin@example.com \
  --version v1.2.3 \
  --license-key "$ULTI_LICENSE_KEY" \
  --deployment-profile cell \
  --cell-id cell-eu-west-1 \
  --router-url https://router.example.com

Profils

Profile Défaut Compose overlay Control plane
standalone oui aucun (stack classique) Jamais requis
cell non deploy/cell/docker-compose.cell.yml (ulti-backend) — pin ULTI_DEPLOYMENT_MODE=cell + ids Déployé à part : deploy/controlplane/docker-compose.controlplane.yml (ulti-router + Postgres). Pas via ce CLI.

Runbooks (ulti-backend) :

install

Flag Description
-y, --non-interactive Sans wizard
-c, --config <file> JSON partiel (voir ci-dessous)
--dry-run Pas de démarrage Docker
--version <tag> Tag images / deploy-kit (ex. v1.2.3)
--license-key <key> Clé licence (ou env ULTI_LICENSE_KEY)
--license-url <url> API licence (défaut / env ULTI_LICENSE_URL)
--dev-source Clone git + build local (interne)
--no-build Pas de rebuild (mode --dev-source)
--domain, --tls, --acme-email, --cert, --key Domaine & TLS
--hosts-mode path|subdomain URLs apex vs sous-domaines
--cookie-domain Cookie SSO (ex. .example.com)
--backend-ref, --client-ref Tag/branche git (--dev-source only)
--enable-module, --disable-module Modules (répétables) : nextcloud, jitsi, ultichat, immich, onlyoffice, ai, stt, richtext, mailEdge, sovereign, license, meilisearch, pgbouncer
--deployment-profile standalone|cell Défaut standalone. cell merge l'overlay cell (env shard) — ne démarre pas ulti-router
--cell-id <id> Identifiant du shard (requis en profil cell)
--router-url <url> URL de base ulti-router déjà déployé (requis en profil cell)
--ear Active le chiffrement au repos (prod uniquement, opt-in)
--ear-key-server <url> URL ultikeyd (implique --ear)
--ear-lease-ttl-hours <n> Bail de déverrouillage LUKS en heures (défaut 168)

upgrade

ulti-deploy upgrade --check-only              # liste sans appliquer
ulti-deploy upgrade -y --yes --no-backup      # applique sans prompt
Flag Description
-y, --non-interactive Sans prompts
--yes Applique (sinon exit 2 si MAJ dispo)
--check-only Détection seule
--backup-password / --backup-password-env Backup pré-upgrade
--no-backup Saute le backup

backup / restore

export ULTI_DEPLOY_BACKUP_PASSWORD='…'
ulti-deploy backup -y -o ./backups/manual.ultibak

export ULTI_DEPLOY_RESTORE_PASSWORD='…'
ulti-deploy restore -y --yes ./backups/manual.ultibak
backup restore
--password / --password-env (ULTI_DEPLOY_BACKUP_PASSWORD) --password / --password-env (ULTI_DEPLOY_RESTORE_PASSWORD)
--include env,overrides,state,database,objectStorage,… --yes requis (destructif)
--no-restart

Doc agents détaillée : .cursor/rules/ulti-deploy-cli.mdc (dans ce repo).

Exemple de deploy.json (tous les champs sont optionnels sauf domain) :

{
  "domain": "suite.example.com",
  "workspaceDir": "/opt/ultisuite",
  "deploymentProfile": "standalone",
  "modules": { "ai": true, "mailEdge": true },
  "tls": { "mode": "managed-acme", "acmeEmail": "admin@example.com" },
  "ear": {
    "enabled": true,
    "keyServerUrl": "https://keys.example.com",
    "leaseTtlHours": 168
  },
  "secrets": { "POSTGRES_PASSWORD": "mon-secret-impose" }
}

Les secrets non fournis sont générés aléatoirement ; ceux présents dans secrets sont conservés.

Encryption at rest (prod)

Chiffrement au repos opt-in, réservé aux installs production (refusé avec --dev-source, domaine local, ou ULTID_ENVproduction).

ulti-deploy install -y \
  --domain suite.example.com \
  --tls managed-acme --acme-email admin@example.com \
  --version v1.2.3 \
  --license-key "$ULTI_LICENSE_KEY" \
  --ear --ear-key-server https://keys.example.com

# ou JSON deploy.json : ear.enabled + ear.keyServerUrl (+ ear.leaseTtlHours optionnel, défaut 168)

Variables hôte (écrites dans le .env backend quand EAR est activé) :

Variable Description
EAR_ENABLED true quand opt-in actif
ULTIKEYD_URL URL du serveur de garde de clés
EAR_LEASE_TTL_HOURS Durée du bail de déverrouillage (défaut 168)
ULTISEALD_SOCKET Socket unix ultiseald (défaut /run/ultiseal/ultiseald.sock)
ULTISEALD_SOCKET_TOKEN Bearer pour wrap/unwrap (doit matcher /etc/ultisuite/ultiseald.env côté serve)
EAR_*_HOST_PATH Bind mounts LUKS (postgres / rustfs / keydb — Valkey data)

Quand EAR_ENABLED=true et ultiseald serve a un bail ouvert : ulti-deploy backup produit ULTIBAK2 (DEK_bak wrappé via socket, sans OTP). Définir ULTISEALD_SOCKET_TOKEN dans l’env du CLI quand serve l’exige. Sans EAR : ULTIBAK1 (mot de passe). Restore V2 exige aussi le lease ouvert.

Détail garde de clés et LUKS : ulti-backend/docs/security/ear-key-custody.md. Rotation DEK (fenêtre maintenance) : ulti-backend/docs/security/ear-rotation.md. Voir aussi .env.example à la racine de ce repo.

Répertoire de travail

Mode images (défaut prod) :

/opt/ultisuite/
├─ deploy-kit/               kit Compose (nginx, overlays, .env.example) — pas de source app
├─ overrides/                fichiers générés (compose TLS, nginx, certs)
├─ backups/                  archives .ultibak
└─ state.json                état (config + version images déployée)

Mode --dev-source (interne) :

/opt/ultisuite/
├─ ulti-backend/             clone backend (build context Docker)
├─ gmail-interface-clone/    clone frontend (sibling Compose)
├─ overrides/
├─ backups/
└─ state.json

Configuration & secrets

Le CLI lit le .env.example du backend et génère un .env en :

  • remplaçant tous les secrets changeme par des valeurs aléatoires fortes (chaque secret reste overridable dans l'assistant) ;
  • préservant les placeholders {{VAR}} (expansés au runtime, comme le fait le backend) ;
  • basculant les URLs publiques en https://<domaine> et le frontend sur suite-frontend:3000 ;
  • activant/désactivant les modules optionnels (Nextcloud, Jitsi, Immich, OnlyOffice, UltiAI, mail edge…).

TLS / certificats

Quatre modes au choix dans l'assistant :

  • Let's Encrypt redondant (managed-acme) : terminateur TLS tls-edge + sidecar acme.sh avec bascule automatique entre autorités (Let's Encrypt → ZeroSSL → Buypass).
  • Certificats custom (managed-custom) : montage de vos cert/key.
  • Greffe nginx existant (graft) : génère un server-block pour votre nginx hôte (qui gère le TLS) et bind la stack sur 127.0.0.1:<port>.
  • HTTP seul (none) : pour le dev ou derrière un autre terminateur TLS.

Sauvegarde & restauration

Les archives .ultibak sont chiffrées en AES-256-GCM :

Format Quand Clé
ULTIBAK1 Dev / non-EAR (défaut) Mot de passe (scrypt) — ULTI_DEPLOY_BACKUP_PASSWORD
ULTIBAK2 EAR_ENABLED=true DEK_bak aléatoire, wrappée via socket ultiseald (lease ouvert, sans OTP)

L'assistant permet de choisir quoi inclure : configuration, overrides, état, dumps PostgreSQL (toutes bases), et optionnellement les volumes object storage.

Object storage (objectStorage, défaut on) : exporte le volume Docker ultisuite_rustfs_data, ou — sous EAR — le bind mount LUKS (EAR_RUSTFS_BIND / EAR_RUSTFS_HOST_PATH). Ce stockage contient tous les buckets RustFS, dont mail-bodies (corps de mails et enveloppes ciphertext Zero-Trust), mail-attachments, et les préfixes Nextcloud S3. Avec MAIL_BODY_STORAGE=s3 (défaut installs neuves), un dump Postgres seul ne suffit pas — garder objectStorage en prod.

Restore ULTIBAK2 : ultiseald serve doit avoir un lease ouvert (unwrap unattended). Restore ULTIBAK1 : mot de passe inchangé.

Scale / knobs associés : ulti-backend/docs/scale.md (PgBouncer, Meilisearch, workers, Hocuspocus Redis, body backfill).

Checklist RGPD (déploiement)

Après installation ou changement de modules :

  1. Région d'hébergementPRIVACY_HOSTING_PROVIDER (défaut OVH) + PRIVACY_DATA_REGION (ex. FR) pour la disclosure.
  2. Contacts confidentialité — renseigner NEXT_PUBLIC_PRIVACY_CONTACT_EMAIL et NEXT_PUBLIC_DPO_EMAIL dans le .env frontend.
  3. Matomo cookieless — si statistiques activées : NEXT_PUBLIC_MATOMO_URL + NEXT_PUBLIC_MATOMO_SITE_ID (Matomo sur la même infra, pas de bandeau cookies).
  4. Pages légales publiques — vérifier /privacy, /gdpr, /terms, /subprocessors, /dpa (HTTP 200 sans login).
  5. Sous-traitants dynamiques — après activation d'une intégration externe (IA, OAuth, Stripe, VirusTotal…), contrôler /subprocessors et GET /api/v1/privacy/disclosure.
  6. Intégrations org — documenter les webhooks et services tiers configurés par l'organisation auprès des utilisateurs.
  7. Sauvegardes vs erasure — voir ulti-backend/docs/compliance/backup-erasure.md : rétention .ultibak, destruction des archives hors délai ; une suppression utilisateur n'efface pas rétroactivement les backups existants.
  8. Restore drill — exercice périodique : ulti-backend/docs/compliance/restore-drill.md (jamais en prod avec une archive pré-erasure).
  9. Registre incidents — Admin → Confidentialité → registre d'incidents (délai CNIL 72 h) ; procédure docs/compliance/incident-response.md.
  10. Smoke RGPDulti-deploy privacy-check (pages légales + GET /api/v1/privacy/disclosure).
  11. SOC2 evidence (optionnel B2B)ulti-backend/docs/compliance/soc2-evidence.md (export revue d'accès utilisateurs + audit).

SecNumCloud (composition OVH)

  • Déployer sur une offre OVH qualifiée SecNumCloud (catalogue ANSSI).
  • Activer le module sovereign (--enable-module sovereign / SOVEREIGN_PROFILE=true) pour dépublier les ports RustFS.
  • Suivre ulti-backend/docs/compliance/secnumcloud-3.2-gap.md et network-segmentation.md.
  • Accords OVH : checklist ulti-backend/docs/compliance/ovh-accords-checklist.md.
  • HDS : guide ulti-backend/docs/compliance/hds-deploy-ovh.md (profil santé org).
  • Ne pas revendiquer le Visa SecNumCloud tant que la qualification UltiSuite (composition) n'est pas obtenue.

Smoke test : ulti-deploy verify inclut les endpoints légaux dans PUBLIC_ENDPOINTS.

CDN (prod)

Pour placer un CDN (Cloudflare, Fastly, CloudFront, etc.) devant la suite sans compromettre l’auth :

  • Doc complète : docs/cdn.md dans le deploy-kit / backend ($workspace/deploy-kit ou $workspace/ulti-backend en mode source).
  • Résumé : NGINX_DEV_NO_CACHE=false, DRIVE_MEDIA_SIGNING_KEY défini, cache edge uniquement sur allowlist (/_next/static/*, /api/v1/drive/media/preview?…, /api/v1/fonts/*), bypass sur le reste de /api/v1/* et les pages /mail, /drive.

Développement

pnpm install
pnpm dev -- --help     # lance le CLI via tsx
pnpm typecheck
pnpm build             # dist/cli.js minifié, sans sourcemaps (tsup)

Publish CI (tag v*) → registry npm Gitea ultisuite (voir .gitea/workflows/publish.yml).

Licence

MIT

Dependencies

Dependencies

ID Version
commander ^12.1.0
execa ^9.5.1
ink ^5.1.0
ink-big-text ^2.0.0
ink-gradient ^3.0.0
ink-select-input ^6.0.0
ink-spinner ^5.0.0
ink-text-input ^6.0.0
react ^18.3.1
semver ^7.6.3
tar ^7.4.3
zod ^3.23.8

Development Dependencies

ID Version
@types/node ^22.9.0
@types/react ^18.3.12
@types/semver ^7.5.8
tsup ^8.3.5
tsx ^4.19.2
typescript ^5.7.2
Details
npm
2026-08-20 09:06:48 +00:00
2
MIT
60 KiB
Assets (1)
Versions (33) View all
0.13.11 2026-09-18
0.13.9 2026-09-14
0.13.7 2026-08-28
0.13.5 2026-08-21
0.13.3 2026-08-21