# Installer Nextcloud avec docker-compose sur Debian 10 avec Nginx en reverse-proxy

## Installer **nginx**

Nginx est un serveur web, comme Apache.  
Nous allons l'utiliser comme reverse-proxy, c'est-à-dire qu'il renverra les requêtes d'un autre serveur, que nous installerons aux côtés de wordpress.  

Ainsi nous pourrons utiliser le serveur de notre choix pour notre web-application Wordpress (Apache ou Nginx).


On installe Nginx à partir des dépôts Debian, de façon à avoir une version stable, avec l'apport des correctifs de sécurité, et qui ne sera jamais cassé par une modification du système.

```
sudo apt update
sudo apt upgrade
sudo apt install nginx
```

Dans votre navigateur, en tapant dabs la barre d'adresse `http://IP_DU_SERVEUR`, vous devriez accéder à la page d'accueil de nginx
![Welcome To Nginx! ](../../assets/divers/server/welcome_to_nginx.png)


## Installation de docker

### Installation des dépendances

```
sudo apt update
sudo apt -y install apt-transport-https ca-certificates curl gnupg2 software-properties-common
```
### Installation de la clé du dépôt Docker

```
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
```

### Ajout du dépôt docker dans le **sources.list**

```
sudo add-apt-repository \
        "deb [arch=amd64] https://download.docker.com/linux/debian \
        $(lsb_release -cs) \
        stable"
```

### Mise à jour de la liste des paquets et installation de docker

```
sudo apt update && sudo apt install docker-ce docker-ce-cli containerd.io
```

### Ajout de l'utilisateur dans le groupe **docker** pour utiliser docker sans sudo

```
sudo usermod -aG docker $USER
newgrp docker
```


## Installation de Docker-Compose

### Téléchargement de Docker-Compose
```
curl -s https://api.github.com/repos/docker/compose/releases/latest \
  | grep browser_download_url \
  | grep docker-compose-linux-x86_64 \
  | cut -d '"' -f 4 \
  | wget -qi -
```

### Mise en place de l'exécutable

```
chmod +x docker-compose-linux-x86_64 && sudo mv docker-compose-linux-x86_64 /usr/local/bin/docker-compose
sudo systemctl restart docker
```

### Auto-complétion pour Bash

```
sudo mkdir -p /etc/bash_completion.d
sudo curl -L https://raw.githubusercontent.com/docker/compose/master/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose
source /etc/bash_completion.d/docker-compose
```

**Docker et Docker-compose sont maintenant installés**

## Mise en place de Nextcloud, collabora, etherpad, coturn, redis avec docker-compose

### Création d'un dossier pour le projet

```
mkdir nextcloud && cd nextcloud
```

### Fichiers de configuration pour nextcloud

Nous avons besoin de créer les fichiers suivants pour qu'ils soient utilisés par l'image de nextcloud:

#### config.php

??? note "config.php"
    ```
    <?php
    $CONFIG = array (
      'htaccess.RewriteBase' => '/',
      'memcache.local' => '\\OC\\Memcache\\APCu',
      'apps_paths' => 
      array (
        0 => 
        array (
          'path' => '/var/www/html/apps',
          'url' => '/apps',
          'writable' => false,
        ),
        1 => 
        array (
          'path' => '/var/www/html/custom_apps',
          'url' => '/custom_apps',
          'writable' => true,
        ),
      ),
      'memcache.distributed' => '\\OC\\Memcache\\Redis',
      'memcache.locking' => '\\OC\\Memcache\\Redis',
      'redis' => 
      array (
        'host' => 'redisnext',
        'port' => 6379,
        'password' => false,
      ),
      'trusted_domains' => 
      array (
        0 => 'nextcloud.mondomaine.fr',
        1 => 'nextcloud',
      ),
      'trusted_proxies' => 
      array (
        0 => '172.17.0.1',
        1 => '172.22.0.1',
        2 => '172.23.0.1',
        3 => '172.21.0.1',
      ),
      'skeletondirectory' => '',
      'datadirectory' => '/data',
      'dbtype' => 'mysql',
      'overwrite.cli.url' => 'https://nextcloud.mondomaine.fr',
      'dbname' => 'dbnext',
      'dbhost' => 'databasenext',
      'dbport' => '',
      'dbtableprefix' => 'oc_',
      'mysql.utf8mb4' => true,
      'dbuser' => 'nextclouduser',
      'dbpassword' => 'azdqsdokpokpokds098098',
      'installed' => true,
      'loglevel' => 2,
      'maintenance' => false,
      'app_install_overwrite' => 
      array (
        0 => 'dashboard',
        1 => 'files_clipboard',
        2 => 'afterlogic',
        3 => 'ownpad',
      ),
      'mail_from_address' => 'contact',
      'mail_smtpmode' => 'smtp',
      'mail_sendmailmode' => 'smtp',
      'mail_domain' => 'mondomaine.fr',
      'mail_smtphost' => 'mail.mymailprovider.net',
      'mail_smtpsecure' => 'tls',
      'mail_smtpport' => '587',
      'mail_smtpauthtype' => 'LOGIN',
      'mail_smtpauth' => 1,
      'mail_smtpname' => 'contact@mondomaine.fr',
      'mail_smtppassword' => 'MYSMTPPASSWORD',
      'has_rebuilt_cache' => true,
      'overwriteprotocol' => 'https',
      'theme' => '',
      'default_language' => 'fr',
      'default_locale' => 'fr_FR',
      'defaultapp' => 'files',
    );
    ```

