Installation d'un forum Discourse avec Apache, Docker et Mailboy


#1

Cette procédure est valable et testée uniquement sous Debian Stretch. Dans tous les cas, elle doit être testée et vérifiée convenablement avant d’être employée en production (ne pas lui faire aveuglément confiance).

Installation de Mailboy

La première étape est de disposer sur son serveur d’un système courriel complètement fonctionnel. Pour cela nous installerons Mailboy en suivant sa procédure d’installation.

Si, lors de l’installation d’Amavis vous rencontrez une erreur, il se peut que le nom d’hôte du serveur diffère du nom de domaine utilisé pour votre service courriel. Dans sa cas, modifier le fichier /etc/amavis/conf.d/05-node_id pour y placer le nom d’hôte du serveur courriel manuellement.

Fichier de conf apache pour Mailboy

Voici un exemple basique avec Mailboy accessible via https://mon-domaine.tld :

<VirtualHost *:80>
        ServerName mon-domaine.tld

	# Utilisé pour certifier le domaine avec let's encrypt
        Alias   /.well-known/acme-challenge/ /var/www/html/acme/.well-known/acme-challenge/
        <Directory /var/www/html/acme/.well-known/acme-challenge/>
                AllowOverride All
                Require all granted
        </Directory>

	RewriteEngine on
	RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

</VirtualHost>

<VirtualHost *:443>
        ServerName mon-domaine.tld

        # Activation du SSL
         SSLEngine On
         SSLProtocol All -SSLv3 -SSLv2
         SSLCipherSuite HIGH:!aNULL:!MD5:!ADH:!RC4:!DH
         SSLHonorCipherOrder on
         SSLCertificateFile "/chemin/vers/cert.pem"
         SSLCertificateKeyFile "/chemin/vers/privkey.pem"
         SSLCertificateChainFile "/chemin/vers/chain.pem"
         Header always set Strict-Transport-Security "max-age=15768000"

        # Accès a l'interface Mailbox (gestion du courriel)
        Alias   /mailboy    /usr/local/mailboy
        <Directory /usr/local/mailboy/>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride All
                Require all granted
        </Directory>

</VirtualHost>

Réglages supplémentaires pour le service courriel

Modification du fichier /etc/postfix/main.cf

Il nous faut maintenant renforcer un peu la configuration courriel proposée de base par Mailboy.

Dans le fichier /etc/postfix/main.cf, peu importe l’endroit dans le fichier, ajouter les lignes suivantes :

# Bloque les clients qui parlent avant leur tours (protection
# anti-spam basique, soulage SpamAssasin).
postscreen_greet_action = drop 

# Désactive la commande "VRFY" qui permet de tester un nom de login (et qui évite à
# un attaquant de tester l'existence d'un compte avant une attaque)
disable_vrfy_command = yes

Au commentaire # TLS parameters juste au dessus de la ligne smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache ajouter le commentaire # TLS coté client puis les lignes suivantes au dessous :

smtp_tls_security_level = dane
smtp_dns_support_level = dnssec
# Cipher TLS haut
smtp_tls_ciphers = high
# Log les négociation TLS
smtp_tls_loglevel = 1
# Vérification de la signature du certificat fournis par le serveur
smtp_tls_CApath = /etc/ssl/certs

Sous # SMTPD restriction supprimer toutes les occurrences de permit_sasl_authenticated, afin de forcer les logiciels clients (MUA) à utiliser les port 587 pour envoyer du courriel et qui est normalement réservé a cet effet.

Et pour finir, déclarer l’utilisation d’une table de transport qui sera créée plus loin en ajoutant la ligne suivante à la fin du fichier :

transport_maps = hash:/etc/postfix/transport

Modification du fichier /etc/postfix/master.cf

Au début du fichier, commenter la ligne 12 et dé-commenter les lignes 13,14 et 16 de manière à ce qu’elles ressemblent à ceci :

