03-comment-je-travaille/guides/hardening-vps.md

How-to — hardening sécurité d'un VPS LAMP Symfony

Documente les opérations manuelles appliquées au VPS OVH le 2026-06-17. Sera ultérieurement remplacé ou complété par des rôles Ansible (tlr-ansible). Le gap poseidon/prod est assumé.

Prérequis : VPS Ubuntu fraîchement provisionné, accès root ou sudo complet.

Pour l'état cible attendu après application : référence sécurité VPS.


Étape 1 — Créer adminvps avant de toucher ubuntu

# En tant que ubuntu (avant toute restriction)
adduser adminvps
usermod -aG sudo adminvps
mkdir -p /home/adminvps/.ssh
cp ~/.ssh/authorized_keys /home/adminvps/.ssh/
chown -R adminvps:adminvps /home/adminvps/.ssh
chmod 700 /home/adminvps/.ssh && chmod 600 /home/adminvps/.ssh/authorized_keys

Ouvrir une deuxième session SSH avec adminvps et vérifier sudo -i avant de continuer.


Étape 2 — Restreindre sudo ubuntu

# /etc/sudoers.d/ubuntu
ubuntu ALL=(ALL) NOPASSWD: /usr/bin/apt, /usr/bin/systemctl, /usr/sbin/ufw, /usr/bin/journalctl

# /etc/sudoers.d/adminvps
adminvps ALL=(ALL) ALL

Attention : si cloud-init a laissé /etc/sudoers.d/90-cloud-init-users avec ubuntu ALL=(ALL) NOPASSWD:ALL, commenter cette ligne (via adminvps + sudo -S) — sinon la restriction ne prend pas effet.


Étape 3 — Durcir SSH

# /etc/ssh/sshd_config.d/70-telaria-hardening.conf
AllowUsers ubuntu adminvps
PermitRootLogin no
sudo systemctl reload ssh

PasswordAuthentication no est déjà dans /etc/ssh/sshd_config.d/60-cloudimg-settings.conf (OVH).


Étape 4 — fail2ban

sudo apt install fail2ban
# /etc/fail2ban/jail.d/sshd-telaria.conf
[sshd]
enabled  = true
port     = 9501
filter   = sshd
maxretry = 3
bantime  = 1h
findtime = 10m
sudo systemctl enable fail2ban && sudo systemctl restart fail2ban

Étape 5 — UFW sortant verrouillé

sudo ufw default deny incoming
sudo ufw default deny outgoing
sudo ufw allow in 80/tcp
sudo ufw allow in 443/tcp
sudo ufw allow in 9501/tcp
sudo ufw allow out 443/tcp
sudo ufw allow out 587/tcp
sudo ufw allow out 53
sudo ufw allow out 123/udp
sudo ufw enable

Étape 6 — MySQL moindre privilège

-- Vérifier les droits du user applicatif
SHOW GRANTS FOR 'telariauser'@'localhost';
-- Attendu : SELECT, INSERT, UPDATE, DELETE sur telaria_dev.* et telaria_fr.*
-- Aucun GRANT ALL, aucun droit global

Supprimer tout user superflu. Ne conserver que telariauser@localhost.


Étape 7 — Permissions /var/www

# Propriété et droits de base pour chaque app
for app in telaria telaria-fr adoption-ia-fr vps-ovh-net; do
  chown -R telaria:www-data /var/www/$app
  find /var/www/$app -type d -exec chmod 750 {} \;
  find /var/www/$app -type f -exec chmod 640 {} \;
done

# var/ — www-data écrit (cache/log Symfony)
for app in telaria telaria-fr adoption-ia-fr; do
  chown -R www-data:www-data /var/www/$app/var
  chmod -R 775 /var/www/$app/var
done

# .env.local — secrets
for app in telaria telaria-fr adoption-ia-fr; do
  chown telaria:www-data /var/www/$app/.env.local
  chmod 640 /var/www/$app/.env.local
done

Avertissement : ne jamais appliquer les chmod récursivement sur un site actif sans exclure var/ de la passe fichiers. Un chmod 640 sur les fichiers de cache Symfony casse le site immédiatement.


Étape 8 — Apache

sudo a2dismod autoindex status
sudo systemctl reload apache2

Dans /etc/apache2/conf-available/security.conf :

ServerTokens Prod
ServerSignature Off
TraceEnable Off

Dans chaque <VirtualHost> :

Options -Indexes -FollowSymLinks

<FilesMatch "\.(env|log|git|htpasswd)">
    Require all denied
</FilesMatch>

Vhost catch-all 000-default (chargé en premier par le préfixe 000-) :

<VirtualHost *:80>
    <Location "/">
        Require all denied
    </Location>
</VirtualHost>

Étape 9 — PHP FPM

# /etc/php/8.5/fpm/conf.d/99-telaria-security.ini
[PHP]
open_basedir = /var/www:/tmp:/var/lib/php/sessions
disable_functions = exec,passthru,shell_exec
sudo systemctl reload php8.5-fpm
# Vérifier absence de xdebug en FPM
php-fpm8.5 -m | grep xdebug   # doit retourner vide

Étape 10 — unattended-upgrades

sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

Note Ansible

Ces opérations seront à terme gérées par tlr-ansible. Quand un rôle Ansible couvrira une étape, la section sera annotée [→ voir rôle ansible X] plutôt que supprimée.

Assistant documentaire

Posez une question sur la documentation. Les réponses citent leurs sources — un clic ouvre le document à gauche.

Loading…
Loading the web debug toolbar…
Attempt #