# ============================================================================= # Ulti Backend — Configuration # ============================================================================= # Secrets : definir UNE FOIS dans la section ci-dessous. # Le reste du fichier utilise {{NOM_VARIABLE}} — expansion au lancement # (docker compose, go run, migrate) via cmd/envexpand → .env.resolved # # Chaque brique peut etre en mode "local" (stack Docker) ou "external". # ============================================================================= # ----------------------------------------------------------------------------- # Secrets — source unique (rotation ici uniquement) # ----------------------------------------------------------------------------- POSTGRES_PASSWORD=changeme RUSTFS_ACCESS_KEY=ultiadmin RUSTFS_SECRET_KEY=changeme123 AUTHENTIK_SECRET_KEY=changeme-generate-a-long-random-string ULTID_OIDC_CLIENT_SECRET=changeme MAIL_CREDENTIAL_KEYS=v1:MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY= MAIL_ACTIVE_CREDENTIAL_KEY_ID=v1 MAIL_WEBHOOK_SHARED_SECRET=changeme-webhook-signing-secret NC_ADMIN_PASSWORD=changeme NC_OIDC_CLIENT_SECRET=changeme ONLYOFFICE_OIDC_CLIENT_SECRET=changeme IMMICH_OIDC_CLIENT_SECRET=changeme JITSI_APP_SECRET=changeme-jwt-secret JITSI_INTERNAL_AUTH_PASSWORD=changeme KEYDB_PASSWORD= MEILISEARCH_API_KEY=changeme TYPESENSE_API_KEY=changeme # ----------------------------------------------------------------------------- # General # ----------------------------------------------------------------------------- DOMAIN=localhost ULTID_PORT=8080 # Origines navigateur autorisees (web app sur autre port/origine que l'API). # Vide = auto : localhost/127.0.0.1/LAN prive en dev ; http(s)://${DOMAIN} en prod. # Exemple dev explicite : ULTID_CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000 # ULTID_CORS_ALLOWED_ORIGINS= # ----------------------------------------------------------------------------- # PostgreSQL # Mode local : deploye dans la stack Docker (deploy/docker-compose.yml) # Mode externe : pointer vers une instance existante # ----------------------------------------------------------------------------- POSTGRES_USER=ulti POSTGRES_DB=ultidb POSTGRES_MULTIPLE_DATABASES=ultidb,authentik,nextcloud,immich # Connection utilisee par ultid (changer host pour instance externe) ULTID_DB_URL=postgres://{{POSTGRES_USER}}:{{POSTGRES_PASSWORD}}@postgres:5432/{{POSTGRES_DB}}?sslmode=disable # Exemple externe : # ULTID_DB_URL=postgres://user:{{POSTGRES_PASSWORD}}@db.example.com:5432/ultidb?sslmode=require # ----------------------------------------------------------------------------- # KeyDB (Redis-compatible) # Mode local : deploye dans la stack # Mode externe : pointer vers un Redis/KeyDB/Valkey existant # ----------------------------------------------------------------------------- ULTID_KEYDB_URL=keydb:6379 ULTID_KEYDB_PASSWORD={{KEYDB_PASSWORD}} ULTID_KEYDB_DB=0 # Exemple externe : ULTID_KEYDB_URL=redis.example.com:6379 KEYDB_HOST=keydb KEYDB_PORT=6379 # ----------------------------------------------------------------------------- # Object Storage (S3-compatible : RustFS, MinIO, AWS S3, Backblaze, etc.) # Mode local : RustFS deploye dans la stack # Mode externe : n'importe quel endpoint S3-compatible # ----------------------------------------------------------------------------- ULTID_RUSTFS_ENDPOINT=rustfs:9000 ULTID_RUSTFS_ACCESS_KEY={{RUSTFS_ACCESS_KEY}} ULTID_RUSTFS_SECRET_KEY={{RUSTFS_SECRET_KEY}} ULTID_RUSTFS_USE_SSL=false ULTID_RUSTFS_REGION=us-east-1 # Exemple AWS S3 : # ULTID_RUSTFS_ENDPOINT=s3.amazonaws.com # ULTID_RUSTFS_USE_SSL=true # ULTID_RUSTFS_REGION=eu-west-1 # ----------------------------------------------------------------------------- # Auth / OIDC (Authentik, Keycloak, ou tout provider OIDC) # Mode local : Authentik deploye dans la stack # Mode externe : n'importe quel provider OIDC existant # ----------------------------------------------------------------------------- # Issuer vu par ultid (via nginx interne Docker). DOMAIN sert de Host header pour discovery # afin que l'issuer attendu = iss des tokens navigateur (http://localhost/auth/application/o/ulti/). ULTID_OIDC_ISSUER=http://nginx/auth/application/o/ulti/ ULTID_OIDC_CLIENT_ID=ulti-backend # ULTID_OIDC_CLIENT_SECRET — defini dans la section Secrets (doit matcher blueprint Authentik) ULTID_AUTO_MIGRATE=true # Exemple Keycloak externe : # ULTID_OIDC_ISSUER=https://auth.example.com/realms/ulti # ULTID_OIDC_CLIENT_ID=ulti-backend # Config du container Authentik local (ignoree si provider externe) # AUTHENTIK_SECRET_KEY — defini dans la section Secrets AUTHENTIK_POSTGRESQL__HOST=postgres AUTHENTIK_POSTGRESQL__USER={{POSTGRES_USER}} AUTHENTIK_POSTGRESQL__PASSWORD={{POSTGRES_PASSWORD}} AUTHENTIK_POSTGRESQL__NAME=authentik AUTHENTIK_REDIS__HOST=keydb AUTHENTIK_WEB__PATH=/auth/ # URL publique affichee dans les redirects OIDC (navigateur) AUTHENTIK_HOST=http://{{DOMAIN}} # API interne (ultid → authentik-server) pour provisionner les apps OIDC au demarrage AUTHENTIK_API_URL=http://authentik-server:9000 # Token admin Authentik (Flows & Stages → Tokens) — active le provisioning API ultid # AUTHENTIK_API_TOKEN — defini dans la section Secrets (optionnel ; sinon blueprints seuls) # ----------------------------------------------------------------------------- # Nextcloud (Drive / Calendar / Contacts) # Mode local : Nextcloud FPM deploye dans la stack # Mode externe : instance Nextcloud existante # ----------------------------------------------------------------------------- # URL interne (ultid → nginx Nextcloud, racine WebDAV) NEXTCLOUD_URL=http://nextcloud:80 # URL publique UI (edge nginx /cloud/) — aussi base Destination WebDAV MOVE/COPY NC_PUBLIC_URL=http://{{DOMAIN}}/cloud NC_OVERWRITE_PROTOCOL=http NC_ADMIN_USER=admin # NC_ADMIN_PASSWORD — defini dans la section Secrets # Exemple externe : # NEXTCLOUD_URL=https://cloud.example.com # NC_ADMIN_USER=ulti-service # Desactiver (pas de Drive/Cal/Contacts) : NEXTCLOUD_ENABLED=false NEXTCLOUD_ENABLED=true # Ce flag pilote aussi le lancement Docker via ./deploy/compose-up.sh NC_OIDC_CLIENT_ID=ulti-nextcloud # NC_OIDC_CLIENT_SECRET — defini dans la section Secrets NC_OIDC_DISCOVERY_URL=http://nginx/auth/application/o/nextcloud/.well-known/openid-configuration NC_S3_BUCKET=nextcloud NC_S3_HOST=rustfs NC_S3_PORT=9000 NC_S3_KEY={{RUSTFS_ACCESS_KEY}} NC_S3_SECRET={{RUSTFS_SECRET_KEY}} NC_S3_SSL=false # ----------------------------------------------------------------------------- # OnlyOffice (Docs / Sheets / Slides) # ----------------------------------------------------------------------------- ONLYOFFICE_ENABLED=false ONLYOFFICE_URL=http://onlyoffice ONLYOFFICE_PUBLIC_URL=http://{{DOMAIN}}/office # URL ultid joignable depuis le conteneur OnlyOffice (fetch doc + callback) ONLYOFFICE_API_INTERNAL_URL=http://ultid:8080 # URL Nextcloud joignable depuis OnlyOffice (host nginx Docker). Nginx route /index.php/* → Nextcloud. # NC_ONLYOFFICE_STORAGE_URL=http://nginx # Docker compose OnlyOffice also sets ALLOW_PRIVATE_IP_ADDRESS=true (required for internal URLs) ONLYOFFICE_JWT_SECRET=changeme-onlyoffice-jwt ONLYOFFICE_OIDC_CLIENT_ID=ulti-onlyoffice # ONLYOFFICE_OIDC_CLIENT_SECRET — defini dans la section Secrets ULTID_PUBLIC_URL=http://{{DOMAIN}} # Base URL for public share links (default: {ULTID_PUBLIC_URL}/drive → /drive/s/{token}) # DRIVE_PUBLIC_URL=http://{{DOMAIN}}/drive # ----------------------------------------------------------------------------- # Jitsi Meet (Visioconference) # Mode local : Jitsi deploye dans la stack # Mode externe : instance Jitsi existante avec JWT configure # ----------------------------------------------------------------------------- JITSI_ENABLED=true # Ce flag pilote aussi le lancement Docker via ./deploy/compose-up.sh JITSI_DOMAIN=meet.jitsi JITSI_APP_ID=ulti # JITSI_APP_SECRET — defini dans la section Secrets JITSI_PUBLIC_URL=https://{{DOMAIN}}/meet JICOFO_AUTH_PASSWORD={{JITSI_INTERNAL_AUTH_PASSWORD}} JVB_AUTH_PASSWORD={{JITSI_INTERNAL_AUTH_PASSWORD}} JVB_STUN_SERVERS=stun.l.google.com:19302 # ----------------------------------------------------------------------------- # Immich (Photos) # Mode local : Immich deploye dans la stack # Mode externe : instance Immich existante # ----------------------------------------------------------------------------- IMMICH_ENABLED=true # Ce flag pilote aussi le lancement Docker via ./deploy/compose-up.sh # Immich utilise son propre Postgres (pgvecto.rs) via immich-postgres IMMICH_API_URL=http://immich-server:2283/api # Quota photos partagé avec Ultidrive (0 = désactivé) ULTID_PHOTOS_MAX_UPLOAD_BYTES=0 ULTID_PHOTOS_QUOTA_RESERVED_BYTES=0 IMMICH_DB_NAME=immich IMMICH_UPLOAD_LOCATION=/upload IMMICH_ML_URL=http://immich-ml:3003 # ----------------------------------------------------------------------------- # Health checks / Observability # ----------------------------------------------------------------------------- # Endpoints vérifiés par /healthz (surchargables pour déploiements externes) HEALTH_NEXTCLOUD_URL={{NEXTCLOUD_URL}}/status.php HEALTH_IMMICH_URL={{IMMICH_API_URL}}/server-info/ping # Par défaut on retire /meet de JITSI_PUBLIC_URL pour viser /about/health HEALTH_JITSI_URL=https://{{DOMAIN}}/about/health HEALTH_HTTP_TIMEOUT=3s # Grafana local (monitoring) GRAFANA_ADMIN_USER=admin GRAFANA_ADMIN_PASSWORD=admin # ----------------------------------------------------------------------------- # Mail (Ultimail) — toujours gere par ultid # ----------------------------------------------------------------------------- MAIL_ATTACHMENTS_BUCKET=mail-attachments MAIL_SYNC_INTERVAL=2m MAIL_OUTBOX_INTERVAL=10s MAIL_OUTBOX_MAX_RETRIES=8 MAIL_SEND_RATE_PER_MINUTE=30 MAIL_SEND_BURST=10 MAIL_SMTP_CIRCUIT_FAILURES=5 MAIL_SMTP_CIRCUIT_COOLDOWN=5m # Credentials IMAP/SMTP chiffrés AES-GCM (format keyring: key_id:base64key,key_id2:base64key2) # Rotation: ajouter nouvelle clé dans MAIL_CREDENTIAL_KEYS puis basculer MAIL_ACTIVE_CREDENTIAL_KEY_ID. # Les anciennes clés restent présentes temporairement pour déchiffrement. # Runtime secrets possibles via *_FILE (ex: MAIL_CREDENTIAL_KEYS_FILE=/run/secrets/mail_keys) # Politique rotation secrets (RFC3339 + durée) SECRET_ROTATION_MAX_AGE=2160h ULTID_OIDC_CLIENT_SECRET_ROTATED_AT=2026-01-01T00:00:00Z MAIL_CREDENTIAL_KEY_ROTATED_AT=2026-01-01T00:00:00Z # Mail provider OAuth (Gmail / Microsoft 365) — optional # Redirect URI must match Google/Azure app config, e.g. https://api.example.com/api/v1/mail/accounts/oauth/callback MAIL_GOOGLE_OAUTH_CLIENT_ID= MAIL_GOOGLE_OAUTH_CLIENT_SECRET= MAIL_MICROSOFT_OAUTH_CLIENT_ID= MAIL_MICROSOFT_OAUTH_CLIENT_SECRET= MAIL_MICROSOFT_OAUTH_TENANT=common MAIL_OAUTH_REDIRECT_URL= MAIL_APP_URL=http://localhost/mail # Cible nginx → suite frontend unifié mail+drive (dev: Next sur l'hôte ; prod: suite-frontend:3000) MAIL_FRONTEND_UPSTREAM=host.docker.internal:3000 MAIL_WEBHOOK_SHARED_SECRET_ROTATED_AT=2026-01-01T00:00:00Z # ----------------------------------------------------------------------------- # Recherche # SEARCH_ENGINE: postgres (defaut) | meilisearch | typesense # ----------------------------------------------------------------------------- SEARCH_ENGINE=postgres # --- Meilisearch (SEARCH_ENGINE=meilisearch) --- # MEILISEARCH_URL=http://meilisearch:7700 # MEILISEARCH_API_KEY={{MEILISEARCH_API_KEY}} # MEILISEARCH_INDEX=ulti # --- Typesense (SEARCH_ENGINE=typesense) --- # TYPESENSE_URL=http://typesense:8108 # TYPESENSE_API_KEY={{TYPESENSE_API_KEY}} # TYPESENSE_COLLECTION=ulti