#### Internal.php

??? note "Internal.php"
    ```
    <?php

    declare(strict_types=1);

    /**
     * @copyright Copyright (c) 2016, ownCloud, Inc.
     *
     * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
     * @author cetra3 <peter@parashift.com.au>
     * @author Christoph Wurst <christoph@winzerhof-wurst.at>
     * @author Lukas Reschke <lukas@statuscode.ch>
     * @author MartB <mart.b@outlook.de>
     * @author Morris Jobke <hey@morrisjobke.de>
     * @author Robin Appelman <robin@icewind.nl>
     * @author Roeland Jago Douma <roeland@famdouma.nl>
     * @author Thomas Müller <thomas.mueller@tmit.eu>
     * @author Victor Dubiniuk <dubiniuk@owncloud.com>
     *
     * @license AGPL-3.0
     *
     * This code is free software: you can redistribute it and/or modify
     * it under the terms of the GNU Affero General Public License, version 3,
     * as published by the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     * GNU Affero General Public License for more details.
     *
     * You should have received a copy of the GNU Affero General Public License, version 3,
     * along with this program. If not, see <http://www.gnu.org/licenses/>
     *
     */

    namespace OC\Session;

    use OC\Authentication\Exceptions\InvalidTokenException;
    use OC\Authentication\Token\IProvider;
    use OCP\Session\Exceptions\SessionNotAvailableException;

    /**
     * Class Internal
     *
     * wrap php's internal session handling into the Session interface
     *
     * @package OC\Session
     */
    class Internal extends Session {
            /**
             * @param string $name
             * @throws \Exception
             */
            public function __construct(string $name) {
                    set_error_handler([$this, 'trapError']);
                    $this->invoke('session_name', [$name]);
                    try {
                            $this->startSession();
                    } catch (\Exception $e) {
                            setcookie($this->invoke('session_name'), '', -1, \OC::$WEBROOT ?: '/');
                    }
                    restore_error_handler();
                    if (!isset($_SESSION)) {
                            throw new \Exception('Failed to start session');
                    }
            }

            /**
             * @param string $key
             * @param integer $value
             */
            public function set(string $key, $value) {
                    $this->validateSession();
                    $_SESSION[$key] = $value;
            }

            /**
             * @param string $key
             * @return mixed
             */
            public function get(string $key) {
                    if (!$this->exists($key)) {
                            return null;
                    }
                    return $_SESSION[$key];
            }

            /**
             * @param string $key
             * @return bool
             */
            public function exists(string $key): bool {
                    return isset($_SESSION[$key]);
            }
            /**
             * @param string $key
             */
            public function remove(string $key) {
                    if (isset($_SESSION[$key])) {
                            unset($_SESSION[$key]);
                    }
            }

            public function clear() {
                    $this->invoke('session_unset');
                    $this->regenerateId();
                    $_SESSION = [];
            }

            public function close() {
                    $this->invoke('session_write_close');
                    parent::close();
            }

            /**
             * Wrapper around session_regenerate_id
             *
             * @param bool $deleteOldSession Whether to delete the old associated session file or not.
             * @param bool $updateToken Wheater to update the associated auth token
             * @return void
             */
            public function regenerateId(bool $deleteOldSession = true, bool $updateToken = false) {
                    $oldId = null;

                    if ($updateToken) {
                            // Get the old id to update the token
                            try {
                                    $oldId = $this->getId();
                            } catch (SessionNotAvailableException $e) {
                                    // We can't update a token if there is no previous id
                                    $updateToken = false;
                            }
                    }

                    try {
                            @session_regenerate_id($deleteOldSession);
                    } catch (\Error $e) {
                            $this->trapError($e->getCode(), $e->getMessage());
                    }

                    if ($updateToken) {
                            // Get the new id to update the token
                            $newId = $this->getId();

                            /** @var IProvider $tokenProvider */
                            $tokenProvider = \OC::$server->query(IProvider::class);

                            try {
                                    $tokenProvider->renewSessionToken($oldId, $newId);
                            } catch (InvalidTokenException $e) {
                                    // Just ignore
                            }
                    }
            }

            /**
             * Wrapper around session_id
             *
             * @return string
             * @throws SessionNotAvailableException
             * @since 9.1.0
             */
            public function getId(): string {
                    $id = $this->invoke('session_id', [], true);
                    if ($id === '') {
                            throw new SessionNotAvailableException();
                    }
                    return $id;
            }

            /**
             * @throws \Exception
             */
            public function reopen() {
                    throw new \Exception('The session cannot be reopened - reopen() is ony to be used in unit testing.');
            }

            /**
             * @param int $errorNumber
             * @param string $errorString
             * @throws \ErrorException
             */
            public function trapError(int $errorNumber, string $errorString) {
                    throw new \ErrorException($errorString);
            }

            /**
             * @throws \Exception
             */
            private function validateSession() {
                    if ($this->sessionClosed) {
                            throw new SessionNotAvailableException('Session has been closed - no further changes to the session are allowed');
                    }
            }

            /**
             * @param string $functionName the full session_* function name
             * @param array $parameters
             * @param bool $silence whether to suppress warnings
             * @throws \ErrorException via trapError
             * @return mixed
             */
            private function invoke(string $functionName, array $parameters = [], bool $silence = false) {
                    try {
                            if ($silence) {
                                    return @call_user_func_array($functionName, $parameters);
                            } else {
                                    return call_user_func_array($functionName, $parameters);
                            }
                    } catch (\Error $e) {
                            $this->trapError($e->getCode(), $e->getMessage());
                    }
            }

            private function startSession() {
                    if (PHP_VERSION_ID < 70300) {
                            $this->invoke('session_start');
                    } else {
                            $this->invoke('session_start', [['cookie_samesite' => 'Lax']]);
                    }
            }
    }
    ```