#smtp      inet  n       -       -       -       -       smtpd
smtp      inet  n       -       -       -       1       postscreen
smtpd     pass  -       -       -       -       -       smtpd
#dnsblog   unix  -       -       -       -       0       dnsblog
tlsproxy  unix  -       -       -       -       0       tlsproxy

Le service submission doit être modifié comme ceci :

submission inet n       -       -       -       -       smtpd
  -o postscreen_pipelining_enable=no
  -o postscreen_non_smtp_command_enable=no
  -o syslog_name=postfix/submission
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o smtpd_sasl_security_options=noanonymous
  -o smtpd_tls_auth_only=yes
  -o smtpd_tls_security_level=encrypt
  -o smtpd_reject_unlisted_recipient=no
  -o smtpd_recipient_restrictions=permit_auth_destination,reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_client_restrictions=permit
  -o smtpd_helo_restrictions=permit
  -o smtpd_sender_restrictions=reject_non_fqdn_sender,permit
  -o milter_macro_daemon_name=ORIGINATING

Sous le service submission, on ajoute un service submission-header-cleanup ayant pour but d’anonymiser un peu mieux le courriel envoyé :

# Règle de nettoyage des en-têtes du courriel
submission-header-cleanup unix n - n 	-	0 	cleanup
 -o header_checks=regexp:/etc/postfix/submission_header_cleanup

Pour le smtps, on désactive l’authentification pour les clients et la possibilité de relayer le courriel par ce service. Au final, il doit être comme ceci :

smtps     inet  n       -       -       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes

Modifier le service dovecot pour qu’il puisse prendre en compte les extension d’adresse courriel comme ceci :

dovecot   unix  -       n       n       -       -       pipe
    flags=DRhu user=mailboy:mailboy argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@${nexthop} -m ${extension}

Juste au dessous, créer un service courriel spécial pour Discourse car tous les courriels qui lui sont envoyés doivent arriver dans son dossier INBOX, il faut donc retirer -m ${extension}. La ligne doit ressembler à ceci :

discourse   unix  -       n       n       -       -       pipe
    flags=DRhu user=mailboy:mailboy argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@${nexthop}

Fichier supplémentaire pour Postfix :

Créer le fichier /etc/postfix/submission_header_cleanup qui contiendra les règle d’anonymisation des entêtes courriel et y placer le contenu suivant :

# Retire certain élément de l'entête fournis par le MUA pour des
# raisons de confidentialités

/^Received:/             IGNORE
/^X-Originating-IP:/   IGNORE
/^X-Mailer:/               IGNORE
/^User-Agent:/          IGNORE

Une fois le fichier modifié, exécuter la commande :

postmap /etc/postfix/submission_header_cleanup

Il faut aussi créer une table de transport pour que les courriels à destination de l’adresse *discourse@mon-domaine.tldsoient envoyés au service Postfixdiscoursecréé plus haut. Créer le fichier/etc/postfix/transport` et y placer le contenu suivant :

discourse@mon-domaine.tld	discourse:

Une fois le fichier créé, exécuter la commande suivante :

postmap /etc/postfix/transport

Activer le délimiteur de recipient dans l’agent de livraison du courriel de Dovecot

Dans le fichier /etc/dovecot/conf.d/15-lda.conf, décommenter la ligne recipient_delimiter = +.

(Optionel) Ajouter quelques dossiers créés automatiquement dans la boîte aux lettres des utilisateurs

Dans les fichiers /etc/dovecot/conf.d/15-mailboxes.conf, ajouter les lignes suivantes avant le } à la fin du fichier :

  # Boîte avec des nom français
  mailbox Brouillons {
    auto = subscribe
    special_use = \Drafts
  }
  mailbox Poubelle {
    auto = subscribe
    special_use = \Trash
  }
  mailbox Envoyés {
    auto = subscribe
    special_use = \Sent
  }
  mailbox Archives {
    auto = subscribe
    special_use = \Archive
  }
  mailbox Spam {
    auto = subscribe
    special_use = \Junk
  }

Finalisation

Recharger la configuration des services :

apachectl restart
postfix reload
doveadm reload

Puis se connecter à l’interface de Mailboy avec l’utilisateur créé pendant l’installation pour y créer la boîte mail discourse@nmon-domaine.tld.

Mise en place du forum Discourse

Installer Docker

Voir ici : https://docs.docker.com/install/linux/docker-ce/debian/

Déployer le forum Dicourse avec Docker

Se placer dans /var/, puis récupérer via git le nécessaire au déploiement de Discourse :

git clone https://github.com/discourse/discourse_docker

Renommer le dossier discourse_docker en discource

mv discourse_docker discourse

Se placer dans le dossier /var/discourse/container/, puis y créer le fichier app.yml avec le contenu suivant :

## this is the all-in-one, standalone Discourse Docker container template
##
## After making changes to this file, you MUST rebuild
## /var/discourse/launcher rebuild app
##
## BE *VERY* CAREFUL WHEN EDITING!
## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
## visit http://www.yamllint.com/ to validate this file as needed

templates:
  - "templates/cron.template.yml"
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
# Ne pas utiliser avec apache, ne fonctionne pas.
# À la place faire, un mappage de port.
# (voir expose: plus bas)
#  - "templates/web.socketed.template.yml"
## Uncomment these two lines if you wish to add Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

## which TCP/IP ports should this container expose?
## If you want Discourse to share a port with another webserver like Apache or nginx,
## see https://meta.discourse.org/t/17247 for details
# Discourse écoutera localement sur le port 20080, Apache sera chargé de faire suivre
# les connexions dessus.
expose:
- "20080:80"   # http
# - "443:443" # https

params:
  db_default_text_search_config: "pg_catalog.english"

  ## Set db_shared_buffers to a max of 25% of the total memory.
  ## will be set automatically by bootstrap based on detected RAM, or you can override
  #db_shared_buffers: "256MB"

  ## can improve sorting performance, but adds memory usage per-connection
  #db_work_mem: "40MB"

  ## Which Git revision should this container use? (default: tests-passed)
  #version: tests-passed

env:
  LANG: fr_FR.UTF-8
  DISCOURSE_DEFAULT_LOCALE: fr

  ## How many concurrent web requests are supported? Depends on memory and CPU cores.
  ## will be set automatically by bootstrap based on detected CPUs, or you can override
  #UNICORN_WORKERS: 3

  ## TODO: The domain name this Discourse instance will respond to
  ## Required. Discourse will not work with a bare IP number.
  DISCOURSE_HOSTNAME: 'forum.mon-domaine.tld'
  ## Uncomment if you want the container to be started with the same
  ## hostname (-h option) as specified above (default "$hostname-$config")
  DOCKER_USE_HOSTNAME: true

  ## TODO: List of comma delimited emails that will be made admin and developer
  ## on initial signup example 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'admin@mon-domaine.tld'

  ## TODO: The SMTP mail server used to validate new accounts and send notifications
  # SMTP ADDRESS, username, and password are required
  # WARNING the char '#' in SMTP password can cause problems!
  DISCOURSE_SMTP_ADDRESS: smtp.mon-domaine.tld
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: discourse@mon-domaine.tld
  DISCOURSE_SMTP_PASSWORD: secret
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (optional, default true)

  ## If you added the Lets Encrypt template, uncomment below to get a free SSL certificate
  #LETSENCRYPT_ACCOUNT_EMAIL: me@example.com

  ## The CDN address for this Discourse instance (configured to pull)
  ## see https://meta.discourse.org/t/14857 for details
  #DISCOURSE_CDN_URL: //discourse-cdn.example.com

## The Docker container is stateless; all data is stored in /shared
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## Plugins go here
## see https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

## Any custom commands to run after building
run:
  - exec: echo "Beginning of custom commands"
  ## If you want to set the 'From' email address for your first registration, uncomment and change:
  ## After getting the first signup email, re-comment the line. It only needs to run once.
  #- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
  - exec: echo "End of custom commands"

Ne pas oublier de personnaliser les paramètres avec ceux de votre installation :

DISCOURSE_HOSTNAME
DISCOURSE_DEVELOPER_EMAILS
DISCOURSE_SMTP_ADDRESS
DISCOURSE_SMTP_PORT
DISCOURSE_SMTP_USER_NAME
DISCOURSE_SMTP_PASSWORD

Une fois le fichier de configuration en place, il n’y a plus qu’a démarrer le forum en utilisant le script fourni :

 /var/discourse/launcher start app

Lors de la première exécution, l’image pour les conteneurs est construite, cela prend beaucoup de temps.

Configuration apache pour accèder à l’inance Discourse

Voici un exemple de fichier de configuration Apache :

<VirtualHost *:80>
        ServerName forum.mon-domaine.tld

	# Utilisé pour certifier le domaine avec let's encrypte
        Alias   /.well-known/acme-challenge/ /var/www/html/acme/.well-known/acme-challenge/
        <Directory /var/www/html/acme/.well-known/acme-challenge/>
                AllowOverride All
                Require all granted
        </Directory>

	RewriteEngine on
	RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

</VirtualHost>

<VirtualHost *:443>
	ServerName forum.mon-domaine.tld
        # Redirection vers le conteneur Docker
	ProxyPass / http://127.0.0.1:20080/
	ProxyPassReverse / http://127.0.0.1:20080/
	ProxyPreserveHost On
        Header always set Strict-Transport-Security "max-age=15768000"
	Header always set X-XSS-Protection "1; mode=block"
	Header always set Frame-Options SAMEORIGIN
	Header always set X-Frame-Options SAMEORIGIN
	Header always set X-Content-Type-Options nosniff
	SSLCertificateFile /chemin/vers/fullchain.pem
	SSLCertificateKeyFile /chemin/vers/privkey.pem
</VirtualHost>

Une fois le fichier créé, redémarrer Apache avec un apachectl restart

Finaliser la configuration Discourse

Se connecter au forum via https://forum.mon-domaine.tld, et suivre les instructions indiquées. Une fois fini, se rendre dans la partie Administration et aller dans Paramètres puis Courriel afin de fournir les réglages nécessaires a ce que Discourse puisse recevoir du courriel de la part de ses utilisateurs pour fonctionner en mode mailing-list.

  • Commencer par fournir au paramètre pop3 polling host l’adresse IP locale du serveur qui héberge le forum et le courriel (par ex : `192.68.XXX.XXX).

