A production workflow for Laravel using Webdock servers
Last updated: May 25th 2021
Introduction
In this series we'll show you how to create a basic workflow between your local development environment and a live environment on our server stacks, leveraging git and git hooks.
We will be setting up a live environment on Webdock and showing you how you can automatically deploy code to your server whenever you push from your local development environment to, for example, Github.
Prerequisites
In order to follow along you need to have:
- A local Laravel project (Laravel 8 or newer)
- A (new) server on Webdock running our latest LEMP Perfect Server Stack
- Shell access
- A Github/Gitlab/Bitbucket account
In addition, we recommend you enable "Passwordless Sudo" script on your server (found on the Shell Users screen) in order to be able to run sudo commands in scripts and on the command-line without entering a password every time.
Set up Git & Git Hooks
Git is already installed on Ubuntu by default, so here we show you how you can initialize your Git repository on the Webdock server and set up hooks.
Once ssh'ed in to your server you initialize git by making a new folder in an appropriate location, for example /var/repo/
by doing:
cd /var sudo mkdir repo
This will move you to the /var/
folder and make a new directory called /repo/
.
To move you inside of that newly created folder type: cd repo
and execute the following:
sudo mkdir site.git && cd site.git sudo chown admin /var/repo/site.git git init --bare
This creates a folder called site.git
, moves you into that folder and initializes git. The --bare flag is generally only used on servers which purpose is to receive pushes from developers. Visit the official git documentation to read more
Before initializing the git repo we change the ownership of the repo. This is nessecary to avoid root user rights to the git repo which causes problems when pushing to your live server. In this example we are using the default "admin" shell user which Webdock creates for you.
Git Hooks
Git repositories have a feature called hooks that can be used to moves files (and perform other actions) when performing a git push. Upon initializing git, a folder called hooks
is created. Cd into that and by creating the following post-receive
script the files will be moved to our specified destination after the push
Inside the hooks folder (/var/repo/site.git/hooks):
sudo nano post-receive
This will open up a blank file. Paste the following into the file and save and exit the file by Ctrl + X then Y to confirm:
#!/bin/sh git --work-tree=/var/www/laravel --git-dir=/var/repo/site.git checkout -f
The first line is the "shebang" operator followed by specifying which shell this script should run under. Here we have specified /bin/sh but it could just as well be /bin/bash if you prefer.
As this is "just a shell script" you can put in further post-receive actions here, such as normalizing permissions, running composer or whatever else you might need after your server has received code from your development environment.
In the command shown, the --work-tree= flag tells git where to copy received files. We set it to point to a web root folder called laravel that we will be making in the next section. The --git-dir= tells git where the bare git directory is that has received the files.
A final step to make the git hooks work is to assign the right permission to it in order to make the script executable. Still in /var/repo/site.git/hooks/ folder:
sudo chmod +x post-receive
That sums up the basic setup of git and hooks.
Add the laravel folder and make it your web root
By default on Webdock stacks the web root is located at /var/www/html
. To use the newly created git hook you will need to create at folder for the push to write to, as specified above. Fortunately this is easy:
sudo mkdir /var/www/laravel sudo chown admin /var/www/laravel
Filesystem permissions
In order to allow Nginx to read your files and serve your content, the web group needs ownership and write permissions to the relevant laravel folders
sudo chown -R :www-data /var/www/laravel sudo chmod -R 775 /var/www/laravel/storage sudo chmod -R 775 /var/www/laravel/bootstrap/cache
You could consider adding these commands to the post-receive script we made above, so they are run every time new code is deployed.
Change the web root in the Webdock dashboard
Laravels index.php is located in the public subfolder in your web root, so in order to serve the application you need to change the web root as interpreted by the web server (Nginx in this case). Locate the pencil icon next to your web root in the Webdock dashboard and change it from /var/www/html
to /var/www/laravel/public
If you want to do this manually you have to change your web root in your nginx configuration, typically found under /etc/nginx/sites-enabled/ and restart nginx with systemctl restart nginx
Connect your local development to your production server
In this example we assume you are using Github, but almost any other Git repository service is compatible with this including Bitbucket, Gitlab and others. As mentioned we used Github with the suggested name 'origin' for our local to the repo provider. You can follow along by typing this into your local terminal window:
git remote add origin https://github.com/user/repo.git
If you made a repo in Github both the user and repo parts come pre-filled for you in the link they provide.
Connecting to production is almost the same as connecting your development files to your repo service provider. You set up a git remote with a name that you think is appropriate. We choose 'production' to represent the production server. Be sure to have both connections to keep version control at your repo provider up to date as well.
First, make sure you still are in your local development terminal and not the server terminal. Then run:
git remote add production ssh://admin@yourservername.vps.webdock.io/var/repo/site.git git push production master
The servername is the name of your created server, in this case laravel. The code from your git development master branch is now pushed to your server!
From now on, you can push to your server from your local computer by typing the command git push production master
and this will push the master branch to our production server.
You can continue to push to github using git push origin master
and let the changes go live once they are ready to push to production.
Note: You can create as many “remotes” as you want in git. It is common to have a secondary server called “staging” which is where push your project to for testing purposes in a live enviroment before pushing to a live production site
Verify it works
To check if everything is working correctly ssh into your server and cd into the /var/www/laravel/
folder and list the files.
cd /var/www/laravel ls -lah
You should be able to see all the files from your development site in this directory.
Install Composer in production server
Now that your files are pushed to the server you need to install all of the composer dependecies for the application to work. In the /var/www/laravel/ folder:
cd /var/www/laravel composer install --no-dev
Make sure to run the --no-dev flag on production. This will prevent composer from installing the unnessecary development dependencies to the production server.
These are also commands you could consider adding to your post-receive script in order to automatically install dependencies.
Laravel configuration
.env file
The .env file is the configuration file for your entire application. You can read more about it here
To create it you just copy the .env.example file from the root directory. In the /var/www/laravel/
folder run:
cp .env.example .env
Edit it by typing:
nano .env
Fill in your own database information and set the url and application environment to production & debug to false. On Webdock stacks the database host should be set to localhost.
App key and finishing configuration touches
You may have noticed when editing the .env file that the application key was missing. Generate it now by running:
php artisan key:generate
All that is left is to cache for production speed load times, migrate the database and create a symlink from the storage to the public folder.
Laravel comes with a lot of configuration which inherits from and cross references each other, all of which makes the configuration easier to read, but is slower for PHP to compile. By collecting all of the configuration in a single file it is a much faster execute by the server. Run:
php artisan config:cache
Now that the configuration is set up, your app is ready to run. If you have a database and a public upload folder the only thing left is to migrate it and create a symlink from the storage folder to the public folder:
php artisan migrate php artisan storage:link
When migrating the database you will get a warning that your app is in production mode to make you think twice about your decision. At this point it is fine but be aware of this in the future.
Additional concerns - The need for a staging and beta/testing server
In order to eliminate errors before they reach your clients/users it is wise to setup a testing/staging environment that matches your production environment.
One way of doing this is to have a seperate server. You can even grab a snapshot of one Webdock server and then create another with the exact same setup and then just adjust your git hooks.
Another suggestion is where you use a single server with different URL's for different versions of your code. For a guide on this setup using multiple urls which contain different Laravel installs - please see our guide on this approach
Series Author: Thomas Damsgaard
Related articles
-
Laravel Chunked Upload - uploading HUGE files
-
The power of Laravel Queues
This guide shows how to run asynchronous jobs with Laravel
-
Laravel and Redis 5 - Introduction, Installation and basic use
-
Laravel and Redis 5 - A Functional Example
-
Build an API in Laravel with JSON Web Tokens (JWT) (Part 1)
-
The Anatomy of JSON Web Tokens (JWT) (Part 2)
-
Database and tracking JSON Web Tokens (JWT) (Part 3)
In this article we will build a database and track our JSON Web Tokens.
-
JSON Web Tokens and Laravel API custom filtering (JWT) (Part 4)