Installer Sharry avec Docker
Sharry

Installer Sharry avec Docker

Table des matières

Au début de mes tests sur Sharry je n'étais pas franchement convaincu de terminer l'article ni de vous le proposer. Mais encore une fois le problème était situé entre la chaise et le clavier.

Le manque de frites...

De base, il n'y a pas forcément les options que j'attendais. Il faut bien lire toute la documentation et ajouter les éléments souhaités.

Je voulais qu'au minimum on puisse:

  • Pouvoir faire le partage de lien par mail.
  • Pouvoir inviter un utilisateur à s’inscrire avec une simple clé de façon à ce qu'il puisse lui même créer son compte et choisir son mot de passe si le site n'est pas ouvert aux inscriptions.
  • Personnaliser son instance.

J'ai donc adapté le fichier de configuration pour vous ayez le moins possible à faire pour que tout fonctionne au poil.

⚡Caractéristiques

  • Langues disponibles: 🇫🇷, 🇬🇧, 🇩🇪, 🇯🇵.
  • Téléchargements : bien que le serveur accepte les requêtes multipart standard, il prend également en charge le protocole tus permettant la reprise des téléchargements. Si le réseau tombe en panne au cours du téléchargement d'un fichier volumineux, téléchargez simplement à nouveau le même fichier et il recommencera là où il s'était arrêté.
  • Inscription: Laissez tous les utilisateurs créer de nouveaux comptes, uniquement ceux invités ou aucun.
  • Client Web pour gérer et accéder aux partages.
  • Restreindre les pages de téléchargement publiques à l'aide de trois propriétés : une durée de vie, un mot de passe (agissant comme un deuxième secret) et une limite de téléchargement.
  • Un nettoyage périodique supprimera les partages expirés.
  • Envoyer des liens de partage par e-mails depuis Sharry.
  • Partage par QR code.
  • Différentes vues des fichiers.
  • Mode clair / Mode sombre.
  • Responsive.

L'installation

Dans mon exemple, le chemin pour installer Sharry sera de la sorte: /srv/appdata/sharry.

Une fois dans le dossier sharry, créez le fichier sharry.conf. Le premier sera sans serveur mail et e second avec serveur mail.

Notez que vous avez ces mêmes fichiers avec prise en charge de la personnalisation ici:
Installer Sharry avec Docker
Tutoriel d’installation de Sharry, application de partage de fichiers avec d’autres, de manière simple.
  • Modifiez base-url = "http://192.168.1.152:9000" par votre nom de domaine ou votre ip:9090 comme dans l’exemple.
  • Modifiez max-size = "2G" par la taille désirée maximale des fichiers que l'on peut envoyer sur le serveur.
sudo nano sharry.conf

Et collez ça dedans (sans serveur mail):

sharry.restserver {

  base-url = "http://192.168.1.152:9090"

  bind {
    address = "0.0.0.0"
    port = 9090
  }

  backend {
    auth {
      fixed.enabled = true ## enabled admin:admin access
    }

    jdbc {
      url = "jdbc:postgresql://db:5432/dbname"
      user = "dbuser"
      password = "dbpass"

   }

   sharry.restserver.backend.signup {
     mode = "open"

     # If mode == 'invite', a password must be provided to generate
     # invitation keys. It must not be empty.
     invite-password = "awaken-matrimony-tablet"

     # If mode == 'invite', this is the period an invitation token is
     # considered valid.
     invite-time = "3 days"
    }

    share {
      # When storing binary data use chunks of this size.
      chunk-size = "512K"

      # Maximum size of a share.
      max-size = "2G"

      # Maximum validity for uploads
      max-validity = 365 days

      # Allows additional database checks to be translated into some
      # meaningful message to the user.
      #
      # This config is used when inspecting database error messages.
      # If the error message from the database contains the defined
      # `native` part, then the server returns a 422 with the error
      # messages given here as `message`.
      #
      # See issue https://github.com/eikek/sharry/issues/255 – the
      # example is a virus check via a postgresql extension "snakeoil".
      database-domain-checks = {
        # Example: This message originates from postgres with an
        # enabled snakeoil extension. This extension allows to virus
        # check byte arrays. It must be setup such that the `bytea`
        # type of the filechunk table is changed to the type
        # `safe_bytea`:
        #
        # CREATE EXTENSION pg_snakeoil;
        # CREATE DOMAIN public.safe_bytea as bytea CHECK (not so_is_infected(value));
        # ALTER TABLE public.filechunk ALTER COLUMN chunkdata TYPE safe_bytea;
        { enabled = false
          native = "domain safe_bytea violates check constraint"
          message = "The uploaded file contains a virus!"
        }
      }
    }

    signup {
      mode = "invite"
      invite-time = "14 days"
      invite-password = "generate-invite"
    }
  }

}

