DEV Community

Cover image for Build and deploy React using Gitlab CI pipeline
Tamilarasu S for AT Digitals

Posted on

Build and deploy React using Gitlab CI pipeline

Prerequisite

  • Repository in Gitlab with react project
  • Production server for which you have SSH access
  • NGINX setup for your domain to a folder in the server. See this tutorial on how to do it

Goal

Setup the Gitlab CI/CD pipeline to create a react production build and deploy to our server whenever code is merged to master branch. The attached steps can also be used for other SPA like Angular, Vue.js.

Step 1 - Give Gitlab access to your server

We are going to use Gitlab CI/CD Variables to save a private SSH key which Gitlab will use to authenticate with the server.

We are going to use SSH keys to authenticate rather than username and password as it is more secure.

This can be configured at a repository level or at a group level.
To view all the CI/CD variables of your repository,

  1. Go to your project’s Settings > CI/CD
  2. Expand the Variables section.

You can also view the same at a group level by first navigating to the group (Menu > Groups > Your Groups) and following the same steps.

If you already have a SSH_PRIVATE_KEY private key variable listed, you can skip this step.

To create a new variable, Select the Add Variable button and fill in the details:

  • Key: SSH_PRIVATE_KEY
  • Value: <ssh_private_key_details>. (To generate a new SSH public and private key pair, follow steps from this guide. Make sure to not accidentally overwrite any existing key pairs.)
  • Type: Variable
  • Choose other settings based on your needs

Click Add Variable to add the variable

Gitlab CI/CD Variable Config

Step 2 - Add Gitlab SSH public key to your server

Now, we need to add SSH public key to the list of authorized_keys in the production server.

  1. SSH into your server (ssh root@example.com)
  2. Add the SSH public key to authorized_keys

    
    
    nano ~/.ssh/authorized_keys
    
3. Paste the SSH public key(starts with`ssh-rsa`) in a new line
4. Save the file

## Step 3 - Configuring Gitlab CI/CD
Gitlab looks for `.gitlab-ci.yml` in the root folder of your repository for CI/CD pipeline configurations

Add a new file `.gitlab-ci.yml` in the root folder
Enter fullscreen mode Exit fullscreen mode

image: node

cache:
paths:
- node_modules/

before_script:

  • apt-get update -qq
  • apt-get install -qq git
  • "which ssh-agent || ( apt-get install -qq openssh-client )"
  • eval $(ssh-agent -s)
  • ssh-add <(echo "$SSH_PRIVATE_KEY")
  • mkdir -p ~/.ssh
  • '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'

deploy:
stage: deploy
environment:
name: production
url: example.com
script:
- bash deploy/deploy.sh
only:
- master

- Update the url in the above file to your domain