#### mimetypemapping.json

??? note "mimetypemapping.json"
    ```
    {
            "drawio": ["application/x-drawio"],
            "pad": ["application/x-ownpad"],
            "calc": ["application/x-ownpad"],
            "3gp": ["video/3gpp"],
            "7z": ["application/x-7z-compressed"],
            "accdb": ["application/msaccess"],
            "ai": ["application/illustrator"],
            "apk": ["application/vnd.android.package-archive"],
            "arw": ["image/x-dcraw"],
            "avi": ["video/x-msvideo"],
            "bash": ["text/x-shellscript"],
            "bat": ["application/x-msdos-program"],
            "blend": ["application/x-blender"],
            "bin": ["application/x-bin"],
            "bmp": ["image/bmp"],
            "bpg": ["image/bpg"],
            "bz2": ["application/x-bzip2"],
            "cb7": ["application/comicbook+7z"],
            "cba": ["application/comicbook+ace"],
            "cbr": ["application/comicbook+rar"],
            "cbt": ["application/comicbook+tar"],
            "cbtc": ["application/comicbook+truecrypt"],
            "cbz": ["application/comicbook+zip"],
            "cc": ["text/x-c"],
            "cdr": ["application/coreldraw"],
            "class": ["application/java"],
            "cmd": ["application/cmd"],
            "cnf": ["text/plain"],
            "conf": ["text/plain"],
            "cpp": ["text/x-c++src"],
            "cr2": ["image/x-dcraw"],
            "css": ["text/css"],
            "csv": ["text/csv"],
            "cvbdl": ["application/x-cbr"],
            "c": ["text/x-c"],
            "c++": ["text/x-c++src"],
            "dcr": ["image/x-dcraw"],
            "deb": ["application/x-deb"],
            "dng": ["image/x-dcraw"],
            "doc": ["application/msword"],
            "docm": ["application/vnd.ms-word.document.macroEnabled.12"],
            "docx": ["application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
            "dot": ["application/msword"],
            "dotx": ["application/vnd.openxmlformats-officedocument.wordprocessingml.template"],
            "dv": ["video/dv"],
            "eot": ["application/vnd.ms-fontobject"],
            "epub": ["application/epub+zip"],
            "eps": ["application/postscript"],
            "erf": ["image/x-dcraw"],
            "exe": ["application/x-ms-dos-executable"],
            "fb2": ["application/x-fictionbook+xml", "text/plain"],
            "flac": ["audio/flac"],
            "flv": ["video/x-flv"],
            "gif": ["image/gif"],
            "gpx": ["application/gpx+xml"],
            "gz": ["application/x-gzip"],
            "gzip": ["application/x-gzip"],
            "h": ["text/x-h"],
            "heic": ["image/heic"],
            "heif": ["image/heif"],
            "hh": ["text/x-h"],
            "hpp": ["text/x-h"],
            "htaccess": ["text/plain"],
            "html": ["text/html", "text/plain"],
            "htm": ["text/html", "text/plain"],
            "ical": ["text/calendar"],
            "ics": ["text/calendar"],
            "iiq": ["image/x-dcraw"],
            "impress": ["text/impress"],
            "java": ["text/x-java-source"],
            "jp2": ["image/jp2"],
            "jpeg": ["image/jpeg"],
            "jpg": ["image/jpeg"],
            "jps": ["image/jpeg"],
            "js": ["application/javascript", "text/plain"],
            "json": ["application/json", "text/plain"],
            "k25": ["image/x-dcraw"],
            "kdbx": ["application/x-kdbx"],
            "kdc": ["image/x-dcraw"],
            "key": ["application/x-iwork-keynote-sffkey"],
            "keynote": ["application/x-iwork-keynote-sffkey"],
            "km": ["application/km"],
            "kml": ["application/vnd.google-earth.kml+xml"],
            "kmz": ["application/vnd.google-earth.kmz"],
            "kra": ["application/x-krita"],
            "ldif": ["text/x-ldif"],
            "lwp": ["application/vnd.lotus-wordpro"],
            "m2t": ["video/mp2t"],
            "m3u": ["audio/mpegurl"],
            "m3u8": ["audio/mpegurl"],
            "m4a": ["audio/mp4"],
            "m4b": ["audio/m4b"],
            "m4v": ["video/mp4"],
            "markdown": ["text/markdown"],
            "mdown": ["text/markdown"],
            "md": ["text/markdown"],
            "mdb": ["application/msaccess"],
            "mdwn": ["text/markdown"],
            "mkd": ["text/markdown"],
            "mef": ["image/x-dcraw"],
            "mkv": ["video/x-matroska"],
            "mm": ["application/x-freemind"],
            "mobi": ["application/x-mobipocket-ebook"],
            "mov": ["video/quicktime"],
            "mp3": ["audio/mpeg"],
            "mp4": ["video/mp4"],
            "mpeg": ["video/mpeg"],
            "mpg": ["video/mpeg"],
            "mpo": ["image/jpeg"],
            "msi": ["application/x-msi"],
            "mts": ["video/MP2T"],
            "mt2s": ["video/MP2T"],
            "nef": ["image/x-dcraw"],
            "numbers": ["application/x-iwork-numbers-sffnumbers"],
            "odf": ["application/vnd.oasis.opendocument.formula"],
            "odg": ["application/vnd.oasis.opendocument.graphics"],
            "odp": ["application/vnd.oasis.opendocument.presentation"],
            "ods": ["application/vnd.oasis.opendocument.spreadsheet"],
            "odt": ["application/vnd.oasis.opendocument.text"],
            "oga": ["audio/ogg"],
            "ogg": ["audio/ogg"],
            "ogv": ["video/ogg"],
            "one": ["application/msonenote"],
            "opus": ["audio/ogg"],
            "orf": ["image/x-dcraw"],
            "otf": ["application/font-sfnt"],
            "pages": ["application/x-iwork-pages-sffpages"],
            "pdf": ["application/pdf"],
            "pfb": ["application/x-font"],
            "pef": ["image/x-dcraw"],
            "php": ["application/x-php"],
            "pl": ["application/x-perl"],
            "pls": ["audio/x-scpls"],
            "png": ["image/png"],
            "pot": ["application/vnd.ms-powerpoint"],
            "potm": ["application/vnd.ms-powerpoint.template.macroEnabled.12"],
            "potx": ["application/vnd.openxmlformats-officedocument.presentationml.template"],
            "ppa": ["application/vnd.ms-powerpoint"],
            "ppam": ["application/vnd.ms-powerpoint.addin.macroEnabled.12"],
            "pps": ["application/vnd.ms-powerpoint"],
            "ppsm": ["application/vnd.ms-powerpoint.slideshow.macroEnabled.12"],
            "ppsx": ["application/vnd.openxmlformats-officedocument.presentationml.slideshow"],
            "ppt": ["application/vnd.ms-powerpoint"],
            "pptm": ["application/vnd.ms-powerpoint.presentation.macroEnabled.12"],
            "pptx": ["application/vnd.openxmlformats-officedocument.presentationml.presentation"],
            "ps": ["application/postscript"],
            "psd": ["application/x-photoshop"],
            "py": ["text/x-python"],
            "raf": ["image/x-dcraw"],
            "rar": ["application/x-rar-compressed"],        "reveal": ["text/reveal"],
            "rss": ["application/rss+xml"],
            "rtf": ["text/rtf"],
            "rw2": ["image/x-dcraw"],
            "schema": ["text/plain"],
            "sgf": ["application/sgf"],
            "sh-lib": ["text/x-shellscript"],
            "sh": ["text/x-shellscript"],
            "srf": ["image/x-dcraw"],
            "sr2": ["image/x-dcraw"],
            "svg": ["image/svg+xml", "text/plain"],
            "swf": ["application/x-shockwave-flash", "application/octet-stream"],
            "tar": ["application/x-tar"],
            "tar.bz2": ["application/x-bzip2"],
            "tar.gz": ["application/x-compressed"],
            "tbz2": ["application/x-bzip2"],
            "tcx": ["application/vnd.garmin.tcx+xml"],
            "tex": ["application/x-tex"],
            "tgz": ["application/x-compressed"],
            "tiff": ["image/tiff"],
            "tif": ["image/tiff"],
            "ttf": ["application/font-sfnt"],
            "txt": ["text/plain"],
            "vcard": ["text/vcard"],
            "vcf": ["text/vcard"],
            "vob": ["video/dvd"],
            "vsd": ["application/vnd.visio"],
            "vsdm": ["application/vnd.ms-visio.drawing.macroEnabled.12"],
            "vsdx": ["application/vnd.ms-visio.drawing"],
            "vssm": ["application/vnd.ms-visio.stencil.macroEnabled.12"],
            "vssx": ["application/vnd.ms-visio.stencil"],
            "vstm": ["application/vnd.ms-visio.template.macroEnabled.12"],
            "vstx": ["application/vnd.ms-visio.template"],
            "wav": ["audio/wav"],
            "webm": ["video/webm"],
            "webp": ["image/webp"],
            "woff": ["application/font-woff"],
            "wpd": ["application/vnd.wordperfect"],
            "wmv": ["video/x-ms-wmv"],
            "xcf": ["application/x-gimp"],
            "xla": ["application/vnd.ms-excel"],
            "xlam": ["application/vnd.ms-excel.addin.macroEnabled.12"],
            "xls": ["application/vnd.ms-excel"],
            "xlsb": ["application/vnd.ms-excel.sheet.binary.macroEnabled.12"],
            "xlsm": ["application/vnd.ms-excel.sheet.macroEnabled.12"],
            "xlsx": ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
            "xlt": ["application/vnd.ms-excel"],
            "xltm": ["application/vnd.ms-excel.template.macroEnabled.12"],
            "xltx": ["application/vnd.openxmlformats-officedocument.spreadsheetml.template"],
            "xmind": ["application/vnd.xmind.workbook"],
            "xml": ["application/xml", "text/plain"],
            "xrf": ["image/x-dcraw"],
            "yaml": ["application/yaml", "text/plain"],
            "yml": ["application/yaml", "text/plain"],
            "zip": ["application/zip"],
            "url": ["application/internet-shortcut"],
            "webloc": ["application/internet-shortcut"]
    }
    ```