Avec serveur mail:

sharry.restserver {

  base-url = "http://192.168.1.152:9090"

  bind {
    address = "0.0.0.0"
    port = 9090
  }

  backend {
    auth {
      fixed.enabled = true ## enabled admin:admin access
    }

    jdbc {
      url = "jdbc:postgresql://db:5432/dbname"
      user = "dbuser"
      password = "dbpass"

   }

   sharry.restserver.backend.signup {
     mode = "open"

     # If mode == 'invite', a password must be provided to generate
     # invitation keys. It must not be empty.
     invite-password = "awaken-matrimony-tablet"

     # If mode == 'invite', this is the period an invitation token is
     # considered valid.
     invite-time = "3 days"
    }

    mail {

      enabled = false
      smtp {
        host = "smtp.gmail.com"
        port = 587
        user = "votre_gmail_complet"
        password = "votre_mot de passe"
        ssl-type = "starttls"
        check-certificates = true
        timeout = "10 seconds"
        default-from = "votre_gmail_complet"

        # When creating mails, the List-Id header is set to this value.
        #
        # This helps identifying these mails in muas. If it is empty,
        # the header is not set.
        list-id = "Sharry"
      }


    }

    share {
      # When storing binary data use chunks of this size.
      chunk-size = "512K"

      # Maximum size of a share.
      max-size = "2G"

      # Maximum validity for uploads
      max-validity = 365 days

      # Allows additional database checks to be translated into some
      # meaningful message to the user.
      #
      # This config is used when inspecting database error messages.
      # If the error message from the database contains the defined
      # `native` part, then the server returns a 422 with the error
      # messages given here as `message`.
      #
      # See issue https://github.com/eikek/sharry/issues/255 – the
      # example is a virus check via a postgresql extension "snakeoil".
      database-domain-checks = {
        # Example: This message originates from postgres with an
        # enabled snakeoil extension. This extension allows to virus
        # check byte arrays. It must be setup such that the `bytea`
        # type of the filechunk table is changed to the type
        # `safe_bytea`:
        #
        # CREATE EXTENSION pg_snakeoil;
        # CREATE DOMAIN public.safe_bytea as bytea CHECK (not so_is_infected(value));
        # ALTER TABLE public.filechunk ALTER COLUMN chunkdata TYPE safe_bytea;
        { enabled = false
          native = "domain safe_bytea violates check constraint"
          message = "The uploaded file contains a virus!"
        }
      }
    }

    signup {
      mode = "invite"
      invite-time = "14 days"
      invite-password = "generate-invite"
    }
  }

}
  1. Créez votre docker-compose.yml:
sudo nano docker-compose.yml
  1. Collez ça dedans en prenant soin d'adapter le port et les volumes suivant votre configuration:
version: '3.7'
services:
  restserver:
    image: eikek0/sharry:latest
    container_name: sharry
    command: /opt/sharry.conf
    ports:
      - "9090:9090"
    volumes:
      - /srv/appdata/sharry.conf:/opt/sharry.conf
    depends_on:
      - db
  db:
    image: postgres:16.2
    container_name: postgres_db
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_USER=dbuser
      - POSTGRES_PASSWORD=dbpass
      - POSTGRES_DB=dbname
volumes:
  postgres_data:
  1. On installe l'application:
docker-compose up -d

ou avec docker-compose V2:

docker compose up -d
  1. Rendez-vous sur l'ip:port, suivant l'IP de votre serveur local et du port choisi, 9090 par défaut. N'hésitez pas à faire F5 sur la page car il faut quand même quelques secondes pour que l'application se lance.
http://ip:9090

Choix de la langue et du mode sombre/clair

En haut à droite, choisissez votre langue préférée et le mode sombre/clair:


Première connexion

Il y a déjà un compte administrateur par défaut:

  • Nom d'utilisateur: admin
  • Mot de passe: admin

⚠️ Il faudra supprimer ce compte! Je vous explique comment dans la partie Création de compte.


Création de compte

Si votre instance est configurée avec des inscriptions ouvertes, il suffira de suivre la procédure classique pour créer un compte et s'identifier.

⚠️ La première chose à faire c'est de créer un nouveau compte administrateur et de supprimer celui de base!

Rendez-vous sur Comptes:

Ensuite cliquez sur + Nouveau compte:

Remplissez les informations demandées ET cochez Admin. Validez en cliquant sur Envoyer une fois que c'est terminé:

Cliquez sur <- Retour, ensuite cliquez sur Éditer sur le compte nommé admin:

Ensuite cliquez sur Supprimer:

Confirmez en cliquant sur Yes, do it!

Inviter un utilisateur avec une clé

Attention, cela ne fonctionne que si vous êtes en mode invite, voir plus bas dans le tutoriel.

Mais avant de créer une clé, il va falloir définir un mot de passe qui va servir à la création de ces clés.

Veillez à éditer le fichier sharry.conf:

sudo nano sharry.conf

Dans le bloc signup, choisissez un mot de passe dans la zone invite-password:

signup {
      mode = "invite"
      invite-time = "14 days"
      invite-password = "generate-invite"

Quand c'est terminé, redémarrer le container Sharry:

docker restart sharry

Passons à la création de la clé pour inviter un utilisateur à créer son compte!

En haut à droite, cliquez sur les trois petites barres horizontale, ensuite sur 🔑 Invitations:

Entrez le mot de passe pour la génération de la clé d'invitation et cliquez sur Envoyer:

Copiez cette clé et partagez-la avec l'utilisateur que vous souhaitez inviter:

Votre utilisateur devra se rendre sur votre instance et cliquer sur S’inscrire:

Il devra renseigner ses informations de compte et coller la clé, quand il aura fait ça il pourra cliquer sur Envoyer:

Son compte sera immédiatement créé et il pourra s'identifier.


Activer et configurer le serveur mail

Veilliez à éditer le fichier sharry.conf

sudo nano sharry.conf

Remplacez false par true:

mail {

      enabled = true

Configurer le SMTP

Dans le cas ou vous utiliseriez Gmail veuillez suivre ces instructions pour le mot de passe:

Configurer le SMTP pour envoyer un mail avec une application Docker
Tutoriel pour configurer le SMTP afin d’envoyer un mail à partir de vos applications self-hosted.

Remplissez les informations demandées, dans cet exemple Gmail, mais cela fonctionne avec n'importe quel serveur mail, bien entendu.

smtp {
        host = "smtp.gmail.com"
        port = 587
        user = "votre_gmail_complet"
        password = "votre_mot de passe"
        ssl-type = "starttls"
        check-certificates = true
        timeout = "10 seconds"
        default-from = "votre_gmail_complet"

Quand c'est terminé, redémarrer Sharry:

docker restart sharry

Configurer les inscriptions

Il existe 3 modes:

  • Ouvert : chaque nouvel utilisateur peut s'inscrire
  • Inviter : les nouveaux utilisateurs ne peuvent s'inscrire que s'ils fournissent une clé d'invitation. Les clés d'invitation peuvent être générées par un administrateur.
  • Fermé : l'inscription est désactivée.

Pour configurer le votre mode préféré, éditer le fichier sharry.conf

sudo nano sharry.conf

Et configurer cette partie du bloc:

signup {
      mode = "invite"
      invite-time = "14 days"
      invite-password = "generate-invite"

Mode correspondant:

  • Ouvert => open
  • Invite => invite
  • Fermé => closed

Quand c'est terminé, redémarrez Sharry:

docker restart sharry

Personnalisation

Si vous voulez personnaliser votre instance:

Ajouter ce bloc:

webapp {
    welcome-message = "Bienvenue sur belginux!"
    default-language = "fr"
    initial-theme = "dark"
    app-name = "belginux"
    app-logo = "https://jjx.com/0YdmSBc2NNVW.png"
    app-icon = "https://jjx.com/0YdmSBc2NNVW.png"
    app-logo-dark = "https://jjx.com/0YdmSBc2NNVW.png"
    app-icon-dark = "https://jjx.com/0YdmSBc2NNVW.png"

  }

Pour que ça donne comme ceci:

  • welcome-message = "Bienvenue sur belginux!" => votre message de bienvenu.
  • default-language = "fr" => la langue par défaut.
  • initial-theme = "dark" => le thème par défaut.
  • app-name = "belginux" => le nom de l'application.
  • app-logo = "https://jjx.com/0YdmSBc2NNVW.png" => l'url du logo par défaut avec le thème clair.
  • app-icon = "https://jjx.com/0YdmSBc2NNVW.png" => l'url de l'icône par défaut avec le thème sombre.
  • app-logo-dark = "https://jjx.com/0YdmSBc2NNVW.png" => l'url du logo par défaut avec le thème sombre.
  • app-icon-dark = "https://jjx.com/0YdmSBc2NNVW.png" => l'url de l'icône par défaut avec le thème clair.

Si jamais vous n'avez pas l'habitude je vous fournis le sharry.conf avec personnalisation, avec et sans serveur mail.

Sans serveur mail:

sharry.restserver {

  base-url = "http://192.168.1.152:9090"

  bind {
    address = "0.0.0.0"
    port = 9090
  } 

  webapp {
    welcome-message = "Bienvenue sur belginux!"
    default-language = "fr"
    initial-theme = "dark"
    app-name = "belginux"
    app-logo = "https://jjx.com/0YdmSBc2NNVW.png"
    app-icon = "https://jjx.com/0YdmSBc2NNVW.png"
    app-logo-dark = "https://jjx.com/0YdmSBc2NNVW.png"
    app-icon-dark = "https://jjx.com/0YdmSBc2NNVW.png"

  }

  backend {
    auth {
      fixed.enabled = true ## enabled admin:admin access
    }

    jdbc {
      url = "jdbc:postgresql://db:5432/dbname"
      user = "dbuser"
      password = "dbpass"

   }

   sharry.restserver.backend.signup {
     mode = "open"

     # If mode == 'invite', a password must be provided to generate
     # invitation keys. It must not be empty.
     invite-password = "awaken-matrimony-tablet"

     # If mode == 'invite', this is the period an invitation token is
     # considered valid.
     invite-time = "3 days"
    }

    share {
      # When storing binary data use chunks of this size.
      chunk-size = "512K"

      # Maximum size of a share.
      max-size = "2G"

      # Maximum validity for uploads
      max-validity = 365 days

      # Allows additional database checks to be translated into some
      # meaningful message to the user.
      #
      # This config is used when inspecting database error messages.
      # If the error message from the database contains the defined
      # `native` part, then the server returns a 422 with the error
      # messages given here as `message`.
      #
      # See issue https://github.com/eikek/sharry/issues/255 – the
      # example is a virus check via a postgresql extension "snakeoil".
      database-domain-checks = [
        # Example: This message originates from postgres with an
        # enabled snakeoil extension. This extension allows to virus
        # check byte arrays. It must be setup such that the `bytea`
        # type of the filechunk table is changed to the type
        # `safe_bytea`:
        #
        # CREATE EXTENSION pg_snakeoil;
        # CREATE DOMAIN public.safe_bytea as bytea CHECK (not so_is_infected(value));
        # ALTER TABLE public.filechunk ALTER COLUMN chunkdata TYPE safe_bytea;
        { enabled = false
          native = "domain safe_bytea violates check constraint"
          message = "The uploaded file contains a virus!"
        }
      ]
    }

    signup {
      mode = "invite"
      invite-time = "14 days"
      invite-password = "generate-invite"
    }
  }

}

Avec serveur mail:

sharry.restserver {

  base-url = "http://192.168.1.152:9090"

  bind {
    address = "0.0.0.0"
    port = 9090
  }

  webapp {
    welcome-message = "Bienvenue sur belginux!"
    default-language = "fr"
    initial-theme = "dark"
    app-name = "belginux"
    app-logo = "https://jjx.com/0YdmSBc2NNVW.png"
    app-icon = "https://jjx.com/0YdmSBc2NNVW.png"
    app-logo-dark = "https://jjx.com/0YdmSBc2NNVW.png"
    app-icon-dark = "https://jjx.com/0YdmSBc2NNVW.png"

  }

  backend {
    auth {
      fixed.enabled = true ## enabled admin:admin access
    }

    jdbc {
      url = "jdbc:postgresql://db:5432/dbname"
      user = "dbuser"
      password = "dbpass"

   }

   sharry.restserver.backend.signup {
     mode = "open"

     # If mode == 'invite', a password must be provided to generate
     # invitation keys. It must not be empty.
     invite-password = "awaken-matrimony-tablet"

     # If mode == 'invite', this is the period an invitation token is
     # considered valid.
     invite-time = "3 days"
    }

    mail {

      enabled = false
      smtp {
        host = "smtp.gmail.com"
        port = 587
        user = "votre_gmail_complet"
        password = "votre_mot de passe"
        ssl-type = "starttls"
        check-certificates = true
        timeout = "10 seconds"
        default-from = "votre_gmail_complet"

        # When creating mails, the List-Id header is set to this value.
        #
        # This helps identifying these mails in muas. If it is empty,
        # the header is not set.
        list-id = "Sharry"
      }


    }

    share {
      # When storing binary data use chunks of this size.
      chunk-size = "512K"

      # Maximum size of a share.
      max-size = "2G"

      # Maximum validity for uploads
      max-validity = 365 days

      # Allows additional database checks to be translated into some
      # meaningful message to the user.
      #
      # This config is used when inspecting database error messages.
      # If the error message from the database contains the defined
      # `native` part, then the server returns a 422 with the error
      # messages given here as `message`.
      #
      # See issue https://github.com/eikek/sharry/issues/255 – the
      # example is a virus check via a postgresql extension "snakeoil".
      database-domain-checks = [
        # Example: This message originates from postgres with an
        # enabled snakeoil extension. This extension allows to virus
        # check byte arrays. It must be setup such that the `bytea`
        # type of the filechunk table is changed to the type
        # `safe_bytea`:
        #
        # CREATE EXTENSION pg_snakeoil;
        # CREATE DOMAIN public.safe_bytea as bytea CHECK (not so_is_infected(value));
        # ALTER TABLE public.filechunk ALTER COLUMN chunkdata TYPE safe_bytea;
        { enabled = false
          native = "domain safe_bytea violates check constraint"
          message = "The uploaded file contains a virus!"
        }
      ]
    }

    signup {
      mode = "invite"
      invite-time = "14 days"
      invite-password = "generate-invite"
    }
  }

}

Reverse-proxy

Avec Cosmos Cloud

Que je conseil vivement car cela apporte plus de paramètres de sécurité.

Exposer une application sur le web avec Cosmos Cloud
Tutoriel pour exposer une application sur le web en tout sécurité avec un certificat SSL certifié.

Si l'application n'est pas sur le serveur ou est installé Cosmos Cloud:

Utiliser le serveur (reverse) proxy de Cosmos Cloud
Comment utiliser le serveur proxy de Cosmos Cloud et le configurer?

Avec NGINX

D'après la documentation de Sharry.

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    server {
        listen 0.0.0.0:80 ;
        listen [::]:80 ;
        server_name subdomain.otherdomain.tld ;
        location /.well-known/acme-challenge {
            root /var/data/nginx/ACME-PUBLIC;
            auth_basic off;
        }
        location / {
            return 301 https://$host$request_uri;
        }
    }
    server {
        listen 0.0.0.0:443 ssl http2 ;
        listen [::]:443 ssl http2 ;
        server_name sharry.example.com ;
        location /.well-known/acme-challenge {
            root /var/data/nginx/ACME-PUBLIC;
            auth_basic off;
        }
        ssl_certificate /var/lib/acme/sharry.example.com/fullchain.pem;
        ssl_certificate_key /var/lib/acme/sharry.example.com/key.pem;
        ssl_trusted_certificate /var/lib/acme/sharry.example.com/full.pem;
        location / {
            proxy_pass http://192.168.1.11:9090;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;

            proxy_set_header    Host                $host;
            proxy_set_header    X-Real-IP           $remote_addr;
            proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
            proxy_set_header    X-Forwarded-Proto   $scheme;

            proxy_buffering off;
            client_max_body_size 105M;
            proxy_send_timeout   300s;
            proxy_read_timeout   300s;
            send_timeout         300s;
        }
    }
}

Cela définit deux serveurs : l'un écoute le trafic http et redirige vers la variante https. De plus, il définit le nom du dossier let's encrypt .well-known. Pour plus d'informations sur la configuration de Let's Encrypt, veuillez vous référer à leur documentation et/ou à la documentation de nginx.

Le point de terminaison du serveur https est configuré avec les certificats let's encrypt et agit comme un proxy pour l'application à l'adresse 192.168.1.11:9090.

Le paramètre client_max_body_size est également pertinent. Il s'agit de la taille maximale d'une requête unique. Cela doit être supérieur au paramètre webapp.chunk-size de Sharry.

Le paramètre proxy_buffering off ; désactive la mise en mémoire tampon des réponses de l'application arrivant sur nginx. La mise en mémoire tampon peut introduire des problèmes de contre-pression si le client ne lit pas assez vite. La réponse provenant de l'application peut vite être trop volumineuse pour tenir en mémoire et nginx écrit alors un fichier temporaire (qui est limité à 1G par défaut). Si cette limite est atteinte, nginx attend que le client ait reçu toutes les données mises en mémoire tampon sur le disque, ce qui peut entraîner des délais d'attente d'envoi.

zarev

->.<-
🐧 Passionné de self-hosting, je partage ce que je connais et me nourris des connaissances des bonnes âmes qui partagent avec moi. Soutenons l'utilisation des apps open source et leurs développeurs.