Déployer Laravel 5 avec SSH, Git et Composer sur un hébergement mutualisé OVH - De A à Z

Article initialement publié sur medium.com. La version la plus à jour est celle ci-dessous.

Ayant eu moi-même pas mal de difficultés à trouver des informations complètes sur cette procédure, j’ai décidé d’écrire cet article.

D’abord, d’aucuns diront que c’est une mauvaise idée de mettre Laravel sur un hébergement mutualisé, et on ne peut pas vraiment leur donner tort… On ne peut pas dire en toute honnêteté que ce soit fait pour… Vous gagnerez certainement en productivité/efficacité/qualité de travail en utilisant un VPS (Digital Ocean, Linode, ou même OVH) + Laravel Forge.

Toutefois, les hébergements mutualisés permettent une très grande simplicité dans la gestion (c’est justement ce qu’on leur reproche ici), un support technique réel (sauf en SSH), et ne nécessitent pas de connaissances particulières en serveur/réseau.

En résumé : c’est possible. Voici comment.


Sommaire

  1. Prérequis techniques
  2. Contraintes liées à l’hébergement OVH mutualisé
  3. Choix de la formule
  4. Configuration globale
  5. Configuration du SSH
  6. Installation de Composer
  7. Utilisation de Git
  8. Ecrire un script de déploiement
  9. Usage concret
  10. Ressources

Prérequis techniques

  • Avoir une app réalisée avec le framework Laravel sur un serveur local.
  • Avoir quelques notions sur l’utilisation du VCS Git.
  • Savoir ouvrir un terminal (par exemple celui intégré à votre éditeur de code). (Pour plus de détails sur les commandes listées dans ce tutoriel, voir l’excellent outil explainshell.com)

⚠️ Contraintes liées à l’hébergement OVH mutualisé

  • Pas de queuing digne de ce nom possible… la faute aux tâches cron OVH limitées à 1 heure minimum.
  • Pas de curl/wget en ssh ou depuis artisan. Ce type de requête externe est bloquée par OVH. Donc impossible d’avoir une notification Slack à la fin d’une commande artisan, par exemple. Pas de sauvegarde dans un cloud non plus. (Depuis php, aucun problème pour curl)
  • Evidemment pas d’installation de nouveaux packages sur le serveur, puisque c’est un mutualisé. Mais si c’est un problème pour vous, c’est que vous n’aurez pas trop de mal avec un VPS.

Choix de la formule

Vous devez opter pour la formule PRO au minimum. Cela permettra d’avoir accès au SSH.

On peut le faire sans SSH, en faisant des transferts FTP, mais c’est vraiment laborieux, et on ne peut pas utiliser Git ni Composer. Ce qui rend la chose très difficilement maintenable à moyen/long terme.


Configuration globale

J’utilise trois environnements :

  1. Local/Dev (sur ma machine locale)
  2. Staging (sur le serveur distant, avec debug activé en cas d’erreur)
  3. Production (sur le serveur distant)

En Local

Sur ma machine locale, j’utilise comme serveur local Laragon que je trouve très bien (par rapport à Wamp c’est un vrai bonheur, surtout pour Laravel).
Sur Windows 10.

J’utilise également les outils de développement suivants : PHPStorm, VSCode.

Sur le serveur

Pour accueillir mon environnement de staging et de production, je crée dans le dossier /www/ deux sous-dossiers :


/www/   
  |__ /stage/
  |__ /prod/

Il faut ensuite aller vous connecter à votre espace client OVH.

On va faire pointer mon-domaine.com vers le dossier /www/prod/public/ qui sera le dossier qui contiendra la partie publique de votre site sur Laravel.

Allez dans “ Hébergement mon-domaine.com > Multisite ”

Modifiez mon-domaine.com pour le faire pointer vers /www/prod/public/

Cliquez ensuite sur “Ajouter un domaine ou un sous-domaine”.

Créez le sous-domaine staging.mon-domaine.com et faites-le pointer vers /www/stage/public/


Configuration du SSH

Connexion

