Laravel 7 Deployment on Centos7 OCI machine using nginx with free SSL

I recently got a chance to do a small work on a friend’s project and will summarize the secret steps to have a production deployment on Oracle Cloud of a Laravel project on Centos 7 updated 2020.

The project is split into the bellow steps:

  • Environment Provisioning
    • OCI Configuration
      • Network Setup
      • Machine creation
    • Domain acquisition
    • Packages installation
      • PHP Installation
      • Composer Installation
      • GIT
  • Database configuration
  • Project setup
    • cerbot installation
    • Laravel project creation
    • ngix installation and configuration

Environment Provisioning

OCI Configuration

This is short version of this post

Network Setup

Create a new VCN using the VCN wizard (make sure it not use DNS hostnames)

Machine creation

Create the VM and get the public ip here we will assume the ip is 139.123.22.3 make sure you open the ports on the VM firewall and the the OCI console firewall, the ports we will use are 80,443,3306

Domain acquisition

The very first thing we need is to obtains a domain, you can buy it wherever you want but I personally prefer google domains, it is cheap (about 10USD annually) and they include the data protection for you domain which is very important of the email that you use for the domain registration will fill of spam in no time.

Once you have bought it you should have something like this

from which you can manage the DNS, click it and go to the bottom, there you can add DNS records to connect the VM where your site is hosted to the domain.

Here we will assume the domain is dragon.dev

Insert the below records

Type:  A
Name:  @
TTL:   1H
Value: 139.123.22.3
Type:  CNAME
Name:  www
TTL:   1H
Value: dragon.dev

hit save and the DNS should be ready, to make sure it works, from the terminal execute

 dig +trace dragon.dev
 dig +trace www.dragon.dev

They should return the IP that you assigned above, the change should take a up to 2 days depending on where you bought the domain and their DNS servers, in google domains it takes like 2 minutes.

Packages installation

PHP 7.4 installation

yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install https://rpms.remirepo.net/enterprise/remi-release-7.rpm
yum -y install yum-utils
yum-config-manager --enable remi-php74
yum update -y
yum install -y php php-cli
yum install -y php-cli php-fpm php-mysqlnd php-zip php-devel php-gd php-mcrypt php-mbstring php-curl php-xml php-pear php-bcmath php-json php-fpm

Composer install

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '756890a4488ce9024fc62c56153228907f1545c228516cbf63f885e036d37e9a59d27d63f46af1d4d07ee0f76181c7d3') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

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

verify installs

php -v
composer -V

nodejs installation

curl -sL https://rpm.nodesource.com/setup_10.x | sudo bash -
sudo yum install -y nodejs

git installation

yum remove -y git*
yum install -y https://packages.endpoint.com/rhel/7/os/x86_64/endpoint-repo-1.7-1.x86_64.rpm
yum install -y git

Database configuration

click here

Project setup

Cerbot Installation

First as root, we need to install cerbot, which is the utility we will use later to generate the certificates for the domain.

yum install -y install python3-devel gcc augeas-libs openssl-devel libffi-devel \ redhat-rpm-config ca-certificates openssl
cd /home/$USER
git clone https://github.com/certbot/certbot
cd certbot
python tools/venv3.py
source venv3/bin/activate

Learn about testing cerbot executions here

Laravel project creation

cd /var/www/
composer create-project --prefer-dist "laravel/laravel=~7" dragon.dev
cd dragon.dev
composer install
npm install
cp .env.example .env

add to the .env the database credentials

APP_KEY=$your key
APP_DEBUG=false
APP_URL=https://dragon.dev
...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=$database
DB_USERNAME=$user
DB_PASSWORD=$pass
...

run the Laravel migrations

php artisan migrate
chmod -R 777 storage
chmod -R 777 bootstrap/cache

the project was deployed home will be /var/www/dragon.dev the Laravel public folder will be on /var/www/dragon.dev/public

nginx installation and configuration

yum install -y nginx

The folder configuration will be /etc/nginx now lets create some folders and files

