Mon nuage Cozy

Je vais vous parler aujourd’hui du nuage Cozy. Cozy est une solution d’informatique en nuage qui permet de faire à peu près tout ce que nous avons mis en place, et bien plus :

  • une galerie de photos,
  • un gestionnaire de mots de passe,
  • une gestion des contacts,
  • le stockage de vos papiers d’identité ou à valeur administrative,

Je ne suis généralement pas un grand promoteur des solutions « qui font tout » pour deux raisons :

  • d’une part elles ne se portent pas au niveau des meilleures solutions dans chaque domaine ; par exemple Cozy n’a pas une solution de gestion des photos comparable à Immich, qui surclasse tous les acteurs du libre en la matière ; par contre Immich s’appuie sur Bitwarden pour sa gestion des mots de passe, ce qui lui permet d’être au niveau de l’acteur de référence,
  • d’autre part elles présentent une surface d’attaque très large compte tenu de l’ampleur de leur périmètre, ce qui est un élément souvent rédhibitoire à mes yeux.

Alors pourquoi ai-je décidé de vous parler de Cozy ? Parce que cette solution propose quelque chose que je n’ai retrouvé jusqu’à présent chez aucun autre acteur du libre, à savoir la capacité à rassembler les données éparpillées chez vos différents fournisseurs ou partenaires : les relevés de banque, les factures télécom, les relevés de remboursement de l’assurance maladie, les avis d’imposition, … Tout cela est récupéré directement auprès de chacun de vos interlocuteurs et stocké dans votre coffre-fort Cozy. Ainsi, une fois que vous avez installé l’application compagnon sur votre téléphone, vous avez en permanence l’essentiel de vos documents sur vous. C’est surtout ce volet-là qui m’intéressait fortement, et dont j’ai envie de faire la promotion par cet article (je précise à nouveau que mon blog n’est pas sponsorisé et ne reçoit aucun financement, ni de la part de partenaires, ni de la part d’annonceurs). Je précise que les connecteurs sont essentiellement disponibles pour les organismes opérant en France ; si des utilisateurs d’autres pays souhaitent contribuer à l’extension du périmètre géographique couvert en développant de nouveaux connecteurs, je suppose qu’ils seront bienvenus.

Comme Cozy permet d’installer les différentes fonctions séparément, je n’ai pas installé celles de galerie photo ou de gestionnaire de mots de passe, pour lesquelles j’ai souhaité conserver Immich et Vaultwarden.

Comme rien n’est jamais parfait, Cozy souffre de quelques défauts :

  • la construction des connecteurs qui vont chercher les données auprès de vos fournisseurs et partenaires est quelque chose d’assez complexe et surtout, ces connecteurs doivent être modifiés à chaque fois que le partenaire fait évoluer ses propres interfaces, ce qui génère des dysfonctionnements pour les connections existantes ; résultat : le nombre de connecteurs est limité ; tous vos partenaires ne seront pas couverts et certaines connections pourront dysfonctionner pendant un certain temps,
  • Cozy ne met pas à disposition de solution Docker immédiatement disponible sur Raspberry Pi (un problème d’incompatibilité avec les spécificités de la puce du Pi) ; j’espère que cette limitation sera rapidement levée ; pour ma part, j’ai profité d’un investissement sur une machine plus puissante pour l’installer. Ceci étant, vous pouvez si vous souhaitez installer Cozy sur votre Raspberry Pi, vous appuyer sur l’image que j’ai concoctée pour vous selon la méthode officielle de Cozy.

L’installation du nuage Cozy

Après cette longue introduction et pour vous qui êtes encore avec moi, je vous propose de passer à l’action en vue d’installer Cozy sur notre machine, en tenant compte de l’ensemble du patrimoine applicatif que nous avons déjà déployé. Ainsi, le modèle fourni par Cozy pour déployer l’application intègre son propre proxy inverse ; comme nous en disposons déjà, nous allons supprimer les éléments qui lui sont spécifiques. Par ailleurs, il nécessite l’accès à un serveur d’émission de courriels, cette solution étant actuellement la seule disponible sur Cozy pour mettre en oeuvre une authentification à deux facteurs, nécessaire notamment à l’application mobile.

La première chose à faire est de copier le répertoire github sur lequel l’application est disponible. Pour cela nous utilisons la commande git clone.

sudo git clone https://github.com/cozy/cozy-stack-compose.git ~/cozy

Nous allons dans le répertoire cozy ainsi créé et repérons le fichier env.template. Il s’agit du modèle de fichier portant les variables d’environnement de notre Cozy. Pour le rendre utilisable, nous le renommons .env et nous l’éditons :