Ouvrez votre console préférée (pendant que vous-y-êtes jetez un œil à Cmder) et connectez-vous à votre hébergement en ssh grâce à la commande :


ssh ssh://username@ssh.cluster001.hosting.ovh.net

N’oubliez pas de remplacer username par votre nom d’utilisateur et cluster001par votre véritable cluster. Vous trouverez ces informations dans Votre espace client OVH dans Hébergement > mon-domaine.com > FTP — SSH

Windows 10 intègre depuis la mise à jour Fall Creator Update un client SSH natif mais caché, qu’il faut aller activer. Voir comment

Pour les versions plus anciennes de Windows, il faudra probablement installer un logiciel supplémentaire, voir ici.

Vous serez invité à saisir votre mot de passe (C’est en principe le même que le mot de passe ftp).

Normalement, vous voilà connecté !

Authentification par clé

Pour ne pas devoir entrer son mot de passe à chaque connexion, nous allons devoir nous authentifier à l’aide d’une clé rsa
Pour créer une clé sous Windows 10 : (En local)

ssh-keygen -A

Cela devrait générer deux clés : une privée (id_ed25519) et une publique (id_ed25519.pub) dans le dossier C:Users\Username\.ssh (par défaut).

Il existe plusieurs autres moyens selon votre système, le plus souvent avec Putty. Vous trouverez beaucoup de tutoriels en ligne.

Communiquer la clé publique au serveur

Cette partie est peu ou pas documentée par ovh et sur internet en général, donc voici comment procéder.

En partant du principe que la clé publique est située à l’adresse C:Users\Username\.ssh\id_ed25519.pub et en sachant qu’on doit la copier sur le serveur dans le fichier /home/username/.ssh/authorized_keys (qui n’existe pas encore), toujours sous Windows on fera (en remplaçant ‘username’ et le cluster) :


# Copy SSH Key command on OVH shared hosting
# Replace "username", "cluster001" with your personal informations
# Replace "~/.ssh/id_ed25519.pub" by the path to your public rsa key if you have a custom one 

cat ~/.ssh/id_ed25519.pub | ssh ssh://username@ssh.cluster001.hosting.ovh.net "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

Sur Mac ou Linux on pourra utiliser la commande ssh-copy-id mais elle n’existe pas sous Windows.

Et voilà, plus besoin de mot de passe !

Utiliser un raccourci (alias)

Dans le même dossier qui contient la clé sur votre machine locale (par défaut C:Users\Username\.ssh\) on peut placer ou modifier un fichier configcontenant ces lignes :


Host monprojet
HostName ssh.cluster001.hosting.ovh.net
User username
IdentityFile ~/.ssh/id_ed25519

Si vous remplacez monprojet par le nom de votre projet et username par votre nom d’utilisateur ssh, vous pourrez alors vous connecter en faisant simplement :


ssh monprojet

Ça change la vie, non ? Notez que vous pouvez faire cela sur plusieurs projets, plusieurs clés, etc.


Installation de Composer

Nous allons maintenant installer Composer sur le serveur, un gestionnaire de dépendances (ou packages) utilisé par Laravel.

Connectez-vous en SSH à votre hébergement et entrez cette commande :


curl -sS https://getcomposer.org/installer | php

Vérifiez que vous êtes bien à la racine de votre hébergement (dans /home/username/)pour ne pas rendre publics les fichiers de Composer.

Composer est désormais installé sous la forme d’un fichier composer.phar

Nous allons là aussi créer des alias pour pouvoir accéder à Composer facilement, car pour l’instant nous devons l’appeler avec la commande ~/composer.phar

Pour ce faire, nous allons modifier le fichier /home/username/.bash_profile


# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# Replace "username" by your username
ME="username"

alias composer="php ~/composer.phar"
alias cdme="cd /home/${ME}"
alias cdstage="cd /home/${ME}/www/stage"
alias cdprod="cd /home/${ME}/www/prod"

# User specific environment and startup programs

PATH=$PATH:$HOME/bin
BASH_ENV=$HOME/.bashrc
USERNAME=""

