How to deploy a laravel application to a VPS

Deploying applications to production the right way is not an easy task for newbies. At times even seasoned developers struggle with DevOps and end up taking days before their applications are available to the public. In this post, I will attempt to show how easy it can be to deploy a laravel application to production in a matter of minutes.
Prerequisites required.
- A server running ubuntu 18.04 or 20.04
- SSH access to the server from a local terminal
- A project hosted with git (GitHub/GitLab/Bitbucket etc)
For the server, you can use any cloud service that suits you, I have personally used AWS and Azure, other services include Digital Ocean, Linode and Google cloud compute engine
For setting up git you can read the docs here. Github now supports free private repositories so you can use it for hosting your project, other alternatives include GitLab and bitbucket.
Once you have all the requirements setup you can now proceed with your deployment.
Step 1: Log in to your server as root
Login to your server using ssh from a terminal. I recommend that you set up ssh keys on your server from the server monitoring dashboard if your service provider supports it.
ssh root@serveripaddress
or with ssh setup
ssh -i /path to ssh keys.pem root@serveripaddress
Once you login to your server there are a few things you need to fix before proceeding. Run the following commands to
sudo apt-get updatesudo apt-get install -y unattended-upgrades
Step 2: Disable password login
Passwords are notoriously insecure at times and you should disable password login to your server. Once password login is disabled you can only login with ssh keys which are more secure. To disable password login, enter the following command to open the ssh config file in your favourite editor. (I am a vim user but you can use nano… but vim is cooler though :-) )
sudo vim /etc/ssh/sshd_config
Once the file opens in your text editor navigate to a line that says PasswordAuthentication. If the line is commented (prefixed by #), then remove the comment and make sure it is set to no. Save the file and restart ssh service with the following command:
sudo service ssh restart
Some service providers disable this by default and there is no need to do this step.
Step 3: Install Fail2Ban
Fail2Ban is a program for Linux based servers that block hackers by scoring server logs and banning IP addresses with malicious patterns
sudo apt-get install -y fail2ban
Step 4: Install Webserver
Nginx is awesome. For the majority of cases, Nginx will suit your needs. Enter the following commands to install and restart Nginx on your server.
sudo apt-get install -y software-properties-commonsudo add-apt-repository ppa:nginx/stablesudo apt-get updatesudo apt-get install -y nginxsudo service nginx restart
Now visit your servers public IP address in a browser (eg. http://127.0.0.1) and you should see a page similar to the following:

if you see an error output that mentions something similar to “Unable to resolve host”, try the command without the ‘sudo’ keyword
Step 5: Install PHP 7, composer, curl, wget and other required libraries
Curl and wget are important HTTP tools needed for composer installation. Git is a source code management tool and will be required for pulling code repo to the installation server
sudo apt-get install -y git curl wget
Install PHP 7
PHP 7 is required for Laravel 5.7+. Before installing PHP 7 first check if there is no PHP 5 installed. Remove PHP 5 using the following commands:
sudo apt-get purge php5-fpmsudo apt-get — purge autoremove
Once you are certain the PHP 5 is removed then proceed to install relevant repositories for PHP 7.
sudo apt-get install -y software-properties-commonsudo apt-get install -y python-software-propertiessudo add-apt-repository ppa:ondrej/phpsudo apt-get update
Install and restart PHP 7 using the following commands.
sudo apt-get install -y php7.4 php7.4-fpm php-mysql php7.4-mysql php-mbstring php-gettext libapache2-mod-php7.4 php-doctrine-dbal php7.4-pgsql php-xml redis-serversudo systemctl restart php7.4-fpm
Install composer for dependency management
Run the following command on your terminal to install composer dependency manager.
curl -sS https://getcomposer.org/installer | sudo php — — install-dir=/usr/local/bin — filename=composer
Install Node & NPM
If your project has NPM dependencies then you need to install Node and NPM package manager with the following commands:
curl -sL https://deb.nodesource.com/setup | sudo bash -sudo apt-get install -y npm#Gulp, Grunt and Yarnln -s /usr/bin/nodejs /usr/bin/nodesudo npm install — global yarn gulp-cli grunt-cli
Make your git repo production-ready
Create a production-ready version of your application on your development machine. Now, create a production branch using the following command.
git branch production
Now that the production branch is ready, check it out and push it to your repo.
Switch to the production branch
git checkout production
Merge changes in the development branch with your production branch.
git merge — no-ff master
*replace master in the command above with your development branch name. Adding “ — no-ff” makes sure it creates a new commit so that we can track merges into the production branch
Push the production branch to your remote repository (Gitlab, Github, Bitbucket)
git push -u origin production
Pull production branch to the production server.
First, create a directory for your app with your app name under /var/www
sudo mkdir /var/www/app_name
Now cd into your application directory and create a new git repo.
cd /var/www/app_namesudo git init
Add your git remote and pull your project to your server
git remote add origin https://github.com/user/repo.gitgit pull origin production
Step 6: Configure the Server to serve our app
Open the Nginx config file using a text editor (vim :-))
sudo vim /etc/nginx/sites-available/default
All edits to this file should be done within the ‘server{ }’ block.
Make URLs Pretty
Change the default ‘location / { }’ block’s contents from
try_files $uri $uri/ =404;
to
try_files $uri $uri/ /index.php?$query_string;
Disallow access to dot files (for obvious security reasons)
location ~ /\.{ deny all;}
Add PHP capability
Find the following line
index index.html index.html index.nginx-debian.html;
and change by adding index.php to make it look like this:
index index.html index.html index.nginx-debian.html index.php;
For php7, add the following lines, replacing 7.4 with the actual PHP version you have installed.
location ~ \.php$ {include snippets/fastcgi-php.conf;fastcgi_pass unix:/run/php/php7.4-fpm.sock;}
Now update the virtual hosts file to server our application.
change this line:
root /var/www/html;
to:
root /var/www/AppName/public;
Now we are done with editing the config file. Save it and run the following command to make sure our config is correct:
sudo nginx -t
If no error comes up then the config is okay, restart Nginx for changes to take effect.
sudo service nginx restart
Set Permissions
Set permissions for the public directory where public files are located.
sudo chown -R www-data:www-data /var/www/AppName/publicsudo chmod 755 /var/wwwsudo chmod -R 755 /var/www/AppName/bootstrap/cachesudo chmod -R 755 /var/www/AppName/storage
Now that permissions are set, its time to install PHP and npm dependencies.
composer install
may need sudo for this command
npm installnpm run production
Your command to compile frontend javascript
Step 7: Setting up your database
Install MySQL 8.0 which is stable and works well with laravel and other application frameworks.
First, download the latest repository with the following command:
wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.11-1_all.deb
Now install the downloaded repository:
sudo dpkg -i mysql-apt-config_0.8.11–1_all.deb
Refresh the repositories (as always)
sudo apt-get update
Install MySQL
sudo apt-get install mysql-server
Once MySQL is installed, set up security using the following command
sudo mysql_secure_installation
Go through the prompts to complete securing your MySQL installation.
Once installation and securing is done the server should start automatically. You can check its status as follows:
sudo service mysql status
stop the service with:
sudo service mysql stop
and start it again with:
sudo service mysql start
Now login with root user. This is root@localhost.
sudo mysql -u root -p
To allow remote connections and other IP addresses make sure to change the MySQL configuration file as follows:
Delete or comment the bind_address parameter from the my.ini file.
(The file name is different depend on the OS. On Linux my.ini is actually my.cnf located in directory /etc/mysql/)
Restart the service.Create the root user (yes, a new user because what exists is ‘root@localhost’ which is local access only):CREATE USER ‘root’@’%’ IDENTIFIED BY ‘123’;Give privileges:GRANT ALL PRIVILEGES ON *.* TO ‘root’@’%’;
For DBA user, add WITH GRANT OPTION at the end.
e.g. CREATE USER ‘root’@’%’ IDENTIFIED BY ‘123’ WITH GRANT OPTION;
Step 8: Setup your environment
Create a .env file for the Laravel app using the following commands
cd /var/www/AppNamecp .env.example .env
Now open the .env file with your favourite text editor.
sudo vim .env
Change the necessary env variables. Change the following variables, as well as other variables that you may have to change such as database, AWS, Redis, mail, pusher configs.
APP_ENV=localAPP_DEBUG=true
to:
APP_ENV=productionAPP_DEBUG=false
Now generate application key which will be used for encryption
php artisan key:generate
Now migrate your database (make sure you have correct database credentials setup in your .env file)
php artisan migrate:installphp artisan migrate
Step 9: Setting up SSL with Lets Encrypt
Let’s Encrypt provides free SSL certificates. Let’s install it using Certbot
sudo apt-get install -y software-properties-commonsudo add-apt-repository ppa:certbot/certbotsudo apt-get updatesudo apt-get install -y python-certbot-nginx
Set up the website’s virtual hosts by opening nginx config file with the following command:
sudo vim /etc/nginx/sites-available/default
Change the following line, replacing example.com with your own domain
server_name _;
changes to
server_name example.com www.example.com;
and this
listen 80 default_server;listen [::]:80 default_server;
changes to:
listen 80 default_server;listen [::]:80;
Copy the newly created virtual hosts file into its own file and then to sites-enabled with the following command.
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example.comsudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/
Install your SSL certificate provided by let’s encrypt with the following command.
sudo certbot — nginx
And you are done, give yourself a pat on the back as your newly created application takes over the internet