sudo mv env.template .env
sudo nano .env

Nous allons le modifier pour y insérer les variables qui lui permettront de s’intégrer dans notre système. Le fichier d’origine se présente comme suit :

##############################################
#                                            #
#     Sample Env file for docker-compose     #
#                                            #
##############################################

## Global configuration
#######################

# The base domain for all your instances
DOMAIN=domain.example

## Reverse proxy
################

# The email address used to generate let's Encrypt certificates on-the-fly
ACME_EMAIL=your.email@domain.example

# CouchDB
##########

COUCHDB_PROTOCOL=http
COUCHDB_HOST=couchdb
COUCHDB_PORT=5984
COUCHDB_USER=cozy
COUCHDB_PASSWORD=SomeRandomlyGeneratedPassword

# Stack
#######

# Admin passphrase for all administrative commands
# Should be set on first container launch to define the password
# If undefined on first start, a random password will be chosen and shown in logs
# You can remove this line and restart container if you want cozy-stack to
# ask for admin password on each command line call
COZY_ADMIN_PASSPHRASE=AnotherRandomlyGeneratedPassword

# Application subdomain type for each cozy.
# could be nested (https://<app>.<instance>.<domain>)
# or flat (https://<instance>-<app>.<domain>)
COZY_SUBDOMAIN_TYPE=flat

# Mail
START_EMBEDDED_POSTFIX=true
MAIL_HOST=localhost
MAIL_PORT=25
MAIL_USERNAME=""
MAIL_PASSWORD=""
MAIL_DISABLE_TLS=true
MAIL_USE_SSL=false
MAIL_SKIP_CERTIFICATE_VALIDATION=false
MAIL_LOCAL_NAME=localhost

Nous allons saisir les informations suivantes :

  • DOMAIN : nous indiquons le nom de notre domaine (ici k-sper.fr) ; attention : il ne s’agit pas du sous-domaine que nous allons utiliser pour l’application (dans notre cas cozy.k-sper.fr),
  • la variable ACME_EMAIL ne nous intéresse pas car elle sert dans le cadre de l’obtention des certificats pour notre nouveau sous-domaine ; cette fonction est chez nous assurée par Swag, qui dispose déjà de sa gestion de l’adresse ; nous laissons donc la variable inchangée,
  • nous laissons le pavé Couchdb inchangé, à l’exception du mot de passe, que nous générons avec Vaultwarden ; de préférence sans caractères spéciaux, qui peuvent interférer avec l’interprétation du fichier,
  • nous générons ensuite également un mot de passe de l’administrateur, toujours à l’aide de Vaultwarden et toujours sans caractères spéciaux, et nous le positionnons sur la variable COZY_ADMIN_PASSPHRASE ; si vous êtes un irréductible des mots de passe avec caractères spéciaux, sachez que vous pourrez le changer à tout moment,
  • nous devons ensuite choisir les modalités de présentation des sous-(sous-)domaines ; j’ai à titre personnel une préférence pour la présentation « nested » qui permet d’avoir un affichage des applications comme ceci : application.cozy.k-sper.fr,
  • ensuite nous devons insérer les données portant sur le serveur courriel que nous utilisons ; je fais partie de ceux qui exploitent leur propre serveur de courriel mais je ne le recommande pas en général compte tenu de la complexité de mise en place et de la difficulté à le sécuriser ; il vous faudra donc ici positionner les données de votre serveur de courriel habituel, telles que vous les insérez dans vos clients de messagerie (serveur SMTP ou serveur sortant) ; si vous n’insérez pas de données de serveur de courriel vous ne pourrez pas utiliser l’application mobile,
  • nous ajoutons également une variable sur le fuseau horaire en fin de fichier : TZ= »Europe/Paris » (selon votre fuseau horaire).

De mon côté, le fichier .env devient :

##############################################
#                                            #
#     Sample Env file for docker-compose     #
#                                            #
##############################################

## Global configuration
#######################

# The base domain for all your instances
DOMAIN=k-sper.fr

## Reverse proxy
################

# The email address used to generate let's Encrypt certificates on-the-fly
ACME_EMAIL=your.email@domain.example

# CouchDB
##########

COUCHDB_PROTOCOL=http
COUCHDB_HOST=couchdb
COUCHDB_PORT=5984
COUCHDB_USER=cozy
COUCHDB_PASSWORD=<mot-de-passe>

# Stack
#######

# Admin passphrase for all administrative commands
# Should be set on first container launch to define the password
# If undefined on first start, a random password will be chosen and shown in logs
# You can remove this line and restart container if you want cozy-stack to
# ask for admin password on each command line call
COZY_ADMIN_PASSPHRASE=<autre-mot-de-passe>