#### Création des dossiers pour les volumes permanents

```bash
sudo mkdir /data/nextcloud/{data,config,apps,mysql} -p
sudo chown -R www-data:root /data/nextcloud
sudo chown -R 999:root /data/nextcloud/mysql
```

### Fichiers de configuration pour Redis

#### redis.conf  

??? note "redis.conf"
    ```
    requirepass aeazddokpokqsd7676
    ```
    
#### redis.config.php

??? note "redis.config.php"
    ```php
    <?php
    if (getenv('REDIS_HOST')) {
      $CONFIG = array (
        'memcache.distributed' => '\OC\Memcache\Redis',
        'memcache.locking' => '\OC\Memcache\Redis',
        'redis' => array(
          'host' => getenv('REDIS_HOST'),
          'password' => getenv('REDIS_HOST_PASSWORD'),
        ),
      );

      if (getenv('REDIS_HOST_PORT') !== false) {
        $CONFIG['redis']['port'] = (int) getenv('REDIS_HOST_PORT');
      } elseif (getenv('REDIS_HOST')[0] != '/') {
        $CONFIG['redis']['port'] = 6379;
      }
    }
    ```
    
### Fichiers de configuration pour etherpad

#### Dockerfile

Nous allons compiler une image d'etherpad en suivant les instructions de **Dockerfile**:

??? info "Dockerfile"
    ```Dockerfile
    # Etherpad Lite Dockerfile
    #
    # https://github.com/ether/etherpad-lite
    #
    # Author: muxator

    FROM node:10-buster-slim
    LABEL maintainer="Etherpad team, https://github.com/ether/etherpad-lite"

    # plugins to install while building the container. By default no plugins are
    # installed.
    # If given a value, it has to be a space-separated, quoted list of plugin names.
    #
    # EXAMPLE:
    #   ETHERPAD_PLUGINS="ep_codepad ep_author_neat"
    ARG ETHERPAD_PLUGINS=

    # By default, Etherpad container is built and run in "production" mode. This is
    # leaner (development dependencies are not installed) and runs faster (among
    # other things, assets are minified & compressed).
    ENV NODE_ENV=production

    # Follow the principle of least privilege: run as unprivileged user.
    #
    # Running as non-root enables running this image in platforms like OpenShift
    # that do not allow images running as root.
    RUN useradd --uid 5001 --create-home etherpad

    RUN mkdir /opt/etherpad-lite && chown etherpad:0 /opt/etherpad-lite

    USER etherpad

    WORKDIR /opt/etherpad-lite

    COPY --chown=etherpad:0 ./ ./

    # install node dependencies for Etherpad
    RUN bin/installDeps.sh && \
            rm -rf ~/.npm/_cacache

    # Install the plugins, if ETHERPAD_PLUGINS is not empty.
    #
    # Bash trick: in the for loop ${ETHERPAD_PLUGINS} is NOT quoted, in order to be
    # able to split at spaces.
    RUN for PLUGIN_NAME in ${ETHERPAD_PLUGINS}; do npm install "${PLUGIN_NAME}"; done

    # Copy the configuration file.
    COPY --chown=etherpad:0 ./settings.json.docker /opt/etherpad-lite/settings.json

    # Fix permissions for root group
    RUN chmod -R g=u .

    EXPOSE 9001
    CMD ["node", "node_modules/ep_etherpad-lite/node/server.js"]
    ```
    
### Copie du projet etherpad sur github

```bash
git clone https://github.com/ether/etherpad-lite.git
```

### Création du fichier de configuration **docker-compose.yml**:

Ce fichier de configuration va déployer une image docker de nextcloud avec collabora et etherpad, avec la base de données mariadb, redis et coturn.

??? info "docker-compose.yml"
    ```yaml  
    version: '3.7'

    services:

      nextcloud:
        image: nextcloud:19
        depends_on:
          - databasenext
          - redisnext
        extra_hosts:
          - nextcloud.mondomaine.fr:$IP_DU_SERVEUR
          - collabora.mondomaine.fr:$IP_DU_SERVEUR
          - pad.mondomaine.fr:$IP_DU_SERVEUR
        environment:
          - NEXTCLOUD_DATA_DIR=/data
          - VIRTUAL_HOST=nexctloud.mondomaine.fr
          - VIRTUAL_NETWORK=proxy-ssl
          - VIRTUAL_PORT=80
          - MYSQL_DATABASE=dbnext
          - MYSQL_USER=nextclouduser
          - MYSQL_PASSWORD=azdqsdokpokpokds098098
          - MYSQL_HOST=databasenext
          - REDIS_HOST=redisnext
          - REDIS_HOST_PASSWORD=aeazddokpokqsd7676
        ports:
          - "127.0.0.1:8889:80"
        volumes:
          - ncdata-data:/data
          - ncdata-config:/var/www/html/config
          - ncdata-apps:/var/www/html/custom_apps
          # - ./Internal.php:/var/www/html/lib/private/Session/Internal.php 
        networks:
          - default
          - back

      databasenext:
        image: mariadb
        restart: always
        environment:
          - MYSQL_ROOT_PASSWORD=DZAJpokpdzaDOPA56667
          - MYSQL_USER=nextclouduser
          - MYSQL_DATABASE=dbnext
          - MYSQL_PASSWORD=azdqsdokpokpokds098098
          #- MYSQL_INITDB_SKIP_TZINFO=1
        volumes:
          - ncdata-mysql:/var/lib/mysql
        networks:
          - back

      redisnext:
        image: redis
        networks:
          - back
        volumes:
          - ./redis.conf:/usr/local/etc/redis/redis.conf
        command: redis-server /usr/local/etc/redis/redis.conf

      coturn:
        image: instrumentisto/coturn
        container_name: nextcloud-coturn
        restart: unless-stopped
        ports:
          - "3478:3478/tcp"
          - "3478:3478/udp"
        networks:
          - back
        command:
          - -n
          - --log-file=stdout
          - --min-port=49160
          - --max-port=49200
          - --realm=nextcloud.mondomaine.fr
          - --use-auth-secret
          - --static-auth-secret=mysecreteasy
          - --cert=/etc/letsencrypt/live/nextcloud.mondomaine.fr/fullchain.pem
          - --pkey=/etc/letsencrypt/live/nextcloud.mondomaine.fr/privkey.pem

      collabora:
        image: collabora/code
        container_name: nextcloud-collabora
        restart: unless-stopped
        extra_hosts:
          - nextcloud.mondomaine.fr:217.70.188.81
          - collabora.mondomaine.fr:217.70.188.81
        networks:
          - back
        ports:
          - 127.0.0.1:9980:9980
        environment:
          - domain=nextcloud.mondomaine.fr
          - dictionaries=fr,en
        cap_add:
          - MKNOD
        tty: true

      paddb:
        restart: always
        image: "postgres:10"
        environment:
          - POSTGRES_DB=etherpad
          - POSTGRES_USER=etherpad
          - POSTGRES_PASSWORD=changeme
        networks:
          - app
      
      etherpad:
        build:
          context: ./etherpad-lite
        ports:
          - 9001:9001
        networks:
          - app

    networks:
      back:
      app:

    volumes:
      ncdata-mysql:
        driver_opts:
          type: none
          device: /data/nextcloud/mysql
          o: bind
      ncdata-data:
        driver_opts:
          type: none
          device: /data/nextcloud/data
          o: bind
      ncdata-config:
        driver_opts:
          type: none
          device: /data/nextcloud/config
          o: bind
      ncdata-apps:
        driver_opts:
          type: none
          device: /data/nextcloud/apps
          o: bind

    ```