### Explanation
- We are using the [Node docker image](https://hub.docker.com/_/node) as the starting point
- We are caching the `node_modules` folder to improve the speed of the build
- We install `git` package and then configure it to add our `SSH_PRIVATE_KEY`
- We also configure `StrictHostKeyChecking` to `no`, to ensure git doesn't show manual prompt during initial connection.
- We have setup pipeline named `deploy` with a single pipeline stage `deploy` which listens to commits on `master` and runs the script in `deploy/deploy.sh`

## Step 4 - Setup the deploy script
Add a new file `deploy.sh` in `deploy` folder
Enter fullscreen mode Exit fullscreen mode

!/bin/bash

DEPLOY_SERVER=$DEPLOY_SERVER
SERVER_FOLDER="html-folder-in-server"

Building React output

yarn install
yarn run build

echo "Deploying to ${DEPLOY_SERVER}"
scp -r build/ root@${DEPLOY_SERVER}:/var/www/html/${SERVER_FOLDER}/

echo "Finished copying the build files"

- Update the server folder to the folder name that you have created in the production server
- Set the CI/CD variable `DEPLOY_SERVER` with value `domain.com` for the repository using step 1.

### Explanation
- We set server and folder variables
- We install dependencies and then start a new react production build using `yarn`
- Once the build is done, we copy the `build` folder to `/var/www/html/html-folder-in-server/build` location in server

## Step 5 - Setup a Gitlab runner (One time setup)
We need a runner to run our CI/CD pipeline jobs. This step is optional if a runner is already configured for your group in Gitlab. 

To setup a new Gitlab group runner
1. Install Gitlab Runner in any server with atleast 2GB of RAM using the steps from the [documentation](https://docs.gitlab.com/runner/install/). The server should be separate from where Gitlab is installed for security reasons.
2. Go to your group's __Settings > CI/CD__ 
3. Expand the __Runners__ section.
4. Under the __Set up a group runner manually__ section, copy the url and token
5. Then register the runner in your server using steps from [documentation](https://docs.gitlab.com/runner/register/index.html)
  - Provide default image as `ubuntu` and empty tags
6. Once the runner is registered, go back to the __Runners__ section in Gitlab to see the runner appear under __Available runners__ section

Push the `.gitlab-ci.yml` and `deploy/deploy.sh` files to master to start the automated deployment.

When the deployment is complete, you should see a green checkmark in the repository home page similar to 
![Pipeline Status Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3yjjkz0hz3ihpz84rtkm.png)

You can click the status icon to go to the pipeline and then to the individual job to see the command line output of your script

## Troubleshooting
- If the job is not scheduled, make sure you have setup a runner and that the runner is active. Also check the runner parameters like `active`, `protected` and `tags` to see if any of the conditions are incorrect.
- If the job fails to produce a build output due to memory allocation issue, try increasing the memory of the server which hosts the runner. 

## References
- https://medium.com/devops-with-valentine/deploy-over-ssh-from-gitlab-ci-pipeline-6a0d7b87e4a
- https://medium.com/@hfally/a-gitlab-ci-config-to-deploy-to-your-server-via-ssh-43bf3cf93775
- https://codeburst.io/gitlab-build-and-push-to-a-server-via-ssh-6d27ca1bf7b4
- https://erangad.medium.com/create-ci-cd-pipeline-for-nodejs-express-with-gitlab-6c420a956b10
Enter fullscreen mode Exit fullscreen mode

Top comments (5)

Collapse
 
megha_khateek_aec27554ca7 profile image
Megha Khateek

This guide was exactly what I needed! I was struggling to figure out how to deploy my React app using GitLab CI/CD, and this step-by-step tutorial made it so much easier to understand. I had been stuck for days on setting up the SSH keys and configuring the pipeline, but now I can confidently push changes to my master branch and have everything automatically deployed to my server.

One thing I found particularly helpful was the section on adding the GitLab SSH public key to the server. That was the missing link for me! It saved me a lot of time, so I really appreciate this tutorial.

Also, if you need help installing NGINX on a newer version of Ubuntu like 24.04, I found this useful guide on upgrading PHP with Nginx. It really helped me sort out some server-side issues while working with NGINX.

Thanks for putting this together, it was a huge time-saver!

Collapse
 
ritik_raj_eb4e6e986982918 profile image
Ritik Raj

This is an excellent and comprehensive guide on setting up a CI/CD pipeline for deploying React apps using GitLab. The use of SSH keys for secure server access and caching node_modules to improve build speed are particularly well-explained. For anyone configuring NGINX as part of their deployment, I found this guide on installing NGINX on Ubuntu 24.04 incredibly useful.

Additionally, if you're exploring automation or troubleshooting your GitLab Runner, the documentation on setting up GitLab Runners is a must-read. Thank you for sharing such a practical approach to managing deployments!"

Collapse
 
ezalivadnyi profile image
Eugene Zalivadnyi

What can happen if we will use the same server for gitalb-runner and production?

Collapse
 
huylv profile image
Lê Vũ Huy

I got this error
$ ssh-add <(echo "$SSH_PRIVATE_KEY")
Error loading key "/dev/fd/63": error in libcrypto

Collapse
 
xpcrts profile image
Phok Chanrithisak • Edited

Where & how to see the result? Is it using server ip address follow with port 3000?