Type Nom Valeur TTL
A @ 203.0.113.42 3600
A www 203.0.113.42 3600dig +short mon-domaine.com
# doit renvoyer 203.0.113.422. Sécuriser l'accès SSH
adduser amar
usermod -aG sudo amar
# copier sa cle publique pour l'authentification sans mot de passe
rsync --archive --chown=amar:amar ~/.ssh /home/amarPuis on durcit la config SSH pour interdire la connexion root et l'authentification par mot de passe :
# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yessudo systemctl restart sshd
# on garde la session root ouverte tant qu'on n'a pas confirme
# qu'on peut se reconnecter avec le nouvel utilisateur, dans un AUTRE terminal
ssh amar@mon-domaine.com3. Mettre à jour le système et installer les paquets nécessaires
sudo apt update && sudo apt upgrade -y
# PHP 8.4 et les extensions dont Symfony a besoin
sudo apt install -y php8.4 php8.4-fpm php8.4-cli php8.4-common \
php8.4-mysql php8.4-xml php8.4-curl php8.4-mbstring \
php8.4-zip php8.4-intl php8.4-opcache php8.4-gd
# Apache, MySQL, Git, outils
sudo apt install -y apache2 mysql-server git unzip curl
# Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composerOn vérifie les versions installées avant d'aller plus loin :
php -v
composer --version
apache2 -v4. Créer la structure de dossiers et les bonnes permissions
sudo mkdir -p /var/www/mon-projet
sudo adduser --system --group --no-create-home --shell /usr/sbin/nologin www-monprojet
# le code appartient a l'utilisateur dedie, le groupe www-data
# (celui du serveur web) doit pouvoir le lire
sudo chown -R www-monprojet:www-data /var/www/mon-projetLe point qui casse le plus souvent une mise en prod Symfony : les dossiers var/cache et var/log doivent être inscriptibles par le processus PHP-FPM, sans pour autant ouvrir tout le projet en écriture :
cd /var/www/mon-projet
sudo chmod -R 755 .
sudo chmod -R 775 var/cache var/log public/uploads
# le bit setgid garde le groupe www-data sur les nouveaux fichiers/dossiers
# crees dans var/ et uploads/, meme si un autre utilisateur les cree
sudo chmod g+s var/cache var/log public/uploadsSi les permissions posent encore problème (erreur Unable to write in the "var/cache" directory), la solution la plus propre est setfacl plutôt que du chmod 777 — jamais 777 en prod :
sudo apt install -y acl
sudo setfacl -R -m u:www-monprojet:rwX -m u:www-data:rwX var/cache var/log public/uploads
sudo setfacl -dR -m u:www-monprojet:rwX -m u:www-data:rwX var/cache var/log public/uploads5. Déployer le code
sudo -u www-monprojet git clone git@github.com:moi/mon-projet.git /var/www/mon-projet
cd /var/www/mon-projet
sudo -u www-monprojet composer install --no-dev --optimize-autoloader --no-interactionsudo -u www-monprojet tee .env.local > /dev/null << 'EOF'
APP_ENV=prod
APP_SECRET=change_moi_avec_une_vraie_valeur_aleatoire
DATABASE_URL="mysql://mon_user:mon_mdp@127.0.0.1:3306/mon_projet?serverVersion=8.0"
EOF
sudo chmod 640 .env.local
sudo chown www-monprojet:www-monprojet .env.localsudo -u www-monprojet php bin/console cache:clear --env=prod --no-debug
sudo -u www-monprojet php bin/console cache:warmup --env=prod6. Créer la base de données
CREATE DATABASE mon_projet CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE USER 'mon_user'@'localhost' IDENTIFIED BY 'mon_mdp';
GRANT ALL PRIVILEGES ON mon_projet.* TO 'mon_user'@'localhost';
FLUSH PRIVILEGES;sudo -u www-monprojet php bin/console doctrine:migrations:migrate --no-interaction7. Un pool PHP-FPM dédié
; /etc/php/8.4/fpm/pool.d/mon-projet.conf
[mon-projet]
user = www-monprojet
group = www-data
listen = /run/php/mon-projet.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3sudo systemctl restart php8.4-fpm8. Le virtual host Apache
<VirtualHost *:80>
ServerName mon-domaine.com
ServerAlias www.mon-domaine.com
DocumentRoot /var/www/mon-projet/public
<Directory /var/www/mon-projet/public>
AllowOverride All
Require all granted
FallbackResource /index.php
</Directory>
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/mon-projet.sock|fcgi://localhost"
</FilesMatch>
ErrorLog ${APACHE_LOG_DIR}/mon-projet-error.log
CustomLog ${APACHE_LOG_DIR}/mon-projet-access.log combined
</VirtualHost>sudo a2enmod proxy_fcgi setenvif rewrite
sudo a2ensite mon-projet.conf
sudo apache2ctl configtest
sudo systemctl reload apache2À ce stade, http://mon-domaine.com (en HTTP, sans le S) doit déjà afficher l'application.
sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache -d mon-domaine.com -d www.mon-domaine.comsudo systemctl status certbot.timer
sudo certbot renew --dry-run#!/usr/bin/env bash
# deploy.sh — a lancer en tant qu'utilisateur www-monprojet
set -euo pipefail
cd /var/www/mon-projet
git pull origin main
composer install --no-dev --optimize-autoloader --no-interaction
php bin/console doctrine:migrations:migrate --no-interaction
php bin/console cache:clear --env=prod --no-debug
php bin/console cache:warmup --env=prod
echo "Déploiement terminé : $(date)"chmod +x deploy.sh
sudo -u www-monprojet ./deploy.shChecklist finale
- DNS : dig +short mon-domaine.com renvoie bien l'IP du VPS.
- SSH : connexion possible uniquement par clé, avec un utilisateur non-root.
- var/cache, var/log et les dossiers d'upload sont inscriptibles par PHP-FPM, sans chmod 777.
- .env.local existe sur le serveur, n'est jamais versionné, et n'est lisible que par l'utilisateur applicatif.
- Le pool PHP-FPM est dédié à l'application, pas partagé avec d'autres sites du VPS.
- https://mon-domaine.com répond avec un certificat valide, et le HTTP redirige vers le HTTPS.
- Un script de déploiement existe pour la prochaine mise à jour, pour ne pas refaire ces étapes à la main.
- Ne jamais utiliser chmod 777 pour résoudre un problème de permissions — setfacl ou un bon chown vers un utilisateur dédié règle le problème sans ouvrir le projet à tout le monde.
- Un utilisateur système et un pool PHP-FPM par application isolent proprement chaque site, même sur un VPS qui en héberge plusieurs (voir mon article sur l'hébergement de 15+ applications sur un seul VPS).
- Certbot avec le plugin Apache fait tout le travail (certificat + redirection HTTPS) en une seule commande — pas besoin de configurer ça à la main.
- Toujours tester la connexion SSH avec le nouvel utilisateur dans un second terminal avant de fermer la session root, pour ne jamais se retrouver enfermé dehors.
- Un script de déploiement, même basique, évite d'oublier une étape (migration, cache) trois mois plus tard quand on aura tout oublié des détails.