export USERNAME BASH_ENV PATH

Grâce à ce fichier, et aux alias à l’intérieur, nous pourrons faire cdstage pour nous rendre dans le dossier /home/username/www/stage, gagnant ainsi un temps précieux.

Vous pouvez ajouter tous les alias que vous souhaitez pour les commandes que vous utilisez fréquemment.


Utilisation de Git

Pour différencier la version de production de celle de développement, aussi bien en local qu’en ligne, j’utilise Git avec GitHub Desktop pour les commandes les plus courantes.

J’initialise un repository dans mon projet et j’utilise la branche master pour la production et la branche dev que j’ai créée pour le développement/staging.

Initialisation du dépôt Git distant

Pour initialiser un dépôt Git distant (le “Remote Repository”) sur votre hébergement, nous allons créer le dossier /home/username/.git.


# Remote server

cd /home/username/
mkdir .git
cd /.git
git init --bare

Nous allons ensuite entrer la commande suivante (dans le dépôt local):


# Local machine

git remote add origin ssh://username@ssh.cluster001.hosting.ovh.net:22/homez.123/username/.git

Ici on remplacera usernamepar le bon nom d’utilisateur et homez.123 par le vrai chemin du dossier que vous pouvez trouver en exécutant la commande pwd.


Clone du dépôt dans les sous-dossiers

Nous allons maintenant cloner notre dépôt git distant dans /www/stage/ et dans /www/prod.


# Remote server

cd /home/username/.git
git clone /home/username/.git /home/username/www/prod
git clone /home/username/.git /home/username/www/stage

Si tout s’est bien passé, vous devriez voir à ce stade votre app sur mon-domaine.com et sur staging.mon-domaine.com


Déploiement manuel

On va désormais pouvoir faire (depuis le local) :


# Local machine
git push origin stage

pour mettre en ligne la branche stage ou


# Local machine
git push origin master

pour mettre en ligne la branche master.

Pour faire un push de toutes les branches, utilisez (avec prudence)


# Local machine
git push origin --all

puis pour déployer sur l’environnement de staging ou de production, deux solutions :


# Remote server

#pour déployer en staging
cdstage
git pull stage

#pour déployer en production
cdprod
git pull master

mais dans ce cas il ne faut jamais modifier un fichier distant par exemple via ftp, sinon vous aurez erreurs sur erreurs quand vous tenterez de faire un push/pull.

Personnellement, j’ai remplacé git pull par une solution plus radicale qui va juste écraser les fichiers sans se poser de question :

cdstage

unset GIT_DIR
git fetch origin stage
git reset --hard FETCH_HEAD

Ce n’est pas vraiment gênant car nous conservons de toute façon une trace de toutes les modifications et donc une sauvegarde de nos fichiers dans le repository situé dans /home/username/.git.

On pourra ensuite faire

composer install

pour mettre à jour les dépendances. Pour la production, on pourra ajouter quelques options, comme --no-dev--prefer-dist--optimize-autoloader.

Jamais de composer update ou de composer require en production car on souhaite que la production utilise les mêmes versions de packages que notre environnement de développement, le fichier composer.json étant le garant de cette similitude.


Automatiser le déploiement avec un hook git

Mise à jour mai 2019
Dans la première version de cet article, je vous montrais comment automatiser ces étapes dans un hook qui permettait de déployer automatiquement à chaque push.
Afin d’avoir plus de contrôle sur le déploiement de votre app, ce n’est pas forcément recommandé de tout automatiser à outrance.
Personnellement je ne m’en sers pas, car le risque d’erreur (humaines) est trop important.


Ecrire un script de déploiement

Rassemblons toutes ces commandes au sein d’un seul et même script de déploiement.
Ou plutôt deux : un pour la production, un autre pour le staging.

J’y ai ajouté les commandes artisan couramment utilisées lors d’un un déploiement Laravel, pour vider/mettre en cache, migrer les bases de données, etc.

Voici celui pour l’environnement de staging :

#!/bin/bash

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# Replace "username" by your username
ME="username"

echo ' '
echo "#######################################################"
echo "##################### STAGE DEPLOY ####################"
echo "#######################################################"
echo ' '

# Go to site directory
echo "GOING TO /home/${ME}/www/stage"
cd /home/${ME}/www/stage
echo "*******************************************************"
echo ' '

# Shutdown the laravel app
echo "SHUTTING DOWN THE LARAVEL APP"
php artisan down
echo "*******************************************************"
echo ' '

# Pull changes from git dir
echo "PULLING CHANGES FROM GIT DIR"
unset GIT_DIR
git fetch origin stage
git reset --hard FETCH_HEAD
echo "*******************************************************"
echo ' '

# Install new composer packages
echo "INSTALLING NEW COMPOSER PACKAGES"
php ~/composer.phar install
echo "*******************************************************"
echo ' '

# Migrate database
echo "MIGRATING DATABASE"
php artisan migrate
echo "*******************************************************"
echo ' '

# Clear caches
echo "CLEARING CACHE"
php artisan cache:clear
echo "*******************************************************"
echo ' '

# Clear expired password reset tokens
echo "CLEARING EXPIRED PASSWORD RESET TOKENS"
php artisan auth:clear-resets
echo "*******************************************************"
echo ' '

# Clear and cache routes
echo "CLEARING AND CACHE ROUTES"
php artisan route:cache
echo "*******************************************************"
echo ' '

# Clear and cache config
echo "CLEARING AND CACHE CONFIG"
php artisan config:cache
echo "*******************************************************"
echo ' '

# Go live
echo "GOING LIVE!"
php artisan up
echo ' '
echo "#######################################################"
echo "###################### DEPLOYED! ######################"
echo "#######################################################"
echo ' '

Enregistrez ce script dans un fichier nommé stage_deploy sans extension, à la racine de votre hébergement, soit dans /home/username/.

Vous devrez enregistrer en mode LF pour la séquence de fin de lignes et non CRLF comme c’est le cas par défaut sur plusieurs éditeurs. Sinon ce fichier « bash » risque de ne pas fonctionner correctement.

Et celui pour l’environnement de production :

C’est quasiment le même, mais avec certaines additions comme les options de composer adaptées à la production.


#!/bin/bash

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# Replace "username" by your username
ME="username"

echo ' '
echo "#######################################################"
echo "##################### PROD DEPLOY #####################"
echo "#######################################################"
echo ' '

# Go to site directory
echo "GOING TO /home/${ME}/www/prod"
cd /home/${ME}/www/prod
echo "*******************************************************"
echo ' '

# Shutdown the laravel app
echo "SHUTTING DOWN THE LARAVEL APP"
php artisan down
echo "*******************************************************"
echo ' '

# Pull changes from git dir
echo "PULLING CHANGES FROM GIT DIR"
unset GIT_DIR
git fetch origin master
git reset --hard FETCH_HEAD
echo "*******************************************************"
echo ' '

# Install new composer packages
echo "INSTALLING NEW COMPOSER PACKAGES"
php ~/composer.phar install --no-dev --prefer-dist --optimize-autoloader
echo "*******************************************************"
echo ' '

# Migrate database 
# (If you don't use "--force" option, 
# laravel will prompt you each time for confirmation)
echo "MIGRATING DATABASE"
php artisan migrate --force
echo "*******************************************************"
echo ' '

# Clear caches
echo "CLEARING CACHE"
php artisan cache:clear
echo "*******************************************************"
echo ' '

# Clear expired password reset tokens
echo "CLEARING EXPIRED PASSWORD RESET TOKENS"
php artisan auth:clear-resets
echo "*******************************************************"
echo ' '

# Clear and cache routes
echo "CLEARING AND CACHE ROUTES"
php artisan route:cache
echo "*******************************************************"
echo ' '

# Clear and cache config
echo "CLEARING AND CACHE CONFIG"
php artisan config:cache
echo "*******************************************************"
echo ' '

# Go live
echo "GOING LIVE!"
php artisan up
echo ' '
echo "#######################################################"
echo "###################### DEPLOYED! ######################"
echo "#######################################################"
echo ' '

Comme pour le premier, enregistrez ce script dans un fichier nommé prod_deploy au même emplacement. (Et en mode LF !)

Ensuite nous allons rajouter aux alias dans /home/username/.bash_profile ces deux lignes :


alias stage_deploy="bash /home/${ME}/stage_deploy"
alias prod_deploy="bash /home/${ME}/prod_deploy"

Usage concret

Voici un cas concret d’utilisation de ces commandes.

Admettons qu’on travaille dans la branche stage. (Je travaille toujours dans cette branche ou d’autres mais jamais directement dans master, pour éviter les ennuis).

Ça fonctionne bien en local, on est content. Maintenant on veut tester en ligne.

  1. on commit les modifs dans stage
  2. on push la branche stage vers le dépôt distant avec git push origin stage
  3. on se connecte au serveur avec ssh mon_projet
  4. on lance le script de déploiement avec la commande stage_deploy
  5. on vérifie que ça fonctionne bien sur l’environnement de staging
  6. Si oui, on retourne à la machine locale (on ferme la session ssh avec exit ou Ctrl+D ou on ouvre un nouvel onglet du terminal)
  7. On passe à la branche master avec git checkout master
  8. Puis on vient apporter les changements dans la branche principale avec git merge stage
  9. On retourne dans la branche stage pour ne pas oublier avec git checkout stage
  10. Enfin on push nos modifications dans la branche master avec git push origin master
  11. On se reconnecte au serveur ssh mon_projet
  12. Puis on lance le script de déploiement avec la commande prod_deploy
  13. Et voilà.

Ressources

S’abonner
Notifier de
guest
7 Commentaires
le plus ancien
le plus récent le plus populaire
Inline Feedbacks
View all comments
Guillaume
4 années il y a

Article très intéressant !
Je vais tenter de l’adapter pour déployer sur un VPS justement. Il me manquera quelques point que je tenterai d’y ajouter, notamment :
– installation des packages via npm
– gestion des assets via Mix
– gestion d’un dossier partagé « shared » à conserver entre chaque déploiement.

Et je ferai le déploiement plutôt depuis un tag qu’une branche, cela facilitera les rollbacks,

Et là je pourrais alors me passer de capistrano.

Guillaume
4 années il y a

Voilà en m’appuyant sur ton script, j’ai créé une version un peu plus complète et adapté à un VPS, je l’ai mis à dispo sur Github en te citant en référence : https://github.com/atlza/noDeploy J’ai notamment rajouté : – Déploiement via un user dédié – Déploiement depuis un tag (demandé via prompt) – Installation des dépendances npm – Installation des dépendances Composer – Exécution de Mix (compilation/minification Js/Scss) – Déploiement d’un pointeur « current » vers le déploiement effectué permettant une mise en ligne sans downtime Il y a encore de petites choses à voir notamment au niveau de la gestion des environnements… Lire la suite »

Floran Patience
4 années il y a

Super intéréssant merci d’avoir écrit ce petit tuto ! Je vais essayer de l’adapter pour Gandi 🙂

Marie
Marie
3 années il y a

Bonjour,
merci beaucoup pour cet article très détaillé. Je dois donner un cours sur le CI/CD et je vais me servir de votre article comme base (je citerai bien entendu les sources) pour la démonstration avec Laravel 8 & OVH. Bonne continuation.

Dan
Dan
3 années il y a

Super article !.. mais je reste bloquée à l’étape « Clone du dépôt dans les sous-dossiers ». Le site ne s’affiche pas lorsque je vais sur le nom de domaine, car je ne sais pas à quel moment et où on doit créer le projet laravel?Au moment du git clone vers www/prod, je ne récupère que le dossier .git et pas de projet laravel avec un dossier public (qui permettrait d’afficher quelque chose).
Je vous remercie par avance de votre aide,

Dan

Défilement vers le haut