Installation serveur HTTP(S) rapide

Voici un article qui va me servir à rassembler les différentes documentations dont je me sert à chaque fois que j’installe un serveur Web. Là, j’ai pris un serveur virtuel chez OVH (à 3 € HT par mois, pour 2 GO de RAM et 10 GO d’espace disque), sur lequel j’ai installé une distribution Ubuntu 16.04.

Une fois l’installation terminée, on reçoit un email avec le mot de passe root. Commençons donc par nous logguer sur la machine.

Installations de base

Installons quelques outils utiles :

# apt-get install tree htop iftop make screen subversion git

Créons un nouvel utilisateur, et ajoutons-le au groupe sudo (pour qu’il puisse exécuter des commandes en tant que root) :

# adduser toto
# usermod -aG sudo toto

Éditons la configuration SSH pour empêcher la connexion avec l’utilisateur root. Pour cela, il faut ouvrir le fichier /etc/ssh/sshd_config et éditer la ligne suivante :

PermitRootLogin no

Firewall

Créons ensuite un firewall minimal. Ouvrir le fichier /etc/init.d/firewall :

#!/bin/sh

### BEGIN INIT INFO
# Provides: firewall
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start firewall at boot time
# Description: Enable service provided by daemon.
### END INIT INFO

# vidage des regles
iptables -F
iptables -X
iptables -t nat -F

# garde les connexions ouvertes
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# autorise les connexions SSH entrantes
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# autorise le ping entrant
iptables -A INPUT -p icmp -j ACCEPT

# autorise les connexions HTTP et HTTPS entrantes
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# bloque les connexions entrantes
iptables -P INPUT DROP
iptables -P FORWARD DROP

# bloque les SYN floods
iptables -N syn_flood
iptables -A INPUT -p tcp --syn -j syn_flood
iptables -A syn_flood -m limit --limit 100/s --limit-burst 150 -j RETURN
iptables -A syn_flood -j DROP

# autorise loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

On exécute le script, puis on fait en sorte qu’il soit exécuté au démarrage du serveur :

# chmod +x /etc/init.d/firewall
# /etc/init.d/firewall
# update-rc.d firewall start 01 2 .

Si vous le souhaitez, vous pouvez installer les locales françaises :

# apt-get install language-pack-fr

Installation de NTP

# apt-get install openntpd ntpdate

Édition du fichier /etc/openntpd/ntpd.conf :

server fr.pool.ntp.org

Redémarrage :

# ntpdate fr.pool.ntp.org
# service openntpd restart

Changement de nom de machine

# hostname nomdelamachine

Modifier le fichier /etc/hostname pour y mettre le nouveau nom.

Ajouter le nom de machine à la boucle locale dans le fichier /etc/hosts :

127.0.0.1    localhost nomdelamachine

Installation MySQL

# apt-get install mysql-server
# mysql_secure_installation

Pour le second script, l’idée est de mettre à jour le mot de passe root, de supprimer le compte anonyme et d’interdire la connexion root distante.

Installation Apache

# apt-get install apache2
# a2enmod headers
# a2enmod rewrite
# a2enmod expires

Modification du fichier /etc/apache2/apache2.conf (pour  diminuer certains timeout pour réduire la charge inutile sur le serveur) :

Timeout 150
KeepAliveTimeout 3

Modification du fichier /etc/apache2/conf-available/security.conf (pour réduire les informations fournies par le serveur) :

ServerTokens Prod
ServerSignature Off

<DirectoryMatch "/\.svn">
    Require all denied
</DirectoryMatch>
<DirectoryMatch "/\.git">
    Require all denied
</DirectoryMatch>

Modification du fichier /etc/apache2/conf-available/charset.conf :

AddDefaultCharset UTF-8

Modification du fichier /etc/apache2/mods-available/mime.conf :

AddType application/x-truetype-font .ttf
AddType application/vnd.ms-fontobject .eot
AddType font/otf .otf
AddType application/x-woff .woff
AddType text/x-component .htc

Modification du fichier /etc/apache2/mods-available/deflate.conf :

AddOutputFilterByType DEFLATE application/x-truetype-font application/vnd.ms-fontobject font/otf application/x-woff

Création du fichier /etc/apache2/mods-available/expires.conf :

<IfModule mod_expires.c>
    ExpiresActive On
    # images
    ExpiresByType image/gif "access 20 days"
    ExpiresByType image/jpg "access 20 days"
    ExpiresByType image/jpeg "access 20 days"
    ExpiresByType image/png "access 20 days"
    ExpiresByType image/x-icon "access 20 days"
    # CSS et javascript
    ExpiresByType text/css "access 20 days"
    ExpiresByType application/javascript "access 20 days"
    ExpiresByType text/javascript "access 20 days"
    ExpiresByType application/x-javascript "access 20 days"
    # fontes
    ExpiresByType application/x-truetype-font "access 20 days"
    ExpiresByType application/vnd.ms-fontobject "access 20 days"
    ExpiresByType font/otf "access 20 days"
    ExpiresByType application/x-woff "access 20 days"
</IfModule>

Création du fichier /etc/apache2/mods-available/headers.conf :

<IfModule mod_headers.c>
    <FilesMatch "\.(ttf|otf|eot|woff|svg)$">
        Header set Access-Control-Allow-Origin "*"
    </FilesMatch>
</IfModule>

Création de liens :

# cd /etc/apache2/mods-enabled
# ln -s ../mods-available/expires.conf
# ln -s ../mods-available/headers.conf

Vérification de la configuration :

# apache2ctl -t

Installation PHP

# apt-get install php7.0 php7.0-cli php7.0-curl php7.0-dev php7.0-gd php7.0-imap php7.0-intl php7.0-json php7.0-mbstring php7.0-mcrypt php7.0-mysql php7.0-opcache php7.0-soap php7.0-tidy php7.0-xml php7.0-zip php-imagick php-memcached php-redis
# apt-get install libapache2-mod-php7.0

Vous pouvez ajouter des librairies PHP supplémentaires, en fonction de vos besoins. Voici quelques-unes de celles qu’il m’arrive d’installer :

# apt-get install smarty3 smarty-gettext
# apt-get install libmarkdown-php
# apt-get install php-fpdf libfpdf-tpl-php libfpdi-php php-pdfparser
# apt-get install php-geoip
# apt-get install php-getid3
# apt-get install php-geshi

Redémarrage Apache

# apache2ctl restart

Installation Memcached

Si vous avez besoin d’un serveur de cache pour vos applications web :

# apt-get install memcached

Si vous souhaitez augmenter la mémoire allouée au cache (disons à 2 GO) et permettre la connexion au cache depuis d’autres machines, éditez le fichier /etc/memcached.conf :

-m 2048
-l 0.0.0.0

Installation Redis

Si vous avez besoin d’un serveur noSQL :

# apt-get install redis-server

Installation Apache status

Si vous voulez voir comment les processus Apache sont utilisés, vous pouvez utiliser le module mod_status. Pour l’ajouter :

# a2enmod status

Il faut ensuite créer un virtual host Apache qui « hébergera » cette page. Vous pouvez vous inspirer de cette configuration :

<VirtualHost *:80>
        ServerName www.mondomaine.fr
        DocumentRoot /opt/finemedia/www.work1.finemedia.fr/www
        <Directory />
                Options FollowSymLinks
                AllowOverride All
        </Directory>
        <Location /server-status>
                SetHandler server-status
                Order allow,deny
                Allow from all
        </Location>
        LogLevel warn
        ErrorLog /var/log/apache2/www.mondomaine.fr-error.log
        CustomLog /var/log/apache2/www.mondomaine.fr-access.log combined
</VirtualHost>

HTTPS

Si vous souhaitez supporter le HTTPS, il faut commencer par activer l’extension :

# a2enmod ssl

Pour le reste de la configuration SSL, vous pouvez regarder le billet que j’avais écrit sur le sujet (qui est maintenant un peu ancien, mais globalement encore valable).

Serveur emails

Envoi d’emails

Pour permettre au serveur d’envoyer des emails (mais pas d’en recevoir), le plus simple est d’installer un serveur SMTP en mode « send-only ». Pour cela, il en existe plusieurs, mais voici comment faire avec Exim :

# apt-get install exim4-daemon-light

Puis exécuter la commande suivante :

# dpkg-reconfigure exim4-config

Répondre aux questions (cf. http://library.linode.com/email/exim/send-only-mta-ubuntu-9.10-karmic) :

  1. Choisir « Distribution directe par SMTP (site Internet) ».
  2. Mettre un nom de domaine qui vous appartient (à défaut laissez « localhost »).
  3. Laisser l’adresse IP de loopback (« 127.0.0.1 ; ::1 ») qui est proposée par défaut, car on ne souhaite pas recevoir d’email venant de l’extérieur.
  4. Vider complètement la liste des domaines locaux de destination finale.
  5. Ne pas mettre de domaine à relayer (choix par défaut).
  6. Ne pas mettre d’adresse IP à relayer (choix par défaut).
  7. Répondre « non » à la question du cache DNS (choix par défaut).
  8. Choisir le stockage « mbox ».
  9. Répondre « non » à la question de la séparation de la configuration en plusieurs fichiers.
  10. Vous pouvez mettre une adresse email externe, vers laquelle seront acheminés les messages à destination des utilisateurs root et postmaster du serveur.

Envoi et réception d’emails

Si par contre vous souhaitez gérer aussi bien l’envoi que la réception des messages, il faut installer un serveur SMTP complet. Voici la marche à suivre avec Exim, auquel on va ajouter Spamassassin pour filtrer les spams et CourierIMAP pour la consultation des emails via le protocole IMAP4. On va même passer par la base de données MySQL pour gérer les comptes qui peuvent envoyer et recevoir des emails (ainsi il n’y a pas besoin de créer un utilisateur Unix pour chaque compte email).

# apt-get install exim4-daemon-heavy sa-exim spamassassin courier-imap courier-authlib-mysql

Pour la configuration de courier-imap, répondre non à la question relative à la création de sous-répertoires de configuration.

Configuration de Spamassassin

Editer le fichier /etc/default/spamassassin :

ENABLED=1
CRON=1

Démarrer le démon spamd :

# service spamassassin start

Mise-à-jour des règles de spam :

# spamassassin -D --lint
# sa-update
# sa-compile
# sa-update -D channel-dns
# spamassassin -D --lint

Editer le fichier /etc/spamassassin/local.cf :

report_safe 1
use_bayes 1
bayes_auto_learn 1
bayes_ignore_header X-Bogosity
bayes_ignore_header X-Spam-Flag
bayes_ignore_header X-Spam-Status

Editer le fichier /etc/spamassassin/v310.pre et décommenter cette ligne :

loadplugin Mail::SpamAssassin::Plugin::AntiVirus

Redémarrer Spamassassin :

# service spamassassin restart

Configuration Exim

Editer le fichier /etc/exim4/sa-exim.conf. Commenter la ligne :

SAEximRunCond: 0

Editer le fichier /etc/exim4/update-exim4.conf.conf :

dc_eximconfig_configtype='internet'
dc_other_hostnames='domaine1.com:domaine2.com:domaine3.com'
dc_local_interfaces='127.0.0.1:XX.XX.XX.XX'
dc_use_split_config='true'
#dc_localdelivery='mail_spool'

Editer le fichier /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs :

local_interfaces = 0.0.0.0.25

Editer le fichier /etc/exim4/conf.d/auth/30_exim4-config_examples :

plain_server:
  driver = plaintext
  public_name = PLAIN
  server_condition = ${lookup mysql{ SELECT IF(COUNT(*)=1,'yes','no') FROM tUser WHERE use_s_email='${quote_mysql:$auth2}' AND use_s_password='${quote_mysql:$auth3}'}}
  server_set_id = $auth2
  server_prompts = :
  .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS
  server_advertise_condition = ${if eq{$tls_cipher}{}{}{*}}
  .endif

login_server:
  driver = plaintext
  public_name = LOGIN
  server_prompts = "Username:: : Password::"
  server_condition = ${lookup mysql{ SELECT IF(COUNT(*)=1,'yes','no') FROM tUser WHERE use_s_login='${quote_mysql:$auth1}' AND use_s_password='${quote_mysql:$auth2}'}}
  server_set_id = $auth1
  .ifndef AUTH_SERVER_ALLOW_NOTLS_PASSWORDS
  server_advertise_condition = ${if eq{$tls_cipher}{}{}{*}}
  .endif

Editer le fichier /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs :

hide mysql_servers = localhost/finemedia_users/finemedia/finemedia
AUTH_SERVER_ALLOW_NOTLS_PASSWORDS="true"
domainlist local_domains = localhost:domaine1.com:domaine2.com:domaine3.com

Editer le fichier /etc/exim4/conf.d/main/02_exim4-config_options :

rfc1413_query_timeout = 0s

Créer le fichier /etc/exim4/conf.d/router/999_exim4-config_mysql_user :

virtual_user:
  driver = redirect
  allow_fail
  allow_defer
  data = ${lookup mysql{ SELECT use_s_maildir_path FROM tUser WHERE use_s_login='${quote_mysql:${local_part}}' LIMIT 1}}${if def:h_X-Spam-Flag {.Junk/}}
  directory_transport = address_directory

Editer le fichier /etc/exim4/conf.d/transport/30_exim4-config_maildir_home. Remplacer les lignes :

delivery_date_add
envelope_to_add
return_path_add
maildir_format

Par :

delivery_date_add
envelope_to_add
return_path_add
maildir_format
mode = 0660
user = mail
group = mail

Remplacer la ligne :

directory_mode = 0700

Par :

directory_mode = 0770

Commenter la ligne :

#mode = 0600

Editer le fichier /etc/exim4/conf.d/transport/30_exim4-config_mail_spool. Remplacer les lignes :

file = /var/mail/$local_part
delivery_date_add
envelope_to_add
return_path_add

Par :

directory = /var/vmail/${local_part}/Maildir/${if def:h_X-Spam-Flag {.Junk/}}
maildir_format
delivery_date_add
envelope_to_add
return_path_add
user = mail

Editer le fichier /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp. Ajouter les lignes (en remplaçant MONSERVEUR par le nom du serveur, et XX.XX.XX.XX par l’adresse IP d’expédition par défaut) :

helo_data = MONSERVEUR
interface = ${lookup{$sender_address_domain}lsearch{/etc/exim4/interfaces} {$value}{XX.XX.XX.XX}}

Editer le fichier /etc/exim4/interfaces. Ajouter une ligne pour chaque nom de domaine d’expédition, avec l’adresse IP équivalente :

domaine1.fr: X.X.X.X
domaine2.com: Y.Y.Y.Y

Editer le fichier /etc/exim4/conf.d/transport/35_exim4-config_address_directory. Ajouter les lignes :

mode = 0600
user = mail
group = mail

Mettre le nom du serveur dans le fichier /etc/mailname.

Redémarrage du démon :

# service exim4 restart

Configuration de Courier-IMAP

Editer le fichier /etc/courier/authdaemonrc. Changer la ligne :

authmodulelist="authpam"

Par :

authmodulelist="authmysql"

Editer le fichier /etc/courier/authmysqlrc :

MYSQL_SERVER localhost
MYSQL_USERNAME dbuser
MYSQL_PASSWORD dbpassword

MYSQL_DATABASE dbtable
MYSQL_USER_TABLE users
#MYSQL_CRYPT_PWFIELD crypt
MYSQL_CLEAR_PWFIELD password
DEFAULT_DOMAIN mondomaine.fr
MYSQL_UID_FIELD uid
MYSQL_GID_FIELD gid
MYSQL_LOGIN_FIELD email
MYSQL_HOME_FIELD home_path
MYSQL_NAME_FIELD display_name

Editer le fichier /etc/courier/imapd :

MAXDAEMONS=250
MAXPERIP=250

Redémarrage du démon :

# service courier-imap restart
# service courier-authdaemon restart

6 commentaires pour “Installation serveur HTTP(S) rapide

  1. Salut Amaury, toute cette documentation prendrait encore plus de sens en s’incarnant dans une « recette » Ansible/Salt/Puppet, si celle-ci est utilisée régulièrement, non ?

  2. Oui, c’est effectivement une bonne idée.

    Je ne le ferai pas pour deux raisons :
    1. J’ai mis plusieurs règles optionnelles (envoi/réception d’emails, Redis, Memcache, HTTPS, …). Difficile d’écrire une recette systématisable, mais on pourrait en écrire plusieurs pour tous les usages possibles.

    2. En ce moment j’aurais plutôt tendance à vouloir faire du serverless à base d’AWS Lambda… 😉

  3. salut, je n’ai pas lu tout l’article-tuto, mais de nos jours, je pense que Dovecot est plus à conseiller que Courier-imapd.
    Ces dernières années, mes migrations/évolution de notre plate-forme mail ont été dans ce sens. La principale raison est qu’au contraire de Courier, dovecot est un serveur avec cache. Mais d’autres raisons peuvent motiver ce choix, en vrac et non exhausif : plus respecteux des standards, plus sécurisé, plus activement développé et suivi, plus configurable, supporte mieux la montée en charge (mon hébergement est avec proxies + backends), fourni avec des outils d’administration (doveadm…).
    Quelques infos :
    http://imapwiki.org/Benchmarking
    http://imapwiki.org/ImapTest/ServerStatus
    http://www.dovecot.org/

    Pour le MTA, je préfère aussi postfix, mais bon, je crois savoir que certains préfèrent exim pour sa facilité de configuration apparente.
    J’utilise moi-même le paquet exim-light-daemon sur les serveurs qui ne reçoivent pas de messages (le canal #postfix sur Freenode et et la doc postfix appellent ça null client).

    Après, je ne dis pas que courier ne « fait pas le job » pour une petite installation avec des utilisateurs « raisonnables » quant à l’utilisation de cet outil.

  4. OK, merci pour ces précisions. C’est vrai que je n’ai jamais pris le temps de regarder Dovecot de plus près. Est-ce qu’il gère l’authentification en passant par une base de données MySQL ?

  5. oui, j’ai oublié de préciser que même ça, c’est bien meilleur. Il supporte même plusieurs base d’authentification appelées « passdb » (pour password database bien sûr) et pour SQL, il est possible de déclarer plusieurs serveurs, et ça, c’est mieux pour la continuité de service et la haute dispo. Je dis que c’est mieux car Courier utilise cyrus-sasl qui est vraiment une plaie à côté :
    http://wiki.dovecot.org/PasswordDatabase

  6. Merci pour tous les billets forts intructifs clairs et de top qualité.
    Perso j’ajoute fail2ban, logwatch et monitorix.
    Avec fail2ban je me sens un peut plus rassurer, logwatch me sert à me rappeler de ce que j’ai fait ou pas fait sur le serveur, et monitorix pour voir la santé du serveur dans le temps en un coup d’oeil puisque ce sont de petits graphiques très parlants.

Laisser un commentaire

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

Notifiez-moi des commentaires à venir via email. Vous pouvez aussi vous abonner sans commenter.