Outils pour utilisateurs

Outils du site


doc:formations:hebergement:service:apache

< Retour à l'index

Serveur web Apache

Installation LAMP classique:

apt update && apt install apache2 php mysql-server libapache2-mod-php php-mysql
a2enmod rewrite
a2enmod vhost_alias

:!: vérifier les priorités des éntrées dans le DirectoryIndex de /etc/apache2/mods-enabled/dir.conf: si vous faites en sorte qu'un index.php passe après le test de la présence d'un index.html, cela vous permettra de placer un simple fichier HTML prioritaire lors des mises à jours du serveur par exemple).

Un "virtualhost" par domaine hébergé

On va créer un dossier par site sur le serveur (selon le principe des VirtualHosts). Par exemple ici avec sub.mondomaine.com. Soit on répète ce bloc pour chacun des domaines hébergés par ce serveur ( correspondants aux champs A de son DNS), soit on utilise un "wildcard" (ci-après).

# Désactiver le site par défaut:

a2dissite 000-default.conf

# Nom du domaine à servir:
dom="sub.mondomaine.com"

# On crée le dossier associé au domaine, avec un index.php "bidon" mais pratique pur vérifier:

mkdir -m 0755 "/var/www/$dom"
chown www-data:www-data "/var/www/$dom"
echo -e "Ce serveur est: $dom\n<?php phpinfo(); ?>" > "/var/www/$dom/index.php"

# On ajoute un "virtualhost" pour ce domaine dans apache:

cat > /etc/apache2/sites-available/$dom.conf << EOF
<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    ServerName $dom
    DocumentRoot /var/www/$dom
    ErrorLog \${APACHE_LOG_DIR}/error.log
    CustomLog \${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
EOF

# Puis on active la configuration:

a2ensite "$dom.conf"
if apache2ctl configtest | grep 'Syntax OK'; then
  systemctl restart apache2
fi

A partir de là si l'accès HTTP est ouvert sur l'extérieur, on devrait voir le nom du site et des informations PHP en allant sur http://sub.mondomaine.com

serveur nginx

Note: si vous utilisez le server nginx et que vous avez besoin de PHP, il ne vient pas sous la forme d'un module conjoint contrairement à libapache2-mod-php. Vous pouvez installer le service PHP indépendant,

apt-get install nginx php-fpm

puis ajouter à la configuration de votre site le paragraphe suivant:

(...)
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }
(...)

Un "virtualhost" unique pour tous les sous-domaines

On peut mettre dans son DNS des entrées de type "wildcard": par exemple * IN CNAME tecrd.com. ou bien * IN A 11.22.33.44.

De cette manière tous les sous-domaines <nom>.tecrd.com qui n'auraient pas déjà une entrée DNS explicite seront automatiquement renvoyés vers le serveur. Ce comportement "par défaut" est pratique: on pourra quand même faire pointer mx.tecrd.com vers un serveur mail indépendant, avec le "joker" ou "wildcard" qui ne gère que les cas par défaut).

Du coté de la configuration Apache sur le serveur, on peut soit avoir un VirtualHost par sous-domaine (comme ci-dessus), soit mettre là aussi une configuration "wildcard" qui va associer un sous-domaine à un DocumentRoot (base de l'arborescence pour ce sous-domaine).

Ce type de configuration DNS+Apache permet de gérer un nouveau sous-domaine sans devoir toucher ni au DNS, ni à Apache.

:!: pour HTTPS il restera néamoins à re-générer le certificat Letsencrypt, afin de lui dire de couvrir le ou les nouveaux sous-domaines servi, ou bien d'avoir acheté un "wildcard certificate" en premier lieu, ce qui est assez couteux.

Voilà un exemple de configuration /etc/apache/site-available/999-wildcard-subdomains.conf (n'oubliez pas le ".conf"!). Il gère automatiquement les sous-domaines en "wildcard". Pensez à l'activer une fois en place avec a2ensite et relancer Apache:

<VirtualHost *:80>
    ServerAlias *.tecrd.com
    VirtualDocumentRoot /var/www/%1/
</VirtualHost>

Ici, http://test.tecrd.com sera donc servi par le dossier /var/www/test, et variante.tecrd.com par /var/www/variante

Astuce: si l'on a comme convention site1.dev.tecrd.com, site2.dev.tecrd.com, site3.prod.tecrd.com… on peut préférer utiliser deux niveaux de dossiers /var/www/dev et /var/www/prod:

<VirtualHost *:80>
    ServerAlias *.*.tecrd.com
    VirtualDocumentRoot /var/www/%2/%1/html
</VirtualHost>

Plus de détails sur ce site (en anglais).

Certificat HTTPS avec Letsencrypt

Préparation

C'est devenu simplissime avec Letsencrypt (un consortium solide qui founit des certificats gratuits tout à fait valables):

apt install certbot python3-certbot-nginx   # nginx pour nginx, logique

# Ou pour la toute dernière version:
#   add-apt-repository ppa:certbot/certbot
#   apt install python-certbot-apache  # a) si vous utilisez Apache2
#   apt install python-certbot-nginx   # b) si vous utilisez nginx

Il faudra vérifier la validité du ServerName mondomaine.com; dans /etc/apache2/sites-available/your_domain.conf, puis recharger éventuellement apache avec systemctl reload apache2

:!: il est recommandé d'écrire le "your_domain.conf" sous une forme exacte, par exemple "sub.domain.com.conf". On évite des ambiguités ainsi et on permet l'automatisation des certificats (ci-dessous).

Création et installation

On peut alors laisser le robot de Letsencrypt faire son travail (:!: penser à lui fournir l'ensemble des domaines à protéger, il est généralement plus compliqué de le faire domaine par domaine):

certbot --apache -d mondomaine.com -d www.mondomaine.com -d sub.mondomaine.com -d autredomaine.com

Le système de validation va tenter de poser un fichier spécial temporairement à la racine du site web, que les serveurs de Letsencrypt doivent pouvoir consulter ensuite. C'est ainsi qu'ils peuvent valider que l'on est bien le propriétaire du serveur et du domaine. Si l'opération se passe mal, c'est la première chose à regarder!

Note: si vous avez de nombreux domaines, pensez à sauvegarder la ligne complète pour la prochaine fois ou vous voudriez en ajouter un.

serveur web NGINX

On peut systématiser et couvrir tous les sites-available s'ils sont bien formés (nom FQDN complet) et en rajoutant les alias de noms de domaines, par exemple avec une commande "sportive", et l'automatiser pour renouvellement toutes les semaine en créant /etc/cron.weekly/letsencrypt et le contenu suivant

#!/bin/sh
# vive linux
# Retirez le -q des options de certbot pour une version avec confirmation
xargs -a <(sed -n 's/^\s*[^#]server_name\s*\([^;]*\)\s*;.*/ -d \1/p' /etc/nginx/sites-enabled/*|sort -u) certbot --nginx

Voilà en outre un exemple de définition de site avant le passage de certbot (toujours pour nginx!):

# Template for a generic nginx-server internet domain
# Replace "tm.tecrd.com" with your domain name,
# enable/disable parts, then run certbot with "-d tm.tecrd.com"
#
# certbot --dry-run --nginx $(grep server_name /etc/nginx/sites-available/*|sed 's/.*server_name \(.*\)\s*;/\1/'| tr ' ' '\n'|sort -u|grep .|xargs -L 1 echo -n " -d")
#
# jeremie@tecrd.com 20200325-083612

server {
    server_name tm.tecrd.com ;
    root /home/www/tm.tecrd.com;
    listen 80;
}

server {
    server_name tm.tecrd.com ;
    root /home/www/tm.tecrd.com;
    index index.html index.php;

# If you need some server-controlled access filtering
#    auth_basic "Time flows here";
#    auth_basic_user_file /home/www/.htusers;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ /\.ht {
        deny all;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
    }

# If you need to proxy some ports:
#    location /sub/ {
#        rewrite ^\/sub\/(.*) /$1 break;
#        proxy_pass http://localhost:3333;
#        proxy_http_version 1.1;
#        proxy_set_header Upgrade $http_upgrade;
#        proxy_set_header Connection 'upgrade';
#        proxy_set_header Host $host;
#        proxy_cache_bypass $http_upgrade;
#    }

    listen 443 ssl; # managed by Certbot
}

Remarque: le robot letsencrypt fonctionne en "posant" un fichier de validation dans un dossier .well-known à la racine du site, puis tente d'y accéder en HTTP depuis l'extérieur. S'il y a une configuration qui l'en empêche, on peut le rediriger et se faciliter la vie avec une clause dédiée de ce type (dans le "listen" HTTP port 80). Si le root est var/www/html (par défaut):

location /.well-known/acme-challenge/ {
  alias /var/www/html/.well-known/acme-challenge/;
}

Redirection forcée vers HTTPS

Pour rediriger une URL particulière vers sa version HTTPS:

<VirtualHost *:80>
   ServerName wiki.mondomaine.com
   Redirect permanent / https://wiki.mondomaine.com/
</VirtualHost>

On peut le faire globalement aussi pour tout le site (vérifier que tous les services sont OK avec ça!):

<VirtualHost *:80>
  [...]
  <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
  </IfModule>
</VirtualHost>

:!: Avec Letsencrypt, attention avec les VirtualHost en "wildcard" (cf VirtualDocumentRoot). Si l'on active la redirection http vers https (option 2 lors de l'installation), le patch effectué par le robot certbot est ineffectif: il faut réécrire la condition sous cette forme (enlever le = et remplacer * par .*), par exemple:

RewriteCond %{SERVER_NAME} .*.mondomaine.com

HSTS

C'est une protection implémentée côté client: s'il voit cet en-tête venant du serveur, c'est le navigateur client qui refusera alors de se connecter autrement qu'en HTTPS vers le serveur. Il faut faire attention à cette option: elle est sécurisante, mais elle est très "collante" (tout service HTTP qui n'a pas de version HTTPS correspondante deviendra inaccessible, c'est aussi le but).

Ex: https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html#toc_2

Activer l'envoi d'en-tête:

a2enmod headers 
systemctl restart apache2

Et dans la configuration apache /etc/apache2/sites-enabled/*:

<VirtualHost *:443>
  ServerName cloud.nextcloud.com
    <IfModule mod_headers.c>
      Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains"
    </IfModule>
 </VirtualHost>

Puis relancer le serveur avec systemctl restart apache2.

Du coté client, pour se débarrasser de ce comportement il faut aller dans la configuration de son ou de ses navigateurs et leur faire oublier qu'ils ont vu l'offre HSTS (et généralement effacer tout l'historique de consultation pour éviter un recyclage des adresses HTTPS!).

Services multiples sur un site ou un domaine

Exceptions

Cas réel: une installation mattermost préconfigurée chez scaleway aura tendance à "occuper" tout le domaine.

Si l'on veut pouvoir ajouter un dokuwiki dans un sous dossier wiki/ par exemple, il faudra ajouter une exception dans la configuration du navigateur:

(ici Nginx)

	rewrite ^/wiki/?$ /wiki/index.php;
	location /wiki {
		root /var/www/html/wiki/;
		location ~ /(data|conf|bin|inc)/ {
			deny all;
		}
	}

Reverse proxy

Dans certains cas, on peut aussi rediriger un "dossier" web vers un autre serveur.

L'intéret est alors d'utiliser un nom de domaine comme portail, mais qui redirige ensuite de façon totalement transparente pour l'utilisateur certaines URL vers d'autres services ou serveurs du réseau local.

Sous Apache par exemple, on redirigera le chemin /mattermost dans un virtual host existant vers l'IP interne (10.5.82.219, telle qu'indiquée par ifconfig) et le port 8065 du service mattermost ainsi:

ProxyPreserveHost On
ProxyPass /mattermost http://10.5.82.219:8065/
ProxyPassReverse /mattermost http://10.5.82.219:8065/

Autre exemple sous nginx, pour dédier l'URL http://talk.tecrd.com (champ A ou CNAME requis) vers le service mattermost local, on créerait un /etc/nginx/sites-enabled/talk.tecrd.com dont le contenu serait le suivant:

server {
  server_name talk.tecrd.com;
  root /home/www/talk.tecrd.com;
  location / {
    proxy_pass http://10.5.82.219:8065;
  }
}

:!: on remarquera ici que la redirection est en HTTP (interne), mais qu'il faudra blinder l'accès externe en HTTPS. Cela ne posera pas de problème car c'est bien le certificat associé au nom de domaine exposé sur l'extérieur qui sera utilisé (il n'y a pas de problème de sécurité à "redescendre" d'HTTPS vers HTTP une fois entré sur le serveur).

Sous nginx la configuration finale serait par exemple:

server {
    server_name talk.tecrd.com;
    listen 80;
    return 301 https://talk.tecrd.com;
}

server {
    server_name talk.tecrd.com ;
    root /home/www/talk.tecrd.com;
    location / {
        proxy_pass http://127.0.0.1:8065;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/admin.tecrd.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/admin.tecrd.com/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
}

Exceptions pour letsencrypt

Lorsqu'un nom de domaine est redirigé sur un service que le robot certbot ne peut gérer, il ne sera pas possible d'installer ou de renouveler le certificat HTTPS. C'est par exemple le cas de Mattermost qui accapare l'URL. Une option est alors de rajouter une règle spécifiquement pour le robot de letsencrypt.

Sous NGINX

Dans une configuration /etc/nginx/sites-available/forum.monsite.com, par exemple, il faudra ajouter un bloc tel que:

location ^~ /.wel-known/acme-challenge {
  root /var/www/nginx/forum.monsite.com;
  default_type "text/plain";
}

Et prévoir la zone d'accueil de validation ainsi:

mkdir -p /var/www/nginx/forum.monsite.com/.wel-known/
chown -R www-data:www-data /var/www/nginx/forum.monsite.com

On peut tester cela ainsi:

echo testok > /var/www/nginx/forum.monsite.com/.wel-known/acme-challenge
chown www-data:www-data /var/www/nginx/forum.monsite.com/.wel-known/acme-challenge
curl http://forum.monsite.com/.wel-known/acme-challenge
rm /var/www/nginx/forum.monsite.com/.wel-known/acme-challenge

Sous Apache

Exemple complet de proxying vers un Nextcloud restreint au LAN, qui tourne dans un docker sur le port local 12345, et qui est associé à un sous domaine dédiéfiles.monsite.com.

L'exécution du script certbot de Let's Encrypt se chargera du reste de la configuration HTTPS. On peut les tester avec certbot --apache --dry-run certonly -d files.monsite.com.

:!: à noter le DocumentRoot qui ne sert ici qu'au test du challenge (il peut se trouver n'importe où www-data pourra écrire temporairement).

<VirtualHost 0.0.0.0:80>
	ServerName files.monsite.com
	DocumentRoot /var/www/files.monsite.com

	ErrorLog ${APACHE_LOG_DIR}/nextcloud_error.log
	CustomLog ${APACHE_LOG_DIR}/nextcloud_access.log combined

	ProxyPreserveHost On
	ProxyPass /.well-known/acme-challenge !
	ProxyPass / http://127.0.0.1:12345/
	ProxyPassReverse / http://127.0.0.1:12345/

	<Location "/.well-known">
		Satisfy Any
		Allow from all
	</Location>

	<LocationMatch "^/(?!\.well-known/)">
		Order Deny,Allow
		Deny from all
		Allow from 127.0.0.1
		Allow from 192.168.1
	</LocationMatch>

</VirtualHost>
doc/formations/hebergement/service/apache.txt · Dernière modification : 2023/07/03 12:35 de jeremie