Pourquoi ne pas fournir le domaine ? Personellement, j’ai rencontré un problème en le faisant de plus, si vous le faites, ne pas oublier de natter le port 995 dans votre routeur.

  • Vu que l’on fournit une IP et pas un nom de domaine, le certificat serveur sera vu comme invalide, il faut donc décocher pop3 polling openssl verify.

  • Fournir à pop3 polling username le nom du compte mail créé pour Discourse tout à l’heure avec Mailboy (discourse@mon-domaine.tld) et le mot de passe qui va avec dans pop3 polling password.

  • Cocher ensuite la case pop3 polling enabled, si elle s’active c’est que Discourse peut maintenant relever le courriel que les utilisateurs lui envoient.

  • Activer la réponse aux sujets par courriel ainsi que leur création en cochant les cases reply by email enabled et email in.

  • Dans le champ reply by email address, y placer la valeur discourse+%{reply_key}@mon-domaine.tld.

Ce devrait être bon pour les réglages minimaux.

Ressources externes

Pour approfondir voir les ressources suivantes :

Configuration des services de courriel

http://www.postfix.org/documentation.html
https://wiki.dovecot.org/FrontPage?action=show&redirect=PageD'Accueil

Alternative à la gestion du courriel via Mailboy
https://thomas-leister.de/en/mailserver-debian-stretch/

Disourse

https://meta.discourse.org/c/howto
https://github.com/discourse/discourse/blob/master/docs/INSTALL.md