# Application subdomain type for each cozy.
# could be nested (https://<app>.<instance>.<domain>)
# or flat (https://<instance>-<app>.<domain>)
COZY_SUBDOMAIN_TYPE=nested

# Mail
START_EMBEDDED_POSTFIX=true
MAIL_HOST=mail.k-sper.fr
MAIL_PORT=465
MAIL_USERNAME="k-sper@k-sper.fr"
MAIL_PASSWORD=<votre-mot-de-passe-de-messagerie>
MAIL_DISABLE_TLS=false
MAIL_USE_SSL=true
MAIL_SKIP_CERTIFICATE_VALIDATION=false
MAIL_LOCAL_NAME=k-sper

TZ="Europe/Paris"

Nous allons maintenant nous intéresser à l’incontournable fichier docker-compose.yml, qui nous simplifie tant l’installation des applications. Il apparaît ainsi :

version: "3.8"
name: cozy

services:
  # Database
  couchdb:
    image: couchdb:3.3
    restart: unless-stopped
    env_file: .env
    volumes:
      - ./volumes/couchdb/data:/opt/couchdb/data
    healthcheck:
      test:
        [
          "CMD",
          "curl",
          "-f",
          "${COUCHDB_PROTOCOL}://${COUCHDB_USER}:${COUCHDB_PASSWORD}@${COUCHDB_HOST}:${COUCHDB_PORT}/_up",
        ]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 30s

  # Cozy Stack
  stack:
    image: cozy/cozy-stack
    pull_policy: always
    restart: unless-stopped
    env_file: .env
    depends_on:
      - couchdb
    healthcheck:
      test: '[ "$(curl -fsSL http://localhost:8080/status | jq -r .status)" = "OK" ]'
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 30s
    volumes:
      - ./volumes/cozy-stack/data:/var/lib/cozy/data
      - ./volumes/cozy-stack/config:/etc/cozy/
      - ./files/cozy.yml:/etc/cozy/cozy.yml

  # Reverse Proxy
  caddy:
    image: caddy:2.7
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
    depends_on:
      - stack
    volumes:
      - ./volumes/caddy/data:/data
      - ./volumes/caddy/etc:/etc/caddy
      - ./files/Caddyfile:/etc/caddy/Caddyfile
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"

