Skip to main content

How to docker a Laravel 7.4 API with NuxtJS and a AWS RDS using Dockerfile and docker-compose.yml in a Centos EC2 instance

Most of the time people use docker to deploy Laravel, NuxtJS, a desired database engine as Mysql or Postgresql and even Nginx, but this tutorial is quite different it is for those ones who wants to deploy one or more Laravel APIs with NuxtJS using an existing AWS RDS, and a Nginx installed in your host with cerbot as the tool to get the ssl for the domain name

Note: you're supposed to have running an AWS RDS with your database already available

used tools:

  1. On Centos 7 

         yum update -y && yum install epel-release -y &&

         yum install update -y && yum upgrade -y && yum install unzip -y &&

         yum install screen -y && yum install nginx -y && yum install telnet -y &&

         systemctl enable nginx && systemctl restart nginx && yum install certbot-nginx -y

         to install docker on linux centos: https://docs.docker.com/engine/install/centos/

         to install docker-compose on linux: https://docs.docker.com/compose/install/         

  1. Ningx installed in the host OS
  2. Cerbot installed in the host OS
  3. Screen and unzip tools

I'll be using a domain name for testing called apitester.xyz for the purpose of the example, I created 2 A records:

one A record @ pointing all traffic to the EC2-instance where we've got the Centos 7 with all the tools listed before and the another  A record www pointing to the EC2-instance

 

NOTE: dont' forget to disable SElinux or to give Nginx permissions to run it with SELinux

setenforce 0

vim /etc/selinux/config

SELINUX=disabled

:wq!

 

before starting with Docker, we'll set up nginx and cerbot getting ready the domain name with ssl.


Creating a server block

Nginx server block configuration files must end with .conf and are stored in /etc/nginx/conf.d directory.

 so, vim /etc/nginx/conf.d/apitester.xyz.conf


server {
        server_name apitester.xyz www.apitester.xyz;

        location /api {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header HOST $http_host;
                proxy_pass http://localhost:8000;
        }


        location / {
              expires -1;
            proxy_set_header Host      $host;
            proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-Proto  $scheme;
                proxy_redirect              off;
                proxy_read_timeout          1m;
                proxy_connect_timeout       1m;
            proxy_pass http://localhost:3000;
      }

}

 

now run  nginx -t 

it must give an ok answer, if there something wrong then must be fixed,  

NOTE: we are setting nginx as a proxy reverse, keep in mind the root of all endpoints of the API start with the word /api if for some reasong you've got another endpoint which starts different from /api then you must add it, for instance if the login endpoint starts different from /api like /auth/login, the must add another location which starts from its root as 

location /aut {}

Example:

server {
        server_name apitester.xyz www.apitester.xyz;
       
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header HOST $http_host;
       
        location /api {
             
                proxy_pass http://localhost:8000;
        }
       
        location /auth {
             
                proxy_pass http://localhost:8000;
        }


        location / {
                expires -1;
                proxy_set_header Host      $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-Proto  $scheme;
                proxy_redirect              off;
                proxy_read_timeout          1m;
                proxy_connect_timeout       1m;
                proxy_pass http://localhost:3000;
      }

}

 

so, let's give the ssl with certbot run

certbot --nginx -d apitester.xyz -d www.apitester.xyz 

if everything went ok then you must get 


Setting Up Auto Renewal SSL

Let’s Encrypt’s certificates are only valid for ninety days. This is to encourage users to automate their certificate renewal process. We’ll need to set up a regularly run command to check for expiring certificates and renew them automatically.

To run the renewal check daily, we will use cron, a standard system service for running periodic jobs. We tell cron what to do by opening and editing a file called a crontab.

crontab -e
. . .
15 3 * * * /usr/bin/certbot renew --quiet

we have set up until now all the necesaries tools to start with dockerizing the application. 

give the name you want to your project, for this example is called laravel_project 

so the directory structure would be:


laravel_project

   ****api

   ****front

   docker-compose.yml   

 

so as it is  shown unzip or copy your Laravel API to the api folder, and the same thing for the NuxtJS front

 

let's create a Dockerfile inside api folder  

FROM php:7.4-fpm

# Arguments defined in docker-compose.yml
ARG user
ARG uid

# Install system dependencies
RUN apt-get update && apt-get install -y \
  git \
  curl \
  libpng-dev \
  libonig-dev \
  libxml2-dev \
  zip \
  unzip

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
  chown -R $user:$user /home/$user

# Set working directory
WORKDIR /var/www

USER $user

EXPOSE 8000



so, this is basically getting the php 7.4 image with all its dependencies in orther to run on it composer exposing the API over the 8000 port


let's edit the .env file inside the API folder, set the values to connect to the database in the section

DB_CONNECTION=mysql
DB_HOST=rds_url
DB_PORT=rds_port
DB_DATABASE=database_name
DB_USERNAME=rds_username
DB_PASSWORD=rds_passowrd


another importan thing the piece of code which says APP_URL mus point to http://localhost:8000

APP_URL=http://localhost:8000




 

so now let's go to the front folder and let's create a Dockerfile inside of it

FROM node:12

# create destination directory
RUN mkdir -p /usr/src/nuxt-app
WORKDIR /usr/src/nuxt-app

# copy the app, note .dockerignore
COPY . /usr/src/nuxt-app/
RUN npm install
RUN npm run build

EXPOSE 3000

ENV NUXT_HOST=0.0.0.0
ENV NUXT_PORT=3000

CMD [ "npm", "start" ]

so, this is basically getting the node 12 image with all its dependencies in orther to run to install, build and expose the front over the 3000 port, this is done with Node so that NuxtJS needs node to work

 

noe let's create the file docker-compose.yml which is the one is going to be build and run both Dockerfiles