cd /etc/nginx
mkdir sistes-available
mkdir sistes-enabled
touch sistes-available/dragon.dev.conf
ln -s sistes-available/dragon.dev.conf sistes-enabled

Then modify the file /etc/nginx/nginx.conf its content should look like this (specially the include part)

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    # this is where the configs are located
    include /etc/nginx/sites-enabled/*.conf;

php fast cgi configuration

systemctl start php-fpm
systemctl enable php-fpm

Now we need to identify the socket created by the above command, to do so, open

 /etc/php-fpm.d/www.conf

if it is not there, you need to locate it using

locate www.conf

Inside, look for listen

listen = 127.0.0.1:9000

This little bastard is where the nginx server will submit the php code, it could also be something like

unix:/run/php/php7.4-fpm.sock;

it depends on the Linux flavor you use, now let’s edit dragon.dev.conf

server {
         listen 80;
         listen [::]:80 ipv6only=on;
 
         # Log files for Debugging
         access_log /var/log/nginx/laravel-access.log;
         error_log /var/log/nginx/laravel-error.log;
 
         # Webroot Directory for Laravel project
         root /var/www/dragon.dev/public;
         index index.php index.html index.htm;
 
         # Your Domain Name
         server_name dragon.dev www.dragon.dev;
 
         location / {
                 try_files $uri $uri/ /index.php?$query_string;
         }
 
         # PHP-FPM Configuration Nginx
         location ~ \.php$ {
                 try_files $uri =404;
                 fastcgi_split_path_info ^(.+\.php)(/.+)$;
                 fastcgi_pass 127.0.0.1:9000;
                 fastcgi_index index.php;
                 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                 include fastcgi_params;
         }
 }

Special attention to the value of fastcgi_pass this is just a temporary configuration that will allow to access to the domain on port 80, however, on modern browser this won’t work due to security reasons, this will be used only to allow validate the domain and generate the certificates with cerbot

Now you can start nginx

systemctl restart nginx

Certificates creation

certbot certonly --webroot \
--webroot-path=/var/www/dragon.dev/public \
 -d dragon.dev \
 -d www.dragon.dev

The expected output should look like

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/dragon.dev/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/dragon.dev/privkey.pem
   Your cert will expire on 2020-12-15. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:
   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

finally, we need to edit /etc/nginx/sites-available/dragon.dev.conf to add the TLS

server {
         listen 80;
         listen [::]:80;
         server_name dragon.dev www.dragon.dev;
         return 301 https://$server_name$request_uri;
}
server {
    listen       443 ssl http2 default_server;
    listen       [::]:443 ssl http2 default_server;
    server_name  _;
    root         /var/www/dragon.dev/public;
    index index.php index.html index.htm;
    ssl_certificate "/etc/letsencrypt/live/dragon.dev/fullchain.pem";
    ssl_certificate_key "/etc/letsencrypt/live/dragon.dev/privkey.pem";
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
     server_name dragon.dev www.dragon.dev;
     location / {
             try_files $uri $uri/ /index.php?$query_string;
     }
     # PHP-FPM Configuration Nginx
     location ~ \.php$ {
             try_files $uri =404;
             fastcgi_split_path_info ^(.+\.php)(/.+)$;
             fastcgi_pass 127.0.0.1:9000;
             fastcgi_index index.php;
             fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
             include fastcgi_params;
     }
     location ~ /\.ht {
                deny all;
     }
     location ~ /.well-known {
                allow all;
     }
}

Restart nginx

systemctl restart nginx

finally open the browser and enjoy

https://dragon.dev
References

https://stackoverflow.com/questions/40059745/nginx-connect-to-unix-var-run-php7-0-fpm-sock-failed-2-no-such-file-or-dir
https://www.digitalocean.com/community/tutorials/how-to-deploy-a-laravel-application-with-nginx-on-ubuntu-16-04
https://www.linode.com/docs/web-servers/apache/how-to-install-and-configure-fastcgi-and-php-fpm-on-centos-8/
https://certbot.eff.org/docs/contributing.html
https://linux4one.com/how-to-install-laravel-php-framework-with-nginx-on-centos-7