Il ne reste plus qu'à démarrer les conteneurs:
```bash
docker-compose up --build -d
```

## Installation de SSL pour Nginx avec Let's Encrypt

Let's encrypt est un service qui permet de générer gratuitement un certificat SSL pour le domaine de notre choix.
```bash
sudo apt install python3-acme python3-certbot python3-mock python3-openssl python3-pkg-resources python3-pyparsing python3-zope.interface
sudo apt install python3-certbot-nginx
sudo certbot certonly -d nextcloud.mondomaine.fr 
sudo certbot certonly -d collabora.mondomaine.fr
sudo certbot certonly -d pad.mondomaine.fr
```

**Les certificats sont alors crés dans `/etc/letsencrypt/nextcloud.mondomaine.fr`!**

## Configuration du **Server Bloc Nginx ** pour nextcloud.mondomaine.fr

On peut maintenant créer le fichier de configuration nginx  dans /etc/nginx/sites-available/nextcloud.mondomaine.fr.conf:

??? info "nextcloud.mondomaine.fr.conf"
    ```
    upstream nextcloud{
      server 127.0.0.1:8889;
    }

    server {
        if ($host = nextcloud.mondomaine.fr) {
            return 301 https://$host$request_uri;
        } # managed by Certbot


        listen 80;
        server_name nextcloud.mondomaine.fr;
        location /.well-known {
                alias /var/www/nextcloud.mondomaine.fr/.well-known;
        }
        location / {
        rewrite ^/(.*)$  https://$host/$1 permanent;
      }
    }

    server {
      listen 443 ssl;
      server_name nextcloud.mondomaine.fr;
      proxy_read_timeout 720s;
      proxy_connect_timeout 720s;
      proxy_send_timeout 720s;

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

      proxy_set_header Host $host;
      
      add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
      
      # Upload limit and security
      client_max_body_size 10000m;
      server_tokens off;

      # SSL parameters
      ssl on;
        ssl_certificate /etc/letsencrypt/live/nextcloud.mondomaine.fr/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/nextcloud.mondomaine.fr/privkey.pem; # managed by Certbot
      ssl_session_timeout 30m;
      ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    # ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    # ssl_prefer_server_ciphers on;

      # log
      access_log /var/log/nginx/nextcloud.access.log;
      error_log /var/log/nginx/nextcloud.error.log;

      # Redirect requests to nextcloud backend server
      location / {
        proxy_redirect off;
        proxy_pass http://nextcloud;
      }
      rewrite ^/.well-known/webfinger /public.php?service=webfinger last;
      location /.well-known/carddav {
          return 301 $scheme://$host/remote.php/dav;
        }
      location /.well-known/caldav {
          return 301 $scheme://$host/remote.php/dav;
        }
      location /.well-known/acme-challenge {
            alias /var/www/nextcloud.mondomaine.fr/.well-known/acme-challenge;
        }

    #  location ^/(.*\.php(/.*)?$ {
    #    proxy_pass fcgi://127.0.0.1:6379/var/www/html/$1;
    #  }
      # common gzip
      gzip_types text/css text/less text/plain text/xml application/xml application/json application/javascript;
      gzip on;
    }
    ```

Pour activer ce fichier de configuration, on créé un lien symbolique vers le dossier sites-enabled:

```bash
sudo ln -s /etc/nginx/sites-available/wordpress.mondomaine.fr.conf /etc/nginx/sites-enabled/
```

## Configuration du **Server Bloc Nginx** pour pad.mondomaine.fr

On peut maintenant créer le fichier de configuration nginx  dans /etc/nginx/sites-available/pad.mondomaine.fr.conf:

??? info "pad.mondomaine.fr.conf"
    ```    
    upstream pad {
        server 127.0.0.1:9001;
    }

    server {
        server_name pad.mondomaine.fr
        listen [::]:443 ssl ipv6only=on; # managed by Certbot
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/pad.mondomaine.fr/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/pad.mondomaine.fr/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

        location / {
            proxy_pass         http://pad;
            proxy_redirect     off;
            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-Host $server_name;
            proxy_set_header   X-Forwarded-Proto https;
        }
    }

    server {
        if ($host = pad.mondomaine.fr) {
            return 301 https://$host$request_uri;
        } # managed by Certbot
       location / {
        rewrite ^/(.*)$  https://$host/$1 permanent;
      }


            listen 80;
            listen [::]:80;

            server_name pad.mondomaine.fr;
        return 404; # managed by Certbot
    }

```

Pour activer ce fichier de configuration, on créé un lien symbolique vers le dossier sites-enabled:

```
sudo ln -s /etc/nginx/sites-available/pad.mondomaine.fr.conf /etc/nginx/sites-enabled/
```



## Configuration du **Server Bloc Nginx** pour collabora.mondomaine.fr

On peut maintenant créer le fichier de configuration nginx  dans /etc/nginx/sites-available/collabora.mondomaine.fr.conf:

??? info "collabora.mondomaine.fr.conf"
    ```
    upstream collabora{
      server 127.0.0.1:9980;
    }

    server {
        listen       443 ssl;
        server_name  collabora.mondomaine.fr;

        ssl on;
        ssl_certificate /etc/letsencrypt/live/collabora.mondomaine.fr/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/collabora.mondomaine.fr/privkey.pem;

        # static files
        location ^~ /loleaflet {
            proxy_pass https://localhost:9980;
            proxy_set_header Host $http_host;
        }

        # WOPI discovery URL
        location ^~ /hosting/discovery {
            proxy_pass https://localhost:9980;
            proxy_set_header Host $http_host;
        }

        # Capabilities
        location ^~ /hosting/capabilities {
            proxy_pass https://localhost:9980;
            proxy_set_header Host $http_host;
        }

        # main websocket
        location ~ ^/lool/(.*)/ws$ {
            proxy_pass https://localhost:9980;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $http_host;
            proxy_read_timeout 36000s;
        }

        # download, presentation and image upload
        location ~ ^/lool {
            proxy_pass https://localhost:9980;
            proxy_set_header Host $http_host;
        }

        # Admin Console websocket
        location ^~ /lool/adminws {
            proxy_pass https://localhost:9980;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $http_host;
            proxy_read_timeout 36000s;
        }
    }

    ```
Pour activer ce fichier de configuration, on créé un lien symbolique vers le dossier sites-enabled:

```bash
sudo ln -s /etc/nginx/sites-available/collabora.mondomaine.fr.conf /etc/nginx/sites-enabled/
```


On recharge la configuration de Nginx: 

```bash
sudo systemctl reload nginx.service
```

***Et voilà, votre site est accessible à `https://nextcloud.mondomaine.fr` !***

??? info "Plus d'infos sur la configuration de Nginx"
    Plus d'infos sur [le guide Nginx de Linode](https://www.linode.com/docs/web-servers/nginx/)

## Configuration des applications dans Nextcloud

### Configuration de etherpad

Il est nécessaire de récupérer la API KEY générée par etherpad:
    docker-compose exec pad bash
    cat APIKEY.txt
    
On la saisit ensuite dans Nextcloud: `Settings > Administration > Additional settings`

## Mise à jour de l'image Docker Nextcloud

#### Vérifier la version en production

> Avant chaque update checker dans les paramètres de base si des indices de table bdd manques ou autre.  

> L'update s'éffectue par palier de versions (20 vers 21 puis 21 vers 22, etc...)

#### étapes

- stopper la stack:

```bash
docker-compose down
```

- editer le tag de l'image Nextcloud dans le docker-compose.yaml:  

```bash
nano docker-compose.yml
```

- Modifier la version d'image vers la version immédiatement supérieure dans le docker-compose.yml
> Exemple: 20 -> 21

- relançer la stack:

```bash
docker-compose up -d
```

> Finir l'update via l'interface web

Une fois la mise à jour des applications éffectuée, se connecter et vérifier avec un compte administrateur dans Paramètres -> Vue d'ensemble si certaines tables de la base de donnée ont besoin d'être modifié via une commande explicitement décrite:

Exemple: 

```bash
docker exec --user www-data -it nextcloud /var/www/html/occ db:add-missing-indices
```

##### Commande générique pour ajouter des colonnes manquantes à certaines tables de la BDD

```bash
docker exec --user www-data -it <NOM_DU_CONTAINER> /var/www/html/occ <COMMANDE-DB>
```

??? "Crontab (pour nettoyer Nextcloud régulierement)"
    ```bash
    crontab -e
    */5  *  *  *  * docker exec -u www-data <NOM_DU_CONTAINER> php -f cron.php
    ```
