Deploy Laravel Application With LEMP Stack (Ubuntu and Enginx)

Sagar Nasit
16 min readSep 7, 2017

--

It is very disappointing after working too hard to develop laravel application then find that deploying is not that easy for laravel application. What we do is google the deploying steps for laravel but, what i found is that there is not enough information available to deploy laravel application. There is something missing in every post. Reason behind this is Laravel Forge which provides easy way to deploy and manage laravel application but it’s not free :( . what if we want to configure our server by our self? I here provide an easy way that i learned while facing all deploying issues.

We are using LEMP stack.
Linux
Enginx (nginx)
MySql
Php

Why Using LEMP Instead of LAMP

The reason I choose LEMP with laravel is that this stack is preferable in laravel community the most. It is just a personal choice. if you comfortable with Apache then you can go with it.

Where to Host?

I here use Digital Ocean Droplet to deploy Application. You will find easy tutorial to create droplet, just google it. Create Ubuntu droplet in the nearest region. If you don’t have Digital Ocean account then you can create it with this referral link which will give you $10 credit for Digital Ocean and will also help me. You can also use any cloud service to deploy Laravel applications.

Step 1: Create Droplet

Click on create droplet after sign up.

Here we select L from our LEMP. Choose the linux distro which you prefer most. i use Ubuntu 16 for this tutorial.

Choose the size of the droplet as your usage and capacity of application. I here choose minimum configuration with 512 MB RAM and 20 GB SSD storage.

Select the datacenter region which is near to your location.

Now choose the SSH key. Create SSH key if you don’t have. If you don’t know how to create SSH key in Ubuntu then click here to read steps. Save the SSH key securely because SSH key allows connect your terminal to connect with the cloud server.

Step 2: Login Via SSH

If you are using Linux or Mac then SSH comes preinstalled with the System. To connect your Windows with a server using PUTTY. Since i am using Ubuntu, use following command to connect with server.

ssh root@10.100.162.1

here root is the super user name of server and 10.100.162.1 is the public IP address of server. you can copy IP address from droplets.

Type yes in terminal. If you see following message in terminal screen then it means you are successfully connected to server terminal.

Step 3: Update Package Installer Of Ubuntu

Ubuntu uses apt-get package installer to install new packages and programmes. Before installing any programme. we need to update package installer first. To do so type following command.

sudo apt-get update

Here sudo means super-user-do that means whatever you install will be installed with super user privileges. Super user is the admin who has all control privileges over the system. Default super user of our droplet is root. above command will install some necessary updates.

Step 4: Install Nginx on Server

let’s install Nginx with following command.

sudo apt-get install nginx

Press y and it will install nginx on our server. Now we can check running server by giving IP address in URL of our browser. It will show Welcome to Nginx message on the browser.

Now its time to install remaining things on the server.

Step 5: Install MySQL on Server

If your laravel application using a relational database then you need to install MySQL on your server to store information. You can also use any other database for your convenient. Run the following command to install MySQL.

sudo apt-get install mysql-server

It will start installing MySQL and a pink screen will show up on your terminal to enter the password for root user. Enter the password that you want. I recommend use strong password because you are now handling database on the server. you can not risk your data.

Now enter the same password to confirm. Remember the password or store it somewhere safe because we will be using a lot going further.

Once your command line finished and displays the root@localhost:~# line again, then you know you are complete with MySQL.

To make your MySQL more secure run following command. it will remove remote root user access and test databases.

sudo mysql_secure_installation

Now enter your MySQL password and it will ask to change the password and some security for the database. press y or n according to your requirements.

Step 6: Install PHP on Server

Run following command to install php 7, i recommend to use php 7 since laravel required php 7 from laravel 5.5. we need to install php-fpm for fast CGI process management, php-mysql to talk with mysql and php-mbstring which require for laravel.

sudo apt install php7.0-cli

sudo apt-get install php-fpm php-mysql php-mbstring

This will install PHP 7.0 and if you need any other PHP installation for your specific application then you can install it just like we did it for php-mbstring and php-mysql with the command-line.

Step 7: Configure PHP

We need to make one security change in php.ini file. php.ini file is the configuration file for php. Run the following command to open php.ini file in nano editor. If you want to use other editors, you can.

sudo nano /etc/php/7.0/fpm/php.ini

we need to change cgi.fix_pathinfo=0 in ini file. you can search for the line by ctr + w in nano editor, type cgi.fix_pathinfo= and press Enter. Cursor now moved to the corresponding line. Now remove semicolon from starting of line and change cgi.fix_pathinfo = 1 to 0 and press ctr + x then press y to save changes.

Before the changes can take effect we need to restart php-fpm by typing in this command:

sudo systemctl restart php7.0-fpm

Now changes has taken effects so, we can move further.

Step 8: Configure Nginx

Now it’s time to configure Nginx for laravel. run the following command to open configuration file with nano editor.

sudo nano /etc/nginx/sites-available/default

It will open file with following lines in editor.

server {
listen 80 default_server;
listen [::]:80 default_server;

root /var/www/html;

index index.html index.htm index.nginx-debian.html;

server_name _;

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

Change the lines by following.

server {
listen 80 default_server;
listen [::]:80 default_server;

root /var/www/html;

index index.php index.html index.htm index.nginx-debian.html;

server_name 10.100.162.1;

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

Add index.php because Nginx first tries to find the index file, then index.php, then index.html until it finds matching file. An order is important here. Change the server name with IP address of your droplet. If you have domain name then you can directly use it instead of IP address.

Now save the changes with ctr + x and type y then press Enter.

sudo nginx -t

If everything is fine then it will show this message.

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

This means you have no errors. Good work, now to let it take effect you can restart Nginx

sudo systemctl reload nginx

Now we are ready to deploy our laravel application on server. Everything is configured. We need to install other tools that will help us to install laravel.

Step 9: Push Laravel Project on Server

It is time to move on our local computer where we have our laravel project. Create a repository on GitHub for git version control for our project. You can make changes on project and save it on GitHub. Push your project from your local computer. Click on following link to see how to create repository and push project on that repo.

Now connect again to server and clone your github project to your targeted folder. We are here cloning project inside /var/www/html/.

After cloning repository, actual path of our laravel project folder is like this

/var/www/html/laravel/

laravel is the project directory name.

If you are following tutorial then you may know that we need to change our Nginx configuration to point our index.php file in project folder. Again run following command to open configuration file.

sudo nano /etc/nginx/sites-available/default

After changing path to point our index.php, it will look like this

server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

root /var/www/laravel/public;
index index.php index.html index.htm;

server_name 10.100.162.1

location / {
try_files $uri $uri/;
}

public folder in laravel will have index.php file. Restart nginx by this command to take effects.

sudo service nginx restart

Step 10: Install and Run Composer

You have installed composer before, and this is no different than before. Follow the instructions just like on the GetComposer.org website.

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

Now we have composer.phar in our home folder, and it’s time to move it into our bin so we can use composer commands easier by just typing composer.

sudo mv composer.phar /usr/local/bin/composer

Now change directory path to our laravel project directory. Make sure you are in it then run following command.

composer install — no-dev

The — no-dev command flag is very important. Without it, composer will try to install a bunch of stuff that you do not need on production. It is also very likely that the install will fail as well, since some of the dev dependencies won’t work on our server. By adding — no-dev we are only installing the main require elements and not other random things.

Step 11: Permit Laravel

In order to run, Nginx needs certain permissions over the Laravel directory we made. We need to first change ownership of the laravel directory to our web group.

sudo chown -R :www-data /var/www/laravel

Now the web group owns the files instead of the root user. Next we need to give the web group write privileges over our storage directory so it can write to this folder. This is where you store log files, cache, and even file uploads.

sudo chmod -R 775 /var/www/laravel/storage

Now go to your web browser and type in your domain or IP address to attempt to view the site. What do you see?

This is because we are running our application on our production. You can not show your error description to your user for security reasons. Now question is how to find what error is there? You can see error with detail description from laravel/storage/logs/laravel.log file. open this file in editor to view detail.

Basically this error says that it is unable to write to the bootstrap/cache/ folder. If we look at the Laravel Installation Documentation we can see that we were supposed to make the bootstrap/cache/ folder writable in addition to the /storage/ folder. So let’s go back and fix that.

sudo chmod -R 775 /var/www/laravel/bootstrap/cache

Ok, now the cache folder is writable. There are a few things though that we need to do. But we are getting really close to our app being ready to deploy.

Step 12: Setup Database

Lets get into MySQL by typing the following command:

mysql -u root -p

After -p press Enter then on next line type your MySQL password.

Now we need to make a new database for our Laravel app to use. You can call it whatever you want. Just make sure to remember the name and keep it all lowercase.

CREATE DATABASE blog;

blog is name of our new database that we want to create.

Now if you wanted, you could run SHOW DATABASE; again and you will find the list of databases and your new database should be in the list.

To leave the MySQL command prompt you simply type:

exit

Step 13: Understand .env File

We will use the config files and also set up a .env file. Remember that when we push to production that any file in our .gitignore will not be sent to our server. So any of those files need to be set up again. If done correctly, this isn’t a big deal, your node_modules should not be there, or your vendor files, which is ok because you don’t need them on production (you should use Elixir to compile the ones you need into your public/ or resources/assets/ folders prior to pushing to production).

Also remember that by default your storage directory is in your .gitignore file which means that anything stored in there (like user avatars) will not be transferred to the server. This is by design, but explaining this design decision is more complicated than we can get into right now.

Really the only important file in your .gitignore file that our application really needs is the .env file. Now once again this is by design, so do not hastily remove it from the .gitignore file. Keep it in there, because it is very dangerous to put your .env file into your repository. The .env will contain private information, passwords, SMTP credentials, API keys, and more that all need to be kept very secret. So you should make a .env file for your server that represents your production environment and this will be different from the one on your local machine which contains information for your local enviroment.

Once you have a .env file set up for your server and one for your local then you can push your code between your local computer and your server and the different settings will instantly take effect. Because git doesn’t touch your .env file, then it will not change when the other code is pushed, but Laravel will use the information in the .env to run everything.

Ok, I think we now know why we use a .env file, so now let’s create one for our server.

It is just a good idea to look at your .gitignore and understand that everything in your .gitignore file will NOT be on the server. If you see something important on there than you either need to recreate it on your server or you need to edit your .gitignore file so that it includes it in your repository.

One file is kept in our git repo and that is the .env. This is an example .env file that we can use to get started. So we will start with this example file to create our server .env. Lets copy the .env.example and rename it .env. We want to copy instead of move because that way the .env.example file doesn’t get pulled from the repo and we can use it again later as a template if we mess up.

Step 14: Configure .env File

To copy and rename the file we will use the cp linux command. Make sure before you do this that you are inside your laravel folder (in /var/www/html/laravel/) because that is where the .env.example is located.

To make sure that you are in the right place, run the lscommand but run it with the -A flag so that you can see the hidden files (the . before the filename indicates that it is hidden).

ls -A

This should show all of your folders and files, including the hidden files. You should see your normal Laravel structure ( app/ , public/, storage/ and so forth) and also normal files like composer.json, gulpfile.js, and finally your .env.example. Now you know you are in the right spot.

Now that you are in the right spot, lets copy the file.

cp .env.example .env

If you run ls -A again then you should see your .env file next to your .env.example (they should both be there).

Now we can edit our .env by opening it with a text editor of your choice (once again we will use nano for simplicity).

nano .env

Inside this file you will be able to overwrite many of the config settings. Remember that anything in the .env file will override whatever is in the config files.

Now that we have created this .env file, it is going to override the settings in our config file. So for example, our config/app.php file has our environment set to ‘production‘ but our new .env file has the APP_ENV set to local instead. So now this will switch our application to localwhich is a security concern. So we either need to remove the line or change it to what we want.

APP_DEBUG is what sets those error messages that we talked about earlier. We need to make sure that is set to false.

APP_ENV needs to also be set, but we will set that in a moment with an artisan command.

Next comes your database settings. You will need to configure your DB_HOST to be localhost, set the DB_DATABASE to be the name of the database we just created in the last step, and then set your username and password for the database in the DB_USERNAME and DB_PASSWORD fields.

You might want to adjust your cache, queue, and session drivers if you know what you are doing. But the defaults are good for most apps.

Lastly you will want to change the MAIL settings as well. Just configure it based on the settings for your email service provider. The settings are pretty self-explanatory and outside of the scope of this tutorial.

Now Save the file using the ctr+ x command we usually do.

APP_ENV=production
APP_DEBUG=false
APP_KEY=SomeRandomString

DB_HOST=localhost
DB_DATABASE=blog
DB_USERNAME=root
DB_PASSWORD=XXXXXXXXX

CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync

REDIS_HOST=localhost
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=sendgrid.com
MAIL_PORT=2525
MAIL_USERNAME=XYZ
MAIL_PASSWORD=XXXXXXXXXXX
MAIL_ENCRYPTION=null

Take extra care to make sure the red parts get changed. If you are not using Redis database then you can delete those lines (but keeping them in won’t hurt anything either). Take extra care to double check that the APP_ENV is set to production and that APP_DEBUG is set to false .

I always like to take a look at my local .env file as well just to make sure that I didn’t add any other .env settings while building my app.

We should now have most of our app set up. Just a few more configurations to make.

Step 15: Set Encryption Key

There is one line we left default in our .env file, the APP_KEY . Laravel needs this key to be set up in order to encrypt our sessions, cookies, and passwords. This needs to be a random key that is unique to our application to make everything more secure. We can generate this key with an artisan command. Remember those? Yeah, we can use those directly on our server, just like we did on our local computer.

Let’s run the artisan command to generate a secure encryption key.

php artisan key:generate

After clicking Enter you should see a green line that says:

Application key [key] set successfully.

Of course the long number inside the square brackets will be different for you, because it is supposed to be random.

If you are curious, this artisan command will actually write to your .env file for you. So you really don’t need to do anything. But for the adventurous among you, go back to your .env file and look inside.

nano .env

You should see the APP_KEY filled out now with your random key.

Step 16: Few More Config Setting

Our .env file is complete, but there are just a few more settings we want to change before we are live. These settings are all in our config/ files.

In config/app.php there are a few things to edit. Set the URLto your actual domain name. Also make sure that your timezon is set correctly too. This needs to be an officially supported PHP time zone string. If you are not sure what your timezone string is, you can find the official timezone strings on the PHP Manual.

Step 17: Cache Configuration Settings

You might have noticed that there are lots of config files in our application. They inherite and cross reference eachother, all of which makes the configuration easier to read, but slower for PHP to compile on the fly.

Because of this, it is a good idea to cache all of the configuration settings into one cached config file. We can do this with another artisan command.

In your terminal (in the /var/www/html/laravel folder):

php artisan config:cache

This will output:

Configuration cache cleared

Configuration cached successfully

Now all of our configuration settings are compiled together into one quick file. Of course don’t forget now that they are cached. So if you make another change to your .env file or to a file in your config/ folder, that you need to also recompile the config cache before it will take effect.

Step 18: Migrate our Database

Now that everything else is set up you can actually run your app. The only problem you might still have is that if your app relies on a database, then you need to migrate your database. We do this in much the same way as on our local computer. At this point our configuration files should have everything we need to set up and communicate with our database, so migrating now should be simple.

php artisan migrate

This will warn you that your app is in production and make sure that you want to actually run your migrations. The default setting is “no” also so its very difficult to accidentally migrate your live database. This can be good because sometimes you might forget you are logged into your server on SSH and just grab the nearest terminal window to run what you think are local migrations, but really they are production migrations. This script makes sure we know what we are doing.

Type Y to continue and migrate your database.

Now with all set up, our laravel application is available world wide

--

--