version: "3.7"
services:
 
  front_nuxt:
    build: ./front/
    container_name: front-nuxtjs
    restart: always
    ports:
      - "3000:3000"
    command:
      "npm run start"

  api_laravel:
    build:
      args:
        user: centos
        uid: 1000
      context: ./api/
      dockerfile: Dockerfile
    image: api-laravel
    container_name: api-laravel
    restart: unless-stopped
    ports:
      - "8000:8000"
    working_dir: /var/www/
    volumes:
      - ./api/:/var/www

there are 2 projects to be build front_nuxt and api_laravel, front_nuxt will be running over the port 3000 in the host machine, and it will be running on the port 3000 in the docker container, the project api_laravel will be running through the port 8000 in the host machine whereas it will be running in the 8000 port in the docker container

Note: 

left port = local machine port

right port = docker container port

 

chown -R centos:centos api

chown -R centos:centos front

now to build and run both services

docker-compose build &&
docker-compose up -d &&
docker-compose exec api_laravel composer install &&
docker-compose exec api_laravel php artisan key:generate &&
docker-compose exec api_laravel php artisan migrate --seed &&
screen -dmS api_laravel_1 bash -c 'cd /home/centos/
laravel_project && docker-compose exec api_laravel php artisan serve --host 0.0.0.0 ; exec bash -i'

 

Note: don't forget to update the path where the application is, in this case its path is /home/centos/laravel_project

 

docker-compose build = this will build each project based on the Dockerfile instructions

docker-compose up -d = this will run the containers and with the flag -d it will help to run the docker containers as services in case the server gets restarted docker will automatically start the containers

docker-compose exec api_laravel composer install  = this executes composer install inside the docker container api_laravel

docker-compose exec api_laravel php artisan key:generate = this willl sets the APP_KEY value in your . env file

docker-compose exec api_laravel php artisan migrate --seed = this will read the settings you've got in your .env and will make the tables into the database you set before

screen -dmS api_laravel bash -c 'cd /home/centos/laravel_project && docker-compose exec api_laravel php artisan serve --host 0.0.0.0 ; exec bash -i' = this will create a screen in which it is going to be running laravel through the port 8000 accepting requests from the host machine 

if there are no other screens running, so run screen -r -d

after that you will be able to get to the screen where php artisan serve is running, if there more screens you will be able to see the id number which  the screen called api_laravel is running and you will be able to get it as screen -r -d idnumber

up to this point your Laravel API is up and runing over PHP 7.4 and running with NuxtJS using node 12 are 


the first thing that I test before anything else is the API

so open a console in the remote server and test telnet through both ports 8000 and 3000

 

 

as we could locally the api and the front are working ok, so test it with your endpoints through insomnia or postman and you must get your answer back when making the test don't specify the port 8000 as it is not needed anylonger so that nginx reverse proxy is making the job for you, it's just enough giving the endpoint name

as you could see, I did not have to do https://apitester.xyz:8000/api/login, it is not needed anylonger, proxy reverse does the job for us 


NOTE: don't forget to set the headers Content-Type application/json and Accept application/json in insomnia or postman


 

now let's try https://apitester.xyz


to start everything from scratch run

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
docker rmi $(docker images -q) -f

runing the given commands will stop and remove any docker container as any build image


  1. Stop the container(s) using the following command:
    docker-compose down
  2. Delete all containers using the following command:
    docker rm -f $(docker ps -a -q)
  3. Delete all volumes using the following command:
    docker volume rm $(docker volume ls -q)
  4. Restart the containers using the following command:
    docker-compose up -d
     

     

     
 


Comments

  1. Nice blog... Thank you for the insightful comparison between Insomnia vs Postman! Your blog post provided a comprehensive analysis of both tools, highlighting their strengths and use cases. As a developer, this was exactly the information I was looking for to make an informed decision. Your clear explanations and pros and cons list made it easy to understand the key differences. Thanks for helping me choose the right tool for my API testing needs. Great job on the blog post!

    ReplyDelete

Post a Comment

Popular posts from this blog

How to deploy a VueJS App using Nginx on Ubuntu

There are thousands of blogs and websites out there explaining how to do a hello world and how to start with VueJS, but in this little post, I’m just going to be explaining how to do deploy a VueJs app after you have run the command through the CLI npm run build . So when you run the command npm run build a dist folder is created and that folder’s got the essential .js files to run our app, when we want to run our app on an Nginx server by default the vue-router is not going to work well so that Nginx does not come ready to work by default with a VueJs app This is basically for a Linux Ubuntu distribution if you’ve got any other Linux distribution just pay attention where is going to be set the www/html folder and the Nginx settings so that this is useful for any Linux distribution  Install and configure nginx sudo apt install nginx Double check to make sure the nginx service is running with command service nginx status, then open your browser and enter ...

How to secure SpringBoot with SSL and Tomcat or Undertow

when we are going to take our applications to production mode, we must have an SSL certificate for the FrontEnd and   BackEnd too, in this case, our backend is a  SpringBoot which is using a tomcat embedded server. Terminology TLS vs SSL TLS is the successor to SSL. It is a protocol that ensures privacy between communicating applications. Unless otherwise stated, in this document consider TLS and SSL as interchangable. Certificate (cert) The public half of a public/private key pair with some additional metadata about who issued it etc. It may be freely given to anyone. Private Key A private key can verify that its corresponding certificate/public key was used to encrypt data. It is never given out publicly. Certificate Authority (CA) A company that issues digital certificates. For SSL/TLS certificates, there are a small number of providers (e.g. Symantec/Versign/Thawte, Comodo, GoDaddy, LetsEncrypt) whose certificates are included by most browsers and Op...