Nous allons lui apporter quelques modifications pour tenir compte des autres éléments qui constituent notre installation :

  • pour les utilisateurs de Raspberry Pi, nous remplacerons « image: cozy/cozy-stack » par « image: eirikr70:cozy-stack »,
  • nous allons supprimer tout le pavé qui concerne le proxy inverse, puisque nous en disposons déjà (suppression de toutes les lignes à partir de # Reverse Proxy),
  • je préfère à titre personnel préciser le nom des conteneurs en spécifiant la variable container_name, que je positionne à cozy-couch pour la base de données, et à cozy pour le conteneur dédié à Cozy,
  • nous allons spécifier le port par lequel l’application sera accessible ; dans le pavé Cozy-Stack nous précisons (il convient de tenir compte des éventuels conflits de ports, et nous avons déjà utilisé le port 8080 de l’hôte pour Vaultwarden) :
    ports
    8085:8080
  • à titre personnel, je préfère renvoyer les volumes qui portent les données sur un disque dédié, ainsi je change toutes les occurrences de ./volume en /srv/nas/cozy.

Pour ma part, je me retrouve ainsi avec le docker-compose.yml suivant :

name: cozy

services:
  # Database
  couchdb:
    image: couchdb:3.3
    container_name: cozy-couch
    restart: unless-stopped
    env_file: .env
    volumes:
      - /srv/nas/cozy/couchdb:/opt/couchdb/data
    healthcheck:
      test:
        [
          "CMD",
          "curl",
          "-f",
          "${COUCHDB_PROTOCOL}://${COUCHDB_USER}:${COUCHDB_PASSWORD}@${COUCHDB_HOST}:${COUCHDB_PORT}/_up",
        ]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 30s

  # Cozy Stack
  stack:
    image: cozy/cozy-stack # sur Raspberry Pi, à remplacer par image: eirikr70/cozy-stack
    container_name: cozy
    pull_policy: always
    restart: unless-stopped
    env_file: .env
    depends_on:
      - couchdb
    healthcheck:
      test: '[ "$(curl -fsSL http://localhost:8080/status | jq -r .status)" = "OK" ]'
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 30s
    ports:
      - 8085:8080
    volumes:
      - /srv/nas/cozy/data:/var/lib/cozy/data
      - /config:/etc/cozy
      - ./files/cozy.yml:/etc/cozy/cozy.yml

Enfin nous allons nous intéresser au fichier files/cozy.yml. Si vous utilisez un serveur de courriel externe, vous ne pourrez pas émettre de courriels avec une adresse en noreply tel que prévu par Cozy. Nous allons donc remplacer la ligne :

  noreply_address: noreply@{{.Env.DOMAIN}}

par

  noreply_address: {{.Env.MAIL_USERNAME}}

Nous sommes maintenant prêts à lancer le conteneur :

sudo docker compose up -d

Nous allons voir le journal du conteneur afin de vérifier s’il rencontre des anomalies :

sudo docker compose logs

Si tout va bien, nous pouvons poursuivre en créant une instance Cozy.

Nous allons utiliser le petit utilitaire cozy-stack.sh mise à notre disposition par Cozy pour créer cette instance :

sudo ./cozy-stack.sh instances add --apps home,banks,contacts,drive,notes,settings,store --passphrase <mot-de-passe-administrateur> cozy.k-sper.fr

Cette commande va créer l’instance en intégrant les applications spécifiées. Elle doit au moins contenir home, settings et store pour être utilisable. Les applications disponibles sont à ce jour :

  • home,
  • banks,
  • contacts,
  • drive,
  • notes,
  • passwords,
  • photos,
  • settings,
  • store

Notre instance est créée et utilisable, mais il nous reste des étapes d’intégration avant d’y accéder.

L’intégration de notre nuage

La première chose que nous allons faire est de paramétrer notre DNS chez notre registraire. Nous allons donc créer un enregistrement A pour le sous-domaine cozy et en n’omettant pas de remplacer 123.45.67.89 par notre adresse IP :

Et nous répétons l’opération avec les sous-sous-domaines que Cozy va générer, en les représentant par une étoile : *.cozy

Notre DNS étant maintenant configuré, nous allons dans le répertoire qui héberge notre proxy inverse, Swag, pour le paramétrer :

cd ~/swag
sudo nano docker-compose.yml

Là, nous devons ajouter tous les sous-domaines que nous allons créer à la variable SUBDOMAINS en les séparant par des virgules

  - SUBDOMAINS=vaultwarden,immich,ntfy,cozy,home.cozy,store.cozy,banks.cozy,contacts.cozy,drive.cozy,notes.cozy,settings.cozy,mespapiers.cozy

Nous allons maintenant créer un fichier de paramétrage de Swag pour qu’il oriente les flux de Cozy vers le conteneur correspondant :

sudo nano ~/swag/config/nginx/proxy-conf/cozy.subdomain.conf
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name cozy.k-sper.fr *.cozy.k-sper.fr;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    # enable for ldap auth, fill in ldap details in ldap.conf
    #include /config/nginx/ldap.conf;

    # enable for Authelia
    #include /config/nginx/authelia-server.conf;

    if ($lan-ip = yes) { set $geo-whitelist yes; }
    if ($geo-whitelist = no) { return 404; }

    location / {
        # enable the next two lines for http auth
        #auth_basic "Restricted";
        #auth_basic_user_file /config/nginx/.htpasswd;

        # enable the next two lines for ldap auth
        #auth_request /auth;
        #error_page 401 =200 /ldaplogin;

        # enable for Authelia
        #include /config/nginx/authelia-location.conf;

        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app cozy;
        set $upstream_port 8080;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;

    }
}

Nous pouvons maintenant relancer le conteneur Swag :

sudo docker compose restart

Nous pouvons maintenant accéder à notre nuage cozy à l’adresse cozy.<notre-domaine>.tld (par exemple cozy.k-sper.fr), et commencer à le paramétrer afin de récupérer les documents disponibles auprès de nos différents partenaires.

Nous pouvons ensuite installer l’application Cloud personnel Cozy. Elle est disponible sur les magasins Google Play et Apple Store. Vous pouvez également l’installer via Obtainium en saisissant son adresse https://github.com/cozy/cozy-flagship-app/releases. Attention : l’utilisation de l’application nécessite l’envoi d’un courriel ; c’est à ce moment-là que vous saurez si vous avez correctement paramétré le serveur de courriels sortants.

Amusez-vous bien !


Si vous avez apprécié cet article, n’hésitez pas à laisser à son auteur un petit commentaire : il l’encouragera à le maintenir et à le développer.


Commentaires

2 réponses à “Mon nuage Cozy”

  1. Merci pour ce tutoriel, bien écrit ! bravo

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *